提交 c12c9a16 编写于 作者: M Mr.doob

r138 (bis) (bis)

上级 473c7e67
......@@ -38,7 +38,6 @@
this.maxPolarAngle = Math.PI; // radians
this.pointerSpeed = 1.0;
const scope = this;
function onMouseMove( event ) {
......
( function () {
/**
* @author sciecode / https://github.com/sciecode
*
* EXR format references:
* https://www.openexr.com/documentation/openexrfilelayout.pdf
*/
const textEncoder = new TextEncoder();
const NO_COMPRESSION = 0;
const ZIPS_COMPRESSION = 2;
const ZIP_COMPRESSION = 3;
class EXRExporter {
parse( renderer, renderTarget, options ) {
if ( ! supported( renderer, renderTarget ) ) return undefined;
const info = buildInfo( renderTarget, options ),
dataBuffer = getPixelData( renderer, renderTarget, info ),
rawContentBuffer = reorganizeDataBuffer( dataBuffer, info ),
chunks = compressData( rawContentBuffer, info );
return fillData( chunks, info );
}
}
function supported( renderer, renderTarget ) {
if ( ! renderer || ! renderer.isWebGLRenderer ) {
console.error( 'EXRExporter.parse: Unsupported first parameter, expected instance of WebGLRenderer.' );
return false;
}
if ( ! renderTarget || ! renderTarget.isWebGLRenderTarget ) {
console.error( 'EXRExporter.parse: Unsupported second parameter, expected instance of WebGLRenderTarget.' );
return false;
}
if ( renderTarget.texture.type !== THREE.FloatType && renderTarget.texture.type !== THREE.HalfFloatType ) {
console.error( 'EXRExporter.parse: Unsupported WebGLRenderTarget texture type.' );
return false;
}
if ( renderTarget.texture.format !== THREE.RGBAFormat ) {
console.error( 'EXRExporter.parse: Unsupported WebGLRenderTarget texture format, expected THREE.RGBAFormat.' );
return false;
}
return true;
}
function buildInfo( renderTarget, options = {} ) {
const compressionSizes = {
0: 1,
2: 1,
3: 16
};
const WIDTH = renderTarget.width,
HEIGHT = renderTarget.height,
TYPE = renderTarget.texture.type,
FORMAT = renderTarget.texture.format,
ENCODING = renderTarget.texture.encoding,
COMPRESSION = options.compression !== undefined ? options.compression : ZIP_COMPRESSION,
EXPORTER_TYPE = options.type !== undefined ? options.type : THREE.HalfFloatType,
OUT_TYPE = EXPORTER_TYPE === THREE.FloatType ? 2 : 1,
COMPRESSION_SIZE = compressionSizes[ COMPRESSION ],
NUM_CHANNELS = 4;
return {
width: WIDTH,
height: HEIGHT,
type: TYPE,
format: FORMAT,
encoding: ENCODING,
compression: COMPRESSION,
blockLines: COMPRESSION_SIZE,
dataType: OUT_TYPE,
dataSize: 2 * OUT_TYPE,
numBlocks: Math.ceil( HEIGHT / COMPRESSION_SIZE ),
numInputChannels: 4,
numOutputChannels: NUM_CHANNELS
};
}
function getPixelData( renderer, rtt, info ) {
let dataBuffer;
if ( info.type === THREE.FloatType ) {
dataBuffer = new Float32Array( info.width * info.height * info.numInputChannels );
} else {
dataBuffer = new Uint16Array( info.width * info.height * info.numInputChannels );
}
renderer.readRenderTargetPixels( rtt, 0, 0, info.width, info.height, dataBuffer );
return dataBuffer;
}
function reorganizeDataBuffer( inBuffer, info ) {
const w = info.width,
h = info.height,
dec = {
r: 0,
g: 0,
b: 0,
a: 0
},
offset = {
value: 0
},
cOffset = info.numOutputChannels == 4 ? 1 : 0,
getValue = info.type == THREE.FloatType ? getFloat32 : getFloat16,
setValue = info.dataType == 1 ? setFloat16 : setFloat32,
outBuffer = new Uint8Array( info.width * info.height * info.numOutputChannels * info.dataSize ),
dv = new DataView( outBuffer.buffer );
for ( let y = 0; y < h; ++ y ) {
for ( let x = 0; x < w; ++ x ) {
const i = y * w * 4 + x * 4;
const r = getValue( inBuffer, i );
const g = getValue( inBuffer, i + 1 );
const b = getValue( inBuffer, i + 2 );
const a = getValue( inBuffer, i + 3 );
const line = ( h - y - 1 ) * w * ( 3 + cOffset ) * info.dataSize;
decodeLinear( dec, r, g, b, a );
offset.value = line + x * info.dataSize;
setValue( dv, dec.a, offset );
offset.value = line + cOffset * w * info.dataSize + x * info.dataSize;
setValue( dv, dec.b, offset );
offset.value = line + ( 1 + cOffset ) * w * info.dataSize + x * info.dataSize;
setValue( dv, dec.g, offset );
offset.value = line + ( 2 + cOffset ) * w * info.dataSize + x * info.dataSize;
setValue( dv, dec.r, offset );
}
}
return outBuffer;
}
function compressData( inBuffer, info ) {
let compress,
tmpBuffer,
sum = 0;
const chunks = {
data: new Array(),
totalSize: 0
},
size = info.width * info.numOutputChannels * info.blockLines * info.dataSize;
switch ( info.compression ) {
case 0:
compress = compressNONE;
break;
case 2:
case 3:
compress = compressZIP;
break;
}
if ( info.compression !== 0 ) {
tmpBuffer = new Uint8Array( size );
}
for ( let i = 0; i < info.numBlocks; ++ i ) {
const arr = inBuffer.subarray( size * i, size * ( i + 1 ) );
const block = compress( arr, tmpBuffer );
sum += block.length;
chunks.data.push( {
dataChunk: block,
size: block.length
} );
}
chunks.totalSize = sum;
return chunks;
}
function compressNONE( data ) {
return data;
}
function compressZIP( data, tmpBuffer ) {
//
// Reorder the pixel data.
//
let t1 = 0,
t2 = Math.floor( ( data.length + 1 ) / 2 ),
s = 0;
const stop = data.length - 1;
while ( true ) {
if ( s > stop ) break;
tmpBuffer[ t1 ++ ] = data[ s ++ ];
if ( s > stop ) break;
tmpBuffer[ t2 ++ ] = data[ s ++ ];
} //
// Predictor.
//
let p = tmpBuffer[ 0 ];
for ( let t = 1; t < tmpBuffer.length; t ++ ) {
const d = tmpBuffer[ t ] - p + ( 128 + 256 );
p = tmpBuffer[ t ];
tmpBuffer[ t ] = d;
}
if ( typeof fflate === 'undefined' ) {
console.error( 'THREE.EXRLoader: External \`fflate.module.js\` required' );
}
const deflate = fflate.zlibSync( tmpBuffer ); // eslint-disable-line no-undef
return deflate;
}
function fillHeader( outBuffer, chunks, info ) {
const offset = {
value: 0
};
const dv = new DataView( outBuffer.buffer );
setUint32( dv, 20000630, offset ); // magic
setUint32( dv, 2, offset ); // mask
// = HEADER =
setString( dv, 'compression', offset );
setString( dv, 'compression', offset );
setUint32( dv, 1, offset );
setUint8( dv, info.compression, offset );
setString( dv, 'screenWindowCenter', offset );
setString( dv, 'v2f', offset );
setUint32( dv, 8, offset );
setUint32( dv, 0, offset );
setUint32( dv, 0, offset );
setString( dv, 'screenWindowWidth', offset );
setString( dv, 'float', offset );
setUint32( dv, 4, offset );
setFloat32( dv, 1.0, offset );
setString( dv, 'pixelAspectRatio', offset );
setString( dv, 'float', offset );
setUint32( dv, 4, offset );
setFloat32( dv, 1.0, offset );
setString( dv, 'lineOrder', offset );
setString( dv, 'lineOrder', offset );
setUint32( dv, 1, offset );
setUint8( dv, 0, offset );
setString( dv, 'dataWindow', offset );
setString( dv, 'box2i', offset );
setUint32( dv, 16, offset );
setUint32( dv, 0, offset );
setUint32( dv, 0, offset );
setUint32( dv, info.width - 1, offset );
setUint32( dv, info.height - 1, offset );
setString( dv, 'displayWindow', offset );
setString( dv, 'box2i', offset );
setUint32( dv, 16, offset );
setUint32( dv, 0, offset );
setUint32( dv, 0, offset );
setUint32( dv, info.width - 1, offset );
setUint32( dv, info.height - 1, offset );
setString( dv, 'channels', offset );
setString( dv, 'chlist', offset );
setUint32( dv, info.numOutputChannels * 18 + 1, offset );
setString( dv, 'A', offset );
setUint32( dv, info.dataType, offset );
offset.value += 4;
setUint32( dv, 1, offset );
setUint32( dv, 1, offset );
setString( dv, 'B', offset );
setUint32( dv, info.dataType, offset );
offset.value += 4;
setUint32( dv, 1, offset );
setUint32( dv, 1, offset );
setString( dv, 'G', offset );
setUint32( dv, info.dataType, offset );
offset.value += 4;
setUint32( dv, 1, offset );
setUint32( dv, 1, offset );
setString( dv, 'R', offset );
setUint32( dv, info.dataType, offset );
offset.value += 4;
setUint32( dv, 1, offset );
setUint32( dv, 1, offset );
setUint8( dv, 0, offset ); // null-byte
setUint8( dv, 0, offset ); // = OFFSET TABLE =
let sum = offset.value + info.numBlocks * 8;
for ( let i = 0; i < chunks.data.length; ++ i ) {
setUint64( dv, sum, offset );
sum += chunks.data[ i ].size + 8;
}
}
function fillData( chunks, info ) {
const TableSize = info.numBlocks * 8,
HeaderSize = 259 + 18 * info.numOutputChannels,
// 259 + 18 * chlist
offset = {
value: HeaderSize + TableSize
},
outBuffer = new Uint8Array( HeaderSize + TableSize + chunks.totalSize + info.numBlocks * 8 ),
dv = new DataView( outBuffer.buffer );
fillHeader( outBuffer, chunks, info );
for ( let i = 0; i < chunks.data.length; ++ i ) {
const data = chunks.data[ i ].dataChunk;
const size = chunks.data[ i ].size;
setUint32( dv, i * info.blockLines, offset );
setUint32( dv, size, offset );
outBuffer.set( data, offset.value );
offset.value += size;
}
return outBuffer;
}
function decodeLinear( dec, r, g, b, a ) {
dec.r = r;
dec.g = g;
dec.b = b;
dec.a = a;
} // function decodeSRGB( dec, r, g, b, a ) {
// dec.r = r > 0.04045 ? Math.pow( r * 0.9478672986 + 0.0521327014, 2.4 ) : r * 0.0773993808;
// dec.g = g > 0.04045 ? Math.pow( g * 0.9478672986 + 0.0521327014, 2.4 ) : g * 0.0773993808;
// dec.b = b > 0.04045 ? Math.pow( b * 0.9478672986 + 0.0521327014, 2.4 ) : b * 0.0773993808;
// dec.a = a;
// }
function setUint8( dv, value, offset ) {
dv.setUint8( offset.value, value );
offset.value += 1;
}
function setUint32( dv, value, offset ) {
dv.setUint32( offset.value, value, true );
offset.value += 4;
}
function setFloat16( dv, value, offset ) {
dv.setUint16( offset.value, THREE.DataUtils.toHalfFloat( value ), true );
offset.value += 2;
}
function setFloat32( dv, value, offset ) {
dv.setFloat32( offset.value, value, true );
offset.value += 4;
}
function setUint64( dv, value, offset ) {
dv.setBigUint64( offset.value, BigInt( value ), true );
offset.value += 8;
}
function setString( dv, string, offset ) {
const tmp = textEncoder.encode( string + '\0' );
for ( let i = 0; i < tmp.length; ++ i ) {
setUint8( dv, tmp[ i ], offset );
}
}
function decodeFloat16( binary ) {
const exponent = ( binary & 0x7C00 ) >> 10,
fraction = binary & 0x03FF;
return ( binary >> 15 ? - 1 : 1 ) * ( exponent ? exponent === 0x1F ? fraction ? NaN : Infinity : Math.pow( 2, exponent - 15 ) * ( 1 + fraction / 0x400 ) : 6.103515625e-5 * ( fraction / 0x400 ) );
}
function getFloat16( arr, i ) {
return decodeFloat16( arr[ i ] );
}
function getFloat32( arr, i ) {
return arr[ i ];
}
THREE.EXRExporter = EXRExporter;
THREE.NO_COMPRESSION = NO_COMPRESSION;
THREE.ZIPS_COMPRESSION = ZIPS_COMPRESSION;
THREE.ZIP_COMPRESSION = ZIP_COMPRESSION;
} )();
......@@ -626,68 +626,55 @@
}
buildORMTexture( material ) {
buildMetalRoughTexture( metalnessMap, roughnessMap ) {
const occlusion = material.aoMap?.image;
const roughness = material.roughnessMap?.image;
const metalness = material.metalnessMap?.image;
if ( occlusion === roughness && roughness === metalness ) return material.aoMap;
if ( metalnessMap === roughnessMap ) return metalnessMap;
console.warn( 'THREE.GLTFExporter: Merged metalnessMap and roughnessMap textures.' );
const metalness = metalnessMap?.image;
const roughness = roughnessMap?.image;
const width = Math.max( metalness?.width || 0, roughness?.width || 0 );
const height = Math.max( metalness?.height || 0, roughness?.height || 0 );
const canvas = document.createElement( 'canvas' );
canvas.width = width;
canvas.height = height;
const context = canvas.getContext( '2d' );
context.fillStyle = '#00ffff';
context.fillRect( 0, 0, width, height );
const composite = context.getImageData( 0, 0, width, height );
if ( occlusion || roughness || metalness ) {
if ( metalness ) {
const width = Math.max( occlusion?.width || 0, roughness?.width || 0, metalness?.width || 0 );
const height = Math.max( occlusion?.height || 0, roughness?.height || 0, metalness?.height || 0 );
const canvas = document.createElement( 'canvas' );
canvas.width = width;
canvas.height = height;
const context = canvas.getContext( '2d' );
context.fillStyle = '#ffffff';
context.fillRect( 0, 0, width, height );
const composite = context.getImageData( 0, 0, width, height );
context.drawImage( metalness, 0, 0, width, height );
const data = context.getImageData( 0, 0, width, height ).data;
if ( occlusion ) {
for ( let i = 2; i < data.length; i += 4 ) {
context.drawImage( occlusion, 0, 0, width, height );
const data = context.getImageData( 0, 0, width, height ).data;
for ( let i = 0; i < data.length; i += 4 ) {
composite.data[ i ] = data[ i ];
}
composite.data[ i ] = data[ i ];
}
if ( roughness ) {
}
context.drawImage( roughness, 0, 0, width, height );
const data = context.getImageData( 0, 0, width, height ).data;
if ( roughness ) {
for ( let i = 1; i < data.length; i += 4 ) {
context.drawImage( roughness, 0, 0, width, height );
const data = context.getImageData( 0, 0, width, height ).data;
composite.data[ i ] = data[ i ];
for ( let i = 1; i < data.length; i += 4 ) {
}
composite.data[ i ] = data[ i ];
}
if ( metalness ) {
context.drawImage( metalness, 0, 0, width, height );
const data = context.getImageData( 0, 0, width, height ).data;
for ( let i = 2; i < data.length; i += 4 ) {
composite.data[ i ] = data[ i ];
}
}
}
context.putImageData( composite, 0, 0 ); //
context.putImageData( composite, 0, 0 );
return new THREE.Texture( canvas );
const reference = metalnessMap || roughnessMap;
const texture = reference.clone(); // TODO Use new Source() instead?
}
texture.source = new THREE.Texture( canvas ).source;
return texture;
}
/**
......@@ -933,11 +920,12 @@
* @param {Image} image to process
* @param {Integer} format of the image (THREE.RGBAFormat)
* @param {Boolean} flipY before writing out the image
* @param {String} mimeType export format
* @return {Integer} Index of the processed texture in the "images" array
*/
processImage( image, format, flipY ) {
processImage( image, format, flipY, mimeType = 'image/png' ) {
const writer = this;
const cache = writer.cache;
......@@ -946,7 +934,6 @@
const pending = writer.pending;
if ( ! cache.images.has( image ) ) cache.images.set( image, {} );
const cachedImages = cache.images.get( image );
const mimeType = 'image/png';
const key = mimeType + ':flipY/' + flipY.toString();
if ( cachedImages[ key ] !== undefined ) return cachedImages[ key ];
if ( ! json.images ) json.images = [];
......@@ -1068,9 +1055,11 @@
const json = this.json;
if ( cache.textures.has( map ) ) return cache.textures.get( map );
if ( ! json.textures ) json.textures = [];
let mimeType = map.userData.mimeType;
if ( mimeType === 'image/webp' ) mimeType = 'image/png';
const textureDef = {
sampler: this.processSampler( map ),
source: this.processImage( map.image, map.format, map.flipY )
source: this.processImage( map.image, map.format, map.flipY, mimeType )
};
if ( map.name ) textureDef.name = map.name;
......@@ -1136,16 +1125,16 @@
materialDef.pbrMetallicRoughness.metallicFactor = 0.5;
materialDef.pbrMetallicRoughness.roughnessFactor = 0.5;
}
} // pbrMetallicRoughness.metallicRoughnessTexture
const ormTexture = this.buildORMTexture( material ); // pbrMetallicRoughness.metallicRoughnessTexture
if ( material.metalnessMap || material.roughnessMap ) {
const metalRoughTexture = this.buildMetalRoughTexture( material.metalnessMap, material.roughnessMap );
const metalRoughMapDef = {
index: this.processTexture( ormTexture )
index: this.processTexture( metalRoughTexture )
};
this.applyTextureTransform( metalRoughMapDef, material.metalnessMap || material.roughnessMap );
this.applyTextureTransform( metalRoughMapDef, metalRoughTexture );
materialDef.pbrMetallicRoughness.metallicRoughnessTexture = metalRoughMapDef;
} // pbrMetallicRoughness.baseColorTexture or pbrSpecularGlossiness diffuseTexture
......@@ -1217,7 +1206,7 @@
if ( material.aoMap ) {
const occlusionMapDef = {
index: this.processTexture( ormTexture ),
index: this.processTexture( material.aoMap ),
texCoord: 1
};
......
( function () {
class OctreeHelper extends THREE.LineSegments {
constructor( octree, color = 0xffff00 ) {
const vertices = [];
function traverse( tree ) {
for ( let i = 0; i < tree.length; i ++ ) {
const min = tree[ i ].box.min;
const max = tree[ i ].box.max;
vertices.push( max.x, max.y, max.z );
vertices.push( min.x, max.y, max.z ); // 0, 1
vertices.push( min.x, max.y, max.z );
vertices.push( min.x, min.y, max.z ); // 1, 2
vertices.push( min.x, min.y, max.z );
vertices.push( max.x, min.y, max.z ); // 2, 3
vertices.push( max.x, min.y, max.z );
vertices.push( max.x, max.y, max.z ); // 3, 0
vertices.push( max.x, max.y, min.z );
vertices.push( min.x, max.y, min.z ); // 4, 5
vertices.push( min.x, max.y, min.z );
vertices.push( min.x, min.y, min.z ); // 5, 6
vertices.push( min.x, min.y, min.z );
vertices.push( max.x, min.y, min.z ); // 6, 7
vertices.push( max.x, min.y, min.z );
vertices.push( max.x, max.y, min.z ); // 7, 4
vertices.push( max.x, max.y, max.z );
vertices.push( max.x, max.y, min.z ); // 0, 4
vertices.push( min.x, max.y, max.z );
vertices.push( min.x, max.y, min.z ); // 1, 5
vertices.push( min.x, min.y, max.z );
vertices.push( min.x, min.y, min.z ); // 2, 6
vertices.push( max.x, min.y, max.z );
vertices.push( max.x, min.y, min.z ); // 3, 7
traverse( tree[ i ].subTrees );
}
}
traverse( octree.subTrees );
const geometry = new THREE.BufferGeometry();
geometry.setAttribute( 'position', new THREE.Float32BufferAttribute( vertices, 3 ) );
super( geometry, new THREE.LineBasicMaterial( {
color: color,
toneMapped: false
} ) );
this.octree = octree;
this.color = color;
this.type = 'OctreeHelper';
}
}
THREE.OctreeHelper = OctreeHelper;
} )();
( function () {
const vpTemp = new THREE.Vector4();
class ViewHelper extends THREE.Object3D {
constructor( editorCamera, dom ) {
super();
this.animating = false;
this.controls = null;
const color1 = new THREE.Color( '#ff3653' );
const color2 = new THREE.Color( '#8adb00' );
const color3 = new THREE.Color( '#2c8fff' );
const interactiveObjects = [];
const raycaster = new THREE.Raycaster();
const mouse = new THREE.Vector2();
const dummy = new THREE.Object3D();
const camera = new THREE.OrthographicCamera( - 2, 2, 2, - 2, 0, 4 );
camera.position.set( 0, 0, 2 );
const geometry = new THREE.BoxGeometry( 0.8, 0.05, 0.05 ).translate( 0.4, 0, 0 );
const xAxis = new THREE.Mesh( geometry, getAxisMaterial( color1 ) );
const yAxis = new THREE.Mesh( geometry, getAxisMaterial( color2 ) );
const zAxis = new THREE.Mesh( geometry, getAxisMaterial( color3 ) );
yAxis.rotation.z = Math.PI / 2;
zAxis.rotation.y = - Math.PI / 2;
this.add( xAxis );
this.add( zAxis );
this.add( yAxis );
const posXAxisHelper = new THREE.Sprite( getSpriteMaterial( color1, 'X' ) );
posXAxisHelper.userData.type = 'posX';
const posYAxisHelper = new THREE.Sprite( getSpriteMaterial( color2, 'Y' ) );
posYAxisHelper.userData.type = 'posY';
const posZAxisHelper = new THREE.Sprite( getSpriteMaterial( color3, 'Z' ) );
posZAxisHelper.userData.type = 'posZ';
const negXAxisHelper = new THREE.Sprite( getSpriteMaterial( color1 ) );
negXAxisHelper.userData.type = 'negX';
const negYAxisHelper = new THREE.Sprite( getSpriteMaterial( color2 ) );
negYAxisHelper.userData.type = 'negY';
const negZAxisHelper = new THREE.Sprite( getSpriteMaterial( color3 ) );
negZAxisHelper.userData.type = 'negZ';
posXAxisHelper.position.x = 1;
posYAxisHelper.position.y = 1;
posZAxisHelper.position.z = 1;
negXAxisHelper.position.x = - 1;
negXAxisHelper.scale.setScalar( 0.8 );
negYAxisHelper.position.y = - 1;
negYAxisHelper.scale.setScalar( 0.8 );
negZAxisHelper.position.z = - 1;
negZAxisHelper.scale.setScalar( 0.8 );
this.add( posXAxisHelper );
this.add( posYAxisHelper );
this.add( posZAxisHelper );
this.add( negXAxisHelper );
this.add( negYAxisHelper );
this.add( negZAxisHelper );
interactiveObjects.push( posXAxisHelper );
interactiveObjects.push( posYAxisHelper );
interactiveObjects.push( posZAxisHelper );
interactiveObjects.push( negXAxisHelper );
interactiveObjects.push( negYAxisHelper );
interactiveObjects.push( negZAxisHelper );
const point = new THREE.Vector3();
const dim = 128;
const turnRate = 2 * Math.PI; // turn rate in angles per second
this.render = function ( renderer ) {
this.quaternion.copy( editorCamera.quaternion ).invert();
this.updateMatrixWorld();
point.set( 0, 0, 1 );
point.applyQuaternion( editorCamera.quaternion );
if ( point.x >= 0 ) {
posXAxisHelper.material.opacity = 1;
negXAxisHelper.material.opacity = 0.5;
} else {
posXAxisHelper.material.opacity = 0.5;
negXAxisHelper.material.opacity = 1;
}
if ( point.y >= 0 ) {
posYAxisHelper.material.opacity = 1;
negYAxisHelper.material.opacity = 0.5;
} else {
posYAxisHelper.material.opacity = 0.5;
negYAxisHelper.material.opacity = 1;
}
if ( point.z >= 0 ) {
posZAxisHelper.material.opacity = 1;
negZAxisHelper.material.opacity = 0.5;
} else {
posZAxisHelper.material.opacity = 0.5;
negZAxisHelper.material.opacity = 1;
} //
const x = dom.offsetWidth - dim;
renderer.clearDepth();
renderer.getViewport( vpTemp );
renderer.setViewport( x, 0, dim, dim );
renderer.render( this, camera );
renderer.setViewport( vpTemp.x, vpTemp.y, vpTemp.z, vpTemp.w );
};
const targetPosition = new THREE.Vector3();
const targetQuaternion = new THREE.Quaternion();
const q1 = new THREE.Quaternion();
const q2 = new THREE.Quaternion();
let radius = 0;
this.handleClick = function ( event ) {
if ( this.animating === true ) return false;
const rect = dom.getBoundingClientRect();
const offsetX = rect.left + ( container.dom.offsetWidth - dim );
const offsetY = rect.top + ( container.dom.offsetHeight - dim );
mouse.x = ( event.clientX - offsetX ) / ( rect.width - offsetX ) * 2 - 1;
mouse.y = - ( ( event.clientY - offsetY ) / ( rect.bottom - offsetY ) ) * 2 + 1;
raycaster.setFromCamera( mouse, camera );
const intersects = raycaster.intersectObjects( interactiveObjects );
if ( intersects.length > 0 ) {
const intersection = intersects[ 0 ];
const object = intersection.object;
prepareAnimationData( object, this.controls.center );
this.animating = true;
return true;
} else {
return false;
}
};
this.update = function ( delta ) {
const step = delta * turnRate;
const focusPoint = this.controls.center; // animate position by doing a slerp and then scaling the position on the unit sphere
q1.rotateTowards( q2, step );
editorCamera.position.set( 0, 0, 1 ).applyQuaternion( q1 ).multiplyScalar( radius ).add( focusPoint ); // animate orientation
editorCamera.quaternion.rotateTowards( targetQuaternion, step );
if ( q1.angleTo( q2 ) === 0 ) {
this.animating = false;
}
};
function prepareAnimationData( object, focusPoint ) {
switch ( object.userData.type ) {
case 'posX':
targetPosition.set( 1, 0, 0 );
targetQuaternion.setFromEuler( new THREE.Euler( 0, Math.PI * 0.5, 0 ) );
break;
case 'posY':
targetPosition.set( 0, 1, 0 );
targetQuaternion.setFromEuler( new THREE.Euler( - Math.PI * 0.5, 0, 0 ) );
break;
case 'posZ':
targetPosition.set( 0, 0, 1 );
targetQuaternion.setFromEuler( new THREE.Euler() );
break;
case 'negX':
targetPosition.set( - 1, 0, 0 );
targetQuaternion.setFromEuler( new THREE.Euler( 0, - Math.PI * 0.5, 0 ) );
break;
case 'negY':
targetPosition.set( 0, - 1, 0 );
targetQuaternion.setFromEuler( new THREE.Euler( Math.PI * 0.5, 0, 0 ) );
break;
case 'negZ':
targetPosition.set( 0, 0, - 1 );
targetQuaternion.setFromEuler( new THREE.Euler( 0, Math.PI, 0 ) );
break;
default:
console.error( 'ViewHelper: Invalid axis.' );
} //
radius = editorCamera.position.distanceTo( focusPoint );
targetPosition.multiplyScalar( radius ).add( focusPoint );
dummy.position.copy( focusPoint );
dummy.lookAt( editorCamera.position );
q1.copy( dummy.quaternion );
dummy.lookAt( targetPosition );
q2.copy( dummy.quaternion );
}
function getAxisMaterial( color ) {
return new THREE.MeshBasicMaterial( {
color: color,
toneMapped: false
} );
}
function getSpriteMaterial( color, text = null ) {
const canvas = document.createElement( 'canvas' );
canvas.width = 64;
canvas.height = 64;
const context = canvas.getContext( '2d' );
context.beginPath();
context.arc( 32, 32, 16, 0, 2 * Math.PI );
context.closePath();
context.fillStyle = color.getStyle();
context.fill();
if ( text !== null ) {
context.font = '24px Arial';
context.textAlign = 'center';
context.fillStyle = '#000000';
context.fillText( text, 32, 41 );
}
const texture = new THREE.CanvasTexture( canvas );
return new THREE.SpriteMaterial( {
map: texture,
toneMapped: false
} );
}
}
}
ViewHelper.prototype.isViewHelper = true;
THREE.ViewHelper = ViewHelper;
} )();
......@@ -88,7 +88,7 @@
for ( file in zip ) {
if ( file.toLowerCase().substr( - 4 ) === '.amf' ) {
if ( file.toLowerCase().slice( - 4 ) === '.amf' ) {
break;
......
......@@ -1821,19 +1821,22 @@
let hasMorphPosition = false;
let hasMorphNormal = false;
let hasMorphColor = false;
for ( let i = 0, il = targets.length; i < il; i ++ ) {
const target = targets[ i ];
if ( target.POSITION !== undefined ) hasMorphPosition = true;
if ( target.NORMAL !== undefined ) hasMorphNormal = true;
if ( hasMorphPosition && hasMorphNormal ) break;
if ( target.COLOR_0 !== undefined ) hasMorphColor = true;
if ( hasMorphPosition && hasMorphNormal && hasMorphColor ) break;
}
if ( ! hasMorphPosition && ! hasMorphNormal ) return Promise.resolve( geometry );
if ( ! hasMorphPosition && ! hasMorphNormal && ! hasMorphColor ) return Promise.resolve( geometry );
const pendingPositionAccessors = [];
const pendingNormalAccessors = [];
const pendingColorAccessors = [];
for ( let i = 0, il = targets.length; i < il; i ++ ) {
......@@ -1853,14 +1856,23 @@
}
if ( hasMorphColor ) {
const pendingAccessor = target.COLOR_0 !== undefined ? parser.getDependency( 'accessor', target.COLOR_0 ) : geometry.attributes.color;
pendingColorAccessors.push( pendingAccessor );
}
}
return Promise.all( [ Promise.all( pendingPositionAccessors ), Promise.all( pendingNormalAccessors ) ] ).then( function ( accessors ) {
return Promise.all( [ Promise.all( pendingPositionAccessors ), Promise.all( pendingNormalAccessors ), Promise.all( pendingColorAccessors ) ] ).then( function ( accessors ) {
const morphPositions = accessors[ 0 ];
const morphNormals = accessors[ 1 ];
const morphColors = accessors[ 2 ];
if ( hasMorphPosition ) geometry.morphAttributes.position = morphPositions;
if ( hasMorphNormal ) geometry.morphAttributes.normal = morphNormals;
if ( hasMorphColor ) geometry.morphAttributes.color = morphColors;
geometry.morphTargetsRelative = true;
return geometry;
......@@ -1969,6 +1981,14 @@
}
}
function getImageURIMimeType( uri ) {
if ( uri.search( /\.jpe?g($|\?)/i ) > 0 || uri.search( /^data\:image\/jpeg/ ) === 0 ) return 'image/jpeg';
if ( uri.search( /\.webp($|\?)/i ) > 0 || uri.search( /^data\:image\/webp/ ) === 0 ) return 'image/webp';
return 'image/png';
}
/* GLTF PARSER */
......@@ -2671,6 +2691,7 @@
}
texture.userData.mimeType = sourceDef.mimeType || getImageURIMimeType( sourceDef.uri );
return texture;
} ).catch( function ( error ) {
......
......@@ -53,7 +53,7 @@
if ( node.nodeType !== 1 ) return;
const transform = getNodeTransform( node );
let traverseChildNodes = true;
let isDefsNode = false;
let path = null;
switch ( node.nodeName ) {
......@@ -105,7 +105,7 @@
break;
case 'defs':
traverseChildNodes = false;
isDefsNode = true;
break;
case 'use':
......@@ -147,16 +147,23 @@
}
if ( traverseChildNodes ) {
const childNodes = node.childNodes;
const nodes = node.childNodes;
for ( let i = 0; i < childNodes.length; i ++ ) {
for ( let i = 0; i < nodes.length; i ++ ) {
const node = childNodes[ i ];
parseNode( nodes[ i ], style );
if ( isDefsNode && node.nodeName !== 'style' && node.nodeName !== 'defs' ) {
// Ignore everything in defs except CSS style definitions
// and nested defs, because it is OK by the standard to have
// <style/> there.
continue;
}
parseNode( node, style );
}
if ( transform ) {
......
......@@ -102,17 +102,16 @@
if ( object.isCSS2DObject ) {
const visible = object.visible && _vector.z >= - 1 && _vector.z <= 1 && object.layers.test( camera.layers );
object.element.style.display = visible ? '' : 'none';
_vector.setFromMatrixPosition( object.matrixWorld );
if ( visible ) {
_vector.applyMatrix4( _viewProjectionMatrix );
object.onBeforeRender( _this, scene, camera );
_vector.setFromMatrixPosition( object.matrixWorld );
const visible = object.visible === true && _vector.z >= - 1 && _vector.z <= 1 && object.layers.test( camera.layers ) === true;
object.element.style.display = visible === true ? '' : 'none';
_vector.applyMatrix4( _viewProjectionMatrix );
if ( visible === true ) {
object.onBeforeRender( _this, scene, camera );
const element = object.element;
if ( /apple/i.test( navigator.vendor ) ) {
......
......@@ -181,10 +181,10 @@
if ( object.isCSS3DObject ) {
const visible = object.visible && object.layers.test( camera.layers );
object.element.style.display = visible ? '' : 'none'; // only getObjectCSSMatrix when object.visible
const visible = object.visible === true && object.layers.test( camera.layers ) === true;
object.element.style.display = visible === true ? '' : 'none';
if ( visible ) {
if ( visible === true ) {
object.onBeforeRender( _this, scene, camera );
let style;
......
{
"name": "three",
"version": "0.138.1",
"version": "0.138.2",
"description": "JavaScript 3D library",
"type": "module",
"main": "./build/three.js",
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册