Skip to content

Conversation

@notrichardpeng
Copy link

@notrichardpeng notrichardpeng commented Mar 27, 2025

This is a sample that renders a 3D torus and box using ray marching and signed distance functions. Ray marching iteratively projects a ray in space and uses signed distance functions of various shapes to decide whether it has hit them:

def rayMarch(origin: Vec3[Float32], rayDirection: Vec3[Float32])(using AnimationInstant): Float32 =
  GSeq.gen[Float32](getDistance(origin), next = dist => {
    val currPosition = origin + (rayDirection * dist)
        val currDistance = getDistance(currPosition)
        dist + currDistance
    })
    .takeWhile(dist => dist > MIN_DIST && dist < MAX_DIST)
    .limit(MAX_STEPS)
    .lastOr(MAX_DIST)

The getDistance() function effectively renders the scene. It returns the distance to the nearest object in the scene. Since we have a torus and a box, we calculate the distance to both and return the minimum (we see whichever is nearest). We use a smooth min function to create a blending effect of the objects when they are close in distance. A similar smoothing technique is applied to blend the color of the two objects.

val torus = sdfTorus(p, TORUS_RADII, position)
val box = sdfBox(BOX_POSITION, BOX_SIZE, position)        
smoothMin(torus, box, 0.5f)

The lighting is calculated using getLight(), which uses the dot product of a vector from the light source to the surface of the object. The scene is animated using Cyfra's animation tools.

The following is the result:

output.mp4

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant