Often times, we'll want to access the actual ThreeJS objects that Threeagent is managing, so that we can leverage ThreeJS functionality. For instance, we might want to use ThreeJS's raycaster to pick objects in our scene, or use a physics simulation to directly drive the transformation of each object.
Threeagent provides a few ways to get access to the ThreeJS substrate.
The threeagent.core/render function returns a context map containing the core ThreeJS objects:
(let [ctx (th/render root-fn (.getElementById js/document "root"))]
(:threejs-renderer ctx) ; WebGPURenderer instance
(:threejs-scene ctx) ; Scene instance (primary scene)
(:threejs-default-camera ctx) ; Default PerspectiveCamera (primary scene)
(:canvas ctx) ; Canvas element
(:threejs-scenes ctx) ; Map of {scene-key -> Scene} for all scenes
(:scene-cameras ctx) ; Map of {scene-key -> Camera} for all scenes
(:threejs-render-pipeline ctx) ; RenderPipeline instance (if :render-pipeline provided)
(:frame-pacer ctx)) ; Frame pacer (if :auto-frame-pacing enabled)
The renderer is a WebGPURenderer from three/webgpu, which automatically falls back to WebGL 2 on browsers without WebGPU support.
When using multi-scene rendering, :threejs-scene and :threejs-default-camera refer to the primary scene (the first in :render-order). Use :threejs-scenes and :scene-cameras to access individual scenes by key.
We can set the :on-added and :on-removed of any entity to a callback function that will be invoked with
the ThreeJS object for that entity. The :on-added callback will be invoked after the object is first
added to the scene graph. The :on-removed callback will be invoked after the object is removed from the
scene graph.
There is also :ref which is an alias for :on-added.
The :entity-registry option allows you to maintain a map of entity IDs to their ThreeJS objects. Pass an
atom to the render function, and Threeagent will automatically populate it with entities that have an :id
property defined.
(def registry (atom {}))
(th/render
root-fn
(.getElementById js/document "root")
{:entity-registry registry})
Now entities with an :id property will be registered:
(defn my-scene []
[:object
[:box {:id :player-box :position [0 1 0]}]
[:sphere {:id :enemy-sphere :position [5 0 0]}]])
You can then access the ThreeJS objects directly by their ID:
(let [player-obj (get @registry :player-box)
enemy-obj (get @registry :enemy-sphere)]
;; Use ThreeJS objects directly
(.lookAt player-obj (.-position enemy-obj)))
This is useful for imperative operations, integrating with physics engines, or any case where you need direct access to specific ThreeJS objects by name.
For more advanced use cases, we can define custom ISystem and IEntityType implementations to create
and manage ThreeJS objects. See Extending Threeagent for more information.
Can you improve this documentation?Edit on GitHub
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |