Last active
February 11, 2022 08:44
-
-
Save unitycoder/7120e492deba748dba3d4e1e424d3c2a to your computer and use it in GitHub Desktop.
Unity Ray Marching with Sphere Tracing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// unity ray marching with sphere marching : https://unitycoder.com/blog/2019/05/06/ray-marching/ | |
// based on Ray Marching tutorial from The Coding Train https://www.youtube.com/watch?v=-6iIc6-Y-kk | |
using System.Collections; | |
using System.Collections.Generic; | |
using UnityEngine; | |
public class RayMarchingSpheres : MonoBehaviour | |
{ | |
// place spheres under this root gameobject | |
public Transform sphereRoot; | |
// how many raymarch steps | |
public int rayMarchSteps = 10; | |
// list of step spheres | |
List<Sphere> rayPoints = new List<Sphere>(); | |
bool isSearching = true; | |
void Update() | |
{ | |
if (isSearching == false) return; | |
isSearching = false; | |
// build ray to mouse (2D) | |
var origin = Vector3.zero; | |
var mousePos = Camera.main.ScreenToWorldPoint(Input.mousePosition); | |
mousePos.z = 0; | |
var dir = (mousePos - origin).normalized; | |
var ray = new Ray(origin, dir); | |
// start from origin | |
var currentPos = ray.origin; | |
rayPoints.Clear(); | |
float totalDistance = 0; | |
// raymarching steps | |
for (int i = 0; i < rayMarchSteps; i++) | |
{ | |
float smallestDistance = Mathf.Infinity; | |
// find closest distance from currentPos sphere from spheres | |
foreach (Transform t in sphereRoot) | |
{ | |
var sphere = new Sphere(); | |
sphere.pos = t.position; | |
// NOTE giving fixed radius, using default unity sphere | |
sphere.r = 1f / 2f; | |
var d = SignedDistance(currentPos, sphere); | |
if (d < smallestDistance) smallestDistance = d; | |
} | |
// hit close enough, then stop marching | |
if (smallestDistance < 0.001f) | |
{ | |
isSearching = false; | |
break; | |
} | |
// keep track of total distance | |
totalDistance += smallestDistance; | |
// record existing circle | |
var s = new Sphere(); | |
s.pos = currentPos; | |
s.r = 1f / 2f; | |
s.minDist = smallestDistance; | |
rayPoints.Add(s); | |
// get next point position | |
var newPos = ray.GetPoint(totalDistance); | |
Debug.DrawLine(currentPos, newPos, rayPoints.Count % 2 == 0 ? Color.cyan : Color.yellow); | |
currentPos = newPos; | |
// draw cross at new currentpost | |
var c = rayPoints.Count % 2 == 0 ? Color.red : Color.blue; | |
Debug.DrawRay(currentPos, Vector3.up * 0.1f, c); | |
Debug.DrawRay(currentPos, -Vector3.up * 0.1f, c); | |
Debug.DrawRay(currentPos, Vector3.right * 0.1f, c); | |
Debug.DrawRay(currentPos, -Vector3.right * 0.1f, c); | |
} | |
} | |
// draw spheres | |
public void OnDrawGizmos() | |
{ | |
Gizmos.color = Color.green; | |
for (int i = 0, length = rayPoints.Count; i < length; i++) | |
{ | |
Gizmos.DrawWireSphere(rayPoints[i].pos, rayPoints[i].minDist); | |
} | |
isSearching = true; | |
} | |
// signed distance to sphere | |
float SignedDistance(Vector3 startPos, Sphere sphere) | |
{ | |
var d = Vector3.Distance(startPos, sphere.pos); | |
return d - sphere.r; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using UnityEngine; | |
public struct Sphere | |
{ | |
public Vector3 pos; | |
public float r; | |
public float minDist; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment