Explorar el Código

USDComposer: add Camera prim parsing

Mr.doob hace 3 días
padre
commit
8d9c591c1c
Se han modificado 1 ficheros con 117 adiciones y 0 borrados
  1. 117 0
      examples/jsm/loaders/usd/USDComposer.js

+ 117 - 0
examples/jsm/loaders/usd/USDComposer.js

@@ -11,6 +11,8 @@ import {
 	MirroredRepeatWrapping,
 	NoColorSpace,
 	Object3D,
+	OrthographicCamera,
+	PerspectiveCamera,
 	Quaternion,
 	QuaternionKeyframeTrack,
 	RepeatWrapping,
@@ -44,6 +46,19 @@ const SpecType = {
 	VariantSet: 11
 };
 
+// UsdGeomCamera fallback values (OpenUSD schema)
+const USD_CAMERA_DEFAULTS = {
+	projection: 'perspective',
+	clippingRange: [ 1, 1000000 ],
+	horizontalAperture: 20.955,
+	verticalAperture: 15.2908,
+	horizontalApertureOffset: 0,
+	verticalApertureOffset: 0,
+	focalLength: 50,
+	focusDistance: 0,
+	fStop: 0
+};
+
 /**
  * USDComposer handles scene composition from parsed USD data.
  * This includes reference resolution, variant selection, transform handling,
@@ -657,6 +672,15 @@ class USDComposer {
 
 				}
 
+			} else if ( typeName === 'Camera' ) {
+
+				const obj = this._buildCamera( path );
+				obj.name = name;
+				const attrs = this._getAttributes( path );
+				this.applyTransform( obj, spec.fields, attrs );
+				parent.add( obj );
+				this._buildHierarchy( obj, path );
+
 			} else if ( typeName === 'Material' || typeName === 'Shader' || typeName === 'GeomSubset' ) {
 
 				// Skip materials/shaders/subsets, they're referenced by meshes
@@ -1191,6 +1215,99 @@ class USDComposer {
 
 	}
 
+	/**
+	 * Build a camera from a Camera spec.
+	 */
+	_buildCamera( path ) {
+
+		const attrs = this._getAttributes( path );
+		const projectionToken = attrs[ 'projection' ];
+		const projection = typeof projectionToken === 'string'
+			? projectionToken.toLowerCase()
+			: USD_CAMERA_DEFAULTS.projection;
+		const clippingRange = attrs[ 'clippingRange' ] || USD_CAMERA_DEFAULTS.clippingRange;
+		const near = Math.max(
+			Number.EPSILON,
+			this._parseNumber( clippingRange[ 0 ], USD_CAMERA_DEFAULTS.clippingRange[ 0 ] )
+		);
+		const far = Math.max(
+			near + Number.EPSILON,
+			this._parseNumber( clippingRange[ 1 ], USD_CAMERA_DEFAULTS.clippingRange[ 1 ] )
+		);
+		const horizontalAperture = this._parseNumber(
+			attrs[ 'horizontalAperture' ],
+			USD_CAMERA_DEFAULTS.horizontalAperture
+		);
+		const verticalAperture = this._parseNumber(
+			attrs[ 'verticalAperture' ],
+			USD_CAMERA_DEFAULTS.verticalAperture
+		);
+		const horizontalApertureOffset = this._parseNumber(
+			attrs[ 'horizontalApertureOffset' ],
+			USD_CAMERA_DEFAULTS.horizontalApertureOffset
+		);
+		const verticalApertureOffset = this._parseNumber(
+			attrs[ 'verticalApertureOffset' ],
+			USD_CAMERA_DEFAULTS.verticalApertureOffset
+		);
+		const focalLength = this._parseNumber( attrs[ 'focalLength' ], USD_CAMERA_DEFAULTS.focalLength );
+		const focusDistance = this._parseNumber( attrs[ 'focusDistance' ], USD_CAMERA_DEFAULTS.focusDistance );
+		const fStop = this._parseNumber( attrs[ 'fStop' ], USD_CAMERA_DEFAULTS.fStop );
+
+		let camera;
+
+		if ( projection === 'orthographic' ) {
+
+			// USD orthographic apertures are in tenths of a world unit.
+			const width = horizontalAperture / 10;
+			const height = verticalAperture / 10;
+			const offsetX = horizontalApertureOffset / 10;
+			const offsetY = verticalApertureOffset / 10;
+
+			camera = new OrthographicCamera(
+				offsetX - width * 0.5,
+				offsetX + width * 0.5,
+				offsetY + height * 0.5,
+				offsetY - height * 0.5,
+				near,
+				far
+			);
+
+		} else {
+
+			const safeVerticalAperture = Math.max( Number.EPSILON, verticalAperture );
+			const safeFocalLength = Math.max( Number.EPSILON, focalLength );
+			const aspect = horizontalAperture / safeVerticalAperture;
+			const fov = 2 * Math.atan( safeVerticalAperture / ( 2 * safeFocalLength ) ) * 180 / Math.PI;
+
+			camera = new PerspectiveCamera( fov, aspect, near, far );
+			camera.filmGauge = Math.max( horizontalAperture, verticalAperture );
+			camera.filmOffset = horizontalApertureOffset;
+			camera.focus = focusDistance;
+			camera.setFocalLength( safeFocalLength );
+
+			if ( verticalApertureOffset !== 0 ) {
+
+				// Three.js supports only horizontal film offset directly.
+				camera.userData.verticalApertureOffset = verticalApertureOffset;
+
+			}
+
+		}
+
+		camera.userData.fStop = fStop;
+		camera.userData.usdProjection = projection;
+		return camera;
+
+	}
+
+	_parseNumber( value, fallback ) {
+
+		const n = Number( value );
+		return Number.isFinite( n ) ? n : fallback;
+
+	}
+
 	_getGeomSubsets( meshPath ) {
 
 		const subsets = [];

粤ICP备19079148号