Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
117 changes: 88 additions & 29 deletions examples/jsm/utils/BufferGeometryUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,27 @@ import {
Vector3,
} from 'three';

/** @module BufferGeometryUtils */

/**
* Computes vertex tangents using the MikkTSpace algorithm. MikkTSpace generates the same tangents consistently,
* and is used in most modelling tools and normal map bakers. Use MikkTSpace for materials with normal maps,
* because inconsistent tangents may lead to subtle visual issues in the normal map, particularly around mirrored
* UV seams.
*
* In comparison to this method, {@link BufferGeometry#computeTangents} (a custom algorithm) generates tangents that
* probably will not match the tangents in other software. The custom algorithm is sufficient for general use with a
* custom material, and may be faster than MikkTSpace.
*
* Returns the original BufferGeometry. Indexed geometries will be de-indexed. Requires position, normal, and uv attributes.
*
* @param {BufferGeometry} geometry - The geometry to compute tangents for.
* @param {Object} MikkTSpace - Instance of `examples/jsm/libs/mikktspace.module.js`, or `mikktspace` npm package.
* Aawait `MikkTSpace.ready` before use.
* @param {boolean} [negateSign=true] - Whether to negate the sign component (.w) of each tangent.
* Required for normal map conventions in some formats, including glTF.
* @return {BufferGeometry} The updated geometry.
*/
function computeMikkTSpaceTangents( geometry, MikkTSpace, negateSign = true ) {

if ( ! MikkTSpace || ! MikkTSpace.isReady ) {
Expand Down Expand Up @@ -100,9 +121,11 @@ function computeMikkTSpaceTangents( geometry, MikkTSpace, negateSign = true ) {
}

/**
* @param {Array<BufferGeometry>} geometries
* @param {boolean} useGroups
* @return {?BufferGeometry}
* Merges a set of geometries into a single instance. All geometries must have compatible attributes.
*
* @param {Array<BufferGeometry>} geometries - The geometries to merge.
* @param {boolean} [useGroups=false] - Whether to use groups or not.
* @return {?BufferGeometry} The merged geometry. Returns `null` if the merge does not succeed.
*/
function mergeGeometries( geometries, useGroups = false ) {

Expand Down Expand Up @@ -296,8 +319,11 @@ function mergeGeometries( geometries, useGroups = false ) {
}

/**
* @param {Array<BufferAttribute>} attributes
* @return {?BufferAttribute}
* Merges a set of attributes into a single instance. All attributes must have compatible properties and types.
* Instances of {@link InterleavedBufferAttribute} are not supported.
*
* @param {Array<BufferAttribute>} attributes - The attributes to merge.
* @return {?BufferAttribute} The merged attribute. Returns `null` if the merge does not succeed.
*/
function mergeAttributes( attributes ) {

Expand Down Expand Up @@ -389,10 +415,12 @@ function mergeAttributes( attributes ) {
}

/**
* @param {BufferAttribute} attribute
* @return {BufferAttribute}
* Performs a deep clone of the given buffer attribute.
*
* @param {BufferAttribute} attribute - The attribute to clone.
* @return {BufferAttribute} The cloned attribute.
*/
export function deepCloneAttribute( attribute ) {
function deepCloneAttribute( attribute ) {

if ( attribute.isInstancedInterleavedBufferAttribute || attribute.isInterleavedBufferAttribute ) {

Expand All @@ -411,8 +439,11 @@ export function deepCloneAttribute( attribute ) {
}

/**
* @param {Array<BufferAttribute>} attributes
* @return {Array<InterleavedBufferAttribute>}
* Interleaves a set of attributes and returns a new array of corresponding attributes that share a
* single {@link InterleavedBuffer} instance. All attributes must have compatible types.
*
* @param {Array<BufferAttribute>} attributes - The attributes to interleave.
* @return {Array<InterleavedBufferAttribute>} An array of interleaved attributes. If interleave does not succeed, the method returns `null`.
*/
function interleaveAttributes( attributes ) {

Expand Down Expand Up @@ -475,8 +506,13 @@ function interleaveAttributes( attributes ) {

}

// returns a new, non-interleaved version of the provided attribute
export function deinterleaveAttribute( attribute ) {
/**
* Returns a new, non-interleaved version of the given attribute.
*
* @param {InterleavedBufferAttribute} attribute - The interleaved attribute.
* @return {BufferAttribute} The non-interleaved attribute.
*/
function deinterleaveAttribute( attribute ) {

const cons = attribute.data.array.constructor;
const count = attribute.count;
Expand Down Expand Up @@ -523,8 +559,12 @@ export function deinterleaveAttribute( attribute ) {

}

// deinterleaves all attributes on the geometry
export function deinterleaveGeometry( geometry ) {
/**
* Deinterleaves all attributes on the given geometry.
*
* @param {BufferGeometry} geometry - The geometry to deinterleave.
*/
function deinterleaveGeometry( geometry ) {

const attributes = geometry.attributes;
const morphTargets = geometry.morphTargets;
Expand Down Expand Up @@ -567,8 +607,10 @@ export function deinterleaveGeometry( geometry ) {
}

/**
* @param {BufferGeometry} geometry
* @return {number}
* Returns the amount of bytes used by all attributes to represent the geometry.
*
* @param {BufferGeometry} geometry - The geometry.
* @return {number} The estimate bytes used.
*/
function estimateBytesUsed( geometry ) {

Expand All @@ -590,9 +632,11 @@ function estimateBytesUsed( geometry ) {
}

/**
* @param {BufferGeometry} geometry
* @param {number} tolerance
* @return {BufferGeometry}
* Returns a new geometry with vertices for which all similar vertex attributes (within tolerance) are merged.
*
* @param {BufferGeometry} geometry - The geometry to merge vertices for.
* @param {number} [tolerance=1e-4] - The tolerance value.
* @return {BufferGeometry} - The new geometry with merged vertices.
*/
function mergeVertices( geometry, tolerance = 1e-4 ) {

Expand Down Expand Up @@ -753,9 +797,12 @@ function mergeVertices( geometry, tolerance = 1e-4 ) {
}

/**
* @param {BufferGeometry} geometry
* @param {number} drawMode
* @return {BufferGeometry}
* Returns a new indexed geometry based on `TrianglesDrawMode` draw mode.
* This mode corresponds to the `gl.TRIANGLES` primitive in WebGL.
*
* @param {BufferGeometry} geometry - The geometry to convert.
* @param {number} drawMode - The current draw mode.
* @return {BufferGeometry} The new geometry using `TrianglesDrawMode`.
*/
function toTrianglesDrawMode( geometry, drawMode ) {

Expand Down Expand Up @@ -864,9 +911,13 @@ function toTrianglesDrawMode( geometry, drawMode ) {

/**
* Calculates the morphed attributes of a morphed/skinned BufferGeometry.
* Helpful for Raytracing or Decals.
* @param {Mesh | Line | Points} object An instance of Mesh, Line or Points.
* @return {Object} An Object with original position/normal attributes and morphed ones.
*
* Helpful for Raytracing or Decals (i.e. a `DecalGeometry` applied to a morphed Object with a `BufferGeometry`
* will use the original `BufferGeometry`, not the morphed/skinned one, generating an incorrect result.
* Using this function to create a shadow `Object3`D the `DecalGeometry` can be correctly generated).
*
* @param {Mesh|Line|Points} object - The 3D object tocompute morph attributes for.
* @return {Object} An object with original position/normal attributes and morphed ones.
*/
function computeMorphedAttributes( object ) {

Expand Down Expand Up @@ -1142,6 +1193,12 @@ function computeMorphedAttributes( object ) {

}

/**
* Merges the {@link BufferGeometry#groups} for the given geometry.
*
* @param {BufferGeometry} geometry - The geometry to modify.
* @return {BufferGeometry} - The updated geometry
*/
function mergeGroups( geometry ) {

if ( geometry.groups.length === 0 ) {
Expand Down Expand Up @@ -1244,15 +1301,14 @@ function mergeGroups( geometry ) {

}


/**
* Modifies the supplied geometry if it is non-indexed, otherwise creates a new,
* non-indexed geometry. Returns the geometry with smooth normals everywhere except
* faces that meet at an angle greater than the crease angle.
*
* @param {BufferGeometry} geometry
* @param {number} [creaseAngle]
* @return {BufferGeometry}
* @param {BufferGeometry} geometry - The geometry to modify.
* @param {number} [creaseAngle=Math.PI/3] - The crease angle in radians.
* @return {BufferGeometry} - The updated geometry
*/
function toCreasedNormals( geometry, creaseAngle = Math.PI / 3 /* 60 degrees */ ) {

Expand Down Expand Up @@ -1363,6 +1419,9 @@ export {
computeMikkTSpaceTangents,
mergeGeometries,
mergeAttributes,
deepCloneAttribute,
deinterleaveAttribute,
deinterleaveGeometry,
interleaveAttributes,
estimateBytesUsed,
mergeVertices,
Expand Down
17 changes: 10 additions & 7 deletions examples/jsm/utils/CameraUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import {
Vector3
} from 'three';

/** @module CameraUtils */

const _va = /*@__PURE__*/ new Vector3(), // from pe to pa
_vb = /*@__PURE__*/ new Vector3(), // from pe to pb
_vc = /*@__PURE__*/ new Vector3(), // from pe to pc
Expand All @@ -14,16 +16,17 @@ const _va = /*@__PURE__*/ new Vector3(), // from pe to pa
_quat = /*@__PURE__*/ new Quaternion(); // temporary quaternion


/** Set a PerspectiveCamera's projectionMatrix and quaternion
/**
* Set projection matrix and the orientation of a perspective camera
* to exactly frame the corners of an arbitrary rectangle.
* NOTE: This function ignores the standard parameters;
* do not call updateProjectionMatrix() after this!
* do not call `updateProjectionMatrix()` after this.
*
* @param {PerspectiveCamera} camera
* @param {Vector3} bottomLeftCorner
* @param {Vector3} bottomRightCorner
* @param {Vector3} topLeftCorner
* @param {boolean} [estimateViewFrustum=false]
* @param {PerspectiveCamera} camera - The camera.
* @param {Vector3} bottomLeftCorner - The bottom-left corner point.
* @param {Vector3} bottomRightCorner - The bottom-right corner point.
* @param {Vector3} topLeftCorner - The top-left corner point.
* @param {boolean} [estimateViewFrustum=false] - If set to `true`, the function tries to estimate the camera's FOV.
*/
function frameCorners( camera, bottomLeftCorner, bottomRightCorner, topLeftCorner, estimateViewFrustum = false ) {

Expand Down
50 changes: 20 additions & 30 deletions examples/jsm/utils/GeometryCompressionUtils.js
Original file line number Diff line number Diff line change
@@ -1,41 +1,35 @@
/**
* Octahedron and Quantization encodings based on work by:
*
* @link https://github.com/tsherif/mesh-quantization-example
*
*/

import {
BufferAttribute,
Matrix3,
Matrix4,
Vector3
} from 'three';

/** @module GeometryCompressionUtils */

// Octahedron and Quantization encodings based on work by: https://github.com/tsherif/mesh-quantization-example

/**
* Make the input geometry's normal attribute encoded and compressed by 3 different methods.
*
* @param {THREE.BufferGeometry} geometry
* @param {string} encodeMethod "DEFAULT" || "OCT1Byte" || "OCT2Byte" || "ANGLES"
* Compressed the given geometry's `normal` attribute by the selected encode method.
*
* @param {BufferGeometry} geometry - The geometry whose normals should be compressed.
* @param {('DEFAULT'|'OCT1Byte'|'OCT2Byte'|'ANGLES')} encodeMethod - The compression method.
*/
function compressNormals( geometry, encodeMethod ) {

const normal = geometry.attributes.normal;

if ( ! normal ) {

console.error( 'Geometry must contain normal attribute. ' );
console.error( 'THREE.GeometryCompressionUtils.compressNormals(): Geometry must contain normal attribute.' );

}

if ( normal.isPacked ) return;

if ( normal.itemSize != 3 ) {

console.error( 'normal.itemSize is not 3, which cannot be encoded. ' );
console.error( 'THREE.GeometryCompressionUtils.compressNormals(): normal.itemSize is not 3, which cannot be encoded.' );

}

Expand Down Expand Up @@ -63,11 +57,10 @@ function compressNormals( geometry, encodeMethod ) {

} else if ( encodeMethod == 'OCT1Byte' ) {

/**
* It is not recommended to use 1-byte octahedron normals encoding unless you want to extremely reduce the memory usage
* As it makes vertex data not aligned to a 4 byte boundary which may harm some WebGL implementations and sometimes the normal distortion is visible
* Please refer to @zeux 's comments in https://github.com/mrdoob/three.js/pull/18208
*/

// It is not recommended to use 1-byte octahedron normals encoding unless you want to extremely reduce the memory usage
// As it makes vertex data not aligned to a 4 byte boundary which may harm some WebGL implementations and sometimes the normal distortion is visible
// Please refer to @zeux 's comments in https://github.com/mrdoob/three.js/pull/18208

result = new Int8Array( count * 2 );

Expand Down Expand Up @@ -127,28 +120,26 @@ function compressNormals( geometry, encodeMethod ) {

}


/**
* Make the input geometry's position attribute encoded and compressed.
*
* @param {THREE.BufferGeometry} geometry
*
*/
* Compressed the given geometry's `position` attribute.
*
* @param {BufferGeometry} geometry - The geometry whose position values should be compressed.
*/
function compressPositions( geometry ) {

const position = geometry.attributes.position;

if ( ! position ) {

console.error( 'Geometry must contain position attribute. ' );
console.error( 'THREE.GeometryCompressionUtils.compressPositions(): Geometry must contain position attribute.' );

}

if ( position.isPacked ) return;

if ( position.itemSize != 3 ) {

console.error( 'position.itemSize is not 3, which cannot be packed. ' );
console.error( 'THREE.GeometryCompressionUtils.compressPositions(): position.itemSize is not 3, which cannot be packed.' );

}

Expand All @@ -171,18 +162,17 @@ function compressPositions( geometry ) {
}

/**
* Make the input geometry's uv attribute encoded and compressed.
*
* @param {THREE.BufferGeometry} geometry
* Compressed the given geometry's `uv` attribute.
*
* @param {BufferGeometry} geometry - The geometry whose texture coordinates should be compressed.
*/
function compressUvs( geometry ) {

const uvs = geometry.attributes.uv;

if ( ! uvs ) {

console.error( 'Geometry must contain uv attribute. ' );
console.error( 'THREE.GeometryCompressionUtils.compressUvs(): Geometry must contain uv attribute.' );

}

Expand Down
Loading
Loading