File size: 3,099 Bytes
a28eca3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
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 };