openrndr / orx

A growing library of assorted data structures, algorithms and utilities for OPENRNDR
https://openrndr.org
BSD 2-Clause "Simplified" License
118 stars 36 forks source link

[orx-camera] OrbitalCamera.isolated is missing a call to update() #321

Open hamoid opened 11 months ago

hamoid commented 11 months ago

Operating System

Any

OPENRNDR version

0.4.4-SNAPSHOT

ORX version

0.4.4-SNAPSHOT

Java version (if applicable)

No response

Describe the bug

Without a call to .update(timeDelta) OrbitalControls do not work.

This is not an issue if we extend(camera), but doing that does not allow the user to draw background items not affected by the camera. If we only extend(controls) then the controls do not work unless we manually call camera.update(seconds - lastSeconds) and keep track of lastSeconds ourselves.

To call update from OrbitalCamera.isolated() we need access to program. Passing program as an argument instead of drawer changes the API, so I'm not sure what the ideal solution is.

Steps to reproduce the bug

            val camera = OrbitalCamera()
            val controls = OrbitalControls(camera)
            // don't extend camera otherwise we can't draw 2D graphics
            // extend(camera)
            extend(controls)
            extend {
              // draw something with ortho projection here
              drawer.rectangle(drawer.bounds)

              camera.isolated(drawer) {
                // draw something in 3D, dragging the mouse does not rotate the camera
              }
            }
hamoid commented 11 months ago

Alternatively, I can update the readme to include an example of having 2D graphics behind the interactive camera.

hamoid commented 4 months ago

Here an example of drawing behind and in front of a 3D interactive layer.

hamoid commented 4 months ago

I tried the following approach:

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.compositor.compose
import org.openrndr.extra.compositor.draw
import org.openrndr.extra.compositor.layer
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()
        }

        val layers = compose {
            layer {
                draw {
                    // Draw in 2D on the back
                    drawer.circle(drawer.bounds.center, 200.0)
                }
            }
            layer {
                draw {
                    // Draw in 3D
                    camera.isolated(drawer) {
                        shadeStyle = gradientShading
                        vertexBuffer(box, DrawPrimitive.TRIANGLES)
                    }
                }
            }
            layer {
                draw {
                    // 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)
                }
            }
        }

        extend(camera)
        extend(controls)
        extend {
            layers.draw(drawer)
        }
    }
}

But as soon as extend(camera) is present, only the 3D layer is rendered, the other two layers are missing. Commenting out that extend reveals the missing layers, but it's no longer interactive. Probably makes sense because the extend can not be applied only to the middle layer.