SpritePlugin.js 8.5 KB
Newer Older
A
alteredq 已提交
1 2 3 4 5
/**
 * @author mikael emtinger / http://gomo.se/
 * @author alteredq / http://alteredqualia.com/
 */

M
Mr.doob 已提交
6
THREE.SpritePlugin = function ( renderer, sprites ) {
A
alteredq 已提交
7

8
	var gl = renderer.context;
M
Mr.doob 已提交
9
	var state = renderer.state;
M
Mr.doob 已提交
10

M
Mr.doob 已提交
11
	var vertexBuffer, elementBuffer;
M
Mr.doob 已提交
12
	var program, attributes, uniforms;
A
alteredq 已提交
13

14
	var texture;
15 16 17 18 19 20 21

	// decompose matrixWorld

	var spritePosition = new THREE.Vector3();
	var spriteRotation = new THREE.Quaternion();
	var spriteScale = new THREE.Vector3();

M
Mr.doob 已提交
22
	function init() {
A
alteredq 已提交
23

M
Mr.doob 已提交
24 25 26 27 28
		var vertices = new Float32Array( [
			- 0.5, - 0.5,  0, 0,
			  0.5, - 0.5,  1, 0,
			  0.5,   0.5,  1, 1,
			- 0.5,   0.5,  0, 1
M
Mr.doob 已提交
29
		] );
A
alteredq 已提交
30

M
Mr.doob 已提交
31
		var faces = new Uint16Array( [
M
Mr.doob 已提交
32 33 34
			0, 1, 2,
			0, 2, 3
		] );
A
alteredq 已提交
35

36 37
		vertexBuffer  = gl.createBuffer();
		elementBuffer = gl.createBuffer();
A
alteredq 已提交
38

39 40
		gl.bindBuffer( gl.ARRAY_BUFFER, vertexBuffer );
		gl.bufferData( gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW );
A
alteredq 已提交
41

42 43
		gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, elementBuffer );
		gl.bufferData( gl.ELEMENT_ARRAY_BUFFER, faces, gl.STATIC_DRAW );
A
alteredq 已提交
44

M
Mr.doob 已提交
45
		program = createProgram();
A
alteredq 已提交
46

M
Mr.doob 已提交
47
		attributes = {
48 49
			position:			gl.getAttribLocation ( program, 'position' ),
			uv:					gl.getAttribLocation ( program, 'uv' )
M
Mr.doob 已提交
50
		};
A
alteredq 已提交
51

M
Mr.doob 已提交
52
		uniforms = {
53 54
			uvOffset:			gl.getUniformLocation( program, 'uvOffset' ),
			uvScale:			gl.getUniformLocation( program, 'uvScale' ),
A
alteredq 已提交
55

56 57
			rotation:			gl.getUniformLocation( program, 'rotation' ),
			scale:				gl.getUniformLocation( program, 'scale' ),
A
alteredq 已提交
58

59 60 61
			color:				gl.getUniformLocation( program, 'color' ),
			map:				gl.getUniformLocation( program, 'map' ),
			opacity:			gl.getUniformLocation( program, 'opacity' ),
A
alteredq 已提交
62

63 64
			modelViewMatrix: 	gl.getUniformLocation( program, 'modelViewMatrix' ),
			projectionMatrix:	gl.getUniformLocation( program, 'projectionMatrix' ),
A
alteredq 已提交
65

66 67 68 69 70
			fogType:			gl.getUniformLocation( program, 'fogType' ),
			fogDensity:			gl.getUniformLocation( program, 'fogDensity' ),
			fogNear:			gl.getUniformLocation( program, 'fogNear' ),
			fogFar:				gl.getUniformLocation( program, 'fogFar' ),
			fogColor:			gl.getUniformLocation( program, 'fogColor' ),
A
alteredq 已提交
71

72
			alphaTest:			gl.getUniformLocation( program, 'alphaTest' )
M
Mr.doob 已提交
73
		};
M
Mr.doob 已提交
74

M
Mr.doob 已提交
75 76 77
		var canvas = document.createElement( 'canvas' );
		canvas.width = 8;
		canvas.height = 8;
M
Mr.doob 已提交
78

M
Mr.doob 已提交
79 80 81 82
		var context = canvas.getContext( '2d' );
		context.fillStyle = 'white';
		context.fillRect( 0, 0, 8, 8 );

83 84
		texture = new THREE.Texture( canvas );
		texture.needsUpdate = true;
85

M
Mr.doob 已提交
86
	}
A
alteredq 已提交
87

