From 56eb71c87d9783b1169e82bdc5ac0da366cd1c72 Mon Sep 17 00:00:00 2001 From: Michael Herzog Date: Thu, 18 Dec 2025 17:42:06 +0100 Subject: [PATCH] VRMLLoader: Add camera support. (#32580) --- examples/jsm/loaders/VRMLLoader.js | 77 ++++++++++++++++++++++++++++++ examples/models/vrml/camera.wrl | 51 ++++++++++++++++++++ examples/webgl_loader_vrml.html | 1 + 3 files changed, 129 insertions(+) create mode 100644 examples/models/vrml/camera.wrl diff --git a/examples/jsm/loaders/VRMLLoader.js b/examples/jsm/loaders/VRMLLoader.js index 91474dcb54de04..61164c73e6c625 100644 --- a/examples/jsm/loaders/VRMLLoader.js +++ b/examples/jsm/loaders/VRMLLoader.js @@ -18,10 +18,13 @@ import { LineSegments, Loader, LoaderUtils, + MathUtils, Mesh, MeshBasicMaterial, MeshPhongMaterial, Object3D, + OrthographicCamera, + PerspectiveCamera, Points, PointsMaterial, Quaternion, @@ -166,6 +169,7 @@ class VRMLLoader extends Loader { const nodeTypes = [ 'Anchor', 'Billboard', 'Collision', 'Group', 'Transform', // grouping nodes 'Inline', 'LOD', 'Switch', // special groups + 'PerspectiveCamera', 'OrthographicCamera', 'AudioClip', 'DirectionalLight', 'PointLight', 'Script', 'Shape', 'Sound', 'SpotLight', 'WorldInfo', // common nodes 'CylinderSensor', 'PlaneSensor', 'ProximitySensor', 'SphereSensor', 'TimeSensor', 'TouchSensor', 'VisibilitySensor', // sensors 'Box', 'Cone', 'Cylinder', 'ElevationGrid', 'Extrusion', 'IndexedFaceSet', 'IndexedLineSet', 'PointSet', 'Sphere', // geometries @@ -733,6 +737,11 @@ class VRMLLoader extends Loader { build = buildWorldInfoNode( node ); break; + case 'OrthographicCamera': + case 'PerspectiveCamera': + build = buildCamera( node, nodeName ); + break; + case 'Billboard': case 'Inline': @@ -1588,6 +1597,74 @@ class VRMLLoader extends Loader { } + function buildCamera( node, type ) { + + const camera = ( type === 'PerspectiveCamera' ) ? new PerspectiveCamera() : new OrthographicCamera(); + + const width = ( typeof window !== 'undefined' ) ? window.innerWidth : 1; + const height = ( typeof window !== 'undefined' ) ? window.innerHeight : 1; + const aspect = width / height; + + const fields = node.fields; + + for ( let i = 0, l = fields.length; i < l; i ++ ) { + + const field = fields[ i ]; + const fieldName = field.name; + const fieldValues = field.values; + + switch ( fieldName ) { + + case 'position': + camera.position.set( fieldValues[ 0 ], fieldValues[ 1 ], fieldValues[ 0 ] ); + break; + + case 'orientation': + const axis = new Vector3( fieldValues[ 0 ], fieldValues[ 1 ], fieldValues[ 2 ] ).normalize(); + const angle = fieldValues[ 3 ]; + camera.quaternion.setFromAxisAngle( axis, angle ); + break; + + case 'focalDistance': + camera.userData.focalDistance = fieldValues[ 0 ]; // might be useful for DoF + break; + + case 'heightAngle': + + // for perspective cams only + + camera.fov = MathUtils.radToDeg( fieldValues[ 0 ] ); + camera.aspect = aspect; + camera.updateProjectionMatrix(); + + break; + + case 'height': + + // for ortho cams only + + const halfHeight = fieldValues[ 0 ] / 2; + const halfWidth = halfHeight * aspect; + + camera.left = - halfWidth; + camera.right = halfWidth; + camera.top = halfHeight; + camera.bottom = - halfHeight; + camera.updateProjectionMatrix(); + break; + + default: + console.warn( 'THREE.VRMLLoader: Unknown field:', fieldName ); + break; + + } + + } + + return camera; + + } + function buildIndexedFaceSetNode( node ) { let color, coord, normal, texCoord; diff --git a/examples/models/vrml/camera.wrl b/examples/models/vrml/camera.wrl new file mode 100644 index 00000000000000..b41ec4f79e344b --- /dev/null +++ b/examples/models/vrml/camera.wrl @@ -0,0 +1,51 @@ +#VRML V2.0 utf8 + +DirectionalLight { + direction 1 0 -1 +} + +PerspectiveCamera { + position -8.6 2.1 5.6 + orientation -0.14 -1 -0.12 1.142 + focalDistance 10.84 + heightAngle 0.785398 +} + +OrthographicCamera { + position 8.6 2.1 -5.6 + orientation -0.14 -1 -0.12 -1.142 + focalDistance 10.84 + height 5 +} + +Transform { + translation 3 0 1 + children [ + Shape { + appearance Appearance { + material Material {diffuseColor 0 0 1} + } + geometry Sphere { + radius 2.3 + } + } + ] +} + +Transform { + translation 2 2.5 1.25 + children [ + Anchor { + url "https://threejs.org/" + description "three.js" + children [ + Shape { + appearance Appearance { + material Material {emissiveColor 1 1 0} + } + geometry Box {} + } + ] + } + ] +} \ No newline at end of file diff --git a/examples/webgl_loader_vrml.html b/examples/webgl_loader_vrml.html index e7a241543f3188..e8362c534177eb 100644 --- a/examples/webgl_loader_vrml.html +++ b/examples/webgl_loader_vrml.html @@ -52,6 +52,7 @@ 'meshWithTexture', 'pixelTexture', 'points', + 'camera' ]; let vrmlScene;