Since camera.update(deltaTime) would no longer work (deltaTime no longer exists), I’m sharing a newer approach.
A fixed 2D circle in the background, an interactive 3D shape in the middle, and a fixed 2D ring on front of everything.

imports
import org.openrndr.application
import org.openrndr.color.ColorRGBa
import org.openrndr.draw.DrawPrimitive
import org.openrndr.draw.shadeStyle
import org.openrndr.extra.camera.OrbitalCamera
import org.openrndr.extra.camera.OrbitalControls
import org.openrndr.extra.camera.isolated
import org.openrndr.extra.meshgenerators.boxMesh
import org.openrndr.math.Vector3
fun main() = application {
program {
val box = boxMesh(50.0, 20.0, 5.0)
val camera = OrbitalCamera(Vector3.ONE * 20.0, Vector3.ZERO, 90.0, 0.1, 5000.0)
val controls = OrbitalControls(camera)
val gradientShading = shadeStyle {
fragmentTransform = """
vec3 c = sin(v_worldPosition * 0.1) * 0.5 + 0.5;
c = c * (dot(va_normal, vec3(0.1, 0.2, 0.8)) * 0.5 + 0.5);
x_fill = vec4(c, 1.0);
""".trimIndent()
}
var secondsLast = seconds
//extend(camera)
extend(controls)
extend {
camera.update(seconds - secondsLast)
secondsLast = seconds
// Draw in 2D on the back
drawer.circle(drawer.bounds.center, 200.0)
// Draw in 3D
camera.isolated(drawer) {
drawer.shadeStyle = gradientShading
drawer.vertexBuffer(box, DrawPrimitive.TRIANGLES)
}
// Draw in 2D on the front
drawer.strokeWeight = 4.0
drawer.shadeStyle = null
drawer.fill = null
drawer.stroke = ColorRGBa.WHITE
drawer.circle(drawer.bounds.center, 220.0)
}
}
}
Note: if you don’t need to revert back to 2D (ortho) mode, you can use
camera.applyTo(drawer)
instead of
camera.isolated(drawer) { ... }
which is a tiny bit faster.