M
Mr.doob 已提交
88
	this.render = function ( scene, camera ) {
A
alteredq 已提交
89

90
		if ( sprites.length === 0 ) return;
91

A
alteredq 已提交
92 93
		// setup gl

94 95 96 97 98 99
		if ( program === undefined ) {

			init();

		}

100
		gl.useProgram( program );
A
alteredq 已提交
101

M
Mr.doob 已提交
102 103 104 105
		state.initAttributes();
		state.enableAttribute( attributes.position );
		state.enableAttribute( attributes.uv );
		state.disableUnusedAttributes();
A
alteredq 已提交
106

107 108
		state.disable( gl.CULL_FACE );
		state.enable( gl.BLEND );
A
alteredq 已提交
109

110 111 112
		gl.bindBuffer( gl.ARRAY_BUFFER, vertexBuffer );
		gl.vertexAttribPointer( attributes.position, 2, gl.FLOAT, false, 2 * 8, 0 );
		gl.vertexAttribPointer( attributes.uv, 2, gl.FLOAT, false, 2 * 8, 8 );
A
alteredq 已提交
113

114
		gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, elementBuffer );
A
alteredq 已提交
115

116
		gl.uniformMatrix4fv( uniforms.projectionMatrix, false, camera.projectionMatrix.elements );
A
alteredq 已提交
117

M
Mr.doob 已提交
118
		state.activeTexture( gl.TEXTURE0 );
119
		gl.uniform1i( uniforms.map, 0 );
A
alteredq 已提交
120

A
alteredq 已提交
121 122 123 124 125 126
		var oldFogType = 0;
		var sceneFogType = 0;
		var fog = scene.fog;

		if ( fog ) {

127
			gl.uniform3f( uniforms.fogColor, fog.color.r, fog.color.g, fog.color.b );
A
alteredq 已提交
128 129 130

			if ( fog instanceof THREE.Fog ) {

131 132
				gl.uniform1f( uniforms.fogNear, fog.near );
				gl.uniform1f( uniforms.fogFar, fog.far );
A
alteredq 已提交
133

134
				gl.uniform1i( uniforms.fogType, 1 );
A
alteredq 已提交
135 136 137 138 139
				oldFogType = 1;
				sceneFogType = 1;

			} else if ( fog instanceof THREE.FogExp2 ) {

140
				gl.uniform1f( uniforms.fogDensity, fog.density );
A
alteredq 已提交
141

142
				gl.uniform1i( uniforms.fogType, 2 );
A
alteredq 已提交
143 144 145 146 147 148 149
				oldFogType = 2;
				sceneFogType = 2;

			}

		} else {

150
			gl.uniform1i( uniforms.fogType, 0 );
A
alteredq 已提交
151 152 153 154 155 156
			oldFogType = 0;
			sceneFogType = 0;

		}


A
alteredq 已提交
157 158
		// update positions and sort

159
		for ( var i = 0, l = sprites.length; i < l; i ++ ) {
160

161
			var sprite = sprites[ i ];
A
alteredq 已提交
162

163 164
			sprite.modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, sprite.matrixWorld );
			sprite.z = - sprite.modelViewMatrix.elements[ 14 ];
A
alteredq 已提交
165 166 167

		}

A
alteredq 已提交
168
		sprites.sort( painterSortStable );
A
alteredq 已提交
169 170 171

		// render all sprites

172
		var scale = [];
A
alteredq 已提交
173

174
		for ( var i = 0, l = sprites.length; i < l; i ++ ) {
175

176 177
			var sprite = sprites[ i ];
			var material = sprite.material;
A
alteredq 已提交
178

179
			gl.uniform1f( uniforms.alphaTest, material.alphaTest );
180
			gl.uniformMatrix4fv( uniforms.modelViewMatrix, false, sprite.modelViewMatrix.elements );
A
alteredq 已提交
181

182 183 184 185
			sprite.matrixWorld.decompose( spritePosition, spriteRotation, spriteScale );

			scale[ 0 ] = spriteScale.x;
			scale[ 1 ] = spriteScale.y;
A
alteredq 已提交
186

187 188
			var fogType = 0;

189
			if ( scene.fog && material.fog ) {
A
alteredq 已提交
190

191
				fogType = sceneFogType;
A
alteredq 已提交
192

193
			}
A
alteredq 已提交
194

195
			if ( oldFogType !== fogType ) {
A
alteredq 已提交
196

197
				gl.uniform1i( uniforms.fogType, fogType );
198
				oldFogType = fogType;
A
alteredq 已提交
199

200
			}
A
alteredq 已提交
201

202 203
			if ( material.map !== null ) {

204 205
				gl.uniform2f( uniforms.uvOffset, material.map.offset.x, material.map.offset.y );
				gl.uniform2f( uniforms.uvScale, material.map.repeat.x, material.map.repeat.y );
206 207 208

			} else {

209 210
				gl.uniform2f( uniforms.uvOffset, 0, 0 );
				gl.uniform2f( uniforms.uvScale, 1, 1 );
211 212

			}
A
alteredq 已提交
213

214 215
			gl.uniform1f( uniforms.opacity, material.opacity );
			gl.uniform3f( uniforms.color, material.color.r, material.color.g, material.color.b );
A
alteredq 已提交
216

217 218
			gl.uniform1f( uniforms.rotation, material.rotation );
			gl.uniform2fv( uniforms.scale, scale );
A
alteredq 已提交
219

M
Mr.doob 已提交
220 221 222
			state.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst );
			state.setDepthTest( material.depthTest );
			state.setDepthWrite( material.depthWrite );
