[orx-camera] Add OrbitalManual, add instant parameter to OrbitalCamera functions
This commit is contained in:
@@ -35,6 +35,7 @@ class Camera2D : Extension, ChangeEvents {
|
|||||||
set(value) {
|
set(value) {
|
||||||
if (value && !field) {
|
if (value && !field) {
|
||||||
changed.trigger(Unit)
|
changed.trigger(Unit)
|
||||||
|
program.window.requestDraw()
|
||||||
}
|
}
|
||||||
field = value
|
field = value
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,9 @@ import org.openrndr.Program
|
|||||||
import org.openrndr.draw.Drawer
|
import org.openrndr.draw.Drawer
|
||||||
import org.openrndr.events.Event
|
import org.openrndr.events.Event
|
||||||
import org.openrndr.math.Vector3
|
import org.openrndr.math.Vector3
|
||||||
|
import kotlin.contracts.ExperimentalContracts
|
||||||
|
import kotlin.contracts.InvocationKind
|
||||||
|
import kotlin.contracts.contract
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extension that provides orbital camera view and controls.
|
* Extension that provides orbital camera view and controls.
|
||||||
@@ -42,6 +45,7 @@ class Orbital : Extension, ChangeEvents {
|
|||||||
val controls by lazy { OrbitalControls(camera, userInteraction, keySpeed) }
|
val controls by lazy { OrbitalControls(camera, userInteraction, keySpeed) }
|
||||||
|
|
||||||
override fun setup(program: Program) {
|
override fun setup(program: Program) {
|
||||||
|
camera.setup(program)
|
||||||
controls.setup(program)
|
controls.setup(program)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -52,4 +56,12 @@ class Orbital : Extension, ChangeEvents {
|
|||||||
override fun afterDraw(drawer: Drawer, program: Program) {
|
override fun afterDraw(drawer: Drawer, program: Program) {
|
||||||
camera.afterDraw(drawer, program)
|
camera.afterDraw(drawer, program)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@OptIn(ExperimentalContracts::class)
|
||||||
|
fun isolated(drawFunction: Drawer.() -> Unit) {
|
||||||
|
contract {
|
||||||
|
callsInPlace(drawFunction, InvocationKind.EXACTLY_ONCE)
|
||||||
|
}
|
||||||
|
camera.isolated(camera.program.drawer, drawFunction)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -9,6 +9,7 @@ import org.openrndr.math.Matrix44
|
|||||||
import org.openrndr.math.Spherical
|
import org.openrndr.math.Spherical
|
||||||
import org.openrndr.math.Vector3
|
import org.openrndr.math.Vector3
|
||||||
import kotlin.math.abs
|
import kotlin.math.abs
|
||||||
|
import kotlin.math.max
|
||||||
import kotlin.math.pow
|
import kotlin.math.pow
|
||||||
import org.openrndr.math.transforms.lookAt as lookAt_
|
import org.openrndr.math.transforms.lookAt as lookAt_
|
||||||
|
|
||||||
@@ -27,6 +28,7 @@ class OrbitalCamera(
|
|||||||
var projectionType: ProjectionType = ProjectionType.PERSPECTIVE
|
var projectionType: ProjectionType = ProjectionType.PERSPECTIVE
|
||||||
) : Extension, ChangeEvents {
|
) : Extension, ChangeEvents {
|
||||||
|
|
||||||
|
internal lateinit var program: Program
|
||||||
override val changed = Event<Unit>()
|
override val changed = Event<Unit>()
|
||||||
|
|
||||||
override val hasChanged: Boolean
|
override val hasChanged: Boolean
|
||||||
@@ -63,6 +65,14 @@ class OrbitalCamera(
|
|||||||
var orthoNear = -1000.0
|
var orthoNear = -1000.0
|
||||||
var orthoFar = 1000.0
|
var orthoFar = 1000.0
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the view for the orbital camera by updating the look-at position, spherical coordinates,
|
||||||
|
* and field of view (FOV). This method initializes both the target and current states of these properties.
|
||||||
|
*
|
||||||
|
* @param lookAt the target position the camera should look at, represented as a 3D vector
|
||||||
|
* @param spherical the spherical coordinates defining the camera's orientation
|
||||||
|
* @param fov the field of view (in degrees) for the camera
|
||||||
|
*/
|
||||||
fun setView(lookAt: Vector3, spherical: Spherical, fov: Double) {
|
fun setView(lookAt: Vector3, spherical: Spherical, fov: Double) {
|
||||||
this.lookAt = lookAt
|
this.lookAt = lookAt
|
||||||
this.lookAtEnd = lookAt
|
this.lookAtEnd = lookAt
|
||||||
@@ -72,82 +82,232 @@ class OrbitalCamera(
|
|||||||
this.fovEnd = fov
|
this.fovEnd = fov
|
||||||
}
|
}
|
||||||
|
|
||||||
fun rotate(rotX: Double, rotY: Double) {
|
|
||||||
sphericalEnd += Spherical(rotX, rotY, 0.0)
|
/**
|
||||||
|
* Rotates the orbital camera by the specified angles in the horizontal and vertical directions.
|
||||||
|
* The rotation can be applied instantly or smoothly interpolated over time.
|
||||||
|
*
|
||||||
|
* @param degreesX the rotation angle in degrees around the horizontal axis (theta)
|
||||||
|
* @param degreesY the rotation angle in degrees around the vertical axis (phi)
|
||||||
|
* @param instant whether the rotation is applied immediately; if false, it interpolates over time (default is false)
|
||||||
|
*/
|
||||||
|
fun rotate(degreesX: Double, degreesY: Double, instant: Boolean = false) {
|
||||||
|
sphericalEnd += Spherical(degreesX, degreesY, 0.0)
|
||||||
sphericalEnd = sphericalEnd.makeSafe()
|
sphericalEnd = sphericalEnd.makeSafe()
|
||||||
|
if (instant) {
|
||||||
|
spherical = sphericalEnd
|
||||||
|
}
|
||||||
dirty = true
|
dirty = true
|
||||||
}
|
}
|
||||||
|
|
||||||
fun rotateTo(rotX: Double, rotY: Double) {
|
/**
|
||||||
sphericalEnd = sphericalEnd.copy(theta = rotX, phi = rotY)
|
* Rotates the camera to the specified spherical angles. The rotation can occur instantly or
|
||||||
|
* smoothly over time based on the `instant` parameter.
|
||||||
|
*
|
||||||
|
* @param degreesX the target horizontal rotation angle (theta) in degrees
|
||||||
|
* @param degreesY the target vertical rotation angle (phi) in degrees
|
||||||
|
* @param instant whether the rotation should be applied immediately (default is `false`)
|
||||||
|
*/
|
||||||
|
fun rotateTo(degreesX: Double, degreesY: Double, instant: Boolean = false) {
|
||||||
|
sphericalEnd = sphericalEnd.copy(theta = degreesX, phi = degreesY)
|
||||||
sphericalEnd = sphericalEnd.makeSafe()
|
sphericalEnd = sphericalEnd.makeSafe()
|
||||||
|
|
||||||
|
if (instant) {
|
||||||
|
spherical = sphericalEnd
|
||||||
|
}
|
||||||
dirty = true
|
dirty = true
|
||||||
}
|
}
|
||||||
|
|
||||||
fun rotateTo(eye: Vector3) {
|
/**
|
||||||
|
* Rotates the orbital camera to the specified position defined by the `eye` vector.
|
||||||
|
* The rotation can either occur instantly or smoothly interpolated over time,
|
||||||
|
* depending on the `instant` parameter.
|
||||||
|
*
|
||||||
|
* @param eye the target position to rotate the camera to, represented as a 3D vector
|
||||||
|
* @param instant whether the rotation should be applied immediately (default is `false`)
|
||||||
|
*/
|
||||||
|
fun rotateTo(eye: Vector3, instant: Boolean = false) {
|
||||||
sphericalEnd = Spherical.fromVector(eye)
|
sphericalEnd = Spherical.fromVector(eye)
|
||||||
sphericalEnd = sphericalEnd.makeSafe()
|
sphericalEnd = sphericalEnd.makeSafe()
|
||||||
|
if (instant) {
|
||||||
|
spherical = sphericalEnd
|
||||||
|
}
|
||||||
dirty = true
|
dirty = true
|
||||||
}
|
}
|
||||||
|
|
||||||
fun dollyIn() {
|
/**
|
||||||
|
* Zooms the camera in by decreasing the distance to the target. The zoom is based on
|
||||||
|
* an exponential scale factor determined by the `zoomSpeed` field. If the `instant`
|
||||||
|
* parameter is set to `true`, the zoom effect is applied immediately; otherwise, it
|
||||||
|
* will interpolate the change over time.
|
||||||
|
*
|
||||||
|
* @param instant whether the zoom-in effect should occur instantly (default is `false`)
|
||||||
|
*/
|
||||||
|
fun dollyIn(instant: Boolean = false) {
|
||||||
val zoomScale = pow(0.95, zoomSpeed)
|
val zoomScale = pow(0.95, zoomSpeed)
|
||||||
dolly(sphericalEnd.radius * zoomScale - sphericalEnd.radius)
|
dolly(sphericalEnd.radius * zoomScale - sphericalEnd.radius, instant)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun dollyOut() {
|
/**
|
||||||
|
* Zooms the camera out by increasing the distance to the target. The zoom operation
|
||||||
|
* is based on an exponential scale factor determined by the `zoomSpeed` field.
|
||||||
|
*
|
||||||
|
* @param instant whether the zoom-out effect should occur instantly (default is `false`)
|
||||||
|
*/
|
||||||
|
fun dollyOut(instant: Boolean = false) {
|
||||||
val zoomScale = pow(0.95, zoomSpeed)
|
val zoomScale = pow(0.95, zoomSpeed)
|
||||||
dolly(sphericalEnd.radius / zoomScale - sphericalEnd.radius)
|
dolly(sphericalEnd.radius / zoomScale - sphericalEnd.radius, instant)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun dolly(distance: Double) {
|
/**
|
||||||
|
* Adjusts the camera's distance from the target by the specified amount.
|
||||||
|
* The change in distance is applied immediately if `instant` is set to `true`,
|
||||||
|
* otherwise it will be interpolated over time with smoothing.
|
||||||
|
*
|
||||||
|
* @param distance the amount to adjust the camera's distance by
|
||||||
|
* @param instant whether the adjustment should be applied immediately (default is `false`)
|
||||||
|
*/
|
||||||
|
fun dolly(distance: Double, instant: Boolean = false) {
|
||||||
sphericalEnd += Spherical(0.0, 0.0, distance)
|
sphericalEnd += Spherical(0.0, 0.0, distance)
|
||||||
|
if (instant) {
|
||||||
|
spherical = sphericalEnd
|
||||||
|
}
|
||||||
dirty = true
|
dirty = true
|
||||||
}
|
}
|
||||||
|
|
||||||
fun pan(x: Double, y: Double, z: Double) {
|
fun pan(x: Double, y: Double, z: Double, instant: Boolean = false) {
|
||||||
val view = viewMatrix()
|
val view = viewMatrix()
|
||||||
val xColumn = Vector3(view.c0r0, view.c1r0, view.c2r0) * x
|
val xColumn = Vector3(view.c0r0, view.c1r0, view.c2r0) * x
|
||||||
val yColumn = Vector3(view.c0r1, view.c1r1, view.c2r1) * y
|
val yColumn = Vector3(view.c0r1, view.c1r1, view.c2r1) * y
|
||||||
val zColumn = Vector3(view.c0r2, view.c1r2, view.c2r2) * z
|
val zColumn = Vector3(view.c0r2, view.c1r2, view.c2r2) * z
|
||||||
lookAtEnd += xColumn + yColumn + zColumn
|
lookAtEnd += xColumn + yColumn + zColumn
|
||||||
|
if (instant) {
|
||||||
|
lookAt = lookAtEnd
|
||||||
|
}
|
||||||
dirty = true
|
dirty = true
|
||||||
}
|
}
|
||||||
|
|
||||||
fun panTo(target: Vector3) {
|
|
||||||
|
/**
|
||||||
|
* Smoothly pans the camera to a specified target position. If the `instant` parameter is set
|
||||||
|
* to `true`, the panning occurs immediately; otherwise, it will be interpolated over time.
|
||||||
|
*
|
||||||
|
* @param target the target position to pan the camera to, represented as a 3D vector
|
||||||
|
* @param instant whether the panning should occur instantly (default is `false`)
|
||||||
|
*/
|
||||||
|
fun panTo(target: Vector3, instant: Boolean = false) {
|
||||||
lookAtEnd = target
|
lookAtEnd = target
|
||||||
|
if (instant) {
|
||||||
|
lookAt = lookAtEnd
|
||||||
|
}
|
||||||
dirty = true
|
dirty = true
|
||||||
}
|
}
|
||||||
|
|
||||||
fun dollyTo(distance: Double) {
|
/**
|
||||||
|
* Adjusts the camera's distance (radius) to the specified value. If the `instant` parameter
|
||||||
|
* is set to true, the distance change is applied immediately; otherwise, it will be interpolated
|
||||||
|
* over time during updates.
|
||||||
|
*
|
||||||
|
* @param distance the target distance (radius) that the camera should move to
|
||||||
|
* @param instant whether the distance adjustment should occur instantly (default is `false`)
|
||||||
|
*/
|
||||||
|
fun dollyTo(distance: Double, instant: Boolean = false) {
|
||||||
sphericalEnd = sphericalEnd.copy(radius = distance)
|
sphericalEnd = sphericalEnd.copy(radius = distance)
|
||||||
|
if (instant) {
|
||||||
|
spherical = sphericalEnd
|
||||||
|
}
|
||||||
dirty = true
|
dirty = true
|
||||||
}
|
}
|
||||||
|
|
||||||
fun scale(s: Double) {
|
/**
|
||||||
magnitudeEnd += s
|
* Adjusts the magnitude of the orbital camera by the specified scale factor.
|
||||||
|
* If the `instant` parameter is set to true, the adjustment is applied immediately;
|
||||||
|
* otherwise, it will be interpolated over time during updates.
|
||||||
|
*
|
||||||
|
* @param scale the amount by which to adjust the camera's magnitude
|
||||||
|
* @param instant whether the scale adjustment should be applied instantly (default is `false`)
|
||||||
|
*/
|
||||||
|
fun scale(scale: Double, instant: Boolean = false) {
|
||||||
|
magnitudeEnd += scale
|
||||||
|
if (instant) {
|
||||||
|
magnitude = magnitudeEnd
|
||||||
|
}
|
||||||
dirty = true
|
dirty = true
|
||||||
}
|
}
|
||||||
|
|
||||||
fun scaleTo(s: Double) {
|
/**
|
||||||
magnitudeEnd = s
|
* Adjusts the camera's scaling factor to the specified value. The scaling can either
|
||||||
|
* be applied instantly or interpolated over time during updates.
|
||||||
|
*
|
||||||
|
* @param scale the target scaling factor for the camera
|
||||||
|
* @param instant whether the scaling should be applied instantly (default is `false`)
|
||||||
|
*/
|
||||||
|
|
||||||
|
fun scaleTo(scale: Double, instant: Boolean = false) {
|
||||||
|
magnitudeEnd = scale
|
||||||
|
if (instant) {
|
||||||
|
magnitude = magnitudeEnd
|
||||||
|
}
|
||||||
dirty = true
|
dirty = true
|
||||||
}
|
}
|
||||||
|
|
||||||
fun zoom(degrees: Double) {
|
/**
|
||||||
|
* Adjusts the camera's field of view (FOV) by the specified number of degrees. The transition can either
|
||||||
|
* happen instantly or be interpolated over time during updates.
|
||||||
|
*
|
||||||
|
* @param degrees the number of degrees to adjust the field of view by
|
||||||
|
* @param instant whether the adjustment should occur instantly (default is `false`)
|
||||||
|
*/
|
||||||
|
fun zoom(degrees: Double, instant: Boolean = false) {
|
||||||
fovEnd += degrees
|
fovEnd += degrees
|
||||||
|
if (instant) {
|
||||||
|
fov = fovEnd
|
||||||
|
}
|
||||||
dirty = true
|
dirty = true
|
||||||
}
|
}
|
||||||
|
|
||||||
fun zoomTo(degrees: Double) {
|
/**
|
||||||
|
* Adjusts the camera's field of view (FOV) to the specified number of degrees. If the `instant`
|
||||||
|
* parameter is set to `true`, the FOV immediately transitions to the specified value; otherwise,
|
||||||
|
* it will be interpolated over time during updates.
|
||||||
|
*
|
||||||
|
* @param degrees the target field of view (in degrees) for the camera
|
||||||
|
* @param instant whether the transition to the target FOV should occur instantly (default is `false`)
|
||||||
|
*/
|
||||||
|
fun zoomTo(degrees: Double, instant: Boolean = false) {
|
||||||
fovEnd = degrees
|
fovEnd = degrees
|
||||||
|
if (instant) {
|
||||||
|
fov = fovEnd
|
||||||
|
}
|
||||||
dirty = true
|
dirty = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the orbital camera state by iteratively applying updates to the camera's parameters
|
||||||
|
* based on a fixed time step. The method ensures smooth interpolation of the camera properties
|
||||||
|
* (e.g., position, orientation) over a specified time delta.
|
||||||
|
*
|
||||||
|
* @param timeDelta the time elapsed for which the camera state should be updated, in seconds
|
||||||
|
*/
|
||||||
fun update(timeDelta: Double) {
|
fun update(timeDelta: Double) {
|
||||||
if (!dirty) return
|
if (!dirty) return
|
||||||
dirty = false
|
dirty = false
|
||||||
|
|
||||||
|
val stepSize = 1.0/60.0
|
||||||
|
val steps = max(timeDelta/stepSize, 1.0).toInt()
|
||||||
|
for (step in 0 until steps) {
|
||||||
|
updateStep(stepSize)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the camera position, orientation, and view properties such as spherical coordinates,
|
||||||
|
* look-at point, field of view, and magnitude based on damping factors and time delta.
|
||||||
|
*
|
||||||
|
* @param timeDelta the time step used to update the interpolation of camera parameters
|
||||||
|
*/
|
||||||
|
fun updateStep(timeDelta: Double) {
|
||||||
|
|
||||||
val dampingFactor = if (dampingFactor > 0.0) {
|
val dampingFactor = if (dampingFactor > 0.0) {
|
||||||
dampingFactor * timeDelta / 0.0060
|
dampingFactor * timeDelta / 0.0060
|
||||||
} else 1.0
|
} else 1.0
|
||||||
@@ -179,6 +339,12 @@ class OrbitalCamera(
|
|||||||
spherical = spherical.makeSafe()
|
spherical = spherical.makeSafe()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Computes and returns the view matrix for the orbital camera. The view matrix is
|
||||||
|
* calculated using the current spherical coordinates, look-at position, and the up vector (Vector3.UNIT_Y).
|
||||||
|
*
|
||||||
|
* @return a 4x4 matrix representing the current view transformation of the camera
|
||||||
|
*/
|
||||||
fun viewMatrix(): Matrix44 {
|
fun viewMatrix(): Matrix44 {
|
||||||
return lookAt_(Vector3.fromSpherical(spherical) + lookAt, lookAt, Vector3.UNIT_Y)
|
return lookAt_(Vector3.fromSpherical(spherical) + lookAt, lookAt, Vector3.UNIT_Y)
|
||||||
}
|
}
|
||||||
@@ -190,9 +356,24 @@ class OrbitalCamera(
|
|||||||
// EXTENSION
|
// EXTENSION
|
||||||
override var enabled: Boolean = true
|
override var enabled: Boolean = true
|
||||||
|
|
||||||
override fun beforeDraw(drawer: Drawer, program: Program) {
|
override fun setup(program: Program) {
|
||||||
|
this.program = program
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun beforeDraw(drawer: Drawer, program: Program) {
|
||||||
drawer.pushTransforms()
|
drawer.pushTransforms()
|
||||||
|
applyTo(drawer)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun afterDraw(drawer: Drawer, program: Program) {
|
||||||
|
drawer.popTransforms()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enables the perspective camera. Use this faster method instead of .isolated()
|
||||||
|
* if you don't need to revert back to the orthographic projection.
|
||||||
|
*/
|
||||||
|
fun OrbitalCamera.applyTo(drawer: Drawer) {
|
||||||
|
|
||||||
if (lastSeconds == -1.0) lastSeconds = program.seconds
|
if (lastSeconds == -1.0) lastSeconds = program.seconds
|
||||||
|
|
||||||
@@ -200,12 +381,21 @@ class OrbitalCamera(
|
|||||||
lastSeconds = program.seconds
|
lastSeconds = program.seconds
|
||||||
|
|
||||||
update(delta)
|
update(delta)
|
||||||
applyTo(drawer)
|
|
||||||
|
if (projectionType == ProjectionType.PERSPECTIVE) {
|
||||||
|
drawer.perspective(fov, drawer.width.toDouble() / drawer.height, near, far)
|
||||||
|
} else {
|
||||||
|
val ar = drawer.width * 1.0 / drawer.height
|
||||||
|
drawer.ortho(-ar * magnitude, ar * magnitude, -1.0 * magnitude, 1.0 * magnitude, orthoNear, orthoFar)
|
||||||
|
}
|
||||||
|
drawer.view = viewMatrix()
|
||||||
|
|
||||||
|
if (depthTest) {
|
||||||
|
drawer.drawStyle.depthWrite = true
|
||||||
|
drawer.drawStyle.depthTestPass = DepthTestPass.LESS_OR_EQUAL
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun afterDraw(drawer: Drawer, program: Program) {
|
|
||||||
drawer.popTransforms()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -226,23 +416,18 @@ fun OrbitalCamera.isolated(drawer: Drawer, function: Drawer.() -> Unit) {
|
|||||||
drawer.popTransforms()
|
drawer.popTransforms()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private fun pow(a: Double, x: Double): Double = a.pow(x)
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enables the perspective camera. Use this faster method instead of .isolated()
|
* Creates an instance of the Orbital extension, sets it up with the calling Program,
|
||||||
* if you don't need to revert back to the orthographic projection.
|
* and returns the configured instance.
|
||||||
|
*
|
||||||
|
* @return a configured Orbital instance ready for use with the calling Program.
|
||||||
*/
|
*/
|
||||||
fun OrbitalCamera.applyTo(drawer: Drawer) {
|
fun Program.OrbitalManual(): Orbital {
|
||||||
if (projectionType == ProjectionType.PERSPECTIVE) {
|
val orbital = Orbital()
|
||||||
drawer.perspective(fov, drawer.width.toDouble() / drawer.height, near, far)
|
orbital.setup(this)
|
||||||
} else {
|
return orbital
|
||||||
val ar = drawer.width * 1.0 / drawer.height
|
}
|
||||||
drawer.ortho(-ar * magnitude, ar * magnitude, -1.0 * magnitude, 1.0 * magnitude, orthoNear, orthoFar)
|
|
||||||
}
|
|
||||||
drawer.view = viewMatrix()
|
|
||||||
|
|
||||||
if (depthTest) {
|
|
||||||
drawer.drawStyle.depthWrite = true
|
|
||||||
drawer.drawStyle.depthTestPass = DepthTestPass.LESS_OR_EQUAL
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun pow(a: Double, x: Double): Double = a.pow(x)
|
|
||||||
@@ -92,7 +92,7 @@ class ParametricOrbital : Extension, ChangeEvents {
|
|||||||
|
|
||||||
|
|
||||||
override fun setup(program: Program) {
|
override fun setup(program: Program) {
|
||||||
|
camera.setup(program)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun beforeDraw(drawer: Drawer, program: Program) {
|
override fun beforeDraw(drawer: Drawer, program: Program) {
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import org.openrndr.PresentationMode
|
||||||
import org.openrndr.application
|
import org.openrndr.application
|
||||||
import org.openrndr.color.ColorRGBa
|
import org.openrndr.color.ColorRGBa
|
||||||
import org.openrndr.draw.isolatedWithTarget
|
import org.openrndr.draw.isolatedWithTarget
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import org.openrndr.WindowMultisample
|
||||||
import org.openrndr.application
|
import org.openrndr.application
|
||||||
import org.openrndr.color.ColorRGBa
|
import org.openrndr.color.ColorRGBa
|
||||||
import org.openrndr.draw.DrawPrimitive
|
import org.openrndr.draw.DrawPrimitive
|
||||||
@@ -10,6 +11,11 @@ import org.openrndr.extra.meshgenerators.sphereMesh
|
|||||||
import org.openrndr.math.Vector3
|
import org.openrndr.math.Vector3
|
||||||
|
|
||||||
fun main() = application {
|
fun main() = application {
|
||||||
|
configure {
|
||||||
|
width = 720
|
||||||
|
height = 720
|
||||||
|
multisample = WindowMultisample.SampleCount(8)
|
||||||
|
}
|
||||||
program {
|
program {
|
||||||
val camera = OrbitalCamera(
|
val camera = OrbitalCamera(
|
||||||
Vector3.UNIT_Z * 90.0, Vector3.ZERO, 90.0, 0.1, 5000.0
|
Vector3.UNIT_Z * 90.0, Vector3.ZERO, 90.0, 0.1, 5000.0
|
||||||
@@ -33,7 +39,7 @@ fun main() = application {
|
|||||||
|
|
||||||
extend {
|
extend {
|
||||||
// mouse and keyboard input can be toggled on and off
|
// mouse and keyboard input can be toggled on and off
|
||||||
controls.userInteraction = seconds.toInt() % 4 < 2
|
controls.userInteraction = true
|
||||||
|
|
||||||
drawer.vertexBuffer(sphere, DrawPrimitive.LINE_LOOP)
|
drawer.vertexBuffer(sphere, DrawPrimitive.LINE_LOOP)
|
||||||
drawer.vertexBuffer(cube, DrawPrimitive.LINE_LOOP)
|
drawer.vertexBuffer(cube, DrawPrimitive.LINE_LOOP)
|
||||||
|
|||||||
49
orx-camera/src/jvmDemo/kotlin/DemoOrbitalManual01.kt
Normal file
49
orx-camera/src/jvmDemo/kotlin/DemoOrbitalManual01.kt
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
import org.openrndr.WindowMultisample
|
||||||
|
import org.openrndr.application
|
||||||
|
import org.openrndr.color.ColorRGBa
|
||||||
|
import org.openrndr.draw.DrawPrimitive
|
||||||
|
import org.openrndr.extra.camera.OrbitalManual
|
||||||
|
import org.openrndr.extra.meshgenerators.boxMesh
|
||||||
|
import org.openrndr.extra.meshgenerators.sphereMesh
|
||||||
|
import org.openrndr.math.Vector3
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Demonstrate the use of an orbital camera to render a sphere and a cube in 3D space as wireframe meshes, positioned
|
||||||
|
* and rendered independently using the camera's isolated drawing state. A stationary pink circle is also drawn in the
|
||||||
|
* center of the scene.
|
||||||
|
*
|
||||||
|
* Functionality:
|
||||||
|
* - Initializes a sphere mesh and a cube mesh with predefined dimensions.
|
||||||
|
* - Spawns an orbital camera, initially positioned away from the origin, to allow for focused rendering.
|
||||||
|
* - Renders 3D wireframe shapes (sphere and cube) using the camera's isolated perspective.
|
||||||
|
* - Draws a static 2D pink circle overlay at the window center.
|
||||||
|
*/
|
||||||
|
fun main() = application {
|
||||||
|
configure {
|
||||||
|
width = 720
|
||||||
|
height = 720
|
||||||
|
multisample = WindowMultisample.SampleCount(8)
|
||||||
|
}
|
||||||
|
|
||||||
|
program {
|
||||||
|
val sphere = sphereMesh(radius = 25.0)
|
||||||
|
val cube = boxMesh(20.0, 20.0, 5.0, 5, 5, 2)
|
||||||
|
|
||||||
|
val camera = OrbitalManual()
|
||||||
|
camera.camera.rotateTo(Vector3(0.0, 0.0, 30.0), instant = true)
|
||||||
|
extend {
|
||||||
|
camera.isolated {
|
||||||
|
drawer.fill = ColorRGBa.WHITE
|
||||||
|
drawer.vertexBuffer(sphere, DrawPrimitive.LINE_LOOP)
|
||||||
|
}
|
||||||
|
|
||||||
|
drawer.fill = ColorRGBa.PINK
|
||||||
|
drawer.circle(drawer.bounds.center, 250.0)
|
||||||
|
|
||||||
|
camera.isolated {
|
||||||
|
drawer.fill = ColorRGBa.WHITE
|
||||||
|
drawer.vertexBuffer(cube, DrawPrimitive.LINE_LOOP)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user