166 lines
		
	
	
		
			3.0 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
		
		
			
		
	
	
			166 lines
		
	
	
		
			3.0 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| 
								 | 
							
								import {
							 | 
						||
| 
								 | 
							
									Vector2
							 | 
						||
| 
								 | 
							
								} from 'three';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * tool for "unwrapping" and debugging three.js geometries UV mapping
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * Sample usage:
							 | 
						||
| 
								 | 
							
								 *	document.body.appendChild( UVsDebug( new THREE.SphereGeometry( 10, 10, 10, 10 ) );
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function UVsDebug( geometry, size = 1024 ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// handles wrapping of uv.x > 1 only
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									const abc = 'abc';
							 | 
						||
| 
								 | 
							
									const a = new Vector2();
							 | 
						||
| 
								 | 
							
									const b = new Vector2();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									const uvs = [
							 | 
						||
| 
								 | 
							
										new Vector2(),
							 | 
						||
| 
								 | 
							
										new Vector2(),
							 | 
						||
| 
								 | 
							
										new Vector2()
							 | 
						||
| 
								 | 
							
									];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									const face = [];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									const canvas = document.createElement( 'canvas' );
							 | 
						||
| 
								 | 
							
									const width = size; // power of 2 required for wrapping
							 | 
						||
| 
								 | 
							
									const height = size;
							 | 
						||
| 
								 | 
							
									canvas.width = width;
							 | 
						||
| 
								 | 
							
									canvas.height = height;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									const ctx = canvas.getContext( '2d' );
							 | 
						||
| 
								 | 
							
									ctx.lineWidth = 1;
							 | 
						||
| 
								 | 
							
									ctx.strokeStyle = 'rgb( 63, 63, 63 )';
							 | 
						||
| 
								 | 
							
									ctx.textAlign = 'center';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// paint background white
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									ctx.fillStyle = 'rgb( 255, 255, 255 )';
							 | 
						||
| 
								 | 
							
									ctx.fillRect( 0, 0, width, height );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									const index = geometry.index;
							 | 
						||
| 
								 | 
							
									const uvAttribute = geometry.attributes.uv;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if ( index ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										// indexed geometry
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										for ( let i = 0, il = index.count; i < il; i += 3 ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											face[ 0 ] = index.getX( i );
							 | 
						||
| 
								 | 
							
											face[ 1 ] = index.getX( i + 1 );
							 | 
						||
| 
								 | 
							
											face[ 2 ] = index.getX( i + 2 );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											uvs[ 0 ].fromBufferAttribute( uvAttribute, face[ 0 ] );
							 | 
						||
| 
								 | 
							
											uvs[ 1 ].fromBufferAttribute( uvAttribute, face[ 1 ] );
							 | 
						||
| 
								 | 
							
											uvs[ 2 ].fromBufferAttribute( uvAttribute, face[ 2 ] );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											processFace( face, uvs, i / 3 );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									} else {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										// non-indexed geometry
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										for ( let i = 0, il = uvAttribute.count; i < il; i += 3 ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											face[ 0 ] = i;
							 | 
						||
| 
								 | 
							
											face[ 1 ] = i + 1;
							 | 
						||
| 
								 | 
							
											face[ 2 ] = i + 2;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											uvs[ 0 ].fromBufferAttribute( uvAttribute, face[ 0 ] );
							 | 
						||
| 
								 | 
							
											uvs[ 1 ].fromBufferAttribute( uvAttribute, face[ 1 ] );
							 | 
						||
| 
								 | 
							
											uvs[ 2 ].fromBufferAttribute( uvAttribute, face[ 2 ] );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											processFace( face, uvs, i / 3 );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									return canvas;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									function processFace( face, uvs, index ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										// draw contour of face
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										ctx.beginPath();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										a.set( 0, 0 );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										for ( let j = 0, jl = uvs.length; j < jl; j ++ ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											const uv = uvs[ j ];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											a.x += uv.x;
							 | 
						||
| 
								 | 
							
											a.y += uv.y;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											if ( j === 0 ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												ctx.moveTo( uv.x * ( width - 2 ) + 0.5, ( 1 - uv.y ) * ( height - 2 ) + 0.5 );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											} else {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												ctx.lineTo( uv.x * ( width - 2 ) + 0.5, ( 1 - uv.y ) * ( height - 2 ) + 0.5 );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										ctx.closePath();
							 | 
						||
| 
								 | 
							
										ctx.stroke();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										// calculate center of face
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										a.divideScalar( uvs.length );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										// label the face number
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										ctx.font = '18px Arial';
							 | 
						||
| 
								 | 
							
										ctx.fillStyle = 'rgb( 63, 63, 63 )';
							 | 
						||
| 
								 | 
							
										ctx.fillText( index, a.x * width, ( 1 - a.y ) * height );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										if ( a.x > 0.95 ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											// wrap x // 0.95 is arbitrary
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											ctx.fillText( index, ( a.x % 1 ) * width, ( 1 - a.y ) * height );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										//
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										ctx.font = '12px Arial';
							 | 
						||
| 
								 | 
							
										ctx.fillStyle = 'rgb( 191, 191, 191 )';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										// label uv edge orders
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										for ( let j = 0, jl = uvs.length; j < jl; j ++ ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											const uv = uvs[ j ];
							 | 
						||
| 
								 | 
							
											b.addVectors( a, uv ).divideScalar( 2 );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											const vnum = face[ 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 );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								export { UVsDebug };
							 |