A
alteredq 已提交
223

224
			if ( material.map && material.map.image && material.map.image.width ) {
A
alteredq 已提交
225

226
				renderer.setTexture( material.map, 0 );
A
alteredq 已提交
227

228 229
			} else {

230
				renderer.setTexture( texture, 0 );
A
alteredq 已提交
231 232 233

			}

234
			gl.drawElements( gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0 );
235

A
alteredq 已提交
236 237 238 239
		}

		// restore gl

240
		state.enable( gl.CULL_FACE );
241

242
		renderer.resetGLState();
A
alteredq 已提交
243 244 245

	};

M
Mr.doob 已提交
246
	function createProgram () {
A
alteredq 已提交
247

248
		var program = gl.createProgram();
A
alteredq 已提交
249

250 251
		var vertexShader = gl.createShader( gl.VERTEX_SHADER );
		var fragmentShader = gl.createShader( gl.FRAGMENT_SHADER );
A
alteredq 已提交
252

253
		gl.shaderSource( vertexShader, [
254

255
			'precision ' + renderer.getPrecision() + ' float;',
256

M
Mr.doob 已提交
257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290
			'uniform mat4 modelViewMatrix;',
			'uniform mat4 projectionMatrix;',
			'uniform float rotation;',
			'uniform vec2 scale;',
			'uniform vec2 uvOffset;',
			'uniform vec2 uvScale;',

			'attribute vec2 position;',
			'attribute vec2 uv;',

			'varying vec2 vUV;',

			'void main() {',

				'vUV = uvOffset + uv * uvScale;',

				'vec2 alignedPosition = position * scale;',

				'vec2 rotatedPosition;',
				'rotatedPosition.x = cos( rotation ) * alignedPosition.x - sin( rotation ) * alignedPosition.y;',
				'rotatedPosition.y = sin( rotation ) * alignedPosition.x + cos( rotation ) * alignedPosition.y;',

				'vec4 finalPosition;',

				'finalPosition = modelViewMatrix * vec4( 0.0, 0.0, 0.0, 1.0 );',
				'finalPosition.xy += rotatedPosition;',
				'finalPosition = projectionMatrix * finalPosition;',

				'gl_Position = finalPosition;',

			'}'

		].join( '\n' ) );

291
		gl.shaderSource( fragmentShader, [
M
Mr.doob 已提交
292

293
			'precision ' + renderer.getPrecision() + ' float;',
M
Mr.doob 已提交
294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327

			'uniform vec3 color;',
			'uniform sampler2D map;',
			'uniform float opacity;',

			'uniform int fogType;',
			'uniform vec3 fogColor;',
			'uniform float fogDensity;',
			'uniform float fogNear;',
			'uniform float fogFar;',
			'uniform float alphaTest;',

			'varying vec2 vUV;',

			'void main() {',

				'vec4 texture = texture2D( map, vUV );',

				'if ( texture.a < alphaTest ) discard;',

				'gl_FragColor = vec4( color * texture.xyz, texture.a * opacity );',

				'if ( fogType > 0 ) {',

					'float depth = gl_FragCoord.z / gl_FragCoord.w;',
					'float fogFactor = 0.0;',

					'if ( fogType == 1 ) {',

						'fogFactor = smoothstep( fogNear, fogFar, depth );',

					'} else {',

						'const float LOG2 = 1.442695;',
328
						'fogFactor = exp2( - fogDensity * fogDensity * depth * depth * LOG2 );',
M
Mr.doob 已提交
329 330 331 332 333 334 335 336 337 338 339
						'fogFactor = 1.0 - clamp( fogFactor, 0.0, 1.0 );',

					'}',

					'gl_FragColor = mix( gl_FragColor, vec4( fogColor, gl_FragColor.w ), fogFactor );',

				'}',

			'}'

		].join( '\n' ) );
A
alteredq 已提交
340

341 342
		gl.compileShader( vertexShader );
		gl.compileShader( fragmentShader );
A
alteredq 已提交
343

344 345
		gl.attachShader( program, vertexShader );
		gl.attachShader( program, fragmentShader );
A
alteredq 已提交
346

347
		gl.linkProgram( program );
A
alteredq 已提交
348 349 350

		return program;

B
brason 已提交
351
	}
A
alteredq 已提交
352

A
alteredq 已提交
353
	function painterSortStable ( a, b ) {
354 355
		
		if ( a.renderOrder !== b.renderOrder ) {
A
alteredq 已提交
356

357 358 359
			return a.renderOrder - b.renderOrder;

		} else if ( a.z !== b.z ) {
A
alteredq 已提交
360 361 362 363 364 365 366 367

			return b.z - a.z;

		} else {

			return b.id - a.id;

		}
A
alteredq 已提交
368

B
brason 已提交
369
	}
A
alteredq 已提交
370

371
};