webvr js meetup initial commit
This commit is contained in:
301
node_modules/three/examples/js/utils/GeometryUtils.js
generated
vendored
Normal file
301
node_modules/three/examples/js/utils/GeometryUtils.js
generated
vendored
Normal file
@@ -0,0 +1,301 @@
|
||||
/**
|
||||
* @author mrdoob / http://mrdoob.com/
|
||||
* @author alteredq / http://alteredqualia.com/
|
||||
*/
|
||||
|
||||
THREE.GeometryUtils = {
|
||||
|
||||
// Merge two geometries or geometry and geometry from object (using object's transform)
|
||||
|
||||
merge: function ( geometry1, geometry2, materialIndexOffset ) {
|
||||
|
||||
console.warn( 'THREE.GeometryUtils: .merge() has been moved to Geometry. Use geometry.merge( geometry2, matrix, materialIndexOffset ) instead.' );
|
||||
|
||||
var matrix;
|
||||
|
||||
if ( geometry2 instanceof THREE.Mesh ) {
|
||||
|
||||
geometry2.matrixAutoUpdate && geometry2.updateMatrix();
|
||||
|
||||
matrix = geometry2.matrix;
|
||||
geometry2 = geometry2.geometry;
|
||||
|
||||
}
|
||||
|
||||
geometry1.merge( geometry2, matrix, materialIndexOffset );
|
||||
|
||||
},
|
||||
|
||||
// Get random point in triangle (via barycentric coordinates)
|
||||
// (uniform distribution)
|
||||
// http://www.cgafaq.info/wiki/Random_Point_In_Triangle
|
||||
|
||||
randomPointInTriangle: function () {
|
||||
|
||||
var vector = new THREE.Vector3();
|
||||
|
||||
return function ( vectorA, vectorB, vectorC ) {
|
||||
|
||||
var point = new THREE.Vector3();
|
||||
|
||||
var a = Math.random();
|
||||
var b = Math.random();
|
||||
|
||||
if ( ( a + b ) > 1 ) {
|
||||
|
||||
a = 1 - a;
|
||||
b = 1 - b;
|
||||
|
||||
}
|
||||
|
||||
var c = 1 - a - b;
|
||||
|
||||
point.copy( vectorA );
|
||||
point.multiplyScalar( a );
|
||||
|
||||
vector.copy( vectorB );
|
||||
vector.multiplyScalar( b );
|
||||
|
||||
point.add( vector );
|
||||
|
||||
vector.copy( vectorC );
|
||||
vector.multiplyScalar( c );
|
||||
|
||||
point.add( vector );
|
||||
|
||||
return point;
|
||||
|
||||
};
|
||||
|
||||
}(),
|
||||
|
||||
// Get random point in face (triangle)
|
||||
// (uniform distribution)
|
||||
|
||||
randomPointInFace: function ( face, geometry ) {
|
||||
|
||||
var vA, vB, vC;
|
||||
|
||||
vA = geometry.vertices[ face.a ];
|
||||
vB = geometry.vertices[ face.b ];
|
||||
vC = geometry.vertices[ face.c ];
|
||||
|
||||
return THREE.GeometryUtils.randomPointInTriangle( vA, vB, vC );
|
||||
|
||||
},
|
||||
|
||||
// Get uniformly distributed random points in mesh
|
||||
// - create array with cumulative sums of face areas
|
||||
// - pick random number from 0 to total area
|
||||
// - find corresponding place in area array by binary search
|
||||
// - get random point in face
|
||||
|
||||
randomPointsInGeometry: function ( geometry, n ) {
|
||||
|
||||
var face, i,
|
||||
faces = geometry.faces,
|
||||
vertices = geometry.vertices,
|
||||
il = faces.length,
|
||||
totalArea = 0,
|
||||
cumulativeAreas = [],
|
||||
vA, vB, vC;
|
||||
|
||||
// precompute face areas
|
||||
|
||||
for ( i = 0; i < il; i ++ ) {
|
||||
|
||||
face = faces[ i ];
|
||||
|
||||
vA = vertices[ face.a ];
|
||||
vB = vertices[ face.b ];
|
||||
vC = vertices[ face.c ];
|
||||
|
||||
face._area = THREE.GeometryUtils.triangleArea( vA, vB, vC );
|
||||
|
||||
totalArea += face._area;
|
||||
|
||||
cumulativeAreas[ i ] = totalArea;
|
||||
|
||||
}
|
||||
|
||||
// binary search cumulative areas array
|
||||
|
||||
function binarySearchIndices( value ) {
|
||||
|
||||
function binarySearch( start, end ) {
|
||||
|
||||
// return closest larger index
|
||||
// if exact number is not found
|
||||
|
||||
if ( end < start )
|
||||
return start;
|
||||
|
||||
var mid = start + Math.floor( ( end - start ) / 2 );
|
||||
|
||||
if ( cumulativeAreas[ mid ] > value ) {
|
||||
|
||||
return binarySearch( start, mid - 1 );
|
||||
|
||||
} else if ( cumulativeAreas[ mid ] < value ) {
|
||||
|
||||
return binarySearch( mid + 1, end );
|
||||
|
||||
} else {
|
||||
|
||||
return mid;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
var result = binarySearch( 0, cumulativeAreas.length - 1 );
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
// pick random face weighted by face area
|
||||
|
||||
var r, index,
|
||||
result = [];
|
||||
|
||||
var stats = {};
|
||||
|
||||
for ( i = 0; i < n; i ++ ) {
|
||||
|
||||
r = Math.random() * totalArea;
|
||||
|
||||
index = binarySearchIndices( r );
|
||||
|
||||
result[ i ] = THREE.GeometryUtils.randomPointInFace( faces[ index ], geometry );
|
||||
|
||||
if ( ! stats[ index ] ) {
|
||||
|
||||
stats[ index ] = 1;
|
||||
|
||||
} else {
|
||||
|
||||
stats[ index ] += 1;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
},
|
||||
|
||||
randomPointsInBufferGeometry: function ( geometry, n ) {
|
||||
|
||||
var i,
|
||||
vertices = geometry.attributes.position.array,
|
||||
totalArea = 0,
|
||||
cumulativeAreas = [],
|
||||
vA, vB, vC;
|
||||
|
||||
// precompute face areas
|
||||
vA = new THREE.Vector3();
|
||||
vB = new THREE.Vector3();
|
||||
vC = new THREE.Vector3();
|
||||
|
||||
// geometry._areas = [];
|
||||
var il = vertices.length / 9;
|
||||
|
||||
for ( i = 0; i < il; i ++ ) {
|
||||
|
||||
vA.set( vertices[ i * 9 + 0 ], vertices[ i * 9 + 1 ], vertices[ i * 9 + 2 ] );
|
||||
vB.set( vertices[ i * 9 + 3 ], vertices[ i * 9 + 4 ], vertices[ i * 9 + 5 ] );
|
||||
vC.set( vertices[ i * 9 + 6 ], vertices[ i * 9 + 7 ], vertices[ i * 9 + 8 ] );
|
||||
|
||||
area = THREE.GeometryUtils.triangleArea( vA, vB, vC );
|
||||
totalArea += area;
|
||||
|
||||
cumulativeAreas.push( totalArea );
|
||||
|
||||
}
|
||||
|
||||
// binary search cumulative areas array
|
||||
|
||||
function binarySearchIndices( value ) {
|
||||
|
||||
function binarySearch( start, end ) {
|
||||
|
||||
// return closest larger index
|
||||
// if exact number is not found
|
||||
|
||||
if ( end < start )
|
||||
return start;
|
||||
|
||||
var mid = start + Math.floor( ( end - start ) / 2 );
|
||||
|
||||
if ( cumulativeAreas[ mid ] > value ) {
|
||||
|
||||
return binarySearch( start, mid - 1 );
|
||||
|
||||
} else if ( cumulativeAreas[ mid ] < value ) {
|
||||
|
||||
return binarySearch( mid + 1, end );
|
||||
|
||||
} else {
|
||||
|
||||
return mid;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
var result = binarySearch( 0, cumulativeAreas.length - 1 );
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
// pick random face weighted by face area
|
||||
|
||||
var r, index,
|
||||
result = [];
|
||||
|
||||
for ( i = 0; i < n; i ++ ) {
|
||||
|
||||
r = Math.random() * totalArea;
|
||||
|
||||
index = binarySearchIndices( r );
|
||||
|
||||
// result[ i ] = THREE.GeometryUtils.randomPointInFace( faces[ index ], geometry, true );
|
||||
vA.set( vertices[ index * 9 + 0 ], vertices[ index * 9 + 1 ], vertices[ index * 9 + 2 ] );
|
||||
vB.set( vertices[ index * 9 + 3 ], vertices[ index * 9 + 4 ], vertices[ index * 9 + 5 ] );
|
||||
vC.set( vertices[ index * 9 + 6 ], vertices[ index * 9 + 7 ], vertices[ index * 9 + 8 ] );
|
||||
result[ i ] = THREE.GeometryUtils.randomPointInTriangle( vA, vB, vC );
|
||||
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
},
|
||||
|
||||
// Get triangle area (half of parallelogram)
|
||||
// http://mathworld.wolfram.com/TriangleArea.html
|
||||
|
||||
triangleArea: function () {
|
||||
|
||||
var vector1 = new THREE.Vector3();
|
||||
var vector2 = new THREE.Vector3();
|
||||
|
||||
return function ( vectorA, vectorB, vectorC ) {
|
||||
|
||||
vector1.subVectors( vectorB, vectorA );
|
||||
vector2.subVectors( vectorC, vectorA );
|
||||
vector1.cross( vector2 );
|
||||
|
||||
return 0.5 * vector1.length();
|
||||
|
||||
};
|
||||
|
||||
}(),
|
||||
|
||||
center: function ( geometry ) {
|
||||
|
||||
console.warn( 'THREE.GeometryUtils: .center() has been moved to Geometry. Use geometry.center() instead.' );
|
||||
return geometry.center();
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
136
node_modules/three/examples/js/utils/ImageUtils.js
generated
vendored
Normal file
136
node_modules/three/examples/js/utils/ImageUtils.js
generated
vendored
Normal file
@@ -0,0 +1,136 @@
|
||||
/**
|
||||
* @author alteredq / http://alteredqualia.com/
|
||||
* @author mrdoob / http://mrdoob.com/
|
||||
* @author Daosheng Mu / https://github.com/DaoshengMu/
|
||||
*/
|
||||
|
||||
THREE.ImageUtils = {
|
||||
|
||||
getNormalMap: function ( image, depth ) {
|
||||
|
||||
// Adapted from http://www.paulbrunt.co.uk/lab/heightnormal/
|
||||
|
||||
function cross( a, b ) {
|
||||
|
||||
return [ a[ 1 ] * b[ 2 ] - a[ 2 ] * b[ 1 ], a[ 2 ] * b[ 0 ] - a[ 0 ] * b[ 2 ], a[ 0 ] * b[ 1 ] - a[ 1 ] * b[ 0 ] ];
|
||||
|
||||
}
|
||||
|
||||
function subtract( a, b ) {
|
||||
|
||||
return [ a[ 0 ] - b[ 0 ], a[ 1 ] - b[ 1 ], a[ 2 ] - b[ 2 ] ];
|
||||
|
||||
}
|
||||
|
||||
function normalize( a ) {
|
||||
|
||||
var l = Math.sqrt( a[ 0 ] * a[ 0 ] + a[ 1 ] * a[ 1 ] + a[ 2 ] * a[ 2 ] );
|
||||
return [ a[ 0 ] / l, a[ 1 ] / l, a[ 2 ] / l ];
|
||||
|
||||
}
|
||||
|
||||
depth = depth | 1;
|
||||
|
||||
var width = image.width;
|
||||
var height = image.height;
|
||||
|
||||
var canvas = document.createElement( 'canvas' );
|
||||
canvas.width = width;
|
||||
canvas.height = height;
|
||||
|
||||
var context = canvas.getContext( '2d' );
|
||||
context.drawImage( image, 0, 0 );
|
||||
|
||||
var data = context.getImageData( 0, 0, width, height ).data;
|
||||
var imageData = context.createImageData( width, height );
|
||||
var output = imageData.data;
|
||||
|
||||
for ( var x = 0; x < width; x ++ ) {
|
||||
|
||||
for ( var y = 0; y < height; y ++ ) {
|
||||
|
||||
var ly = y - 1 < 0 ? 0 : y - 1;
|
||||
var uy = y + 1 > height - 1 ? height - 1 : y + 1;
|
||||
var lx = x - 1 < 0 ? 0 : x - 1;
|
||||
var ux = x + 1 > width - 1 ? width - 1 : x + 1;
|
||||
|
||||
var points = [];
|
||||
var origin = [ 0, 0, data[ ( y * width + x ) * 4 ] / 255 * depth ];
|
||||
points.push( [ - 1, 0, data[ ( y * width + lx ) * 4 ] / 255 * depth ] );
|
||||
points.push( [ - 1, - 1, data[ ( ly * width + lx ) * 4 ] / 255 * depth ] );
|
||||
points.push( [ 0, - 1, data[ ( ly * width + x ) * 4 ] / 255 * depth ] );
|
||||
points.push( [ 1, - 1, data[ ( ly * width + ux ) * 4 ] / 255 * depth ] );
|
||||
points.push( [ 1, 0, data[ ( y * width + ux ) * 4 ] / 255 * depth ] );
|
||||
points.push( [ 1, 1, data[ ( uy * width + ux ) * 4 ] / 255 * depth ] );
|
||||
points.push( [ 0, 1, data[ ( uy * width + x ) * 4 ] / 255 * depth ] );
|
||||
points.push( [ - 1, 1, data[ ( uy * width + lx ) * 4 ] / 255 * depth ] );
|
||||
|
||||
var normals = [];
|
||||
var num_points = points.length;
|
||||
|
||||
for ( var i = 0; i < num_points; i ++ ) {
|
||||
|
||||
var v1 = points[ i ];
|
||||
var v2 = points[ ( i + 1 ) % num_points ];
|
||||
v1 = subtract( v1, origin );
|
||||
v2 = subtract( v2, origin );
|
||||
normals.push( normalize( cross( v1, v2 ) ) );
|
||||
|
||||
}
|
||||
|
||||
var normal = [ 0, 0, 0 ];
|
||||
|
||||
for ( var i = 0; i < normals.length; i ++ ) {
|
||||
|
||||
normal[ 0 ] += normals[ i ][ 0 ];
|
||||
normal[ 1 ] += normals[ i ][ 1 ];
|
||||
normal[ 2 ] += normals[ i ][ 2 ];
|
||||
|
||||
}
|
||||
|
||||
normal[ 0 ] /= normals.length;
|
||||
normal[ 1 ] /= normals.length;
|
||||
normal[ 2 ] /= normals.length;
|
||||
|
||||
var idx = ( y * width + x ) * 4;
|
||||
|
||||
output[ idx ] = ( ( normal[ 0 ] + 1.0 ) / 2.0 * 255 ) | 0;
|
||||
output[ idx + 1 ] = ( ( normal[ 1 ] + 1.0 ) / 2.0 * 255 ) | 0;
|
||||
output[ idx + 2 ] = ( normal[ 2 ] * 255 ) | 0;
|
||||
output[ idx + 3 ] = 255;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
context.putImageData( imageData, 0, 0 );
|
||||
|
||||
return canvas;
|
||||
|
||||
},
|
||||
|
||||
generateDataTexture: function ( width, height, color ) {
|
||||
|
||||
var size = width * height;
|
||||
var data = new Uint8Array( 3 * size );
|
||||
|
||||
var r = Math.floor( color.r * 255 );
|
||||
var g = Math.floor( color.g * 255 );
|
||||
var b = Math.floor( color.b * 255 );
|
||||
|
||||
for ( var i = 0; i < size; i ++ ) {
|
||||
|
||||
data[ i * 3 ] = r;
|
||||
data[ i * 3 + 1 ] = g;
|
||||
data[ i * 3 + 2 ] = b;
|
||||
|
||||
}
|
||||
|
||||
var texture = new THREE.DataTexture( data, width, height, THREE.RGBFormat );
|
||||
texture.needsUpdate = true;
|
||||
|
||||
return texture;
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
190
node_modules/three/examples/js/utils/ShadowMapViewer.js
generated
vendored
Normal file
190
node_modules/three/examples/js/utils/ShadowMapViewer.js
generated
vendored
Normal file
@@ -0,0 +1,190 @@
|
||||
/**
|
||||
* @author arya-s / https://github.com/arya-s
|
||||
*
|
||||
* This is a helper for visualising a given light's shadow map.
|
||||
* It works for shadow casting lights: THREE.DirectionalLight and THREE.SpotLight.
|
||||
* It renders out the shadow map and displays it on a HUD.
|
||||
*
|
||||
* Example usage:
|
||||
* 1) Include <script src='examples/js/utils/ShadowMapViewer.js'><script> in your html file
|
||||
*
|
||||
* 2) Create a shadow casting light and name it optionally:
|
||||
* var light = new THREE.DirectionalLight( 0xffffff, 1 );
|
||||
* light.castShadow = true;
|
||||
* light.name = 'Sun';
|
||||
*
|
||||
* 3) Create a shadow map viewer for that light and set its size and position optionally:
|
||||
* var shadowMapViewer = new THREE.ShadowMapViewer( light );
|
||||
* shadowMapViewer.size.set( 128, 128 ); //width, height default: 256, 256
|
||||
* shadowMapViewer.position.set( 10, 10 ); //x, y in pixel default: 0, 0 (top left corner)
|
||||
*
|
||||
* 4) Render the shadow map viewer in your render loop:
|
||||
* shadowMapViewer.render( renderer );
|
||||
*
|
||||
* 5) Optionally: Update the shadow map viewer on window resize:
|
||||
* shadowMapViewer.updateForWindowResize();
|
||||
*
|
||||
* 6) If you set the position or size members directly, you need to call shadowMapViewer.update();
|
||||
*/
|
||||
|
||||
THREE.ShadowMapViewer = function ( light ) {
|
||||
|
||||
//- Internals
|
||||
var scope = this;
|
||||
var doRenderLabel = ( light.name !== undefined && light.name !== '' );
|
||||
var userAutoClearSetting;
|
||||
|
||||
//Holds the initial position and dimension of the HUD
|
||||
var frame = {
|
||||
x: 10,
|
||||
y: 10,
|
||||
width: 256,
|
||||
height: 256
|
||||
};
|
||||
|
||||
var camera = new THREE.OrthographicCamera( window.innerWidth / - 2, window.innerWidth / 2, window.innerHeight / 2, window.innerHeight / - 2, 1, 10 );
|
||||
camera.position.set( 0, 0, 2 );
|
||||
var scene = new THREE.Scene();
|
||||
|
||||
//HUD for shadow map
|
||||
var shader = THREE.UnpackDepthRGBAShader;
|
||||
|
||||
var uniforms = new THREE.UniformsUtils.clone( shader.uniforms );
|
||||
var material = new THREE.ShaderMaterial( {
|
||||
uniforms: uniforms,
|
||||
vertexShader: shader.vertexShader,
|
||||
fragmentShader: shader.fragmentShader
|
||||
} );
|
||||
var plane = new THREE.PlaneBufferGeometry( frame.width, frame.height );
|
||||
var mesh = new THREE.Mesh( plane, material );
|
||||
|
||||
scene.add( mesh );
|
||||
|
||||
|
||||
//Label for light's name
|
||||
var labelCanvas, labelMesh;
|
||||
|
||||
if ( doRenderLabel ) {
|
||||
|
||||
labelCanvas = document.createElement( 'canvas' );
|
||||
|
||||
var context = labelCanvas.getContext( '2d' );
|
||||
context.font = 'Bold 20px Arial';
|
||||
|
||||
var labelWidth = context.measureText( light.name ).width;
|
||||
labelCanvas.width = labelWidth;
|
||||
labelCanvas.height = 25; //25 to account for g, p, etc.
|
||||
|
||||
context.font = 'Bold 20px Arial';
|
||||
context.fillStyle = 'rgba( 255, 0, 0, 1 )';
|
||||
context.fillText( light.name, 0, 20 );
|
||||
|
||||
var labelTexture = new THREE.Texture( labelCanvas );
|
||||
labelTexture.magFilter = THREE.LinearFilter;
|
||||
labelTexture.minFilter = THREE.LinearFilter;
|
||||
labelTexture.needsUpdate = true;
|
||||
|
||||
var labelMaterial = new THREE.MeshBasicMaterial( { map: labelTexture, side: THREE.DoubleSide } );
|
||||
labelMaterial.transparent = true;
|
||||
|
||||
var labelPlane = new THREE.PlaneBufferGeometry( labelCanvas.width, labelCanvas.height );
|
||||
labelMesh = new THREE.Mesh( labelPlane, labelMaterial );
|
||||
|
||||
scene.add( labelMesh );
|
||||
|
||||
}
|
||||
|
||||
|
||||
function resetPosition () {
|
||||
|
||||
scope.position.set( scope.position.x, scope.position.y );
|
||||
|
||||
}
|
||||
|
||||
//- API
|
||||
// Set to false to disable displaying this shadow map
|
||||
this.enabled = true;
|
||||
|
||||
// Set the size of the displayed shadow map on the HUD
|
||||
this.size = {
|
||||
width: frame.width,
|
||||
height: frame.height,
|
||||
set: function ( width, height ) {
|
||||
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
|
||||
mesh.scale.set( this.width / frame.width, this.height / frame.height, 1 );
|
||||
|
||||
//Reset the position as it is off when we scale stuff
|
||||
resetPosition();
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
// Set the position of the displayed shadow map on the HUD
|
||||
this.position = {
|
||||
x: frame.x,
|
||||
y: frame.y,
|
||||
set: function ( x, y ) {
|
||||
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
|
||||
var width = scope.size.width;
|
||||
var height = scope.size.height;
|
||||
|
||||
mesh.position.set( - window.innerWidth / 2 + width / 2 + this.x, window.innerHeight / 2 - height / 2 - this.y, 0 );
|
||||
|
||||
if ( doRenderLabel ) labelMesh.position.set( mesh.position.x, mesh.position.y - scope.size.height / 2 + labelCanvas.height / 2, 0 );
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
this.render = function ( renderer ) {
|
||||
|
||||
if ( this.enabled ) {
|
||||
|
||||
//Because a light's .shadowMap is only initialised after the first render pass
|
||||
//we have to make sure the correct map is sent into the shader, otherwise we
|
||||
//always end up with the scene's first added shadow casting light's shadowMap
|
||||
//in the shader
|
||||
//See: https://github.com/mrdoob/three.js/issues/5932
|
||||
uniforms.tDiffuse.value = light.shadow.map.texture;
|
||||
|
||||
userAutoClearSetting = renderer.autoClear;
|
||||
renderer.autoClear = false; // To allow render overlay
|
||||
renderer.clearDepth();
|
||||
renderer.render( scene, camera );
|
||||
renderer.autoClear = userAutoClearSetting; //Restore user's setting
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
this.updateForWindowResize = function () {
|
||||
|
||||
if ( this.enabled ) {
|
||||
|
||||
camera.left = window.innerWidth / - 2;
|
||||
camera.right = window.innerWidth / 2;
|
||||
camera.top = window.innerHeight / 2;
|
||||
camera.bottom = window.innerHeight / - 2;
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
this.update = function () {
|
||||
|
||||
this.position.set( this.position.x, this.position.y );
|
||||
this.size.set( this.size.width, this.size.height );
|
||||
|
||||
};
|
||||
|
||||
//Force an update to set position/size
|
||||
this.update();
|
||||
|
||||
};
|
||||
|
||||
THREE.ShadowMapViewer.prototype.constructor = THREE.ShadowMapViewer;
|
||||
123
node_modules/three/examples/js/utils/UVsDebug.js
generated
vendored
Normal file
123
node_modules/three/examples/js/utils/UVsDebug.js
generated
vendored
Normal file
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
* @author zz85 / http://github.com/zz85
|
||||
* @author WestLangley / http://github.com/WestLangley
|
||||
*
|
||||
* tool for "unwrapping" and debugging three.js
|
||||
* geometries UV mapping
|
||||
*
|
||||
* Sample usage:
|
||||
* document.body.appendChild( THREE.UVsDebug( new THREE.SphereGeometry( 10, 10, 10, 10 ) );
|
||||
*
|
||||
*/
|
||||
|
||||
THREE.UVsDebug = function( geometry, size ) {
|
||||
|
||||
// handles wrapping of uv.x > 1 only
|
||||
|
||||
var abc = 'abc';
|
||||
|
||||
var uv, u, ax, ay;
|
||||
var i, il, j, jl;
|
||||
var vnum;
|
||||
|
||||
var a = new THREE.Vector2();
|
||||
var b = new THREE.Vector2();
|
||||
|
||||
var geo = ( geometry instanceof THREE.BufferGeometry ) ? new THREE.Geometry().fromBufferGeometry( geometry ) : geometry;
|
||||
|
||||
var faces = geo.faces;
|
||||
var uvs = geo.faceVertexUvs[ 0 ];
|
||||
|
||||
var canvas = document.createElement( 'canvas' );
|
||||
var width = size || 1024; // power of 2 required for wrapping
|
||||
var height = size || 1024;
|
||||
canvas.width = width;
|
||||
canvas.height = height;
|
||||
|
||||
var ctx = canvas.getContext( '2d' );
|
||||
ctx.lineWidth = 2;
|
||||
ctx.strokeStyle = 'rgba( 0, 0, 0, 1.0 )';
|
||||
ctx.textAlign = 'center';
|
||||
|
||||
// paint background white
|
||||
|
||||
ctx.fillStyle = 'rgba( 255, 255, 255, 1.0 )';
|
||||
ctx.fillRect( 0, 0, width, height );
|
||||
|
||||
for ( i = 0, il = uvs.length; i < il; i ++ ) {
|
||||
|
||||
uv = uvs[ i ];
|
||||
|
||||
// draw lines
|
||||
|
||||
ctx.beginPath();
|
||||
|
||||
a.set( 0, 0 );
|
||||
|
||||
for ( j = 0, jl = uv.length; j < jl; j ++ ) {
|
||||
|
||||
u = uv[ j ];
|
||||
|
||||
a.x += u.x;
|
||||
a.y += u.y;
|
||||
|
||||
if ( j == 0 ) {
|
||||
|
||||
ctx.moveTo( u.x * width, ( 1 - u.y ) * height );
|
||||
|
||||
} else {
|
||||
|
||||
ctx.lineTo( u.x * width, ( 1 - u.y ) * height );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ctx.closePath();
|
||||
ctx.stroke();
|
||||
|
||||
a.divideScalar( jl );
|
||||
|
||||
// label the face number
|
||||
|
||||
ctx.font = "12pt Arial bold";
|
||||
ctx.fillStyle = 'rgba( 0, 0, 0, 1.0 )';
|
||||
ctx.fillText( i, a.x * width, ( 1 - a.y ) * height );
|
||||
|
||||
if ( a.x > 0.95 ) {
|
||||
|
||||
// wrap x // 0.95 is arbitrary
|
||||
|
||||
ctx.fillText( i, ( a.x % 1 ) * width, ( 1 - a.y ) * height );
|
||||
|
||||
}
|
||||
|
||||
ctx.font = "8pt Arial bold";
|
||||
ctx.fillStyle = 'rgba( 0, 0, 0, 1.0 )';
|
||||
|
||||
// label uv edge orders
|
||||
|
||||
for ( j = 0, jl = uv.length; j < jl; j ++ ) {
|
||||
|
||||
u = uv[ j ];
|
||||
b.addVectors( a, u ).divideScalar( 2 );
|
||||
|
||||
vnum = faces[ i ][ abc[ j ] ];
|
||||
ctx.fillText( abc[ j ] + vnum, b.x * width, ( 1 - b.y ) * height );
|
||||
|
||||
if ( b.x > 0.95 ) {
|
||||
|
||||
// wrap x
|
||||
|
||||
ctx.fillText( abc[ j ] + vnum, ( b.x % 1 ) * width, ( 1 - b.y ) * height );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return canvas;
|
||||
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user