source: other-projects/playing-in-the-street/summer-2013/trunk/Playing-in-the-Street-WPF/Content/Web/mrdoob-three.js-4862f5f/src/renderers/WebGLRenderer.js@ 28897

Last change on this file since 28897 was 28897, checked in by davidb, 10 years ago

GUI front-end to server base plus web page content

File size: 154.0 KB
Line 
1/**
2 * @author supereggbert / http://www.paulbrunt.co.uk/
3 * @author mrdoob / http://mrdoob.com/
4 * @author alteredq / http://alteredqualia.com/
5 * @author szimek / https://github.com/szimek/
6 */
7
8THREE.WebGLRenderer = function ( parameters ) {
9
10 console.log( 'THREE.WebGLRenderer', THREE.REVISION );
11
12 parameters = parameters || {};
13
14 var _canvas = parameters.canvas !== undefined ? parameters.canvas : document.createElement( 'canvas' ),
15
16 _precision = parameters.precision !== undefined ? parameters.precision : 'highp',
17
18 _alpha = parameters.alpha !== undefined ? parameters.alpha : false,
19 _premultipliedAlpha = parameters.premultipliedAlpha !== undefined ? parameters.premultipliedAlpha : true,
20 _antialias = parameters.antialias !== undefined ? parameters.antialias : false,
21 _stencil = parameters.stencil !== undefined ? parameters.stencil : true,
22 _preserveDrawingBuffer = parameters.preserveDrawingBuffer !== undefined ? parameters.preserveDrawingBuffer : false,
23
24 _clearColor = new THREE.Color( 0x000000 ),
25 _clearAlpha = 0;
26
27 // public properties
28
29 this.domElement = _canvas;
30 this.context = null;
31 this.devicePixelRatio = parameters.devicePixelRatio !== undefined
32 ? parameters.devicePixelRatio
33 : self.devicePixelRatio !== undefined
34 ? self.devicePixelRatio
35 : 1;
36
37 // clearing
38
39 this.autoClear = true;
40 this.autoClearColor = true;
41 this.autoClearDepth = true;
42 this.autoClearStencil = true;
43
44 // scene graph
45
46 this.sortObjects = true;
47 this.autoUpdateObjects = true;
48
49 // physically based shading
50
51 this.gammaInput = false;
52 this.gammaOutput = false;
53
54 // shadow map
55
56 this.shadowMapEnabled = false;
57 this.shadowMapAutoUpdate = true;
58 this.shadowMapType = THREE.PCFShadowMap;
59 this.shadowMapCullFace = THREE.CullFaceFront;
60 this.shadowMapDebug = false;
61 this.shadowMapCascade = false;
62
63 // morphs
64
65 this.maxMorphTargets = 8;
66 this.maxMorphNormals = 4;
67
68 // flags
69
70 this.autoScaleCubemaps = true;
71
72 // custom render plugins
73
74 this.renderPluginsPre = [];
75 this.renderPluginsPost = [];
76
77 // info
78
79 this.info = {
80
81 memory: {
82
83 programs: 0,
84 geometries: 0,
85 textures: 0
86
87 },
88
89 render: {
90
91 calls: 0,
92 vertices: 0,
93 faces: 0,
94 points: 0
95
96 }
97
98 };
99
100 // internal properties
101
102 var _this = this,
103
104 _programs = [],
105 _programs_counter = 0,
106
107 // internal state cache
108
109 _currentProgram = null,
110 _currentFramebuffer = null,
111 _currentMaterialId = -1,
112 _currentGeometryGroupHash = null,
113 _currentCamera = null,
114 _geometryGroupCounter = 0,
115
116 _usedTextureUnits = 0,
117
118 // GL state cache
119
120 _oldDoubleSided = -1,
121 _oldFlipSided = -1,
122
123 _oldBlending = -1,
124
125 _oldBlendEquation = -1,
126 _oldBlendSrc = -1,
127 _oldBlendDst = -1,
128
129 _oldDepthTest = -1,
130 _oldDepthWrite = -1,
131
132 _oldPolygonOffset = null,
133 _oldPolygonOffsetFactor = null,
134 _oldPolygonOffsetUnits = null,
135
136 _oldLineWidth = null,
137
138 _viewportX = 0,
139 _viewportY = 0,
140 _viewportWidth = _canvas.width,
141 _viewportHeight = _canvas.height,
142 _currentWidth = 0,
143 _currentHeight = 0,
144
145 _enabledAttributes = {},
146
147 // frustum
148
149 _frustum = new THREE.Frustum(),
150
151 // camera matrices cache
152
153 _projScreenMatrix = new THREE.Matrix4(),
154 _projScreenMatrixPS = new THREE.Matrix4(),
155
156 _vector3 = new THREE.Vector3(),
157
158 // light arrays cache
159
160 _direction = new THREE.Vector3(),
161
162 _lightsNeedUpdate = true,
163
164 _lights = {
165
166 ambient: [ 0, 0, 0 ],
167 directional: { length: 0, colors: new Array(), positions: new Array() },
168 point: { length: 0, colors: new Array(), positions: new Array(), distances: new Array() },
169 spot: { length: 0, colors: new Array(), positions: new Array(), distances: new Array(), directions: new Array(), anglesCos: new Array(), exponents: new Array() },
170 hemi: { length: 0, skyColors: new Array(), groundColors: new Array(), positions: new Array() }
171
172 };
173
174 // initialize
175
176 var _gl;
177
178 var _glExtensionTextureFloat;
179 var _glExtensionTextureFloatLinear;
180 var _glExtensionStandardDerivatives;
181 var _glExtensionTextureFilterAnisotropic;
182 var _glExtensionCompressedTextureS3TC;
183
184 initGL();
185
186 setDefaultGLState();
187
188 this.context = _gl;
189
190 // GPU capabilities
191
192 var _maxTextures = _gl.getParameter( _gl.MAX_TEXTURE_IMAGE_UNITS );
193 var _maxVertexTextures = _gl.getParameter( _gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS );
194 var _maxTextureSize = _gl.getParameter( _gl.MAX_TEXTURE_SIZE );
195 var _maxCubemapSize = _gl.getParameter( _gl.MAX_CUBE_MAP_TEXTURE_SIZE );
196
197 var _maxAnisotropy = _glExtensionTextureFilterAnisotropic ? _gl.getParameter( _glExtensionTextureFilterAnisotropic.MAX_TEXTURE_MAX_ANISOTROPY_EXT ) : 0;
198
199 var _supportsVertexTextures = ( _maxVertexTextures > 0 );
200 var _supportsBoneTextures = _supportsVertexTextures && _glExtensionTextureFloat;
201
202 var _compressedTextureFormats = _glExtensionCompressedTextureS3TC ? _gl.getParameter( _gl.COMPRESSED_TEXTURE_FORMATS ) : [];
203
204 //
205
206 var _vertexShaderPrecisionHighpFloat = _gl.getShaderPrecisionFormat( _gl.VERTEX_SHADER, _gl.HIGH_FLOAT );
207 var _vertexShaderPrecisionMediumpFloat = _gl.getShaderPrecisionFormat( _gl.VERTEX_SHADER, _gl.MEDIUM_FLOAT );
208 var _vertexShaderPrecisionLowpFloat = _gl.getShaderPrecisionFormat( _gl.VERTEX_SHADER, _gl.LOW_FLOAT );
209
210 var _fragmentShaderPrecisionHighpFloat = _gl.getShaderPrecisionFormat( _gl.FRAGMENT_SHADER, _gl.HIGH_FLOAT );
211 var _fragmentShaderPrecisionMediumpFloat = _gl.getShaderPrecisionFormat( _gl.FRAGMENT_SHADER, _gl.MEDIUM_FLOAT );
212 var _fragmentShaderPrecisionLowpFloat = _gl.getShaderPrecisionFormat( _gl.FRAGMENT_SHADER, _gl.LOW_FLOAT );
213
214 var _vertexShaderPrecisionHighpInt = _gl.getShaderPrecisionFormat( _gl.VERTEX_SHADER, _gl.HIGH_INT );
215 var _vertexShaderPrecisionMediumpInt = _gl.getShaderPrecisionFormat( _gl.VERTEX_SHADER, _gl.MEDIUM_INT );
216 var _vertexShaderPrecisionLowpInt = _gl.getShaderPrecisionFormat( _gl.VERTEX_SHADER, _gl.LOW_INT );
217
218 var _fragmentShaderPrecisionHighpInt = _gl.getShaderPrecisionFormat( _gl.FRAGMENT_SHADER, _gl.HIGH_INT );
219 var _fragmentShaderPrecisionMediumpInt = _gl.getShaderPrecisionFormat( _gl.FRAGMENT_SHADER, _gl.MEDIUM_INT );
220 var _fragmentShaderPrecisionLowpInt = _gl.getShaderPrecisionFormat( _gl.FRAGMENT_SHADER, _gl.LOW_INT );
221
222 // clamp precision to maximum available
223
224 var highpAvailable = _vertexShaderPrecisionHighpFloat.precision > 0 && _fragmentShaderPrecisionHighpFloat.precision > 0;
225 var mediumpAvailable = _vertexShaderPrecisionMediumpFloat.precision > 0 && _fragmentShaderPrecisionMediumpFloat.precision > 0;
226
227 if ( _precision === "highp" && ! highpAvailable ) {
228
229 if ( mediumpAvailable ) {
230
231 _precision = "mediump";
232 console.warn( "WebGLRenderer: highp not supported, using mediump" );
233
234 } else {
235
236 _precision = "lowp";
237 console.warn( "WebGLRenderer: highp and mediump not supported, using lowp" );
238
239 }
240
241 }
242
243 if ( _precision === "mediump" && ! mediumpAvailable ) {
244
245 _precision = "lowp";
246 console.warn( "WebGLRenderer: mediump not supported, using lowp" );
247
248 }
249
250 // API
251
252 this.getContext = function () {
253
254 return _gl;
255
256 };
257
258 this.supportsVertexTextures = function () {
259
260 return _supportsVertexTextures;
261
262 };
263
264 this.supportsFloatTextures = function () {
265
266 return _glExtensionTextureFloat;
267
268 };
269
270 this.supportsStandardDerivatives = function () {
271
272 return _glExtensionStandardDerivatives;
273
274 };
275
276 this.supportsCompressedTextureS3TC = function () {
277
278 return _glExtensionCompressedTextureS3TC;
279
280 };
281
282 this.getMaxAnisotropy = function () {
283
284 return _maxAnisotropy;
285
286 };
287
288 this.getPrecision = function () {
289
290 return _precision;
291
292 };
293
294 this.setSize = function ( width, height, updateStyle ) {
295
296 _canvas.width = width * this.devicePixelRatio;
297 _canvas.height = height * this.devicePixelRatio;
298
299 if ( this.devicePixelRatio !== 1 && updateStyle !== false ) {
300
301 _canvas.style.width = width + 'px';
302 _canvas.style.height = height + 'px';
303
304 }
305
306 this.setViewport( 0, 0, _canvas.width, _canvas.height );
307
308 };
309
310 this.setViewport = function ( x, y, width, height ) {
311
312 _viewportX = x !== undefined ? x : 0;
313 _viewportY = y !== undefined ? y : 0;
314
315 _viewportWidth = width !== undefined ? width : _canvas.width;
316 _viewportHeight = height !== undefined ? height : _canvas.height;
317
318 _gl.viewport( _viewportX, _viewportY, _viewportWidth, _viewportHeight );
319
320 };
321
322 this.setScissor = function ( x, y, width, height ) {
323
324 _gl.scissor( x, y, width, height );
325
326 };
327
328 this.enableScissorTest = function ( enable ) {
329
330 enable ? _gl.enable( _gl.SCISSOR_TEST ) : _gl.disable( _gl.SCISSOR_TEST );
331
332 };
333
334 // Clearing
335
336 this.setClearColor = function ( color, alpha ) {
337
338 _clearColor.set( color );
339 _clearAlpha = alpha !== undefined ? alpha : 1;
340
341 _gl.clearColor( _clearColor.r, _clearColor.g, _clearColor.b, _clearAlpha );
342
343 };
344
345 this.setClearColorHex = function ( hex, alpha ) {
346
347 console.warn( 'DEPRECATED: .setClearColorHex() is being removed. Use .setClearColor() instead.' );
348 this.setClearColor( hex, alpha );
349
350 };
351
352 this.getClearColor = function () {
353
354 return _clearColor;
355
356 };
357
358 this.getClearAlpha = function () {
359
360 return _clearAlpha;
361
362 };
363
364 this.clear = function ( color, depth, stencil ) {
365
366 var bits = 0;
367
368 if ( color === undefined || color ) bits |= _gl.COLOR_BUFFER_BIT;
369 if ( depth === undefined || depth ) bits |= _gl.DEPTH_BUFFER_BIT;
370 if ( stencil === undefined || stencil ) bits |= _gl.STENCIL_BUFFER_BIT;
371
372 _gl.clear( bits );
373
374 };
375
376 this.clearColor = function () {
377
378 _gl.clear( _gl.COLOR_BUFFER_BIT );
379
380 };
381
382 this.clearDepth = function () {
383
384 _gl.clear( _gl.DEPTH_BUFFER_BIT );
385
386 };
387
388 this.clearStencil = function () {
389
390 _gl.clear( _gl.STENCIL_BUFFER_BIT );
391
392 };
393
394 this.clearTarget = function ( renderTarget, color, depth, stencil ) {
395
396 this.setRenderTarget( renderTarget );
397 this.clear( color, depth, stencil );
398
399 };
400
401 // Plugins
402
403 this.addPostPlugin = function ( plugin ) {
404
405 plugin.init( this );
406 this.renderPluginsPost.push( plugin );
407
408 };
409
410 this.addPrePlugin = function ( plugin ) {
411
412 plugin.init( this );
413 this.renderPluginsPre.push( plugin );
414
415 };
416
417 // Rendering
418
419 this.updateShadowMap = function ( scene, camera ) {
420
421 _currentProgram = null;
422 _oldBlending = -1;
423 _oldDepthTest = -1;
424 _oldDepthWrite = -1;
425 _currentGeometryGroupHash = -1;
426 _currentMaterialId = -1;
427 _lightsNeedUpdate = true;
428 _oldDoubleSided = -1;
429 _oldFlipSided = -1;
430
431 this.shadowMapPlugin.update( scene, camera );
432
433 };
434
435 // Internal functions
436
437 // Buffer allocation
438
439 function createParticleBuffers ( geometry ) {
440
441 geometry.__webglVertexBuffer = _gl.createBuffer();
442 geometry.__webglColorBuffer = _gl.createBuffer();
443
444 _this.info.memory.geometries ++;
445
446 };
447
448 function createLineBuffers ( geometry ) {
449
450 geometry.__webglVertexBuffer = _gl.createBuffer();
451 geometry.__webglColorBuffer = _gl.createBuffer();
452 geometry.__webglLineDistanceBuffer = _gl.createBuffer();
453
454 _this.info.memory.geometries ++;
455
456 };
457
458 function createMeshBuffers ( geometryGroup ) {
459
460 geometryGroup.__webglVertexBuffer = _gl.createBuffer();
461 geometryGroup.__webglNormalBuffer = _gl.createBuffer();
462 geometryGroup.__webglTangentBuffer = _gl.createBuffer();
463 geometryGroup.__webglColorBuffer = _gl.createBuffer();
464 geometryGroup.__webglUVBuffer = _gl.createBuffer();
465 geometryGroup.__webglUV2Buffer = _gl.createBuffer();
466
467 geometryGroup.__webglSkinIndicesBuffer = _gl.createBuffer();
468 geometryGroup.__webglSkinWeightsBuffer = _gl.createBuffer();
469
470 geometryGroup.__webglFaceBuffer = _gl.createBuffer();
471 geometryGroup.__webglLineBuffer = _gl.createBuffer();
472
473 var m, ml;
474
475 if ( geometryGroup.numMorphTargets ) {
476
477 geometryGroup.__webglMorphTargetsBuffers = [];
478
479 for ( m = 0, ml = geometryGroup.numMorphTargets; m < ml; m ++ ) {
480
481 geometryGroup.__webglMorphTargetsBuffers.push( _gl.createBuffer() );
482
483 }
484
485 }
486
487 if ( geometryGroup.numMorphNormals ) {
488
489 geometryGroup.__webglMorphNormalsBuffers = [];
490
491 for ( m = 0, ml = geometryGroup.numMorphNormals; m < ml; m ++ ) {
492
493 geometryGroup.__webglMorphNormalsBuffers.push( _gl.createBuffer() );
494
495 }
496
497 }
498
499 _this.info.memory.geometries ++;
500
501 };
502
503 // Events
504
505 var onGeometryDispose = function ( event ) {
506
507 var geometry = event.target;
508
509 geometry.removeEventListener( 'dispose', onGeometryDispose );
510
511 deallocateGeometry( geometry );
512
513 };
514
515 var onTextureDispose = function ( event ) {
516
517 var texture = event.target;
518
519 texture.removeEventListener( 'dispose', onTextureDispose );
520
521 deallocateTexture( texture );
522
523 _this.info.memory.textures --;
524
525
526 };
527
528 var onRenderTargetDispose = function ( event ) {
529
530 var renderTarget = event.target;
531
532 renderTarget.removeEventListener( 'dispose', onRenderTargetDispose );
533
534 deallocateRenderTarget( renderTarget );
535
536 _this.info.memory.textures --;
537
538 };
539
540 var onMaterialDispose = function ( event ) {
541
542 var material = event.target;
543
544 material.removeEventListener( 'dispose', onMaterialDispose );
545
546 deallocateMaterial( material );
547
548 };
549
550 // Buffer deallocation
551
552 var deleteBuffers = function ( geometry ) {
553
554 if ( geometry.__webglVertexBuffer !== undefined ) _gl.deleteBuffer( geometry.__webglVertexBuffer );
555 if ( geometry.__webglNormalBuffer !== undefined ) _gl.deleteBuffer( geometry.__webglNormalBuffer );
556 if ( geometry.__webglTangentBuffer !== undefined ) _gl.deleteBuffer( geometry.__webglTangentBuffer );
557 if ( geometry.__webglColorBuffer !== undefined ) _gl.deleteBuffer( geometry.__webglColorBuffer );
558 if ( geometry.__webglUVBuffer !== undefined ) _gl.deleteBuffer( geometry.__webglUVBuffer );
559 if ( geometry.__webglUV2Buffer !== undefined ) _gl.deleteBuffer( geometry.__webglUV2Buffer );
560
561 if ( geometry.__webglSkinIndicesBuffer !== undefined ) _gl.deleteBuffer( geometry.__webglSkinIndicesBuffer );
562 if ( geometry.__webglSkinWeightsBuffer !== undefined ) _gl.deleteBuffer( geometry.__webglSkinWeightsBuffer );
563
564 if ( geometry.__webglFaceBuffer !== undefined ) _gl.deleteBuffer( geometry.__webglFaceBuffer );
565 if ( geometry.__webglLineBuffer !== undefined ) _gl.deleteBuffer( geometry.__webglLineBuffer );
566
567 if ( geometry.__webglLineDistanceBuffer !== undefined ) _gl.deleteBuffer( geometry.__webglLineDistanceBuffer );
568 // custom attributes
569
570 if ( geometry.__webglCustomAttributesList !== undefined ) {
571
572 for ( var id in geometry.__webglCustomAttributesList ) {
573
574 _gl.deleteBuffer( geometry.__webglCustomAttributesList[ id ].buffer );
575
576 }
577
578 }
579
580 _this.info.memory.geometries --;
581
582 };
583
584 var deallocateGeometry = function ( geometry ) {
585
586 geometry.__webglInit = undefined;
587
588 if ( geometry instanceof THREE.BufferGeometry ) {
589
590 var attributes = geometry.attributes;
591
592 for ( var key in attributes ) {
593
594 if ( attributes[ key ].buffer !== undefined ) {
595
596 _gl.deleteBuffer( attributes[ key ].buffer );
597
598 }
599
600 }
601
602 _this.info.memory.geometries --;
603
604 } else {
605
606 if ( geometry.geometryGroups !== undefined ) {
607
608 for ( var g in geometry.geometryGroups ) {
609
610 var geometryGroup = geometry.geometryGroups[ g ];
611
612 if ( geometryGroup.numMorphTargets !== undefined ) {
613
614 for ( var m = 0, ml = geometryGroup.numMorphTargets; m < ml; m ++ ) {
615
616 _gl.deleteBuffer( geometryGroup.__webglMorphTargetsBuffers[ m ] );
617
618 }
619
620 }
621
622 if ( geometryGroup.numMorphNormals !== undefined ) {
623
624 for ( var m = 0, ml = geometryGroup.numMorphNormals; m < ml; m ++ ) {
625
626 _gl.deleteBuffer( geometryGroup.__webglMorphNormalsBuffers[ m ] );
627
628 }
629
630 }
631
632 deleteBuffers( geometryGroup );
633
634 }
635
636 } else {
637
638 deleteBuffers( geometry );
639
640 }
641
642 }
643
644 };
645
646 var deallocateTexture = function ( texture ) {
647
648 if ( texture.image && texture.image.__webglTextureCube ) {
649
650 // cube texture
651
652 _gl.deleteTexture( texture.image.__webglTextureCube );
653
654 } else {
655
656 // 2D texture
657
658 if ( ! texture.__webglInit ) return;
659
660 texture.__webglInit = false;
661 _gl.deleteTexture( texture.__webglTexture );
662
663 }
664
665 };
666
667 var deallocateRenderTarget = function ( renderTarget ) {
668
669 if ( !renderTarget || ! renderTarget.__webglTexture ) return;
670
671 _gl.deleteTexture( renderTarget.__webglTexture );
672
673 if ( renderTarget instanceof THREE.WebGLRenderTargetCube ) {
674
675 for ( var i = 0; i < 6; i ++ ) {
676
677 _gl.deleteFramebuffer( renderTarget.__webglFramebuffer[ i ] );
678 _gl.deleteRenderbuffer( renderTarget.__webglRenderbuffer[ i ] );
679
680 }
681
682 } else {
683
684 _gl.deleteFramebuffer( renderTarget.__webglFramebuffer );
685 _gl.deleteRenderbuffer( renderTarget.__webglRenderbuffer );
686
687 }
688
689 };
690
691 var deallocateMaterial = function ( material ) {
692
693 var program = material.program;
694
695 if ( program === undefined ) return;
696
697 material.program = undefined;
698
699 // only deallocate GL program if this was the last use of shared program
700 // assumed there is only single copy of any program in the _programs list
701 // (that's how it's constructed)
702
703 var i, il, programInfo;
704 var deleteProgram = false;
705
706 for ( i = 0, il = _programs.length; i < il; i ++ ) {
707
708 programInfo = _programs[ i ];
709
710 if ( programInfo.program === program ) {
711
712 programInfo.usedTimes --;
713
714 if ( programInfo.usedTimes === 0 ) {
715
716 deleteProgram = true;
717
718 }
719
720 break;
721
722 }
723
724 }
725
726 if ( deleteProgram === true ) {
727
728 // avoid using array.splice, this is costlier than creating new array from scratch
729
730 var newPrograms = [];
731
732 for ( i = 0, il = _programs.length; i < il; i ++ ) {
733
734 programInfo = _programs[ i ];
735
736 if ( programInfo.program !== program ) {
737
738 newPrograms.push( programInfo );
739
740 }
741
742 }
743
744 _programs = newPrograms;
745
746 _gl.deleteProgram( program );
747
748 _this.info.memory.programs --;
749
750 }
751
752 };
753
754 // Buffer initialization
755
756 function initCustomAttributes ( geometry, object ) {
757
758 var nvertices = geometry.vertices.length;
759
760 var material = object.material;
761
762 if ( material.attributes ) {
763
764 if ( geometry.__webglCustomAttributesList === undefined ) {
765
766 geometry.__webglCustomAttributesList = [];
767
768 }
769
770 for ( var a in material.attributes ) {
771
772 var attribute = material.attributes[ a ];
773
774 if ( !attribute.__webglInitialized || attribute.createUniqueBuffers ) {
775
776 attribute.__webglInitialized = true;
777
778 var size = 1; // "f" and "i"
779
780 if ( attribute.type === "v2" ) size = 2;
781 else if ( attribute.type === "v3" ) size = 3;
782 else if ( attribute.type === "v4" ) size = 4;
783 else if ( attribute.type === "c" ) size = 3;
784
785 attribute.size = size;
786
787 attribute.array = new Float32Array( nvertices * size );
788
789 attribute.buffer = _gl.createBuffer();
790 attribute.buffer.belongsToAttribute = a;
791
792 attribute.needsUpdate = true;
793
794 }
795
796 geometry.__webglCustomAttributesList.push( attribute );
797
798 }
799
800 }
801
802 };
803
804 function initParticleBuffers ( geometry, object ) {
805
806 var nvertices = geometry.vertices.length;
807
808 geometry.__vertexArray = new Float32Array( nvertices * 3 );
809 geometry.__colorArray = new Float32Array( nvertices * 3 );
810
811 geometry.__sortArray = [];
812
813 geometry.__webglParticleCount = nvertices;
814
815 initCustomAttributes ( geometry, object );
816
817 };
818
819 function initLineBuffers ( geometry, object ) {
820
821 var nvertices = geometry.vertices.length;
822
823 geometry.__vertexArray = new Float32Array( nvertices * 3 );
824 geometry.__colorArray = new Float32Array( nvertices * 3 );
825 geometry.__lineDistanceArray = new Float32Array( nvertices * 1 );
826
827 geometry.__webglLineCount = nvertices;
828
829 initCustomAttributes ( geometry, object );
830
831 };
832
833 function initMeshBuffers ( geometryGroup, object ) {
834
835 var geometry = object.geometry,
836 faces3 = geometryGroup.faces3,
837
838 nvertices = faces3.length * 3,
839 ntris = faces3.length * 1,
840 nlines = faces3.length * 3,
841
842 material = getBufferMaterial( object, geometryGroup ),
843
844 uvType = bufferGuessUVType( material ),
845 normalType = bufferGuessNormalType( material ),
846 vertexColorType = bufferGuessVertexColorType( material );
847
848 // console.log( "uvType", uvType, "normalType", normalType, "vertexColorType", vertexColorType, object, geometryGroup, material );
849
850 geometryGroup.__vertexArray = new Float32Array( nvertices * 3 );
851
852 if ( normalType ) {
853
854 geometryGroup.__normalArray = new Float32Array( nvertices * 3 );
855
856 }
857
858 if ( geometry.hasTangents ) {
859
860 geometryGroup.__tangentArray = new Float32Array( nvertices * 4 );
861
862 }
863
864 if ( vertexColorType ) {
865
866 geometryGroup.__colorArray = new Float32Array( nvertices * 3 );
867
868 }
869
870 if ( uvType ) {
871
872 if ( geometry.faceVertexUvs.length > 0 ) {
873
874 geometryGroup.__uvArray = new Float32Array( nvertices * 2 );
875
876 }
877
878 if ( geometry.faceVertexUvs.length > 1 ) {
879
880 geometryGroup.__uv2Array = new Float32Array( nvertices * 2 );
881
882 }
883
884 }
885
886 if ( object.geometry.skinWeights.length && object.geometry.skinIndices.length ) {
887
888 geometryGroup.__skinIndexArray = new Float32Array( nvertices * 4 );
889 geometryGroup.__skinWeightArray = new Float32Array( nvertices * 4 );
890
891 }
892
893 geometryGroup.__faceArray = new Uint16Array( ntris * 3 );
894 geometryGroup.__lineArray = new Uint16Array( nlines * 2 );
895
896 var m, ml;
897
898 if ( geometryGroup.numMorphTargets ) {
899
900 geometryGroup.__morphTargetsArrays = [];
901
902 for ( m = 0, ml = geometryGroup.numMorphTargets; m < ml; m ++ ) {
903
904 geometryGroup.__morphTargetsArrays.push( new Float32Array( nvertices * 3 ) );
905
906 }
907
908 }
909
910 if ( geometryGroup.numMorphNormals ) {
911
912 geometryGroup.__morphNormalsArrays = [];
913
914 for ( m = 0, ml = geometryGroup.numMorphNormals; m < ml; m ++ ) {
915
916 geometryGroup.__morphNormalsArrays.push( new Float32Array( nvertices * 3 ) );
917
918 }
919
920 }
921
922 geometryGroup.__webglFaceCount = ntris * 3;
923 geometryGroup.__webglLineCount = nlines * 2;
924
925
926 // custom attributes
927
928 if ( material.attributes ) {
929
930 if ( geometryGroup.__webglCustomAttributesList === undefined ) {
931
932 geometryGroup.__webglCustomAttributesList = [];
933
934 }
935
936 for ( var a in material.attributes ) {
937
938 // Do a shallow copy of the attribute object so different geometryGroup chunks use different
939 // attribute buffers which are correctly indexed in the setMeshBuffers function
940
941 var originalAttribute = material.attributes[ a ];
942
943 var attribute = {};
944
945 for ( var property in originalAttribute ) {
946
947 attribute[ property ] = originalAttribute[ property ];
948
949 }
950
951 if ( !attribute.__webglInitialized || attribute.createUniqueBuffers ) {
952
953 attribute.__webglInitialized = true;
954
955 var size = 1; // "f" and "i"
956
957 if( attribute.type === "v2" ) size = 2;
958 else if( attribute.type === "v3" ) size = 3;
959 else if( attribute.type === "v4" ) size = 4;
960 else if( attribute.type === "c" ) size = 3;
961
962 attribute.size = size;
963
964 attribute.array = new Float32Array( nvertices * size );
965
966 attribute.buffer = _gl.createBuffer();
967 attribute.buffer.belongsToAttribute = a;
968
969 originalAttribute.needsUpdate = true;
970 attribute.__original = originalAttribute;
971
972 }
973
974 geometryGroup.__webglCustomAttributesList.push( attribute );
975
976 }
977
978 }
979
980 geometryGroup.__inittedArrays = true;
981
982 };
983
984 function getBufferMaterial( object, geometryGroup ) {
985
986 return object.material instanceof THREE.MeshFaceMaterial
987 ? object.material.materials[ geometryGroup.materialIndex ]
988 : object.material;
989
990 };
991
992 function materialNeedsSmoothNormals ( material ) {
993
994 return material && material.shading !== undefined && material.shading === THREE.SmoothShading;
995
996 };
997
998 function bufferGuessNormalType ( material ) {
999
1000 // only MeshBasicMaterial and MeshDepthMaterial don't need normals
1001
1002 if ( ( material instanceof THREE.MeshBasicMaterial && !material.envMap ) || material instanceof THREE.MeshDepthMaterial ) {
1003
1004 return false;
1005
1006 }
1007
1008 if ( materialNeedsSmoothNormals( material ) ) {
1009
1010 return THREE.SmoothShading;
1011
1012 } else {
1013
1014 return THREE.FlatShading;
1015
1016 }
1017
1018 };
1019
1020 function bufferGuessVertexColorType( material ) {
1021
1022 if ( material.vertexColors ) {
1023
1024 return material.vertexColors;
1025
1026 }
1027
1028 return false;
1029
1030 };
1031
1032 function bufferGuessUVType( material ) {
1033
1034 // material must use some texture to require uvs
1035
1036 if ( material.map ||
1037 material.lightMap ||
1038 material.bumpMap ||
1039 material.normalMap ||
1040 material.specularMap ||
1041 material instanceof THREE.ShaderMaterial ) {
1042
1043 return true;
1044
1045 }
1046
1047 return false;
1048
1049 };
1050
1051 //
1052
1053 function initDirectBuffers( geometry ) {
1054
1055 var a, attribute, type;
1056
1057 for ( a in geometry.attributes ) {
1058
1059 if ( a === "index" ) {
1060
1061 type = _gl.ELEMENT_ARRAY_BUFFER;
1062
1063 } else {
1064
1065 type = _gl.ARRAY_BUFFER;
1066
1067 }
1068
1069 attribute = geometry.attributes[ a ];
1070
1071 if ( attribute.numItems === undefined ) {
1072
1073 attribute.numItems = attribute.array.length;
1074
1075 }
1076
1077 attribute.buffer = _gl.createBuffer();
1078
1079 _gl.bindBuffer( type, attribute.buffer );
1080 _gl.bufferData( type, attribute.array, _gl.STATIC_DRAW );
1081
1082 }
1083
1084 };
1085
1086 // Buffer setting
1087
1088 function setParticleBuffers ( geometry, hint, object ) {
1089
1090 var v, c, vertex, offset, index, color,
1091
1092 vertices = geometry.vertices,
1093 vl = vertices.length,
1094
1095 colors = geometry.colors,
1096 cl = colors.length,
1097
1098 vertexArray = geometry.__vertexArray,
1099 colorArray = geometry.__colorArray,
1100
1101 sortArray = geometry.__sortArray,
1102
1103 dirtyVertices = geometry.verticesNeedUpdate,
1104 dirtyElements = geometry.elementsNeedUpdate,
1105 dirtyColors = geometry.colorsNeedUpdate,
1106
1107 customAttributes = geometry.__webglCustomAttributesList,
1108 i, il,
1109 a, ca, cal, value,
1110 customAttribute;
1111
1112 if ( object.sortParticles ) {
1113
1114 _projScreenMatrixPS.copy( _projScreenMatrix );
1115 _projScreenMatrixPS.multiply( object.matrixWorld );
1116
1117 for ( v = 0; v < vl; v ++ ) {
1118
1119 vertex = vertices[ v ];
1120
1121 _vector3.copy( vertex );
1122 _vector3.applyProjection( _projScreenMatrixPS );
1123
1124 sortArray[ v ] = [ _vector3.z, v ];
1125
1126 }
1127
1128 sortArray.sort( numericalSort );
1129
1130 for ( v = 0; v < vl; v ++ ) {
1131
1132 vertex = vertices[ sortArray[v][1] ];
1133
1134 offset = v * 3;
1135
1136 vertexArray[ offset ] = vertex.x;
1137 vertexArray[ offset + 1 ] = vertex.y;
1138 vertexArray[ offset + 2 ] = vertex.z;
1139
1140 }
1141
1142 for ( c = 0; c < cl; c ++ ) {
1143
1144 offset = c * 3;
1145
1146 color = colors[ sortArray[c][1] ];
1147
1148 colorArray[ offset ] = color.r;
1149 colorArray[ offset + 1 ] = color.g;
1150 colorArray[ offset + 2 ] = color.b;
1151
1152 }
1153
1154 if ( customAttributes ) {
1155
1156 for ( i = 0, il = customAttributes.length; i < il; i ++ ) {
1157
1158 customAttribute = customAttributes[ i ];
1159
1160 if ( ! ( customAttribute.boundTo === undefined || customAttribute.boundTo === "vertices" ) ) continue;
1161
1162 offset = 0;
1163
1164 cal = customAttribute.value.length;
1165
1166 if ( customAttribute.size === 1 ) {
1167
1168 for ( ca = 0; ca < cal; ca ++ ) {
1169
1170 index = sortArray[ ca ][ 1 ];
1171
1172 customAttribute.array[ ca ] = customAttribute.value[ index ];
1173
1174 }
1175
1176 } else if ( customAttribute.size === 2 ) {
1177
1178 for ( ca = 0; ca < cal; ca ++ ) {
1179
1180 index = sortArray[ ca ][ 1 ];
1181
1182 value = customAttribute.value[ index ];
1183
1184 customAttribute.array[ offset ] = value.x;
1185 customAttribute.array[ offset + 1 ] = value.y;
1186
1187 offset += 2;
1188
1189 }
1190
1191 } else if ( customAttribute.size === 3 ) {
1192
1193 if ( customAttribute.type === "c" ) {
1194
1195 for ( ca = 0; ca < cal; ca ++ ) {
1196
1197 index = sortArray[ ca ][ 1 ];
1198
1199 value = customAttribute.value[ index ];
1200
1201 customAttribute.array[ offset ] = value.r;
1202 customAttribute.array[ offset + 1 ] = value.g;
1203 customAttribute.array[ offset + 2 ] = value.b;
1204
1205 offset += 3;
1206
1207 }
1208
1209 } else {
1210
1211 for ( ca = 0; ca < cal; ca ++ ) {
1212
1213 index = sortArray[ ca ][ 1 ];
1214
1215 value = customAttribute.value[ index ];
1216
1217 customAttribute.array[ offset ] = value.x;
1218 customAttribute.array[ offset + 1 ] = value.y;
1219 customAttribute.array[ offset + 2 ] = value.z;
1220
1221 offset += 3;
1222
1223 }
1224
1225 }
1226
1227 } else if ( customAttribute.size === 4 ) {
1228
1229 for ( ca = 0; ca < cal; ca ++ ) {
1230
1231 index = sortArray[ ca ][ 1 ];
1232
1233 value = customAttribute.value[ index ];
1234
1235 customAttribute.array[ offset ] = value.x;
1236 customAttribute.array[ offset + 1 ] = value.y;
1237 customAttribute.array[ offset + 2 ] = value.z;
1238 customAttribute.array[ offset + 3 ] = value.w;
1239
1240 offset += 4;
1241
1242 }
1243
1244 }
1245
1246 }
1247
1248 }
1249
1250 } else {
1251
1252 if ( dirtyVertices ) {
1253
1254 for ( v = 0; v < vl; v ++ ) {
1255
1256 vertex = vertices[ v ];
1257
1258 offset = v * 3;
1259
1260 vertexArray[ offset ] = vertex.x;
1261 vertexArray[ offset + 1 ] = vertex.y;
1262 vertexArray[ offset + 2 ] = vertex.z;
1263
1264 }
1265
1266 }
1267
1268 if ( dirtyColors ) {
1269
1270 for ( c = 0; c < cl; c ++ ) {
1271
1272 color = colors[ c ];
1273
1274 offset = c * 3;
1275
1276 colorArray[ offset ] = color.r;
1277 colorArray[ offset + 1 ] = color.g;
1278 colorArray[ offset + 2 ] = color.b;
1279
1280 }
1281
1282 }
1283
1284 if ( customAttributes ) {
1285
1286 for ( i = 0, il = customAttributes.length; i < il; i ++ ) {
1287
1288 customAttribute = customAttributes[ i ];
1289
1290 if ( customAttribute.needsUpdate &&
1291 ( customAttribute.boundTo === undefined ||
1292 customAttribute.boundTo === "vertices") ) {
1293
1294 cal = customAttribute.value.length;
1295
1296 offset = 0;
1297
1298 if ( customAttribute.size === 1 ) {
1299
1300 for ( ca = 0; ca < cal; ca ++ ) {
1301
1302 customAttribute.array[ ca ] = customAttribute.value[ ca ];
1303
1304 }
1305
1306 } else if ( customAttribute.size === 2 ) {
1307
1308 for ( ca = 0; ca < cal; ca ++ ) {
1309
1310 value = customAttribute.value[ ca ];
1311
1312 customAttribute.array[ offset ] = value.x;
1313 customAttribute.array[ offset + 1 ] = value.y;
1314
1315 offset += 2;
1316
1317 }
1318
1319 } else if ( customAttribute.size === 3 ) {
1320
1321 if ( customAttribute.type === "c" ) {
1322
1323 for ( ca = 0; ca < cal; ca ++ ) {
1324
1325 value = customAttribute.value[ ca ];
1326
1327 customAttribute.array[ offset ] = value.r;
1328 customAttribute.array[ offset + 1 ] = value.g;
1329 customAttribute.array[ offset + 2 ] = value.b;
1330
1331 offset += 3;
1332
1333 }
1334
1335 } else {
1336
1337 for ( ca = 0; ca < cal; ca ++ ) {
1338
1339 value = customAttribute.value[ ca ];
1340
1341 customAttribute.array[ offset ] = value.x;
1342 customAttribute.array[ offset + 1 ] = value.y;
1343 customAttribute.array[ offset + 2 ] = value.z;
1344
1345 offset += 3;
1346
1347 }
1348
1349 }
1350
1351 } else if ( customAttribute.size === 4 ) {
1352
1353 for ( ca = 0; ca < cal; ca ++ ) {
1354
1355 value = customAttribute.value[ ca ];
1356
1357 customAttribute.array[ offset ] = value.x;
1358 customAttribute.array[ offset + 1 ] = value.y;
1359 customAttribute.array[ offset + 2 ] = value.z;
1360 customAttribute.array[ offset + 3 ] = value.w;
1361
1362 offset += 4;
1363
1364 }
1365
1366 }
1367
1368 }
1369
1370 }
1371
1372 }
1373
1374 }
1375
1376 if ( dirtyVertices || object.sortParticles ) {
1377
1378 _gl.bindBuffer( _gl.ARRAY_BUFFER, geometry.__webglVertexBuffer );
1379 _gl.bufferData( _gl.ARRAY_BUFFER, vertexArray, hint );
1380
1381 }
1382
1383 if ( dirtyColors || object.sortParticles ) {
1384
1385 _gl.bindBuffer( _gl.ARRAY_BUFFER, geometry.__webglColorBuffer );
1386 _gl.bufferData( _gl.ARRAY_BUFFER, colorArray, hint );
1387
1388 }
1389
1390 if ( customAttributes ) {
1391
1392 for ( i = 0, il = customAttributes.length; i < il; i ++ ) {
1393
1394 customAttribute = customAttributes[ i ];
1395
1396 if ( customAttribute.needsUpdate || object.sortParticles ) {
1397
1398 _gl.bindBuffer( _gl.ARRAY_BUFFER, customAttribute.buffer );
1399 _gl.bufferData( _gl.ARRAY_BUFFER, customAttribute.array, hint );
1400
1401 }
1402
1403 }
1404
1405 }
1406
1407
1408 };
1409
1410 function setLineBuffers ( geometry, hint ) {
1411
1412 var v, c, d, vertex, offset, color,
1413
1414 vertices = geometry.vertices,
1415 colors = geometry.colors,
1416 lineDistances = geometry.lineDistances,
1417
1418 vl = vertices.length,
1419 cl = colors.length,
1420 dl = lineDistances.length,
1421
1422 vertexArray = geometry.__vertexArray,
1423 colorArray = geometry.__colorArray,
1424 lineDistanceArray = geometry.__lineDistanceArray,
1425
1426 dirtyVertices = geometry.verticesNeedUpdate,
1427 dirtyColors = geometry.colorsNeedUpdate,
1428 dirtyLineDistances = geometry.lineDistancesNeedUpdate,
1429
1430 customAttributes = geometry.__webglCustomAttributesList,
1431
1432 i, il,
1433 a, ca, cal, value,
1434 customAttribute;
1435
1436 if ( dirtyVertices ) {
1437
1438 for ( v = 0; v < vl; v ++ ) {
1439
1440 vertex = vertices[ v ];
1441
1442 offset = v * 3;
1443
1444 vertexArray[ offset ] = vertex.x;
1445 vertexArray[ offset + 1 ] = vertex.y;
1446 vertexArray[ offset + 2 ] = vertex.z;
1447
1448 }
1449
1450 _gl.bindBuffer( _gl.ARRAY_BUFFER, geometry.__webglVertexBuffer );
1451 _gl.bufferData( _gl.ARRAY_BUFFER, vertexArray, hint );
1452
1453 }
1454
1455 if ( dirtyColors ) {
1456
1457 for ( c = 0; c < cl; c ++ ) {
1458
1459 color = colors[ c ];
1460
1461 offset = c * 3;
1462
1463 colorArray[ offset ] = color.r;
1464 colorArray[ offset + 1 ] = color.g;
1465 colorArray[ offset + 2 ] = color.b;
1466
1467 }
1468
1469 _gl.bindBuffer( _gl.ARRAY_BUFFER, geometry.__webglColorBuffer );
1470 _gl.bufferData( _gl.ARRAY_BUFFER, colorArray, hint );
1471
1472 }
1473
1474 if ( dirtyLineDistances ) {
1475
1476 for ( d = 0; d < dl; d ++ ) {
1477
1478 lineDistanceArray[ d ] = lineDistances[ d ];
1479
1480 }
1481
1482 _gl.bindBuffer( _gl.ARRAY_BUFFER, geometry.__webglLineDistanceBuffer );
1483 _gl.bufferData( _gl.ARRAY_BUFFER, lineDistanceArray, hint );
1484
1485 }
1486
1487 if ( customAttributes ) {
1488
1489 for ( i = 0, il = customAttributes.length; i < il; i ++ ) {
1490
1491 customAttribute = customAttributes[ i ];
1492
1493 if ( customAttribute.needsUpdate &&
1494 ( customAttribute.boundTo === undefined ||
1495 customAttribute.boundTo === "vertices" ) ) {
1496
1497 offset = 0;
1498
1499 cal = customAttribute.value.length;
1500
1501 if ( customAttribute.size === 1 ) {
1502
1503 for ( ca = 0; ca < cal; ca ++ ) {
1504
1505 customAttribute.array[ ca ] = customAttribute.value[ ca ];
1506
1507 }
1508
1509 } else if ( customAttribute.size === 2 ) {
1510
1511 for ( ca = 0; ca < cal; ca ++ ) {
1512
1513 value = customAttribute.value[ ca ];
1514
1515 customAttribute.array[ offset ] = value.x;
1516 customAttribute.array[ offset + 1 ] = value.y;
1517
1518 offset += 2;
1519
1520 }
1521
1522 } else if ( customAttribute.size === 3 ) {
1523
1524 if ( customAttribute.type === "c" ) {
1525
1526 for ( ca = 0; ca < cal; ca ++ ) {
1527
1528 value = customAttribute.value[ ca ];
1529
1530 customAttribute.array[ offset ] = value.r;
1531 customAttribute.array[ offset + 1 ] = value.g;
1532 customAttribute.array[ offset + 2 ] = value.b;
1533
1534 offset += 3;
1535
1536 }
1537
1538 } else {
1539
1540 for ( ca = 0; ca < cal; ca ++ ) {
1541
1542 value = customAttribute.value[ ca ];
1543
1544 customAttribute.array[ offset ] = value.x;
1545 customAttribute.array[ offset + 1 ] = value.y;
1546 customAttribute.array[ offset + 2 ] = value.z;
1547
1548 offset += 3;
1549
1550 }
1551
1552 }
1553
1554 } else if ( customAttribute.size === 4 ) {
1555
1556 for ( ca = 0; ca < cal; ca ++ ) {
1557
1558 value = customAttribute.value[ ca ];
1559
1560 customAttribute.array[ offset ] = value.x;
1561 customAttribute.array[ offset + 1 ] = value.y;
1562 customAttribute.array[ offset + 2 ] = value.z;
1563 customAttribute.array[ offset + 3 ] = value.w;
1564
1565 offset += 4;
1566
1567 }
1568
1569 }
1570
1571 _gl.bindBuffer( _gl.ARRAY_BUFFER, customAttribute.buffer );
1572 _gl.bufferData( _gl.ARRAY_BUFFER, customAttribute.array, hint );
1573
1574 }
1575
1576 }
1577
1578 }
1579
1580 };
1581
1582 function setMeshBuffers( geometryGroup, object, hint, dispose, material ) {
1583
1584 if ( ! geometryGroup.__inittedArrays ) {
1585
1586 return;
1587
1588 }
1589
1590 var normalType = bufferGuessNormalType( material ),
1591 vertexColorType = bufferGuessVertexColorType( material ),
1592 uvType = bufferGuessUVType( material ),
1593
1594 needsSmoothNormals = ( normalType === THREE.SmoothShading );
1595
1596 var f, fl, fi, face,
1597 vertexNormals, faceNormal, normal,
1598 vertexColors, faceColor,
1599 vertexTangents,
1600 uv, uv2, v1, v2, v3, v4, t1, t2, t3, t4, n1, n2, n3, n4,
1601 c1, c2, c3, c4,
1602 sw1, sw2, sw3, sw4,
1603 si1, si2, si3, si4,
1604 sa1, sa2, sa3, sa4,
1605 sb1, sb2, sb3, sb4,
1606 m, ml, i, il,
1607 vn, uvi, uv2i,
1608 vk, vkl, vka,
1609 nka, chf, faceVertexNormals,
1610 a,
1611
1612 vertexIndex = 0,
1613
1614 offset = 0,
1615 offset_uv = 0,
1616 offset_uv2 = 0,
1617 offset_face = 0,
1618 offset_normal = 0,
1619 offset_tangent = 0,
1620 offset_line = 0,
1621 offset_color = 0,
1622 offset_skin = 0,
1623 offset_morphTarget = 0,
1624 offset_custom = 0,
1625 offset_customSrc = 0,
1626
1627 value,
1628
1629 vertexArray = geometryGroup.__vertexArray,
1630 uvArray = geometryGroup.__uvArray,
1631 uv2Array = geometryGroup.__uv2Array,
1632 normalArray = geometryGroup.__normalArray,
1633 tangentArray = geometryGroup.__tangentArray,
1634 colorArray = geometryGroup.__colorArray,
1635
1636 skinIndexArray = geometryGroup.__skinIndexArray,
1637 skinWeightArray = geometryGroup.__skinWeightArray,
1638
1639 morphTargetsArrays = geometryGroup.__morphTargetsArrays,
1640 morphNormalsArrays = geometryGroup.__morphNormalsArrays,
1641
1642 customAttributes = geometryGroup.__webglCustomAttributesList,
1643 customAttribute,
1644
1645 faceArray = geometryGroup.__faceArray,
1646 lineArray = geometryGroup.__lineArray,
1647
1648 geometry = object.geometry, // this is shared for all chunks
1649
1650 dirtyVertices = geometry.verticesNeedUpdate,
1651 dirtyElements = geometry.elementsNeedUpdate,
1652 dirtyUvs = geometry.uvsNeedUpdate,
1653 dirtyNormals = geometry.normalsNeedUpdate,
1654 dirtyTangents = geometry.tangentsNeedUpdate,
1655 dirtyColors = geometry.colorsNeedUpdate,
1656 dirtyMorphTargets = geometry.morphTargetsNeedUpdate,
1657
1658 vertices = geometry.vertices,
1659 chunk_faces3 = geometryGroup.faces3,
1660 obj_faces = geometry.faces,
1661
1662 obj_uvs = geometry.faceVertexUvs[ 0 ],
1663 obj_uvs2 = geometry.faceVertexUvs[ 1 ],
1664
1665 obj_colors = geometry.colors,
1666
1667 obj_skinIndices = geometry.skinIndices,
1668 obj_skinWeights = geometry.skinWeights,
1669
1670 morphTargets = geometry.morphTargets,
1671 morphNormals = geometry.morphNormals;
1672
1673 if ( dirtyVertices ) {
1674
1675 for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
1676
1677 face = obj_faces[ chunk_faces3[ f ] ];
1678
1679 v1 = vertices[ face.a ];
1680 v2 = vertices[ face.b ];
1681 v3 = vertices[ face.c ];
1682
1683 vertexArray[ offset ] = v1.x;
1684 vertexArray[ offset + 1 ] = v1.y;
1685 vertexArray[ offset + 2 ] = v1.z;
1686
1687 vertexArray[ offset + 3 ] = v2.x;
1688 vertexArray[ offset + 4 ] = v2.y;
1689 vertexArray[ offset + 5 ] = v2.z;
1690
1691 vertexArray[ offset + 6 ] = v3.x;
1692 vertexArray[ offset + 7 ] = v3.y;
1693 vertexArray[ offset + 8 ] = v3.z;
1694
1695 offset += 9;
1696
1697 }
1698
1699 _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglVertexBuffer );
1700 _gl.bufferData( _gl.ARRAY_BUFFER, vertexArray, hint );
1701
1702 }
1703
1704 if ( dirtyMorphTargets ) {
1705
1706 for ( vk = 0, vkl = morphTargets.length; vk < vkl; vk ++ ) {
1707
1708 offset_morphTarget = 0;
1709
1710 for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
1711
1712 chf = chunk_faces3[ f ];
1713 face = obj_faces[ chf ];
1714
1715 // morph positions
1716
1717 v1 = morphTargets[ vk ].vertices[ face.a ];
1718 v2 = morphTargets[ vk ].vertices[ face.b ];
1719 v3 = morphTargets[ vk ].vertices[ face.c ];
1720
1721 vka = morphTargetsArrays[ vk ];
1722
1723 vka[ offset_morphTarget ] = v1.x;
1724 vka[ offset_morphTarget + 1 ] = v1.y;
1725 vka[ offset_morphTarget + 2 ] = v1.z;
1726
1727 vka[ offset_morphTarget + 3 ] = v2.x;
1728 vka[ offset_morphTarget + 4 ] = v2.y;
1729 vka[ offset_morphTarget + 5 ] = v2.z;
1730
1731 vka[ offset_morphTarget + 6 ] = v3.x;
1732 vka[ offset_morphTarget + 7 ] = v3.y;
1733 vka[ offset_morphTarget + 8 ] = v3.z;
1734
1735 // morph normals
1736
1737 if ( material.morphNormals ) {
1738
1739 if ( needsSmoothNormals ) {
1740
1741 faceVertexNormals = morphNormals[ vk ].vertexNormals[ chf ];
1742
1743 n1 = faceVertexNormals.a;
1744 n2 = faceVertexNormals.b;
1745 n3 = faceVertexNormals.c;
1746
1747 } else {
1748
1749 n1 = morphNormals[ vk ].faceNormals[ chf ];
1750 n2 = n1;
1751 n3 = n1;
1752
1753 }
1754
1755 nka = morphNormalsArrays[ vk ];
1756
1757 nka[ offset_morphTarget ] = n1.x;
1758 nka[ offset_morphTarget + 1 ] = n1.y;
1759 nka[ offset_morphTarget + 2 ] = n1.z;
1760
1761 nka[ offset_morphTarget + 3 ] = n2.x;
1762 nka[ offset_morphTarget + 4 ] = n2.y;
1763 nka[ offset_morphTarget + 5 ] = n2.z;
1764
1765 nka[ offset_morphTarget + 6 ] = n3.x;
1766 nka[ offset_morphTarget + 7 ] = n3.y;
1767 nka[ offset_morphTarget + 8 ] = n3.z;
1768
1769 }
1770
1771 //
1772
1773 offset_morphTarget += 9;
1774
1775 }
1776
1777 _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphTargetsBuffers[ vk ] );
1778 _gl.bufferData( _gl.ARRAY_BUFFER, morphTargetsArrays[ vk ], hint );
1779
1780 if ( material.morphNormals ) {
1781
1782 _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphNormalsBuffers[ vk ] );
1783 _gl.bufferData( _gl.ARRAY_BUFFER, morphNormalsArrays[ vk ], hint );
1784
1785 }
1786
1787 }
1788
1789 }
1790
1791 if ( obj_skinWeights.length ) {
1792
1793 for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
1794
1795 face = obj_faces[ chunk_faces3[ f ] ];
1796
1797 // weights
1798
1799 sw1 = obj_skinWeights[ face.a ];
1800 sw2 = obj_skinWeights[ face.b ];
1801 sw3 = obj_skinWeights[ face.c ];
1802
1803 skinWeightArray[ offset_skin ] = sw1.x;
1804 skinWeightArray[ offset_skin + 1 ] = sw1.y;
1805 skinWeightArray[ offset_skin + 2 ] = sw1.z;
1806 skinWeightArray[ offset_skin + 3 ] = sw1.w;
1807
1808 skinWeightArray[ offset_skin + 4 ] = sw2.x;
1809 skinWeightArray[ offset_skin + 5 ] = sw2.y;
1810 skinWeightArray[ offset_skin + 6 ] = sw2.z;
1811 skinWeightArray[ offset_skin + 7 ] = sw2.w;
1812
1813 skinWeightArray[ offset_skin + 8 ] = sw3.x;
1814 skinWeightArray[ offset_skin + 9 ] = sw3.y;
1815 skinWeightArray[ offset_skin + 10 ] = sw3.z;
1816 skinWeightArray[ offset_skin + 11 ] = sw3.w;
1817
1818 // indices
1819
1820 si1 = obj_skinIndices[ face.a ];
1821 si2 = obj_skinIndices[ face.b ];
1822 si3 = obj_skinIndices[ face.c ];
1823
1824 skinIndexArray[ offset_skin ] = si1.x;
1825 skinIndexArray[ offset_skin + 1 ] = si1.y;
1826 skinIndexArray[ offset_skin + 2 ] = si1.z;
1827 skinIndexArray[ offset_skin + 3 ] = si1.w;
1828
1829 skinIndexArray[ offset_skin + 4 ] = si2.x;
1830 skinIndexArray[ offset_skin + 5 ] = si2.y;
1831 skinIndexArray[ offset_skin + 6 ] = si2.z;
1832 skinIndexArray[ offset_skin + 7 ] = si2.w;
1833
1834 skinIndexArray[ offset_skin + 8 ] = si3.x;
1835 skinIndexArray[ offset_skin + 9 ] = si3.y;
1836 skinIndexArray[ offset_skin + 10 ] = si3.z;
1837 skinIndexArray[ offset_skin + 11 ] = si3.w;
1838
1839 offset_skin += 12;
1840
1841 }
1842
1843 if ( offset_skin > 0 ) {
1844
1845 _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglSkinIndicesBuffer );
1846 _gl.bufferData( _gl.ARRAY_BUFFER, skinIndexArray, hint );
1847
1848 _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglSkinWeightsBuffer );
1849 _gl.bufferData( _gl.ARRAY_BUFFER, skinWeightArray, hint );
1850
1851 }
1852
1853 }
1854
1855 if ( dirtyColors && vertexColorType ) {
1856
1857 for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
1858
1859 face = obj_faces[ chunk_faces3[ f ] ];
1860
1861 vertexColors = face.vertexColors;
1862 faceColor = face.color;
1863
1864 if ( vertexColors.length === 3 && vertexColorType === THREE.VertexColors ) {
1865
1866 c1 = vertexColors[ 0 ];
1867 c2 = vertexColors[ 1 ];
1868 c3 = vertexColors[ 2 ];
1869
1870 } else {
1871
1872 c1 = faceColor;
1873 c2 = faceColor;
1874 c3 = faceColor;
1875
1876 }
1877
1878 colorArray[ offset_color ] = c1.r;
1879 colorArray[ offset_color + 1 ] = c1.g;
1880 colorArray[ offset_color + 2 ] = c1.b;
1881
1882 colorArray[ offset_color + 3 ] = c2.r;
1883 colorArray[ offset_color + 4 ] = c2.g;
1884 colorArray[ offset_color + 5 ] = c2.b;
1885
1886 colorArray[ offset_color + 6 ] = c3.r;
1887 colorArray[ offset_color + 7 ] = c3.g;
1888 colorArray[ offset_color + 8 ] = c3.b;
1889
1890 offset_color += 9;
1891
1892 }
1893
1894 if ( offset_color > 0 ) {
1895
1896 _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglColorBuffer );
1897 _gl.bufferData( _gl.ARRAY_BUFFER, colorArray, hint );
1898
1899 }
1900
1901 }
1902
1903 if ( dirtyTangents && geometry.hasTangents ) {
1904
1905 for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
1906
1907 face = obj_faces[ chunk_faces3[ f ] ];
1908
1909 vertexTangents = face.vertexTangents;
1910
1911 t1 = vertexTangents[ 0 ];
1912 t2 = vertexTangents[ 1 ];
1913 t3 = vertexTangents[ 2 ];
1914
1915 tangentArray[ offset_tangent ] = t1.x;
1916 tangentArray[ offset_tangent + 1 ] = t1.y;
1917 tangentArray[ offset_tangent + 2 ] = t1.z;
1918 tangentArray[ offset_tangent + 3 ] = t1.w;
1919
1920 tangentArray[ offset_tangent + 4 ] = t2.x;
1921 tangentArray[ offset_tangent + 5 ] = t2.y;
1922 tangentArray[ offset_tangent + 6 ] = t2.z;
1923 tangentArray[ offset_tangent + 7 ] = t2.w;
1924
1925 tangentArray[ offset_tangent + 8 ] = t3.x;
1926 tangentArray[ offset_tangent + 9 ] = t3.y;
1927 tangentArray[ offset_tangent + 10 ] = t3.z;
1928 tangentArray[ offset_tangent + 11 ] = t3.w;
1929
1930 offset_tangent += 12;
1931
1932 }
1933
1934 _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglTangentBuffer );
1935 _gl.bufferData( _gl.ARRAY_BUFFER, tangentArray, hint );
1936
1937 }
1938
1939 if ( dirtyNormals && normalType ) {
1940
1941 for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
1942
1943 face = obj_faces[ chunk_faces3[ f ] ];
1944
1945 vertexNormals = face.vertexNormals;
1946 faceNormal = face.normal;
1947
1948 if ( vertexNormals.length === 3 && needsSmoothNormals ) {
1949
1950 for ( i = 0; i < 3; i ++ ) {
1951
1952 vn = vertexNormals[ i ];
1953
1954 normalArray[ offset_normal ] = vn.x;
1955 normalArray[ offset_normal + 1 ] = vn.y;
1956 normalArray[ offset_normal + 2 ] = vn.z;
1957
1958 offset_normal += 3;
1959
1960 }
1961
1962 } else {
1963
1964 for ( i = 0; i < 3; i ++ ) {
1965
1966 normalArray[ offset_normal ] = faceNormal.x;
1967 normalArray[ offset_normal + 1 ] = faceNormal.y;
1968 normalArray[ offset_normal + 2 ] = faceNormal.z;
1969
1970 offset_normal += 3;
1971
1972 }
1973
1974 }
1975
1976 }
1977
1978 _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglNormalBuffer );
1979 _gl.bufferData( _gl.ARRAY_BUFFER, normalArray, hint );
1980
1981 }
1982
1983 if ( dirtyUvs && obj_uvs && uvType ) {
1984
1985 for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
1986
1987 fi = chunk_faces3[ f ];
1988
1989 uv = obj_uvs[ fi ];
1990
1991 if ( uv === undefined ) continue;
1992
1993 for ( i = 0; i < 3; i ++ ) {
1994
1995 uvi = uv[ i ];
1996
1997 uvArray[ offset_uv ] = uvi.x;
1998 uvArray[ offset_uv + 1 ] = uvi.y;
1999
2000 offset_uv += 2;
2001
2002 }
2003
2004 }
2005
2006 if ( offset_uv > 0 ) {
2007
2008 _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglUVBuffer );
2009 _gl.bufferData( _gl.ARRAY_BUFFER, uvArray, hint );
2010
2011 }
2012
2013 }
2014
2015 if ( dirtyUvs && obj_uvs2 && uvType ) {
2016
2017 for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
2018
2019 fi = chunk_faces3[ f ];
2020
2021 uv2 = obj_uvs2[ fi ];
2022
2023 if ( uv2 === undefined ) continue;
2024
2025 for ( i = 0; i < 3; i ++ ) {
2026
2027 uv2i = uv2[ i ];
2028
2029 uv2Array[ offset_uv2 ] = uv2i.x;
2030 uv2Array[ offset_uv2 + 1 ] = uv2i.y;
2031
2032 offset_uv2 += 2;
2033
2034 }
2035
2036 }
2037
2038 if ( offset_uv2 > 0 ) {
2039
2040 _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglUV2Buffer );
2041 _gl.bufferData( _gl.ARRAY_BUFFER, uv2Array, hint );
2042
2043 }
2044
2045 }
2046
2047 if ( dirtyElements ) {
2048
2049 for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
2050
2051 faceArray[ offset_face ] = vertexIndex;
2052 faceArray[ offset_face + 1 ] = vertexIndex + 1;
2053 faceArray[ offset_face + 2 ] = vertexIndex + 2;
2054
2055 offset_face += 3;
2056
2057 lineArray[ offset_line ] = vertexIndex;
2058 lineArray[ offset_line + 1 ] = vertexIndex + 1;
2059
2060 lineArray[ offset_line + 2 ] = vertexIndex;
2061 lineArray[ offset_line + 3 ] = vertexIndex + 2;
2062
2063 lineArray[ offset_line + 4 ] = vertexIndex + 1;
2064 lineArray[ offset_line + 5 ] = vertexIndex + 2;
2065
2066 offset_line += 6;
2067
2068 vertexIndex += 3;
2069
2070 }
2071
2072 _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, geometryGroup.__webglFaceBuffer );
2073 _gl.bufferData( _gl.ELEMENT_ARRAY_BUFFER, faceArray, hint );
2074
2075 _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, geometryGroup.__webglLineBuffer );
2076 _gl.bufferData( _gl.ELEMENT_ARRAY_BUFFER, lineArray, hint );
2077
2078 }
2079
2080 if ( customAttributes ) {
2081
2082 for ( i = 0, il = customAttributes.length; i < il; i ++ ) {
2083
2084 customAttribute = customAttributes[ i ];
2085
2086 if ( ! customAttribute.__original.needsUpdate ) continue;
2087
2088 offset_custom = 0;
2089 offset_customSrc = 0;
2090
2091 if ( customAttribute.size === 1 ) {
2092
2093 if ( customAttribute.boundTo === undefined || customAttribute.boundTo === "vertices" ) {
2094
2095 for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
2096
2097 face = obj_faces[ chunk_faces3[ f ] ];
2098
2099 customAttribute.array[ offset_custom ] = customAttribute.value[ face.a ];
2100 customAttribute.array[ offset_custom + 1 ] = customAttribute.value[ face.b ];
2101 customAttribute.array[ offset_custom + 2 ] = customAttribute.value[ face.c ];
2102
2103 offset_custom += 3;
2104
2105 }
2106
2107 } else if ( customAttribute.boundTo === "faces" ) {
2108
2109 for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
2110
2111 value = customAttribute.value[ chunk_faces3[ f ] ];
2112
2113 customAttribute.array[ offset_custom ] = value;
2114 customAttribute.array[ offset_custom + 1 ] = value;
2115 customAttribute.array[ offset_custom + 2 ] = value;
2116
2117 offset_custom += 3;
2118
2119 }
2120
2121 }
2122
2123 } else if ( customAttribute.size === 2 ) {
2124
2125 if ( customAttribute.boundTo === undefined || customAttribute.boundTo === "vertices" ) {
2126
2127 for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
2128
2129 face = obj_faces[ chunk_faces3[ f ] ];
2130
2131 v1 = customAttribute.value[ face.a ];
2132 v2 = customAttribute.value[ face.b ];
2133 v3 = customAttribute.value[ face.c ];
2134
2135 customAttribute.array[ offset_custom ] = v1.x;
2136 customAttribute.array[ offset_custom + 1 ] = v1.y;
2137
2138 customAttribute.array[ offset_custom + 2 ] = v2.x;
2139 customAttribute.array[ offset_custom + 3 ] = v2.y;
2140
2141 customAttribute.array[ offset_custom + 4 ] = v3.x;
2142 customAttribute.array[ offset_custom + 5 ] = v3.y;
2143
2144 offset_custom += 6;
2145
2146 }
2147
2148 } else if ( customAttribute.boundTo === "faces" ) {
2149
2150 for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
2151
2152 value = customAttribute.value[ chunk_faces3[ f ] ];
2153
2154 v1 = value;
2155 v2 = value;
2156 v3 = value;
2157
2158 customAttribute.array[ offset_custom ] = v1.x;
2159 customAttribute.array[ offset_custom + 1 ] = v1.y;
2160
2161 customAttribute.array[ offset_custom + 2 ] = v2.x;
2162 customAttribute.array[ offset_custom + 3 ] = v2.y;
2163
2164 customAttribute.array[ offset_custom + 4 ] = v3.x;
2165 customAttribute.array[ offset_custom + 5 ] = v3.y;
2166
2167 offset_custom += 6;
2168
2169 }
2170
2171 }
2172
2173 } else if ( customAttribute.size === 3 ) {
2174
2175 var pp;
2176
2177 if ( customAttribute.type === "c" ) {
2178
2179 pp = [ "r", "g", "b" ];
2180
2181 } else {
2182
2183 pp = [ "x", "y", "z" ];
2184
2185 }
2186
2187 if ( customAttribute.boundTo === undefined || customAttribute.boundTo === "vertices" ) {
2188
2189 for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
2190
2191 face = obj_faces[ chunk_faces3[ f ] ];
2192
2193 v1 = customAttribute.value[ face.a ];
2194 v2 = customAttribute.value[ face.b ];
2195 v3 = customAttribute.value[ face.c ];
2196
2197 customAttribute.array[ offset_custom ] = v1[ pp[ 0 ] ];
2198 customAttribute.array[ offset_custom + 1 ] = v1[ pp[ 1 ] ];
2199 customAttribute.array[ offset_custom + 2 ] = v1[ pp[ 2 ] ];
2200
2201 customAttribute.array[ offset_custom + 3 ] = v2[ pp[ 0 ] ];
2202 customAttribute.array[ offset_custom + 4 ] = v2[ pp[ 1 ] ];
2203 customAttribute.array[ offset_custom + 5 ] = v2[ pp[ 2 ] ];
2204
2205 customAttribute.array[ offset_custom + 6 ] = v3[ pp[ 0 ] ];
2206 customAttribute.array[ offset_custom + 7 ] = v3[ pp[ 1 ] ];
2207 customAttribute.array[ offset_custom + 8 ] = v3[ pp[ 2 ] ];
2208
2209 offset_custom += 9;
2210
2211 }
2212
2213 } else if ( customAttribute.boundTo === "faces" ) {
2214
2215 for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
2216
2217 value = customAttribute.value[ chunk_faces3[ f ] ];
2218
2219 v1 = value;
2220 v2 = value;
2221 v3 = value;
2222
2223 customAttribute.array[ offset_custom ] = v1[ pp[ 0 ] ];
2224 customAttribute.array[ offset_custom + 1 ] = v1[ pp[ 1 ] ];
2225 customAttribute.array[ offset_custom + 2 ] = v1[ pp[ 2 ] ];
2226
2227 customAttribute.array[ offset_custom + 3 ] = v2[ pp[ 0 ] ];
2228 customAttribute.array[ offset_custom + 4 ] = v2[ pp[ 1 ] ];
2229 customAttribute.array[ offset_custom + 5 ] = v2[ pp[ 2 ] ];
2230
2231 customAttribute.array[ offset_custom + 6 ] = v3[ pp[ 0 ] ];
2232 customAttribute.array[ offset_custom + 7 ] = v3[ pp[ 1 ] ];
2233 customAttribute.array[ offset_custom + 8 ] = v3[ pp[ 2 ] ];
2234
2235 offset_custom += 9;
2236
2237 }
2238
2239 } else if ( customAttribute.boundTo === "faceVertices" ) {
2240
2241 for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
2242
2243 value = customAttribute.value[ chunk_faces3[ f ] ];
2244
2245 v1 = value[ 0 ];
2246 v2 = value[ 1 ];
2247 v3 = value[ 2 ];
2248
2249 customAttribute.array[ offset_custom ] = v1[ pp[ 0 ] ];
2250 customAttribute.array[ offset_custom + 1 ] = v1[ pp[ 1 ] ];
2251 customAttribute.array[ offset_custom + 2 ] = v1[ pp[ 2 ] ];
2252
2253 customAttribute.array[ offset_custom + 3 ] = v2[ pp[ 0 ] ];
2254 customAttribute.array[ offset_custom + 4 ] = v2[ pp[ 1 ] ];
2255 customAttribute.array[ offset_custom + 5 ] = v2[ pp[ 2 ] ];
2256
2257 customAttribute.array[ offset_custom + 6 ] = v3[ pp[ 0 ] ];
2258 customAttribute.array[ offset_custom + 7 ] = v3[ pp[ 1 ] ];
2259 customAttribute.array[ offset_custom + 8 ] = v3[ pp[ 2 ] ];
2260
2261 offset_custom += 9;
2262
2263 }
2264
2265 }
2266
2267 } else if ( customAttribute.size === 4 ) {
2268
2269 if ( customAttribute.boundTo === undefined || customAttribute.boundTo === "vertices" ) {
2270
2271 for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
2272
2273 face = obj_faces[ chunk_faces3[ f ] ];
2274
2275 v1 = customAttribute.value[ face.a ];
2276 v2 = customAttribute.value[ face.b ];
2277 v3 = customAttribute.value[ face.c ];
2278
2279 customAttribute.array[ offset_custom ] = v1.x;
2280 customAttribute.array[ offset_custom + 1 ] = v1.y;
2281 customAttribute.array[ offset_custom + 2 ] = v1.z;
2282 customAttribute.array[ offset_custom + 3 ] = v1.w;
2283
2284 customAttribute.array[ offset_custom + 4 ] = v2.x;
2285 customAttribute.array[ offset_custom + 5 ] = v2.y;
2286 customAttribute.array[ offset_custom + 6 ] = v2.z;
2287 customAttribute.array[ offset_custom + 7 ] = v2.w;
2288
2289 customAttribute.array[ offset_custom + 8 ] = v3.x;
2290 customAttribute.array[ offset_custom + 9 ] = v3.y;
2291 customAttribute.array[ offset_custom + 10 ] = v3.z;
2292 customAttribute.array[ offset_custom + 11 ] = v3.w;
2293
2294 offset_custom += 12;
2295
2296 }
2297
2298 } else if ( customAttribute.boundTo === "faces" ) {
2299
2300 for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
2301
2302 value = customAttribute.value[ chunk_faces3[ f ] ];
2303
2304 v1 = value;
2305 v2 = value;
2306 v3 = value;
2307
2308 customAttribute.array[ offset_custom ] = v1.x;
2309 customAttribute.array[ offset_custom + 1 ] = v1.y;
2310 customAttribute.array[ offset_custom + 2 ] = v1.z;
2311 customAttribute.array[ offset_custom + 3 ] = v1.w;
2312
2313 customAttribute.array[ offset_custom + 4 ] = v2.x;
2314 customAttribute.array[ offset_custom + 5 ] = v2.y;
2315 customAttribute.array[ offset_custom + 6 ] = v2.z;
2316 customAttribute.array[ offset_custom + 7 ] = v2.w;
2317
2318 customAttribute.array[ offset_custom + 8 ] = v3.x;
2319 customAttribute.array[ offset_custom + 9 ] = v3.y;
2320 customAttribute.array[ offset_custom + 10 ] = v3.z;
2321 customAttribute.array[ offset_custom + 11 ] = v3.w;
2322
2323 offset_custom += 12;
2324
2325 }
2326
2327 } else if ( customAttribute.boundTo === "faceVertices" ) {
2328
2329 for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
2330
2331 value = customAttribute.value[ chunk_faces3[ f ] ];
2332
2333 v1 = value[ 0 ];
2334 v2 = value[ 1 ];
2335 v3 = value[ 2 ];
2336
2337 customAttribute.array[ offset_custom ] = v1.x;
2338 customAttribute.array[ offset_custom + 1 ] = v1.y;
2339 customAttribute.array[ offset_custom + 2 ] = v1.z;
2340 customAttribute.array[ offset_custom + 3 ] = v1.w;
2341
2342 customAttribute.array[ offset_custom + 4 ] = v2.x;
2343 customAttribute.array[ offset_custom + 5 ] = v2.y;
2344 customAttribute.array[ offset_custom + 6 ] = v2.z;
2345 customAttribute.array[ offset_custom + 7 ] = v2.w;
2346
2347 customAttribute.array[ offset_custom + 8 ] = v3.x;
2348 customAttribute.array[ offset_custom + 9 ] = v3.y;
2349 customAttribute.array[ offset_custom + 10 ] = v3.z;
2350 customAttribute.array[ offset_custom + 11 ] = v3.w;
2351
2352 offset_custom += 12;
2353
2354 }
2355
2356 }
2357
2358 }
2359
2360 _gl.bindBuffer( _gl.ARRAY_BUFFER, customAttribute.buffer );
2361 _gl.bufferData( _gl.ARRAY_BUFFER, customAttribute.array, hint );
2362
2363 }
2364
2365 }
2366
2367 if ( dispose ) {
2368
2369 delete geometryGroup.__inittedArrays;
2370 delete geometryGroup.__colorArray;
2371 delete geometryGroup.__normalArray;
2372 delete geometryGroup.__tangentArray;
2373 delete geometryGroup.__uvArray;
2374 delete geometryGroup.__uv2Array;
2375 delete geometryGroup.__faceArray;
2376 delete geometryGroup.__vertexArray;
2377 delete geometryGroup.__lineArray;
2378 delete geometryGroup.__skinIndexArray;
2379 delete geometryGroup.__skinWeightArray;
2380
2381 }
2382
2383 };
2384
2385 function setDirectBuffers ( geometry, hint, dispose ) {
2386
2387 var attributes = geometry.attributes;
2388
2389 var attributeName, attributeItem;
2390
2391 for ( attributeName in attributes ) {
2392
2393 attributeItem = attributes[ attributeName ];
2394
2395 if ( attributeItem.needsUpdate ) {
2396
2397 if ( attributeName === 'index' ) {
2398
2399 _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, attributeItem.buffer );
2400 _gl.bufferData( _gl.ELEMENT_ARRAY_BUFFER, attributeItem.array, hint );
2401
2402 } else {
2403
2404 _gl.bindBuffer( _gl.ARRAY_BUFFER, attributeItem.buffer );
2405 _gl.bufferData( _gl.ARRAY_BUFFER, attributeItem.array, hint );
2406
2407 }
2408
2409 attributeItem.needsUpdate = false;
2410
2411 }
2412
2413 if ( dispose && ! attributeItem.dynamic ) {
2414
2415 attributeItem.array = null;
2416
2417 }
2418
2419 }
2420
2421 };
2422
2423 // Buffer rendering
2424
2425 this.renderBufferImmediate = function ( object, program, material ) {
2426
2427 if ( object.hasPositions && ! object.__webglVertexBuffer ) object.__webglVertexBuffer = _gl.createBuffer();
2428 if ( object.hasNormals && ! object.__webglNormalBuffer ) object.__webglNormalBuffer = _gl.createBuffer();
2429 if ( object.hasUvs && ! object.__webglUvBuffer ) object.__webglUvBuffer = _gl.createBuffer();
2430 if ( object.hasColors && ! object.__webglColorBuffer ) object.__webglColorBuffer = _gl.createBuffer();
2431
2432 if ( object.hasPositions ) {
2433
2434 _gl.bindBuffer( _gl.ARRAY_BUFFER, object.__webglVertexBuffer );
2435 _gl.bufferData( _gl.ARRAY_BUFFER, object.positionArray, _gl.DYNAMIC_DRAW );
2436 _gl.enableVertexAttribArray( program.attributes.position );
2437 _gl.vertexAttribPointer( program.attributes.position, 3, _gl.FLOAT, false, 0, 0 );
2438
2439 }
2440
2441 if ( object.hasNormals ) {
2442
2443 _gl.bindBuffer( _gl.ARRAY_BUFFER, object.__webglNormalBuffer );
2444
2445 if ( material.shading === THREE.FlatShading ) {
2446
2447 var nx, ny, nz,
2448 nax, nbx, ncx, nay, nby, ncy, naz, nbz, ncz,
2449 normalArray,
2450 i, il = object.count * 3;
2451
2452 for( i = 0; i < il; i += 9 ) {
2453
2454 normalArray = object.normalArray;
2455
2456 nax = normalArray[ i ];
2457 nay = normalArray[ i + 1 ];
2458 naz = normalArray[ i + 2 ];
2459
2460 nbx = normalArray[ i + 3 ];
2461 nby = normalArray[ i + 4 ];
2462 nbz = normalArray[ i + 5 ];
2463
2464 ncx = normalArray[ i + 6 ];
2465 ncy = normalArray[ i + 7 ];
2466 ncz = normalArray[ i + 8 ];
2467
2468 nx = ( nax + nbx + ncx ) / 3;
2469 ny = ( nay + nby + ncy ) / 3;
2470 nz = ( naz + nbz + ncz ) / 3;
2471
2472 normalArray[ i ] = nx;
2473 normalArray[ i + 1 ] = ny;
2474 normalArray[ i + 2 ] = nz;
2475
2476 normalArray[ i + 3 ] = nx;
2477 normalArray[ i + 4 ] = ny;
2478 normalArray[ i + 5 ] = nz;
2479
2480 normalArray[ i + 6 ] = nx;
2481 normalArray[ i + 7 ] = ny;
2482 normalArray[ i + 8 ] = nz;
2483
2484 }
2485
2486 }
2487
2488 _gl.bufferData( _gl.ARRAY_BUFFER, object.normalArray, _gl.DYNAMIC_DRAW );
2489 _gl.enableVertexAttribArray( program.attributes.normal );
2490 _gl.vertexAttribPointer( program.attributes.normal, 3, _gl.FLOAT, false, 0, 0 );
2491
2492 }
2493
2494 if ( object.hasUvs && material.map ) {
2495
2496 _gl.bindBuffer( _gl.ARRAY_BUFFER, object.__webglUvBuffer );
2497 _gl.bufferData( _gl.ARRAY_BUFFER, object.uvArray, _gl.DYNAMIC_DRAW );
2498 _gl.enableVertexAttribArray( program.attributes.uv );
2499 _gl.vertexAttribPointer( program.attributes.uv, 2, _gl.FLOAT, false, 0, 0 );
2500
2501 }
2502
2503 if ( object.hasColors && material.vertexColors !== THREE.NoColors ) {
2504
2505 _gl.bindBuffer( _gl.ARRAY_BUFFER, object.__webglColorBuffer );
2506 _gl.bufferData( _gl.ARRAY_BUFFER, object.colorArray, _gl.DYNAMIC_DRAW );
2507 _gl.enableVertexAttribArray( program.attributes.color );
2508 _gl.vertexAttribPointer( program.attributes.color, 3, _gl.FLOAT, false, 0, 0 );
2509
2510 }
2511
2512 _gl.drawArrays( _gl.TRIANGLES, 0, object.count );
2513
2514 object.count = 0;
2515
2516 };
2517
2518 this.renderBufferDirect = function ( camera, lights, fog, material, geometry, object ) {
2519
2520 if ( material.visible === false ) return;
2521
2522 var linewidth, a, attribute;
2523 var attributeItem, attributeName, attributePointer, attributeSize;
2524
2525 var program = setProgram( camera, lights, fog, material, object );
2526
2527 var programAttributes = program.attributes;
2528 var geometryAttributes = geometry.attributes;
2529
2530 var updateBuffers = false,
2531 wireframeBit = material.wireframe ? 1 : 0,
2532 geometryHash = ( geometry.id * 0xffffff ) + ( program.id * 2 ) + wireframeBit;
2533
2534 if ( geometryHash !== _currentGeometryGroupHash ) {
2535
2536 _currentGeometryGroupHash = geometryHash;
2537 updateBuffers = true;
2538
2539 }
2540
2541 if ( updateBuffers ) {
2542
2543 disableAttributes();
2544
2545 }
2546
2547 // render mesh
2548
2549 if ( object instanceof THREE.Mesh ) {
2550
2551 var index = geometryAttributes[ "index" ];
2552
2553 // indexed triangles
2554
2555 if ( index ) {
2556
2557 var offsets = geometry.offsets;
2558
2559 // if there is more than 1 chunk
2560 // must set attribute pointers to use new offsets for each chunk
2561 // even if geometry and materials didn't change
2562
2563 if ( offsets.length > 1 ) updateBuffers = true;
2564
2565 for ( var i = 0, il = offsets.length; i < il; i ++ ) {
2566
2567 var startIndex = offsets[ i ].index;
2568
2569 if ( updateBuffers ) {
2570
2571 for ( attributeName in programAttributes ) {
2572
2573 attributePointer = programAttributes[ attributeName ];
2574 attributeItem = geometryAttributes[ attributeName ];
2575
2576 if ( attributePointer >= 0 ) {
2577
2578 if ( attributeItem ) {
2579
2580 attributeSize = attributeItem.itemSize;
2581 _gl.bindBuffer( _gl.ARRAY_BUFFER, attributeItem.buffer );
2582 enableAttribute( attributePointer );
2583 _gl.vertexAttribPointer( attributePointer, attributeSize, _gl.FLOAT, false, 0, startIndex * attributeSize * 4 ); // 4 bytes per Float32
2584
2585 } else if ( material.defaultAttributeValues ) {
2586
2587 if ( material.defaultAttributeValues[ attributeName ].length === 2 ) {
2588
2589 _gl.vertexAttrib2fv( attributePointer, material.defaultAttributeValues[ attributeName ] );
2590
2591 } else if ( material.defaultAttributeValues[ attributeName ].length === 3 ) {
2592
2593 _gl.vertexAttrib3fv( attributePointer, material.defaultAttributeValues[ attributeName ] );
2594
2595 }
2596
2597 }
2598
2599 }
2600
2601 }
2602
2603 // indices
2604
2605 _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, index.buffer );
2606
2607 }
2608
2609 // render indexed triangles
2610
2611 _gl.drawElements( _gl.TRIANGLES, offsets[ i ].count, _gl.UNSIGNED_SHORT, offsets[ i ].start * 2 ); // 2 bytes per Uint16
2612
2613 _this.info.render.calls ++;
2614 _this.info.render.vertices += offsets[ i ].count; // not really true, here vertices can be shared
2615 _this.info.render.faces += offsets[ i ].count / 3;
2616
2617 }
2618
2619 // non-indexed triangles
2620
2621 } else {
2622
2623 if ( updateBuffers ) {
2624
2625 for ( attributeName in programAttributes ) {
2626
2627 if ( attributeName === 'index') continue;
2628
2629 attributePointer = programAttributes[ attributeName ];
2630 attributeItem = geometryAttributes[ attributeName ];
2631
2632 if ( attributePointer >= 0 ) {
2633
2634 if ( attributeItem ) {
2635
2636 attributeSize = attributeItem.itemSize;
2637 _gl.bindBuffer( _gl.ARRAY_BUFFER, attributeItem.buffer );
2638 enableAttribute( attributePointer );
2639 _gl.vertexAttribPointer( attributePointer, attributeSize, _gl.FLOAT, false, 0, 0 );
2640
2641 } else if ( material.defaultAttributeValues && material.defaultAttributeValues[ attributeName ] ) {
2642
2643 if ( material.defaultAttributeValues[ attributeName ].length === 2 ) {
2644
2645 _gl.vertexAttrib2fv( attributePointer, material.defaultAttributeValues[ attributeName ] );
2646
2647 } else if ( material.defaultAttributeValues[ attributeName ].length === 3 ) {
2648
2649 _gl.vertexAttrib3fv( attributePointer, material.defaultAttributeValues[ attributeName ] );
2650
2651 }
2652
2653 }
2654
2655 }
2656
2657 }
2658
2659 }
2660
2661 var position = geometry.attributes[ "position" ];
2662
2663 // render non-indexed triangles
2664
2665 _gl.drawArrays( _gl.TRIANGLES, 0, position.numItems / 3 );
2666
2667 _this.info.render.calls ++;
2668 _this.info.render.vertices += position.numItems / 3;
2669 _this.info.render.faces += position.numItems / 3 / 3;
2670
2671 }
2672
2673 // render particles
2674
2675 } else if ( object instanceof THREE.ParticleSystem ) {
2676
2677 if ( updateBuffers ) {
2678
2679 for ( attributeName in programAttributes ) {
2680
2681 attributePointer = programAttributes[ attributeName ];
2682 attributeItem = geometryAttributes[ attributeName ];
2683
2684 if ( attributePointer >= 0 ) {
2685
2686 if ( attributeItem ) {
2687
2688 attributeSize = attributeItem.itemSize;
2689 _gl.bindBuffer( _gl.ARRAY_BUFFER, attributeItem.buffer );
2690 enableAttribute( attributePointer );
2691 _gl.vertexAttribPointer( attributePointer, attributeSize, _gl.FLOAT, false, 0, 0 );
2692
2693 } else if ( material.defaultAttributeValues && material.defaultAttributeValues[ attributeName ] ) {
2694
2695 if ( material.defaultAttributeValues[ attributeName ].length === 2 ) {
2696
2697 _gl.vertexAttrib2fv( attributePointer, material.defaultAttributeValues[ attributeName ] );
2698
2699 } else if ( material.defaultAttributeValues[ attributeName ].length === 3 ) {
2700
2701 _gl.vertexAttrib3fv( attributePointer, material.defaultAttributeValues[ attributeName ] );
2702
2703 }
2704
2705 }
2706
2707 }
2708
2709 }
2710
2711 }
2712
2713 var position = geometryAttributes[ "position" ];
2714
2715 // render particles
2716
2717 _gl.drawArrays( _gl.POINTS, 0, position.numItems / 3 );
2718
2719 _this.info.render.calls ++;
2720 _this.info.render.points += position.numItems / 3;
2721
2722 } else if ( object instanceof THREE.Line ) {
2723
2724 if ( updateBuffers ) {
2725
2726 for ( attributeName in programAttributes ) {
2727
2728 attributePointer = programAttributes[ attributeName ];
2729 attributeItem = geometryAttributes[ attributeName ];
2730
2731 if ( attributePointer >= 0 ) {
2732
2733 if ( attributeItem ) {
2734
2735 attributeSize = attributeItem.itemSize;
2736 _gl.bindBuffer( _gl.ARRAY_BUFFER, attributeItem.buffer );
2737 enableAttribute( attributePointer );
2738 _gl.vertexAttribPointer( attributePointer, attributeSize, _gl.FLOAT, false, 0, 0 );
2739
2740 } else if ( material.defaultAttributeValues && material.defaultAttributeValues[ attributeName ] ) {
2741
2742 if ( material.defaultAttributeValues[ attributeName ].length === 2 ) {
2743
2744 _gl.vertexAttrib2fv( attributePointer, material.defaultAttributeValues[ attributeName ] );
2745
2746 } else if ( material.defaultAttributeValues[ attributeName ].length === 3 ) {
2747
2748 _gl.vertexAttrib3fv( attributePointer, material.defaultAttributeValues[ attributeName ] );
2749
2750 }
2751
2752 }
2753
2754 }
2755
2756 }
2757
2758 }
2759
2760 // render lines
2761
2762 var primitives = ( object.type === THREE.LineStrip ) ? _gl.LINE_STRIP : _gl.LINES;
2763
2764 setLineWidth( material.linewidth );
2765
2766 var position = geometryAttributes[ "position" ];
2767
2768 _gl.drawArrays( primitives, 0, position.numItems / 3 );
2769
2770 _this.info.render.calls ++;
2771 _this.info.render.points += position.numItems;
2772
2773 }
2774
2775 };
2776
2777 this.renderBuffer = function ( camera, lights, fog, material, geometryGroup, object ) {
2778
2779 if ( material.visible === false ) return;
2780
2781 var linewidth, a, attribute, i, il;
2782
2783 var program = setProgram( camera, lights, fog, material, object );
2784
2785 var attributes = program.attributes;
2786
2787 var updateBuffers = false,
2788 wireframeBit = material.wireframe ? 1 : 0,
2789 geometryGroupHash = ( geometryGroup.id * 0xffffff ) + ( program.id * 2 ) + wireframeBit;
2790
2791 if ( geometryGroupHash !== _currentGeometryGroupHash ) {
2792
2793 _currentGeometryGroupHash = geometryGroupHash;
2794 updateBuffers = true;
2795
2796 }
2797
2798 if ( updateBuffers ) {
2799
2800 disableAttributes();
2801
2802 }
2803
2804 // vertices
2805
2806 if ( !material.morphTargets && attributes.position >= 0 ) {
2807
2808 if ( updateBuffers ) {
2809
2810 _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglVertexBuffer );
2811 enableAttribute( attributes.position );
2812 _gl.vertexAttribPointer( attributes.position, 3, _gl.FLOAT, false, 0, 0 );
2813
2814 }
2815
2816 } else {
2817
2818 if ( object.morphTargetBase ) {
2819
2820 setupMorphTargets( material, geometryGroup, object );
2821
2822 }
2823
2824 }
2825
2826
2827 if ( updateBuffers ) {
2828
2829 // custom attributes
2830
2831 // Use the per-geometryGroup custom attribute arrays which are setup in initMeshBuffers
2832
2833 if ( geometryGroup.__webglCustomAttributesList ) {
2834
2835 for ( i = 0, il = geometryGroup.__webglCustomAttributesList.length; i < il; i ++ ) {
2836
2837 attribute = geometryGroup.__webglCustomAttributesList[ i ];
2838
2839 if ( attributes[ attribute.buffer.belongsToAttribute ] >= 0 ) {
2840
2841 _gl.bindBuffer( _gl.ARRAY_BUFFER, attribute.buffer );
2842 enableAttribute( attributes[ attribute.buffer.belongsToAttribute ] );
2843 _gl.vertexAttribPointer( attributes[ attribute.buffer.belongsToAttribute ], attribute.size, _gl.FLOAT, false, 0, 0 );
2844
2845 }
2846
2847 }
2848
2849 }
2850
2851
2852 // colors
2853
2854 if ( attributes.color >= 0 ) {
2855
2856 if ( object.geometry.colors.length > 0 || object.geometry.faces.length > 0 ) {
2857
2858 _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglColorBuffer );
2859 enableAttribute( attributes.color );
2860 _gl.vertexAttribPointer( attributes.color, 3, _gl.FLOAT, false, 0, 0 );
2861
2862 } else if ( material.defaultAttributeValues ) {
2863
2864
2865 _gl.vertexAttrib3fv( attributes.color, material.defaultAttributeValues.color );
2866
2867 }
2868
2869 }
2870
2871 // normals
2872
2873 if ( attributes.normal >= 0 ) {
2874
2875 _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglNormalBuffer );
2876 enableAttribute( attributes.normal );
2877 _gl.vertexAttribPointer( attributes.normal, 3, _gl.FLOAT, false, 0, 0 );
2878
2879 }
2880
2881 // tangents
2882
2883 if ( attributes.tangent >= 0 ) {
2884
2885 _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglTangentBuffer );
2886 enableAttribute( attributes.tangent );
2887 _gl.vertexAttribPointer( attributes.tangent, 4, _gl.FLOAT, false, 0, 0 );
2888
2889 }
2890
2891 // uvs
2892
2893 if ( attributes.uv >= 0 ) {
2894
2895 if ( object.geometry.faceVertexUvs[0] ) {
2896
2897 _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglUVBuffer );
2898 enableAttribute( attributes.uv );
2899 _gl.vertexAttribPointer( attributes.uv, 2, _gl.FLOAT, false, 0, 0 );
2900
2901 } else if ( material.defaultAttributeValues ) {
2902
2903
2904 _gl.vertexAttrib2fv( attributes.uv, material.defaultAttributeValues.uv );
2905
2906 }
2907
2908 }
2909
2910 if ( attributes.uv2 >= 0 ) {
2911
2912 if ( object.geometry.faceVertexUvs[1] ) {
2913
2914 _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglUV2Buffer );
2915 enableAttribute( attributes.uv2 );
2916 _gl.vertexAttribPointer( attributes.uv2, 2, _gl.FLOAT, false, 0, 0 );
2917
2918 } else if ( material.defaultAttributeValues ) {
2919
2920
2921 _gl.vertexAttrib2fv( attributes.uv2, material.defaultAttributeValues.uv2 );
2922
2923 }
2924
2925 }
2926
2927 if ( material.skinning &&
2928 attributes.skinIndex >= 0 && attributes.skinWeight >= 0 ) {
2929
2930 _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglSkinIndicesBuffer );
2931 enableAttribute( attributes.skinIndex );
2932 _gl.vertexAttribPointer( attributes.skinIndex, 4, _gl.FLOAT, false, 0, 0 );
2933
2934 _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglSkinWeightsBuffer );
2935 enableAttribute( attributes.skinWeight );
2936 _gl.vertexAttribPointer( attributes.skinWeight, 4, _gl.FLOAT, false, 0, 0 );
2937
2938 }
2939
2940 // line distances
2941
2942 if ( attributes.lineDistance >= 0 ) {
2943
2944 _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglLineDistanceBuffer );
2945 enableAttribute( attributes.lineDistance );
2946 _gl.vertexAttribPointer( attributes.lineDistance, 1, _gl.FLOAT, false, 0, 0 );
2947
2948 }
2949
2950 }
2951
2952 // render mesh
2953
2954 if ( object instanceof THREE.Mesh ) {
2955
2956 // wireframe
2957
2958 if ( material.wireframe ) {
2959
2960 setLineWidth( material.wireframeLinewidth );
2961
2962 if ( updateBuffers ) _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, geometryGroup.__webglLineBuffer );
2963 _gl.drawElements( _gl.LINES, geometryGroup.__webglLineCount, _gl.UNSIGNED_SHORT, 0 );
2964
2965 // triangles
2966
2967 } else {
2968
2969 if ( updateBuffers ) _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, geometryGroup.__webglFaceBuffer );
2970 _gl.drawElements( _gl.TRIANGLES, geometryGroup.__webglFaceCount, _gl.UNSIGNED_SHORT, 0 );
2971
2972 }
2973
2974 _this.info.render.calls ++;
2975 _this.info.render.vertices += geometryGroup.__webglFaceCount;
2976 _this.info.render.faces += geometryGroup.__webglFaceCount / 3;
2977
2978 // render lines
2979
2980 } else if ( object instanceof THREE.Line ) {
2981
2982 var primitives = ( object.type === THREE.LineStrip ) ? _gl.LINE_STRIP : _gl.LINES;
2983
2984 setLineWidth( material.linewidth );
2985
2986 _gl.drawArrays( primitives, 0, geometryGroup.__webglLineCount );
2987
2988 _this.info.render.calls ++;
2989
2990 // render particles
2991
2992 } else if ( object instanceof THREE.ParticleSystem ) {
2993
2994 _gl.drawArrays( _gl.POINTS, 0, geometryGroup.__webglParticleCount );
2995
2996 _this.info.render.calls ++;
2997 _this.info.render.points += geometryGroup.__webglParticleCount;
2998
2999 }
3000
3001 };
3002
3003 function enableAttribute( attribute ) {
3004
3005 if ( ! _enabledAttributes[ attribute ] ) {
3006
3007 _gl.enableVertexAttribArray( attribute );
3008 _enabledAttributes[ attribute ] = true;
3009
3010 }
3011
3012 };
3013
3014 function disableAttributes() {
3015
3016 for ( var attribute in _enabledAttributes ) {
3017
3018 if ( _enabledAttributes[ attribute ] ) {
3019
3020 _gl.disableVertexAttribArray( attribute );
3021 _enabledAttributes[ attribute ] = false;
3022
3023 }
3024
3025 }
3026
3027 };
3028
3029 function setupMorphTargets ( material, geometryGroup, object ) {
3030
3031 // set base
3032
3033 var attributes = material.program.attributes;
3034
3035 if ( object.morphTargetBase !== -1 && attributes.position >= 0 ) {
3036
3037 _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphTargetsBuffers[ object.morphTargetBase ] );
3038 enableAttribute( attributes.position );
3039 _gl.vertexAttribPointer( attributes.position, 3, _gl.FLOAT, false, 0, 0 );
3040
3041 } else if ( attributes.position >= 0 ) {
3042
3043 _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglVertexBuffer );
3044 enableAttribute( attributes.position );
3045 _gl.vertexAttribPointer( attributes.position, 3, _gl.FLOAT, false, 0, 0 );
3046
3047 }
3048
3049 if ( object.morphTargetForcedOrder.length ) {
3050
3051 // set forced order
3052
3053 var m = 0;
3054 var order = object.morphTargetForcedOrder;
3055 var influences = object.morphTargetInfluences;
3056
3057 while ( m < material.numSupportedMorphTargets && m < order.length ) {
3058
3059 if ( attributes[ "morphTarget" + m ] >= 0 ) {
3060
3061 _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphTargetsBuffers[ order[ m ] ] );
3062 enableAttribute( attributes[ "morphTarget" + m ] );
3063 _gl.vertexAttribPointer( attributes[ "morphTarget" + m ], 3, _gl.FLOAT, false, 0, 0 );
3064
3065 }
3066
3067 if ( attributes[ "morphNormal" + m ] >= 0 && material.morphNormals ) {
3068
3069 _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphNormalsBuffers[ order[ m ] ] );
3070 enableAttribute( attributes[ "morphNormal" + m ] );
3071 _gl.vertexAttribPointer( attributes[ "morphNormal" + m ], 3, _gl.FLOAT, false, 0, 0 );
3072
3073 }
3074
3075 object.__webglMorphTargetInfluences[ m ] = influences[ order[ m ] ];
3076
3077 m ++;
3078 }
3079
3080 } else {
3081
3082 // find the most influencing
3083
3084 var influence, activeInfluenceIndices = [];
3085 var influences = object.morphTargetInfluences;
3086 var i, il = influences.length;
3087
3088 for ( i = 0; i < il; i ++ ) {
3089
3090 influence = influences[ i ];
3091
3092 if ( influence > 0 ) {
3093
3094 activeInfluenceIndices.push( [ influence, i ] );
3095
3096 }
3097
3098 }
3099
3100 if ( activeInfluenceIndices.length > material.numSupportedMorphTargets ) {
3101
3102 activeInfluenceIndices.sort( numericalSort );
3103 activeInfluenceIndices.length = material.numSupportedMorphTargets;
3104
3105 } else if ( activeInfluenceIndices.length > material.numSupportedMorphNormals ) {
3106
3107 activeInfluenceIndices.sort( numericalSort );
3108
3109 } else if ( activeInfluenceIndices.length === 0 ) {
3110
3111 activeInfluenceIndices.push( [ 0, 0 ] );
3112
3113 };
3114
3115 var influenceIndex, m = 0;
3116
3117 while ( m < material.numSupportedMorphTargets ) {
3118
3119 if ( activeInfluenceIndices[ m ] ) {
3120
3121 influenceIndex = activeInfluenceIndices[ m ][ 1 ];
3122
3123 if ( attributes[ "morphTarget" + m ] >= 0 ) {
3124
3125 _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphTargetsBuffers[ influenceIndex ] );
3126 enableAttribute( attributes[ "morphTarget" + m ] );
3127 _gl.vertexAttribPointer( attributes[ "morphTarget" + m ], 3, _gl.FLOAT, false, 0, 0 );
3128
3129 }
3130
3131 if ( attributes[ "morphNormal" + m ] >= 0 && material.morphNormals ) {
3132
3133 _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphNormalsBuffers[ influenceIndex ] );
3134 enableAttribute( attributes[ "morphNormal" + m ] );
3135 _gl.vertexAttribPointer( attributes[ "morphNormal" + m ], 3, _gl.FLOAT, false, 0, 0 );
3136
3137
3138 }
3139
3140 object.__webglMorphTargetInfluences[ m ] = influences[ influenceIndex ];
3141
3142 } else {
3143
3144 /*
3145 _gl.vertexAttribPointer( attributes[ "morphTarget" + m ], 3, _gl.FLOAT, false, 0, 0 );
3146
3147 if ( material.morphNormals ) {
3148
3149 _gl.vertexAttribPointer( attributes[ "morphNormal" + m ], 3, _gl.FLOAT, false, 0, 0 );
3150
3151 }
3152 */
3153
3154 object.__webglMorphTargetInfluences[ m ] = 0;
3155
3156 }
3157
3158 m ++;
3159
3160 }
3161
3162 }
3163
3164 // load updated influences uniform
3165
3166 if ( material.program.uniforms.morphTargetInfluences !== null ) {
3167
3168 _gl.uniform1fv( material.program.uniforms.morphTargetInfluences, object.__webglMorphTargetInfluences );
3169
3170 }
3171
3172 };
3173
3174 // Sorting
3175
3176 function painterSortStable ( a, b ) {
3177
3178 if ( a.z !== b.z ) {
3179
3180 return b.z - a.z;
3181
3182 } else {
3183
3184 return a.id - b.id;
3185
3186 }
3187
3188 };
3189
3190 function numericalSort ( a, b ) {
3191
3192 return b[ 0 ] - a[ 0 ];
3193
3194 };
3195
3196
3197 // Rendering
3198
3199 this.render = function ( scene, camera, renderTarget, forceClear ) {
3200
3201 if ( camera instanceof THREE.Camera === false ) {
3202
3203 console.error( 'THREE.WebGLRenderer.render: camera is not an instance of THREE.Camera.' );
3204 return;
3205
3206 }
3207
3208 var i, il,
3209
3210 webglObject, object,
3211 renderList,
3212
3213 lights = scene.__lights,
3214 fog = scene.fog;
3215
3216 // reset caching for this frame
3217
3218 _currentMaterialId = -1;
3219 _lightsNeedUpdate = true;
3220
3221 // update scene graph
3222
3223 if ( scene.autoUpdate === true ) scene.updateMatrixWorld();
3224
3225 // update camera matrices and frustum
3226
3227 if ( camera.parent === undefined ) camera.updateMatrixWorld();
3228
3229 camera.matrixWorldInverse.getInverse( camera.matrixWorld );
3230
3231 _projScreenMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse );
3232 _frustum.setFromMatrix( _projScreenMatrix );
3233
3234 // update WebGL objects
3235
3236 if ( this.autoUpdateObjects ) this.initWebGLObjects( scene );
3237
3238 // custom render plugins (pre pass)
3239
3240 renderPlugins( this.renderPluginsPre, scene, camera );
3241
3242 //
3243
3244 _this.info.render.calls = 0;
3245 _this.info.render.vertices = 0;
3246 _this.info.render.faces = 0;
3247 _this.info.render.points = 0;
3248
3249 this.setRenderTarget( renderTarget );
3250
3251 if ( this.autoClear || forceClear ) {
3252
3253 this.clear( this.autoClearColor, this.autoClearDepth, this.autoClearStencil );
3254
3255 }
3256
3257 // set matrices for regular objects (frustum culled)
3258
3259 renderList = scene.__webglObjects;
3260
3261 for ( i = 0, il = renderList.length; i < il; i ++ ) {
3262
3263 webglObject = renderList[ i ];
3264 object = webglObject.object;
3265
3266 webglObject.id = i;
3267 webglObject.render = false;
3268
3269 if ( object.visible ) {
3270
3271 if ( ! ( object instanceof THREE.Mesh || object instanceof THREE.ParticleSystem ) || ! ( object.frustumCulled ) || _frustum.intersectsObject( object ) ) {
3272
3273 setupMatrices( object, camera );
3274
3275 unrollBufferMaterial( webglObject );
3276
3277 webglObject.render = true;
3278
3279 if ( this.sortObjects === true ) {
3280
3281 if ( object.renderDepth !== null ) {
3282
3283 webglObject.z = object.renderDepth;
3284
3285 } else {
3286
3287 _vector3.setFromMatrixPosition( object.matrixWorld );
3288 _vector3.applyProjection( _projScreenMatrix );
3289
3290 webglObject.z = _vector3.z;
3291
3292 }
3293
3294 }
3295
3296 }
3297
3298 }
3299
3300 }
3301
3302 if ( this.sortObjects ) {
3303
3304 renderList.sort( painterSortStable );
3305
3306 }
3307
3308 // set matrices for immediate objects
3309
3310 renderList = scene.__webglObjectsImmediate;
3311
3312 for ( i = 0, il = renderList.length; i < il; i ++ ) {
3313
3314 webglObject = renderList[ i ];
3315 object = webglObject.object;
3316
3317 if ( object.visible ) {
3318
3319 setupMatrices( object, camera );
3320
3321 unrollImmediateBufferMaterial( webglObject );
3322
3323 }
3324
3325 }
3326
3327 if ( scene.overrideMaterial ) {
3328
3329 var material = scene.overrideMaterial;
3330
3331 this.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst );
3332 this.setDepthTest( material.depthTest );
3333 this.setDepthWrite( material.depthWrite );
3334 setPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits );
3335
3336 renderObjects( scene.__webglObjects, false, "", camera, lights, fog, true, material );
3337 renderObjectsImmediate( scene.__webglObjectsImmediate, "", camera, lights, fog, false, material );
3338
3339 } else {
3340
3341 var material = null;
3342
3343 // opaque pass (front-to-back order)
3344
3345 this.setBlending( THREE.NoBlending );
3346
3347 renderObjects( scene.__webglObjects, true, "opaque", camera, lights, fog, false, material );
3348 renderObjectsImmediate( scene.__webglObjectsImmediate, "opaque", camera, lights, fog, false, material );
3349
3350 // transparent pass (back-to-front order)
3351
3352 renderObjects( scene.__webglObjects, false, "transparent", camera, lights, fog, true, material );
3353 renderObjectsImmediate( scene.__webglObjectsImmediate, "transparent", camera, lights, fog, true, material );
3354
3355 }
3356
3357 // custom render plugins (post pass)
3358
3359 renderPlugins( this.renderPluginsPost, scene, camera );
3360
3361
3362 // Generate mipmap if we're using any kind of mipmap filtering
3363
3364 if ( renderTarget && renderTarget.generateMipmaps && renderTarget.minFilter !== THREE.NearestFilter && renderTarget.minFilter !== THREE.LinearFilter ) {
3365
3366 updateRenderTargetMipmap( renderTarget );
3367
3368 }
3369
3370 // Ensure depth buffer writing is enabled so it can be cleared on next render
3371
3372 this.setDepthTest( true );
3373 this.setDepthWrite( true );
3374
3375 // _gl.finish();
3376
3377 };
3378
3379 function renderPlugins( plugins, scene, camera ) {
3380
3381 if ( ! plugins.length ) return;
3382
3383 for ( var i = 0, il = plugins.length; i < il; i ++ ) {
3384
3385 // reset state for plugin (to start from clean slate)
3386
3387 _currentProgram = null;
3388 _currentCamera = null;
3389
3390 _oldBlending = -1;
3391 _oldDepthTest = -1;
3392 _oldDepthWrite = -1;
3393 _oldDoubleSided = -1;
3394 _oldFlipSided = -1;
3395 _currentGeometryGroupHash = -1;
3396 _currentMaterialId = -1;
3397
3398 _lightsNeedUpdate = true;
3399
3400 plugins[ i ].render( scene, camera, _currentWidth, _currentHeight );
3401
3402 // reset state after plugin (anything could have changed)
3403
3404 _currentProgram = null;
3405 _currentCamera = null;
3406
3407 _oldBlending = -1;
3408 _oldDepthTest = -1;
3409 _oldDepthWrite = -1;
3410 _oldDoubleSided = -1;
3411 _oldFlipSided = -1;
3412 _currentGeometryGroupHash = -1;
3413 _currentMaterialId = -1;
3414
3415 _lightsNeedUpdate = true;
3416
3417 }
3418
3419 };
3420
3421 function renderObjects ( renderList, reverse, materialType, camera, lights, fog, useBlending, overrideMaterial ) {
3422
3423 var webglObject, object, buffer, material, start, end, delta;
3424
3425 if ( reverse ) {
3426
3427 start = renderList.length - 1;
3428 end = -1;
3429 delta = -1;
3430
3431 } else {
3432
3433 start = 0;
3434 end = renderList.length;
3435 delta = 1;
3436 }
3437
3438 for ( var i = start; i !== end; i += delta ) {
3439
3440 webglObject = renderList[ i ];
3441
3442 if ( webglObject.render ) {
3443
3444 object = webglObject.object;
3445 buffer = webglObject.buffer;
3446
3447 if ( overrideMaterial ) {
3448
3449 material = overrideMaterial;
3450
3451 } else {
3452
3453 material = webglObject[ materialType ];
3454
3455 if ( ! material ) continue;
3456
3457 if ( useBlending ) _this.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst );
3458
3459 _this.setDepthTest( material.depthTest );
3460 _this.setDepthWrite( material.depthWrite );
3461 setPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits );
3462
3463 }
3464
3465 _this.setMaterialFaces( material );
3466
3467 if ( buffer instanceof THREE.BufferGeometry ) {
3468
3469 _this.renderBufferDirect( camera, lights, fog, material, buffer, object );
3470
3471 } else {
3472
3473 _this.renderBuffer( camera, lights, fog, material, buffer, object );
3474
3475 }
3476
3477 }
3478
3479 }
3480
3481 };
3482
3483 function renderObjectsImmediate ( renderList, materialType, camera, lights, fog, useBlending, overrideMaterial ) {
3484
3485 var webglObject, object, material, program;
3486
3487 for ( var i = 0, il = renderList.length; i < il; i ++ ) {
3488
3489 webglObject = renderList[ i ];
3490 object = webglObject.object;
3491
3492 if ( object.visible ) {
3493
3494 if ( overrideMaterial ) {
3495
3496 material = overrideMaterial;
3497
3498 } else {
3499
3500 material = webglObject[ materialType ];
3501
3502 if ( ! material ) continue;
3503
3504 if ( useBlending ) _this.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst );
3505
3506 _this.setDepthTest( material.depthTest );
3507 _this.setDepthWrite( material.depthWrite );
3508 setPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits );
3509
3510 }
3511
3512 _this.renderImmediateObject( camera, lights, fog, material, object );
3513
3514 }
3515
3516 }
3517
3518 };
3519
3520 this.renderImmediateObject = function ( camera, lights, fog, material, object ) {
3521
3522 var program = setProgram( camera, lights, fog, material, object );
3523
3524 _currentGeometryGroupHash = -1;
3525
3526 _this.setMaterialFaces( material );
3527
3528 if ( object.immediateRenderCallback ) {
3529
3530 object.immediateRenderCallback( program, _gl, _frustum );
3531
3532 } else {
3533
3534 object.render( function( object ) { _this.renderBufferImmediate( object, program, material ); } );
3535
3536 }
3537
3538 };
3539
3540 function unrollImmediateBufferMaterial ( globject ) {
3541
3542 var object = globject.object,
3543 material = object.material;
3544
3545 if ( material.transparent ) {
3546
3547 globject.transparent = material;
3548 globject.opaque = null;
3549
3550 } else {
3551
3552 globject.opaque = material;
3553 globject.transparent = null;
3554
3555 }
3556
3557 };
3558
3559 function unrollBufferMaterial ( globject ) {
3560
3561 var object = globject.object,
3562 buffer = globject.buffer,
3563 material, materialIndex, meshMaterial;
3564
3565 meshMaterial = object.material;
3566
3567 if ( meshMaterial instanceof THREE.MeshFaceMaterial ) {
3568
3569 materialIndex = buffer.materialIndex;
3570
3571 material = meshMaterial.materials[ materialIndex ];
3572
3573 if ( material.transparent ) {
3574
3575 globject.transparent = material;
3576 globject.opaque = null;
3577
3578 } else {
3579
3580 globject.opaque = material;
3581 globject.transparent = null;
3582
3583 }
3584
3585 } else {
3586
3587 material = meshMaterial;
3588
3589 if ( material ) {
3590
3591 if ( material.transparent ) {
3592
3593 globject.transparent = material;
3594 globject.opaque = null;
3595
3596 } else {
3597
3598 globject.opaque = material;
3599 globject.transparent = null;
3600
3601 }
3602
3603 }
3604
3605 }
3606
3607 };
3608
3609 // Geometry splitting
3610
3611 function sortFacesByMaterial ( geometry, material ) {
3612
3613 var f, fl, face, materialIndex, vertices,
3614 groupHash, hash_map = {};
3615
3616 var numMorphTargets = geometry.morphTargets.length;
3617 var numMorphNormals = geometry.morphNormals.length;
3618
3619 var usesFaceMaterial = material instanceof THREE.MeshFaceMaterial;
3620
3621 geometry.geometryGroups = {};
3622
3623 for ( f = 0, fl = geometry.faces.length; f < fl; f ++ ) {
3624
3625 face = geometry.faces[ f ];
3626 materialIndex = usesFaceMaterial ? face.materialIndex : 0;
3627
3628 if ( hash_map[ materialIndex ] === undefined ) {
3629
3630 hash_map[ materialIndex ] = { 'hash': materialIndex, 'counter': 0 };
3631
3632 }
3633
3634 groupHash = hash_map[ materialIndex ].hash + '_' + hash_map[ materialIndex ].counter;
3635
3636 if ( geometry.geometryGroups[ groupHash ] === undefined ) {
3637
3638 geometry.geometryGroups[ groupHash ] = { 'faces3': [], 'materialIndex': materialIndex, 'vertices': 0, 'numMorphTargets': numMorphTargets, 'numMorphNormals': numMorphNormals };
3639
3640 }
3641
3642 vertices = 3;
3643
3644 if ( geometry.geometryGroups[ groupHash ].vertices + vertices > 65535 ) {
3645
3646 hash_map[ materialIndex ].counter += 1;
3647 groupHash = hash_map[ materialIndex ].hash + '_' + hash_map[ materialIndex ].counter;
3648
3649 if ( geometry.geometryGroups[ groupHash ] === undefined ) {
3650
3651 geometry.geometryGroups[ groupHash ] = { 'faces3': [], 'materialIndex': materialIndex, 'vertices': 0, 'numMorphTargets': numMorphTargets, 'numMorphNormals': numMorphNormals };
3652
3653 }
3654
3655 }
3656
3657 geometry.geometryGroups[ groupHash ].faces3.push( f );
3658 geometry.geometryGroups[ groupHash ].vertices += vertices;
3659
3660 }
3661
3662 geometry.geometryGroupsList = [];
3663
3664 for ( var g in geometry.geometryGroups ) {
3665
3666 geometry.geometryGroups[ g ].id = _geometryGroupCounter ++;
3667
3668 geometry.geometryGroupsList.push( geometry.geometryGroups[ g ] );
3669
3670 }
3671
3672 };
3673
3674 // Objects refresh
3675
3676 this.initWebGLObjects = function ( scene ) {
3677
3678 if ( !scene.__webglObjects ) {
3679
3680 scene.__webglObjects = [];
3681 scene.__webglObjectsImmediate = [];
3682 scene.__webglSprites = [];
3683 scene.__webglFlares = [];
3684
3685 }
3686
3687 while ( scene.__objectsAdded.length ) {
3688
3689 addObject( scene.__objectsAdded[ 0 ], scene );
3690 scene.__objectsAdded.splice( 0, 1 );
3691
3692 }
3693
3694 while ( scene.__objectsRemoved.length ) {
3695
3696 removeObject( scene.__objectsRemoved[ 0 ], scene );
3697 scene.__objectsRemoved.splice( 0, 1 );
3698
3699 }
3700
3701 // update must be called after objects adding / removal
3702
3703 for ( var o = 0, ol = scene.__webglObjects.length; o < ol; o ++ ) {
3704
3705 var object = scene.__webglObjects[ o ].object;
3706
3707 // TODO: Remove this hack (WebGLRenderer refactoring)
3708
3709 if ( object.__webglInit === undefined ) {
3710
3711 if ( object.__webglActive !== undefined ) {
3712
3713 removeObject( object, scene );
3714
3715 }
3716
3717 addObject( object, scene );
3718
3719 }
3720
3721 updateObject( object );
3722
3723 }
3724
3725 };
3726
3727 // Objects adding
3728
3729 function addObject( object, scene ) {
3730
3731 var g, geometry, material, geometryGroup;
3732
3733 if ( object.__webglInit === undefined ) {
3734
3735 object.__webglInit = true;
3736
3737 object._modelViewMatrix = new THREE.Matrix4();
3738 object._normalMatrix = new THREE.Matrix3();
3739
3740 if ( object.geometry !== undefined && object.geometry.__webglInit === undefined ) {
3741
3742 object.geometry.__webglInit = true;
3743 object.geometry.addEventListener( 'dispose', onGeometryDispose );
3744
3745 }
3746
3747 geometry = object.geometry;
3748
3749 if ( geometry === undefined ) {
3750
3751 // fail silently for now
3752
3753 } else if ( geometry instanceof THREE.BufferGeometry ) {
3754
3755 initDirectBuffers( geometry );
3756
3757 } else if ( object instanceof THREE.Mesh ) {
3758
3759 material = object.material;
3760
3761 if ( geometry.geometryGroups === undefined ) {
3762
3763 sortFacesByMaterial( geometry, material );
3764
3765 }
3766
3767 // create separate VBOs per geometry chunk
3768
3769 for ( g in geometry.geometryGroups ) {
3770
3771 geometryGroup = geometry.geometryGroups[ g ];
3772
3773 // initialise VBO on the first access
3774
3775 if ( ! geometryGroup.__webglVertexBuffer ) {
3776
3777 createMeshBuffers( geometryGroup );
3778 initMeshBuffers( geometryGroup, object );
3779
3780 geometry.verticesNeedUpdate = true;
3781 geometry.morphTargetsNeedUpdate = true;
3782 geometry.elementsNeedUpdate = true;
3783 geometry.uvsNeedUpdate = true;
3784 geometry.normalsNeedUpdate = true;
3785 geometry.tangentsNeedUpdate = true;
3786 geometry.colorsNeedUpdate = true;
3787
3788 }
3789
3790 }
3791
3792 } else if ( object instanceof THREE.Line ) {
3793
3794 if ( ! geometry.__webglVertexBuffer ) {
3795
3796 createLineBuffers( geometry );
3797 initLineBuffers( geometry, object );
3798
3799 geometry.verticesNeedUpdate = true;
3800 geometry.colorsNeedUpdate = true;
3801 geometry.lineDistancesNeedUpdate = true;
3802
3803 }
3804
3805 } else if ( object instanceof THREE.ParticleSystem ) {
3806
3807 if ( ! geometry.__webglVertexBuffer ) {
3808
3809 createParticleBuffers( geometry );
3810 initParticleBuffers( geometry, object );
3811
3812 geometry.verticesNeedUpdate = true;
3813 geometry.colorsNeedUpdate = true;
3814
3815 }
3816
3817 }
3818
3819 }
3820
3821 if ( object.__webglActive === undefined ) {
3822
3823 if ( object instanceof THREE.Mesh ) {
3824
3825 geometry = object.geometry;
3826
3827 if ( geometry instanceof THREE.BufferGeometry ) {
3828
3829 addBuffer( scene.__webglObjects, geometry, object );
3830
3831 } else if ( geometry instanceof THREE.Geometry ) {
3832
3833 for ( g in geometry.geometryGroups ) {
3834
3835 geometryGroup = geometry.geometryGroups[ g ];
3836
3837 addBuffer( scene.__webglObjects, geometryGroup, object );
3838
3839 }
3840
3841 }
3842
3843 } else if ( object instanceof THREE.Line ||
3844 object instanceof THREE.ParticleSystem ) {
3845
3846 geometry = object.geometry;
3847 addBuffer( scene.__webglObjects, geometry, object );
3848
3849 } else if ( object instanceof THREE.ImmediateRenderObject || object.immediateRenderCallback ) {
3850
3851 addBufferImmediate( scene.__webglObjectsImmediate, object );
3852
3853 } else if ( object instanceof THREE.Sprite ) {
3854
3855 scene.__webglSprites.push( object );
3856
3857 } else if ( object instanceof THREE.LensFlare ) {
3858
3859 scene.__webglFlares.push( object );
3860
3861 }
3862
3863 object.__webglActive = true;
3864
3865 }
3866
3867 };
3868
3869 function addBuffer( objlist, buffer, object ) {
3870
3871 objlist.push(
3872 {
3873 id: null,
3874 buffer: buffer,
3875 object: object,
3876 opaque: null,
3877 transparent: null,
3878 z: 0
3879 }
3880 );
3881
3882 };
3883
3884 function addBufferImmediate( objlist, object ) {
3885
3886 objlist.push(
3887 {
3888 id: null,
3889 object: object,
3890 opaque: null,
3891 transparent: null,
3892 z: 0
3893 }
3894 );
3895
3896 };
3897
3898 // Objects updates
3899
3900 function updateObject( object ) {
3901
3902 var geometry = object.geometry,
3903 geometryGroup, customAttributesDirty, material;
3904
3905 if ( geometry instanceof THREE.BufferGeometry ) {
3906
3907 setDirectBuffers( geometry, _gl.DYNAMIC_DRAW, !geometry.dynamic );
3908
3909 } else if ( object instanceof THREE.Mesh ) {
3910
3911 // check all geometry groups
3912
3913 for( var i = 0, il = geometry.geometryGroupsList.length; i < il; i ++ ) {
3914
3915 geometryGroup = geometry.geometryGroupsList[ i ];
3916
3917 material = getBufferMaterial( object, geometryGroup );
3918
3919 if ( geometry.buffersNeedUpdate ) {
3920
3921 initMeshBuffers( geometryGroup, object );
3922
3923 }
3924
3925 customAttributesDirty = material.attributes && areCustomAttributesDirty( material );
3926
3927 if ( geometry.verticesNeedUpdate || geometry.morphTargetsNeedUpdate || geometry.elementsNeedUpdate ||
3928 geometry.uvsNeedUpdate || geometry.normalsNeedUpdate ||
3929 geometry.colorsNeedUpdate || geometry.tangentsNeedUpdate || customAttributesDirty ) {
3930
3931 setMeshBuffers( geometryGroup, object, _gl.DYNAMIC_DRAW, !geometry.dynamic, material );
3932
3933 }
3934
3935 }
3936
3937 geometry.verticesNeedUpdate = false;
3938 geometry.morphTargetsNeedUpdate = false;
3939 geometry.elementsNeedUpdate = false;
3940 geometry.uvsNeedUpdate = false;
3941 geometry.normalsNeedUpdate = false;
3942 geometry.colorsNeedUpdate = false;
3943 geometry.tangentsNeedUpdate = false;
3944
3945 geometry.buffersNeedUpdate = false;
3946
3947 material.attributes && clearCustomAttributes( material );
3948
3949 } else if ( object instanceof THREE.Line ) {
3950
3951 material = getBufferMaterial( object, geometry );
3952
3953 customAttributesDirty = material.attributes && areCustomAttributesDirty( material );
3954
3955 if ( geometry.verticesNeedUpdate || geometry.colorsNeedUpdate || geometry.lineDistancesNeedUpdate || customAttributesDirty ) {
3956
3957 setLineBuffers( geometry, _gl.DYNAMIC_DRAW );
3958
3959 }
3960
3961 geometry.verticesNeedUpdate = false;
3962 geometry.colorsNeedUpdate = false;
3963 geometry.lineDistancesNeedUpdate = false;
3964
3965 material.attributes && clearCustomAttributes( material );
3966
3967
3968 } else if ( object instanceof THREE.ParticleSystem ) {
3969
3970 material = getBufferMaterial( object, geometry );
3971
3972 customAttributesDirty = material.attributes && areCustomAttributesDirty( material );
3973
3974 if ( geometry.verticesNeedUpdate || geometry.colorsNeedUpdate || object.sortParticles || customAttributesDirty ) {
3975
3976 setParticleBuffers( geometry, _gl.DYNAMIC_DRAW, object );
3977
3978 }
3979
3980 geometry.verticesNeedUpdate = false;
3981 geometry.colorsNeedUpdate = false;
3982
3983 material.attributes && clearCustomAttributes( material );
3984
3985 }
3986
3987 };
3988
3989 // Objects updates - custom attributes check
3990
3991 function areCustomAttributesDirty( material ) {
3992
3993 for ( var a in material.attributes ) {
3994
3995 if ( material.attributes[ a ].needsUpdate ) return true;
3996
3997 }
3998
3999 return false;
4000
4001 };
4002
4003 function clearCustomAttributes( material ) {
4004
4005 for ( var a in material.attributes ) {
4006
4007 material.attributes[ a ].needsUpdate = false;
4008
4009 }
4010
4011 };
4012
4013 // Objects removal
4014
4015 function removeObject( object, scene ) {
4016
4017 if ( object instanceof THREE.Mesh ||
4018 object instanceof THREE.ParticleSystem ||
4019 object instanceof THREE.Line ) {
4020
4021 removeInstances( scene.__webglObjects, object );
4022
4023 } else if ( object instanceof THREE.Sprite ) {
4024
4025 removeInstancesDirect( scene.__webglSprites, object );
4026
4027 } else if ( object instanceof THREE.LensFlare ) {
4028
4029 removeInstancesDirect( scene.__webglFlares, object );
4030
4031 } else if ( object instanceof THREE.ImmediateRenderObject || object.immediateRenderCallback ) {
4032
4033 removeInstances( scene.__webglObjectsImmediate, object );
4034
4035 }
4036
4037 delete object.__webglActive;
4038
4039 };
4040
4041 function removeInstances( objlist, object ) {
4042
4043 for ( var o = objlist.length - 1; o >= 0; o -- ) {
4044
4045 if ( objlist[ o ].object === object ) {
4046
4047 objlist.splice( o, 1 );
4048
4049 }
4050
4051 }
4052
4053 };
4054
4055 function removeInstancesDirect( objlist, object ) {
4056
4057 for ( var o = objlist.length - 1; o >= 0; o -- ) {
4058
4059 if ( objlist[ o ] === object ) {
4060
4061 objlist.splice( o, 1 );
4062
4063 }
4064
4065 }
4066
4067 };
4068
4069 // Materials
4070
4071 this.initMaterial = function ( material, lights, fog, object ) {
4072
4073 material.addEventListener( 'dispose', onMaterialDispose );
4074
4075 var u, a, identifiers, i, parameters, maxLightCount, maxBones, maxShadows, shaderID;
4076
4077 if ( material instanceof THREE.MeshDepthMaterial ) {
4078
4079 shaderID = 'depth';
4080
4081 } else if ( material instanceof THREE.MeshNormalMaterial ) {
4082
4083 shaderID = 'normal';
4084
4085 } else if ( material instanceof THREE.MeshBasicMaterial ) {
4086
4087 shaderID = 'basic';
4088
4089 } else if ( material instanceof THREE.MeshLambertMaterial ) {
4090
4091 shaderID = 'lambert';
4092
4093 } else if ( material instanceof THREE.MeshPhongMaterial ) {
4094
4095 shaderID = 'phong';
4096
4097 } else if ( material instanceof THREE.LineBasicMaterial ) {
4098
4099 shaderID = 'basic';
4100
4101 } else if ( material instanceof THREE.LineDashedMaterial ) {
4102
4103 shaderID = 'dashed';
4104
4105 } else if ( material instanceof THREE.ParticleSystemMaterial ) {
4106
4107 shaderID = 'particle_basic';
4108
4109 }
4110
4111 if ( shaderID ) {
4112
4113 setMaterialShaders( material, THREE.ShaderLib[ shaderID ] );
4114
4115 }
4116
4117 // heuristics to create shader parameters according to lights in the scene
4118 // (not to blow over maxLights budget)
4119
4120 maxLightCount = allocateLights( lights );
4121
4122 maxShadows = allocateShadows( lights );
4123
4124 maxBones = allocateBones( object );
4125
4126 parameters = {
4127
4128 map: !!material.map,
4129 envMap: !!material.envMap,
4130 lightMap: !!material.lightMap,
4131 bumpMap: !!material.bumpMap,
4132 normalMap: !!material.normalMap,
4133 specularMap: !!material.specularMap,
4134
4135 vertexColors: material.vertexColors,
4136
4137 fog: fog,
4138 useFog: material.fog,
4139 fogExp: fog instanceof THREE.FogExp2,
4140
4141 sizeAttenuation: material.sizeAttenuation,
4142
4143 skinning: material.skinning,
4144 maxBones: maxBones,
4145 useVertexTexture: _supportsBoneTextures && object && object.useVertexTexture,
4146
4147 morphTargets: material.morphTargets,
4148 morphNormals: material.morphNormals,
4149 maxMorphTargets: this.maxMorphTargets,
4150 maxMorphNormals: this.maxMorphNormals,
4151
4152 maxDirLights: maxLightCount.directional,
4153 maxPointLights: maxLightCount.point,
4154 maxSpotLights: maxLightCount.spot,
4155 maxHemiLights: maxLightCount.hemi,
4156
4157 maxShadows: maxShadows,
4158 shadowMapEnabled: this.shadowMapEnabled && object.receiveShadow,
4159 shadowMapType: this.shadowMapType,
4160 shadowMapDebug: this.shadowMapDebug,
4161 shadowMapCascade: this.shadowMapCascade,
4162
4163 alphaTest: material.alphaTest,
4164 metal: material.metal,
4165 perPixel: material.perPixel,
4166 wrapAround: material.wrapAround,
4167 doubleSided: material.side === THREE.DoubleSide,
4168 flipSided: material.side === THREE.BackSide
4169
4170 };
4171
4172 material.program = buildProgram( shaderID, material.fragmentShader, material.vertexShader, material.uniforms, material.attributes, material.defines, parameters, material.index0AttributeName );
4173
4174 var attributes = material.program.attributes;
4175
4176 if ( material.morphTargets ) {
4177
4178 material.numSupportedMorphTargets = 0;
4179
4180 var id, base = "morphTarget";
4181
4182 for ( i = 0; i < this.maxMorphTargets; i ++ ) {
4183
4184 id = base + i;
4185
4186 if ( attributes[ id ] >= 0 ) {
4187
4188 material.numSupportedMorphTargets ++;
4189
4190 }
4191
4192 }
4193
4194 }
4195
4196 if ( material.morphNormals ) {
4197
4198 material.numSupportedMorphNormals = 0;
4199
4200 var id, base = "morphNormal";
4201
4202 for ( i = 0; i < this.maxMorphNormals; i ++ ) {
4203
4204 id = base + i;
4205
4206 if ( attributes[ id ] >= 0 ) {
4207
4208 material.numSupportedMorphNormals ++;
4209
4210 }
4211
4212 }
4213
4214 }
4215
4216 material.uniformsList = [];
4217
4218 for ( u in material.uniforms ) {
4219
4220 material.uniformsList.push( [ material.uniforms[ u ], u ] );
4221
4222 }
4223
4224 };
4225
4226 function setMaterialShaders( material, shaders ) {
4227
4228 material.uniforms = THREE.UniformsUtils.clone( shaders.uniforms );
4229 material.vertexShader = shaders.vertexShader;
4230 material.fragmentShader = shaders.fragmentShader;
4231
4232 };
4233
4234 function setProgram( camera, lights, fog, material, object ) {
4235
4236 _usedTextureUnits = 0;
4237
4238 if ( material.needsUpdate ) {
4239
4240 if ( material.program ) deallocateMaterial( material );
4241
4242 _this.initMaterial( material, lights, fog, object );
4243 material.needsUpdate = false;
4244
4245 }
4246
4247 if ( material.morphTargets ) {
4248
4249 if ( ! object.__webglMorphTargetInfluences ) {
4250
4251 object.__webglMorphTargetInfluences = new Float32Array( _this.maxMorphTargets );
4252
4253 }
4254
4255 }
4256
4257 var refreshMaterial = false;
4258
4259 var program = material.program,
4260 p_uniforms = program.uniforms,
4261 m_uniforms = material.uniforms;
4262
4263 if ( program !== _currentProgram ) {
4264
4265 _gl.useProgram( program );
4266 _currentProgram = program;
4267
4268 refreshMaterial = true;
4269
4270 }
4271
4272 if ( material.id !== _currentMaterialId ) {
4273
4274 _currentMaterialId = material.id;
4275 refreshMaterial = true;
4276
4277 }
4278
4279 if ( refreshMaterial || camera !== _currentCamera ) {
4280
4281 _gl.uniformMatrix4fv( p_uniforms.projectionMatrix, false, camera.projectionMatrix.elements );
4282
4283 if ( camera !== _currentCamera ) _currentCamera = camera;
4284
4285 }
4286
4287 // skinning uniforms must be set even if material didn't change
4288 // auto-setting of texture unit for bone texture must go before other textures
4289 // not sure why, but otherwise weird things happen
4290
4291 if ( material.skinning ) {
4292
4293 if ( _supportsBoneTextures && object.useVertexTexture ) {
4294
4295 if ( p_uniforms.boneTexture !== null ) {
4296
4297 var textureUnit = getTextureUnit();
4298
4299 _gl.uniform1i( p_uniforms.boneTexture, textureUnit );
4300 _this.setTexture( object.boneTexture, textureUnit );
4301
4302 }
4303
4304 if ( p_uniforms.boneTextureWidth !== null ) {
4305
4306 _gl.uniform1i( p_uniforms.boneTextureWidth, object.boneTextureWidth );
4307
4308 }
4309
4310 if ( p_uniforms.boneTextureHeight !== null ) {
4311
4312 _gl.uniform1i( p_uniforms.boneTextureHeight, object.boneTextureHeight );
4313
4314 }
4315
4316 } else {
4317
4318 if ( p_uniforms.boneGlobalMatrices !== null ) {
4319
4320 _gl.uniformMatrix4fv( p_uniforms.boneGlobalMatrices, false, object.boneMatrices );
4321
4322 }
4323
4324 }
4325
4326 }
4327
4328 if ( refreshMaterial ) {
4329
4330 // refresh uniforms common to several materials
4331
4332 if ( fog && material.fog ) {
4333
4334 refreshUniformsFog( m_uniforms, fog );
4335
4336 }
4337
4338 if ( material instanceof THREE.MeshPhongMaterial ||
4339 material instanceof THREE.MeshLambertMaterial ||
4340 material.lights ) {
4341
4342 if ( _lightsNeedUpdate ) {
4343
4344 setupLights( program, lights );
4345 _lightsNeedUpdate = false;
4346
4347 }
4348
4349 refreshUniformsLights( m_uniforms, _lights );
4350
4351 }
4352
4353 if ( material instanceof THREE.MeshBasicMaterial ||
4354 material instanceof THREE.MeshLambertMaterial ||
4355 material instanceof THREE.MeshPhongMaterial ) {
4356
4357 refreshUniformsCommon( m_uniforms, material );
4358
4359 }
4360
4361 // refresh single material specific uniforms
4362
4363 if ( material instanceof THREE.LineBasicMaterial ) {
4364
4365 refreshUniformsLine( m_uniforms, material );
4366
4367 } else if ( material instanceof THREE.LineDashedMaterial ) {
4368
4369 refreshUniformsLine( m_uniforms, material );
4370 refreshUniformsDash( m_uniforms, material );
4371
4372 } else if ( material instanceof THREE.ParticleSystemMaterial ) {
4373
4374 refreshUniformsParticle( m_uniforms, material );
4375
4376 } else if ( material instanceof THREE.MeshPhongMaterial ) {
4377
4378 refreshUniformsPhong( m_uniforms, material );
4379
4380 } else if ( material instanceof THREE.MeshLambertMaterial ) {
4381
4382 refreshUniformsLambert( m_uniforms, material );
4383
4384 } else if ( material instanceof THREE.MeshDepthMaterial ) {
4385
4386 m_uniforms.mNear.value = camera.near;
4387 m_uniforms.mFar.value = camera.far;
4388 m_uniforms.opacity.value = material.opacity;
4389
4390 } else if ( material instanceof THREE.MeshNormalMaterial ) {
4391
4392 m_uniforms.opacity.value = material.opacity;
4393
4394 }
4395
4396 if ( object.receiveShadow && ! material._shadowPass ) {
4397
4398 refreshUniformsShadow( m_uniforms, lights );
4399
4400 }
4401
4402 // load common uniforms
4403
4404 loadUniformsGeneric( program, material.uniformsList );
4405
4406 // load material specific uniforms
4407 // (shader material also gets them for the sake of genericity)
4408
4409 if ( material instanceof THREE.ShaderMaterial ||
4410 material instanceof THREE.MeshPhongMaterial ||
4411 material.envMap ) {
4412
4413 if ( p_uniforms.cameraPosition !== null ) {
4414
4415 _vector3.setFromMatrixPosition( camera.matrixWorld );
4416 _gl.uniform3f( p_uniforms.cameraPosition, _vector3.x, _vector3.y, _vector3.z );
4417
4418 }
4419
4420 }
4421
4422 if ( material instanceof THREE.MeshPhongMaterial ||
4423 material instanceof THREE.MeshLambertMaterial ||
4424 material instanceof THREE.ShaderMaterial ||
4425 material.skinning ) {
4426
4427 if ( p_uniforms.viewMatrix !== null ) {
4428
4429 _gl.uniformMatrix4fv( p_uniforms.viewMatrix, false, camera.matrixWorldInverse.elements );
4430
4431 }
4432
4433 }
4434
4435 }
4436
4437 loadUniformsMatrices( p_uniforms, object );
4438
4439 if ( p_uniforms.modelMatrix !== null ) {
4440
4441 _gl.uniformMatrix4fv( p_uniforms.modelMatrix, false, object.matrixWorld.elements );
4442
4443 }
4444
4445 return program;
4446
4447 };
4448
4449 // Uniforms (refresh uniforms objects)
4450
4451 function refreshUniformsCommon ( uniforms, material ) {
4452
4453 uniforms.opacity.value = material.opacity;
4454
4455 if ( _this.gammaInput ) {
4456
4457 uniforms.diffuse.value.copyGammaToLinear( material.color );
4458
4459 } else {
4460
4461 uniforms.diffuse.value = material.color;
4462
4463 }
4464
4465 uniforms.map.value = material.map;
4466 uniforms.lightMap.value = material.lightMap;
4467 uniforms.specularMap.value = material.specularMap;
4468
4469 if ( material.bumpMap ) {
4470
4471 uniforms.bumpMap.value = material.bumpMap;
4472 uniforms.bumpScale.value = material.bumpScale;
4473
4474 }
4475
4476 if ( material.normalMap ) {
4477
4478 uniforms.normalMap.value = material.normalMap;
4479 uniforms.normalScale.value.copy( material.normalScale );
4480
4481 }
4482
4483 // uv repeat and offset setting priorities
4484 // 1. color map
4485 // 2. specular map
4486 // 3. normal map
4487 // 4. bump map
4488
4489 var uvScaleMap;
4490
4491 if ( material.map ) {
4492
4493 uvScaleMap = material.map;
4494
4495 } else if ( material.specularMap ) {
4496
4497 uvScaleMap = material.specularMap;
4498
4499 } else if ( material.normalMap ) {
4500
4501 uvScaleMap = material.normalMap;
4502
4503 } else if ( material.bumpMap ) {
4504
4505 uvScaleMap = material.bumpMap;
4506
4507 }
4508
4509 if ( uvScaleMap !== undefined ) {
4510
4511 var offset = uvScaleMap.offset;
4512 var repeat = uvScaleMap.repeat;
4513
4514 uniforms.offsetRepeat.value.set( offset.x, offset.y, repeat.x, repeat.y );
4515
4516 }
4517
4518 uniforms.envMap.value = material.envMap;
4519 uniforms.flipEnvMap.value = ( material.envMap instanceof THREE.WebGLRenderTargetCube ) ? 1 : -1;
4520
4521 if ( _this.gammaInput ) {
4522
4523 //uniforms.reflectivity.value = material.reflectivity * material.reflectivity;
4524 uniforms.reflectivity.value = material.reflectivity;
4525
4526 } else {
4527
4528 uniforms.reflectivity.value = material.reflectivity;
4529
4530 }
4531
4532 uniforms.refractionRatio.value = material.refractionRatio;
4533 uniforms.combine.value = material.combine;
4534 uniforms.useRefract.value = material.envMap && material.envMap.mapping instanceof THREE.CubeRefractionMapping;
4535
4536 };
4537
4538 function refreshUniformsLine ( uniforms, material ) {
4539
4540 uniforms.diffuse.value = material.color;
4541 uniforms.opacity.value = material.opacity;
4542
4543 };
4544
4545 function refreshUniformsDash ( uniforms, material ) {
4546
4547 uniforms.dashSize.value = material.dashSize;
4548 uniforms.totalSize.value = material.dashSize + material.gapSize;
4549 uniforms.scale.value = material.scale;
4550
4551 };
4552
4553 function refreshUniformsParticle ( uniforms, material ) {
4554
4555 uniforms.psColor.value = material.color;
4556 uniforms.opacity.value = material.opacity;
4557 uniforms.size.value = material.size;
4558 uniforms.scale.value = _canvas.height / 2.0; // TODO: Cache this.
4559
4560 uniforms.map.value = material.map;
4561
4562 };
4563
4564 function refreshUniformsFog ( uniforms, fog ) {
4565
4566 uniforms.fogColor.value = fog.color;
4567
4568 if ( fog instanceof THREE.Fog ) {
4569
4570 uniforms.fogNear.value = fog.near;
4571 uniforms.fogFar.value = fog.far;
4572
4573 } else if ( fog instanceof THREE.FogExp2 ) {
4574
4575 uniforms.fogDensity.value = fog.density;
4576
4577 }
4578
4579 };
4580
4581 function refreshUniformsPhong ( uniforms, material ) {
4582
4583 uniforms.shininess.value = material.shininess;
4584
4585 if ( _this.gammaInput ) {
4586
4587 uniforms.ambient.value.copyGammaToLinear( material.ambient );
4588 uniforms.emissive.value.copyGammaToLinear( material.emissive );
4589 uniforms.specular.value.copyGammaToLinear( material.specular );
4590
4591 } else {
4592
4593 uniforms.ambient.value = material.ambient;
4594 uniforms.emissive.value = material.emissive;
4595 uniforms.specular.value = material.specular;
4596
4597 }
4598
4599 if ( material.wrapAround ) {
4600
4601 uniforms.wrapRGB.value.copy( material.wrapRGB );
4602
4603 }
4604
4605 };
4606
4607 function refreshUniformsLambert ( uniforms, material ) {
4608
4609 if ( _this.gammaInput ) {
4610
4611 uniforms.ambient.value.copyGammaToLinear( material.ambient );
4612 uniforms.emissive.value.copyGammaToLinear( material.emissive );
4613
4614 } else {
4615
4616 uniforms.ambient.value = material.ambient;
4617 uniforms.emissive.value = material.emissive;
4618
4619 }
4620
4621 if ( material.wrapAround ) {
4622
4623 uniforms.wrapRGB.value.copy( material.wrapRGB );
4624
4625 }
4626
4627 };
4628
4629 function refreshUniformsLights ( uniforms, lights ) {
4630
4631 uniforms.ambientLightColor.value = lights.ambient;
4632
4633 uniforms.directionalLightColor.value = lights.directional.colors;
4634 uniforms.directionalLightDirection.value = lights.directional.positions;
4635
4636 uniforms.pointLightColor.value = lights.point.colors;
4637 uniforms.pointLightPosition.value = lights.point.positions;
4638 uniforms.pointLightDistance.value = lights.point.distances;
4639
4640 uniforms.spotLightColor.value = lights.spot.colors;
4641 uniforms.spotLightPosition.value = lights.spot.positions;
4642 uniforms.spotLightDistance.value = lights.spot.distances;
4643 uniforms.spotLightDirection.value = lights.spot.directions;
4644 uniforms.spotLightAngleCos.value = lights.spot.anglesCos;
4645 uniforms.spotLightExponent.value = lights.spot.exponents;
4646
4647 uniforms.hemisphereLightSkyColor.value = lights.hemi.skyColors;
4648 uniforms.hemisphereLightGroundColor.value = lights.hemi.groundColors;
4649 uniforms.hemisphereLightDirection.value = lights.hemi.positions;
4650
4651 };
4652
4653 function refreshUniformsShadow ( uniforms, lights ) {
4654
4655 if ( uniforms.shadowMatrix ) {
4656
4657 var j = 0;
4658
4659 for ( var i = 0, il = lights.length; i < il; i ++ ) {
4660
4661 var light = lights[ i ];
4662
4663 if ( ! light.castShadow ) continue;
4664
4665 if ( light instanceof THREE.SpotLight || ( light instanceof THREE.DirectionalLight && ! light.shadowCascade ) ) {
4666
4667 uniforms.shadowMap.value[ j ] = light.shadowMap;
4668 uniforms.shadowMapSize.value[ j ] = light.shadowMapSize;
4669
4670 uniforms.shadowMatrix.value[ j ] = light.shadowMatrix;
4671
4672 uniforms.shadowDarkness.value[ j ] = light.shadowDarkness;
4673 uniforms.shadowBias.value[ j ] = light.shadowBias;
4674
4675 j ++;
4676
4677 }
4678
4679 }
4680
4681 }
4682
4683 };
4684
4685 // Uniforms (load to GPU)
4686
4687 function loadUniformsMatrices ( uniforms, object ) {
4688
4689 _gl.uniformMatrix4fv( uniforms.modelViewMatrix, false, object._modelViewMatrix.elements );
4690
4691 if ( uniforms.normalMatrix ) {
4692
4693 _gl.uniformMatrix3fv( uniforms.normalMatrix, false, object._normalMatrix.elements );
4694
4695 }
4696
4697 };
4698
4699 function getTextureUnit() {
4700
4701 var textureUnit = _usedTextureUnits;
4702
4703 if ( textureUnit >= _maxTextures ) {
4704
4705 console.warn( "WebGLRenderer: trying to use " + textureUnit + " texture units while this GPU supports only " + _maxTextures );
4706
4707 }
4708
4709 _usedTextureUnits += 1;
4710
4711 return textureUnit;
4712
4713 };
4714
4715 function loadUniformsGeneric ( program, uniforms ) {
4716
4717 var uniform, value, type, location, texture, textureUnit, i, il, j, jl, offset;
4718
4719 for ( j = 0, jl = uniforms.length; j < jl; j ++ ) {
4720
4721 location = program.uniforms[ uniforms[ j ][ 1 ] ];
4722 if ( !location ) continue;
4723
4724 uniform = uniforms[ j ][ 0 ];
4725
4726 type = uniform.type;
4727 value = uniform.value;
4728
4729 if ( type === "i" ) { // single integer
4730
4731 _gl.uniform1i( location, value );
4732
4733 } else if ( type === "f" ) { // single float
4734
4735 _gl.uniform1f( location, value );
4736
4737 } else if ( type === "v2" ) { // single THREE.Vector2
4738
4739 _gl.uniform2f( location, value.x, value.y );
4740
4741 } else if ( type === "v3" ) { // single THREE.Vector3
4742
4743 _gl.uniform3f( location, value.x, value.y, value.z );
4744
4745 } else if ( type === "v4" ) { // single THREE.Vector4
4746
4747 _gl.uniform4f( location, value.x, value.y, value.z, value.w );
4748
4749 } else if ( type === "c" ) { // single THREE.Color
4750
4751 _gl.uniform3f( location, value.r, value.g, value.b );
4752
4753 } else if ( type === "iv1" ) { // flat array of integers (JS or typed array)
4754
4755 _gl.uniform1iv( location, value );
4756
4757 } else if ( type === "iv" ) { // flat array of integers with 3 x N size (JS or typed array)
4758
4759 _gl.uniform3iv( location, value );
4760
4761 } else if ( type === "fv1" ) { // flat array of floats (JS or typed array)
4762
4763 _gl.uniform1fv( location, value );
4764
4765 } else if ( type === "fv" ) { // flat array of floats with 3 x N size (JS or typed array)
4766
4767 _gl.uniform3fv( location, value );
4768
4769 } else if ( type === "v2v" ) { // array of THREE.Vector2
4770
4771 if ( uniform._array === undefined ) {
4772
4773 uniform._array = new Float32Array( 2 * value.length );
4774
4775 }
4776
4777 for ( i = 0, il = value.length; i < il; i ++ ) {
4778
4779 offset = i * 2;
4780
4781 uniform._array[ offset ] = value[ i ].x;
4782 uniform._array[ offset + 1 ] = value[ i ].y;
4783
4784 }
4785
4786 _gl.uniform2fv( location, uniform._array );
4787
4788 } else if ( type === "v3v" ) { // array of THREE.Vector3
4789
4790 if ( uniform._array === undefined ) {
4791
4792 uniform._array = new Float32Array( 3 * value.length );
4793
4794 }
4795
4796 for ( i = 0, il = value.length; i < il; i ++ ) {
4797
4798 offset = i * 3;
4799
4800 uniform._array[ offset ] = value[ i ].x;
4801 uniform._array[ offset + 1 ] = value[ i ].y;
4802 uniform._array[ offset + 2 ] = value[ i ].z;
4803
4804 }
4805
4806 _gl.uniform3fv( location, uniform._array );
4807
4808 } else if ( type === "v4v" ) { // array of THREE.Vector4
4809
4810 if ( uniform._array === undefined ) {
4811
4812 uniform._array = new Float32Array( 4 * value.length );
4813
4814 }
4815
4816 for ( i = 0, il = value.length; i < il; i ++ ) {
4817
4818 offset = i * 4;
4819
4820 uniform._array[ offset ] = value[ i ].x;
4821 uniform._array[ offset + 1 ] = value[ i ].y;
4822 uniform._array[ offset + 2 ] = value[ i ].z;
4823 uniform._array[ offset + 3 ] = value[ i ].w;
4824
4825 }
4826
4827 _gl.uniform4fv( location, uniform._array );
4828
4829 } else if ( type === "m4") { // single THREE.Matrix4
4830
4831 if ( uniform._array === undefined ) {
4832
4833 uniform._array = new Float32Array( 16 );
4834
4835 }
4836
4837 value.flattenToArray( uniform._array );
4838 _gl.uniformMatrix4fv( location, false, uniform._array );
4839
4840 } else if ( type === "m4v" ) { // array of THREE.Matrix4
4841
4842 if ( uniform._array === undefined ) {
4843
4844 uniform._array = new Float32Array( 16 * value.length );
4845
4846 }
4847
4848 for ( i = 0, il = value.length; i < il; i ++ ) {
4849
4850 value[ i ].flattenToArrayOffset( uniform._array, i * 16 );
4851
4852 }
4853
4854 _gl.uniformMatrix4fv( location, false, uniform._array );
4855
4856 } else if ( type === "t" ) { // single THREE.Texture (2d or cube)
4857
4858 texture = value;
4859 textureUnit = getTextureUnit();
4860
4861 _gl.uniform1i( location, textureUnit );
4862
4863 if ( !texture ) continue;
4864
4865 if ( texture.image instanceof Array && texture.image.length === 6 ) {
4866
4867 setCubeTexture( texture, textureUnit );
4868
4869 } else if ( texture instanceof THREE.WebGLRenderTargetCube ) {
4870
4871 setCubeTextureDynamic( texture, textureUnit );
4872
4873 } else {
4874
4875 _this.setTexture( texture, textureUnit );
4876
4877 }
4878
4879 } else if ( type === "tv" ) { // array of THREE.Texture (2d)
4880
4881 if ( uniform._array === undefined ) {
4882
4883 uniform._array = [];
4884
4885 }
4886
4887 for( i = 0, il = uniform.value.length; i < il; i ++ ) {
4888
4889 uniform._array[ i ] = getTextureUnit();
4890
4891 }
4892
4893 _gl.uniform1iv( location, uniform._array );
4894
4895 for( i = 0, il = uniform.value.length; i < il; i ++ ) {
4896
4897 texture = uniform.value[ i ];
4898 textureUnit = uniform._array[ i ];
4899
4900 if ( !texture ) continue;
4901
4902 _this.setTexture( texture, textureUnit );
4903
4904 }
4905
4906 } else {
4907
4908 console.warn( 'THREE.WebGLRenderer: Unknown uniform type: ' + type );
4909
4910 }
4911
4912 }
4913
4914 };
4915
4916 function setupMatrices ( object, camera ) {
4917
4918 object._modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, object.matrixWorld );
4919 object._normalMatrix.getNormalMatrix( object._modelViewMatrix );
4920
4921 };
4922
4923 //
4924
4925 function setColorGamma( array, offset, color, intensitySq ) {
4926
4927 array[ offset ] = color.r * color.r * intensitySq;
4928 array[ offset + 1 ] = color.g * color.g * intensitySq;
4929 array[ offset + 2 ] = color.b * color.b * intensitySq;
4930
4931 };
4932
4933 function setColorLinear( array, offset, color, intensity ) {
4934
4935 array[ offset ] = color.r * intensity;
4936 array[ offset + 1 ] = color.g * intensity;
4937 array[ offset + 2 ] = color.b * intensity;
4938
4939 };
4940
4941 function setupLights ( program, lights ) {
4942
4943 var l, ll, light, n,
4944 r = 0, g = 0, b = 0,
4945 color, skyColor, groundColor,
4946 intensity, intensitySq,
4947 position,
4948 distance,
4949
4950 zlights = _lights,
4951
4952 dirColors = zlights.directional.colors,
4953 dirPositions = zlights.directional.positions,
4954
4955 pointColors = zlights.point.colors,
4956 pointPositions = zlights.point.positions,
4957 pointDistances = zlights.point.distances,
4958
4959 spotColors = zlights.spot.colors,
4960 spotPositions = zlights.spot.positions,
4961 spotDistances = zlights.spot.distances,
4962 spotDirections = zlights.spot.directions,
4963 spotAnglesCos = zlights.spot.anglesCos,
4964 spotExponents = zlights.spot.exponents,
4965
4966 hemiSkyColors = zlights.hemi.skyColors,
4967 hemiGroundColors = zlights.hemi.groundColors,
4968 hemiPositions = zlights.hemi.positions,
4969
4970 dirLength = 0,
4971 pointLength = 0,
4972 spotLength = 0,
4973 hemiLength = 0,
4974
4975 dirCount = 0,
4976 pointCount = 0,
4977 spotCount = 0,
4978 hemiCount = 0,
4979
4980 dirOffset = 0,
4981 pointOffset = 0,
4982 spotOffset = 0,
4983 hemiOffset = 0;
4984
4985 for ( l = 0, ll = lights.length; l < ll; l ++ ) {
4986
4987 light = lights[ l ];
4988
4989 if ( light.onlyShadow ) continue;
4990
4991 color = light.color;
4992 intensity = light.intensity;
4993 distance = light.distance;
4994
4995 if ( light instanceof THREE.AmbientLight ) {
4996
4997 if ( ! light.visible ) continue;
4998
4999 if ( _this.gammaInput ) {
5000
5001 r += color.r * color.r;
5002 g += color.g * color.g;
5003 b += color.b * color.b;
5004
5005 } else {
5006
5007 r += color.r;
5008 g += color.g;
5009 b += color.b;
5010
5011 }
5012
5013 } else if ( light instanceof THREE.DirectionalLight ) {
5014
5015 dirCount += 1;
5016
5017 if ( ! light.visible ) continue;
5018
5019 _direction.setFromMatrixPosition( light.matrixWorld );
5020 _vector3.setFromMatrixPosition( light.target.matrixWorld );
5021 _direction.sub( _vector3 );
5022 _direction.normalize();
5023
5024 // skip lights with undefined direction
5025 // these create troubles in OpenGL (making pixel black)
5026
5027 if ( _direction.x === 0 && _direction.y === 0 && _direction.z === 0 ) continue;
5028
5029 dirOffset = dirLength * 3;
5030
5031 dirPositions[ dirOffset ] = _direction.x;
5032 dirPositions[ dirOffset + 1 ] = _direction.y;
5033 dirPositions[ dirOffset + 2 ] = _direction.z;
5034
5035 if ( _this.gammaInput ) {
5036
5037 setColorGamma( dirColors, dirOffset, color, intensity * intensity );
5038
5039 } else {
5040
5041 setColorLinear( dirColors, dirOffset, color, intensity );
5042
5043 }
5044
5045 dirLength += 1;
5046
5047 } else if ( light instanceof THREE.PointLight ) {
5048
5049 pointCount += 1;
5050
5051 if ( ! light.visible ) continue;
5052
5053 pointOffset = pointLength * 3;
5054
5055 if ( _this.gammaInput ) {
5056
5057 setColorGamma( pointColors, pointOffset, color, intensity * intensity );
5058
5059 } else {
5060
5061 setColorLinear( pointColors, pointOffset, color, intensity );
5062
5063 }
5064
5065 _vector3.setFromMatrixPosition( light.matrixWorld );
5066
5067 pointPositions[ pointOffset ] = _vector3.x;
5068 pointPositions[ pointOffset + 1 ] = _vector3.y;
5069 pointPositions[ pointOffset + 2 ] = _vector3.z;
5070
5071 pointDistances[ pointLength ] = distance;
5072
5073 pointLength += 1;
5074
5075 } else if ( light instanceof THREE.SpotLight ) {
5076
5077 spotCount += 1;
5078
5079 if ( ! light.visible ) continue;
5080
5081 spotOffset = spotLength * 3;
5082
5083 if ( _this.gammaInput ) {
5084
5085 setColorGamma( spotColors, spotOffset, color, intensity * intensity );
5086
5087 } else {
5088
5089 setColorLinear( spotColors, spotOffset, color, intensity );
5090
5091 }
5092
5093 _vector3.setFromMatrixPosition( light.matrixWorld );
5094
5095 spotPositions[ spotOffset ] = _vector3.x;
5096 spotPositions[ spotOffset + 1 ] = _vector3.y;
5097 spotPositions[ spotOffset + 2 ] = _vector3.z;
5098
5099 spotDistances[ spotLength ] = distance;
5100
5101 _direction.copy( _vector3 );
5102 _vector3.setFromMatrixPosition( light.target.matrixWorld );
5103 _direction.sub( _vector3 );
5104 _direction.normalize();
5105
5106 spotDirections[ spotOffset ] = _direction.x;
5107 spotDirections[ spotOffset + 1 ] = _direction.y;
5108 spotDirections[ spotOffset + 2 ] = _direction.z;
5109
5110 spotAnglesCos[ spotLength ] = Math.cos( light.angle );
5111 spotExponents[ spotLength ] = light.exponent;
5112
5113 spotLength += 1;
5114
5115 } else if ( light instanceof THREE.HemisphereLight ) {
5116
5117 hemiCount += 1;
5118
5119 if ( ! light.visible ) continue;
5120
5121 _direction.setFromMatrixPosition( light.matrixWorld );
5122 _direction.normalize();
5123
5124 // skip lights with undefined direction
5125 // these create troubles in OpenGL (making pixel black)
5126
5127 if ( _direction.x === 0 && _direction.y === 0 && _direction.z === 0 ) continue;
5128
5129 hemiOffset = hemiLength * 3;
5130
5131 hemiPositions[ hemiOffset ] = _direction.x;
5132 hemiPositions[ hemiOffset + 1 ] = _direction.y;
5133 hemiPositions[ hemiOffset + 2 ] = _direction.z;
5134
5135 skyColor = light.color;
5136 groundColor = light.groundColor;
5137
5138 if ( _this.gammaInput ) {
5139
5140 intensitySq = intensity * intensity;
5141
5142 setColorGamma( hemiSkyColors, hemiOffset, skyColor, intensitySq );
5143 setColorGamma( hemiGroundColors, hemiOffset, groundColor, intensitySq );
5144
5145 } else {
5146
5147 setColorLinear( hemiSkyColors, hemiOffset, skyColor, intensity );
5148 setColorLinear( hemiGroundColors, hemiOffset, groundColor, intensity );
5149
5150 }
5151
5152 hemiLength += 1;
5153
5154 }
5155
5156 }
5157
5158 // null eventual remains from removed lights
5159 // (this is to avoid if in shader)
5160
5161 for ( l = dirLength * 3, ll = Math.max( dirColors.length, dirCount * 3 ); l < ll; l ++ ) dirColors[ l ] = 0.0;
5162 for ( l = pointLength * 3, ll = Math.max( pointColors.length, pointCount * 3 ); l < ll; l ++ ) pointColors[ l ] = 0.0;
5163 for ( l = spotLength * 3, ll = Math.max( spotColors.length, spotCount * 3 ); l < ll; l ++ ) spotColors[ l ] = 0.0;
5164 for ( l = hemiLength * 3, ll = Math.max( hemiSkyColors.length, hemiCount * 3 ); l < ll; l ++ ) hemiSkyColors[ l ] = 0.0;
5165 for ( l = hemiLength * 3, ll = Math.max( hemiGroundColors.length, hemiCount * 3 ); l < ll; l ++ ) hemiGroundColors[ l ] = 0.0;
5166
5167 zlights.directional.length = dirLength;
5168 zlights.point.length = pointLength;
5169 zlights.spot.length = spotLength;
5170 zlights.hemi.length = hemiLength;
5171
5172 zlights.ambient[ 0 ] = r;
5173 zlights.ambient[ 1 ] = g;
5174 zlights.ambient[ 2 ] = b;
5175
5176 };
5177
5178 // GL state setting
5179
5180 this.setFaceCulling = function ( cullFace, frontFaceDirection ) {
5181
5182 if ( cullFace === THREE.CullFaceNone ) {
5183
5184 _gl.disable( _gl.CULL_FACE );
5185
5186 } else {
5187
5188 if ( frontFaceDirection === THREE.FrontFaceDirectionCW ) {
5189
5190 _gl.frontFace( _gl.CW );
5191
5192 } else {
5193
5194 _gl.frontFace( _gl.CCW );
5195
5196 }
5197
5198 if ( cullFace === THREE.CullFaceBack ) {
5199
5200 _gl.cullFace( _gl.BACK );
5201
5202 } else if ( cullFace === THREE.CullFaceFront ) {
5203
5204 _gl.cullFace( _gl.FRONT );
5205
5206 } else {
5207
5208 _gl.cullFace( _gl.FRONT_AND_BACK );
5209
5210 }
5211
5212 _gl.enable( _gl.CULL_FACE );
5213
5214 }
5215
5216 };
5217
5218 this.setMaterialFaces = function ( material ) {
5219
5220 var doubleSided = material.side === THREE.DoubleSide;
5221 var flipSided = material.side === THREE.BackSide;
5222
5223 if ( _oldDoubleSided !== doubleSided ) {
5224
5225 if ( doubleSided ) {
5226
5227 _gl.disable( _gl.CULL_FACE );
5228
5229 } else {
5230
5231 _gl.enable( _gl.CULL_FACE );
5232
5233 }
5234
5235 _oldDoubleSided = doubleSided;
5236
5237 }
5238
5239 if ( _oldFlipSided !== flipSided ) {
5240
5241 if ( flipSided ) {
5242
5243 _gl.frontFace( _gl.CW );
5244
5245 } else {
5246
5247 _gl.frontFace( _gl.CCW );
5248
5249 }
5250
5251 _oldFlipSided = flipSided;
5252
5253 }
5254
5255 };
5256
5257 this.setDepthTest = function ( depthTest ) {
5258
5259 if ( _oldDepthTest !== depthTest ) {
5260
5261 if ( depthTest ) {
5262
5263 _gl.enable( _gl.DEPTH_TEST );
5264
5265 } else {
5266
5267 _gl.disable( _gl.DEPTH_TEST );
5268
5269 }
5270
5271 _oldDepthTest = depthTest;
5272
5273 }
5274
5275 };
5276
5277 this.setDepthWrite = function ( depthWrite ) {
5278
5279 if ( _oldDepthWrite !== depthWrite ) {
5280
5281 _gl.depthMask( depthWrite );
5282 _oldDepthWrite = depthWrite;
5283
5284 }
5285
5286 };
5287
5288 function setLineWidth ( width ) {
5289
5290 if ( width !== _oldLineWidth ) {
5291
5292 _gl.lineWidth( width );
5293
5294 _oldLineWidth = width;
5295
5296 }
5297
5298 };
5299
5300 function setPolygonOffset ( polygonoffset, factor, units ) {
5301
5302 if ( _oldPolygonOffset !== polygonoffset ) {
5303
5304 if ( polygonoffset ) {
5305
5306 _gl.enable( _gl.POLYGON_OFFSET_FILL );
5307
5308 } else {
5309
5310 _gl.disable( _gl.POLYGON_OFFSET_FILL );
5311
5312 }
5313
5314 _oldPolygonOffset = polygonoffset;
5315
5316 }
5317
5318 if ( polygonoffset && ( _oldPolygonOffsetFactor !== factor || _oldPolygonOffsetUnits !== units ) ) {
5319
5320 _gl.polygonOffset( factor, units );
5321
5322 _oldPolygonOffsetFactor = factor;
5323 _oldPolygonOffsetUnits = units;
5324
5325 }
5326
5327 };
5328
5329 this.setBlending = function ( blending, blendEquation, blendSrc, blendDst ) {
5330
5331 if ( blending !== _oldBlending ) {
5332
5333 if ( blending === THREE.NoBlending ) {
5334
5335 _gl.disable( _gl.BLEND );
5336
5337 } else if ( blending === THREE.AdditiveBlending ) {
5338
5339 _gl.enable( _gl.BLEND );
5340 _gl.blendEquation( _gl.FUNC_ADD );
5341 _gl.blendFunc( _gl.SRC_ALPHA, _gl.ONE );
5342
5343 } else if ( blending === THREE.SubtractiveBlending ) {
5344
5345 // TODO: Find blendFuncSeparate() combination
5346 _gl.enable( _gl.BLEND );
5347 _gl.blendEquation( _gl.FUNC_ADD );
5348 _gl.blendFunc( _gl.ZERO, _gl.ONE_MINUS_SRC_COLOR );
5349
5350 } else if ( blending === THREE.MultiplyBlending ) {
5351
5352 // TODO: Find blendFuncSeparate() combination
5353 _gl.enable( _gl.BLEND );
5354 _gl.blendEquation( _gl.FUNC_ADD );
5355 _gl.blendFunc( _gl.ZERO, _gl.SRC_COLOR );
5356
5357 } else if ( blending === THREE.CustomBlending ) {
5358
5359 _gl.enable( _gl.BLEND );
5360
5361 } else {
5362
5363 _gl.enable( _gl.BLEND );
5364 _gl.blendEquationSeparate( _gl.FUNC_ADD, _gl.FUNC_ADD );
5365 _gl.blendFuncSeparate( _gl.SRC_ALPHA, _gl.ONE_MINUS_SRC_ALPHA, _gl.ONE, _gl.ONE_MINUS_SRC_ALPHA );
5366
5367 }
5368
5369 _oldBlending = blending;
5370
5371 }
5372
5373 if ( blending === THREE.CustomBlending ) {
5374
5375 if ( blendEquation !== _oldBlendEquation ) {
5376
5377 _gl.blendEquation( paramThreeToGL( blendEquation ) );
5378
5379 _oldBlendEquation = blendEquation;
5380
5381 }
5382
5383 if ( blendSrc !== _oldBlendSrc || blendDst !== _oldBlendDst ) {
5384
5385 _gl.blendFunc( paramThreeToGL( blendSrc ), paramThreeToGL( blendDst ) );
5386
5387 _oldBlendSrc = blendSrc;
5388 _oldBlendDst = blendDst;
5389
5390 }
5391
5392 } else {
5393
5394 _oldBlendEquation = null;
5395 _oldBlendSrc = null;
5396 _oldBlendDst = null;
5397
5398 }
5399
5400 };
5401
5402 // Defines
5403
5404 function generateDefines ( defines ) {
5405
5406 var value, chunk, chunks = [];
5407
5408 for ( var d in defines ) {
5409
5410 value = defines[ d ];
5411 if ( value === false ) continue;
5412
5413 chunk = "#define " + d + " " + value;
5414 chunks.push( chunk );
5415
5416 }
5417
5418 return chunks.join( "\n" );
5419
5420 };
5421
5422 // Shaders
5423
5424 function buildProgram ( shaderID, fragmentShader, vertexShader, uniforms, attributes, defines, parameters, index0AttributeName ) {
5425
5426 var p, pl, d, program, code;
5427 var chunks = [];
5428
5429 // Generate code
5430
5431 if ( shaderID ) {
5432
5433 chunks.push( shaderID );
5434
5435 } else {
5436
5437 chunks.push( fragmentShader );
5438 chunks.push( vertexShader );
5439
5440 }
5441
5442 for ( d in defines ) {
5443
5444 chunks.push( d );
5445 chunks.push( defines[ d ] );
5446
5447 }
5448
5449 for ( p in parameters ) {
5450
5451 chunks.push( p );
5452 chunks.push( parameters[ p ] );
5453
5454 }
5455
5456 code = chunks.join();
5457
5458 // Check if code has been already compiled
5459
5460 for ( p = 0, pl = _programs.length; p < pl; p ++ ) {
5461
5462 var programInfo = _programs[ p ];
5463
5464 if ( programInfo.code === code ) {
5465
5466 // console.log( "Code already compiled." /*: \n\n" + code*/ );
5467
5468 programInfo.usedTimes ++;
5469
5470 return programInfo.program;
5471
5472 }
5473
5474 }
5475
5476 var shadowMapTypeDefine = "SHADOWMAP_TYPE_BASIC";
5477
5478 if ( parameters.shadowMapType === THREE.PCFShadowMap ) {
5479
5480 shadowMapTypeDefine = "SHADOWMAP_TYPE_PCF";
5481
5482 } else if ( parameters.shadowMapType === THREE.PCFSoftShadowMap ) {
5483
5484 shadowMapTypeDefine = "SHADOWMAP_TYPE_PCF_SOFT";
5485
5486 }
5487
5488 // console.log( "building new program " );
5489
5490 //
5491
5492 var customDefines = generateDefines( defines );
5493
5494 //
5495
5496 program = _gl.createProgram();
5497
5498 var prefix_vertex = [
5499
5500 "precision " + _precision + " float;",
5501 "precision " + _precision + " int;",
5502
5503 customDefines,
5504
5505 _supportsVertexTextures ? "#define VERTEX_TEXTURES" : "",
5506
5507 _this.gammaInput ? "#define GAMMA_INPUT" : "",
5508 _this.gammaOutput ? "#define GAMMA_OUTPUT" : "",
5509
5510 "#define MAX_DIR_LIGHTS " + parameters.maxDirLights,
5511 "#define MAX_POINT_LIGHTS " + parameters.maxPointLights,
5512 "#define MAX_SPOT_LIGHTS " + parameters.maxSpotLights,
5513 "#define MAX_HEMI_LIGHTS " + parameters.maxHemiLights,
5514
5515 "#define MAX_SHADOWS " + parameters.maxShadows,
5516
5517 "#define MAX_BONES " + parameters.maxBones,
5518
5519 parameters.map ? "#define USE_MAP" : "",
5520 parameters.envMap ? "#define USE_ENVMAP" : "",
5521 parameters.lightMap ? "#define USE_LIGHTMAP" : "",
5522 parameters.bumpMap ? "#define USE_BUMPMAP" : "",
5523 parameters.normalMap ? "#define USE_NORMALMAP" : "",
5524 parameters.specularMap ? "#define USE_SPECULARMAP" : "",
5525 parameters.vertexColors ? "#define USE_COLOR" : "",
5526
5527 parameters.skinning ? "#define USE_SKINNING" : "",
5528 parameters.useVertexTexture ? "#define BONE_TEXTURE" : "",
5529
5530 parameters.morphTargets ? "#define USE_MORPHTARGETS" : "",
5531 parameters.morphNormals ? "#define USE_MORPHNORMALS" : "",
5532 parameters.perPixel ? "#define PHONG_PER_PIXEL" : "",
5533 parameters.wrapAround ? "#define WRAP_AROUND" : "",
5534 parameters.doubleSided ? "#define DOUBLE_SIDED" : "",
5535 parameters.flipSided ? "#define FLIP_SIDED" : "",
5536
5537 parameters.shadowMapEnabled ? "#define USE_SHADOWMAP" : "",
5538 parameters.shadowMapEnabled ? "#define " + shadowMapTypeDefine : "",
5539 parameters.shadowMapDebug ? "#define SHADOWMAP_DEBUG" : "",
5540 parameters.shadowMapCascade ? "#define SHADOWMAP_CASCADE" : "",
5541
5542 parameters.sizeAttenuation ? "#define USE_SIZEATTENUATION" : "",
5543
5544 "uniform mat4 modelMatrix;",
5545 "uniform mat4 modelViewMatrix;",
5546 "uniform mat4 projectionMatrix;",
5547 "uniform mat4 viewMatrix;",
5548 "uniform mat3 normalMatrix;",
5549 "uniform vec3 cameraPosition;",
5550
5551 "attribute vec3 position;",
5552 "attribute vec3 normal;",
5553 "attribute vec2 uv;",
5554 "attribute vec2 uv2;",
5555
5556 "#ifdef USE_COLOR",
5557
5558 "attribute vec3 color;",
5559
5560 "#endif",
5561
5562 "#ifdef USE_MORPHTARGETS",
5563
5564 "attribute vec3 morphTarget0;",
5565 "attribute vec3 morphTarget1;",
5566 "attribute vec3 morphTarget2;",
5567 "attribute vec3 morphTarget3;",
5568
5569 "#ifdef USE_MORPHNORMALS",
5570
5571 "attribute vec3 morphNormal0;",
5572 "attribute vec3 morphNormal1;",
5573 "attribute vec3 morphNormal2;",
5574 "attribute vec3 morphNormal3;",
5575
5576 "#else",
5577
5578 "attribute vec3 morphTarget4;",
5579 "attribute vec3 morphTarget5;",
5580 "attribute vec3 morphTarget6;",
5581 "attribute vec3 morphTarget7;",
5582
5583 "#endif",
5584
5585 "#endif",
5586
5587 "#ifdef USE_SKINNING",
5588
5589 "attribute vec4 skinIndex;",
5590 "attribute vec4 skinWeight;",
5591
5592 "#endif",
5593
5594 ""
5595
5596 ].join("\n");
5597
5598 var prefix_fragment = [
5599
5600 "precision " + _precision + " float;",
5601 "precision " + _precision + " int;",
5602
5603 ( parameters.bumpMap || parameters.normalMap ) ? "#extension GL_OES_standard_derivatives : enable" : "",
5604
5605 customDefines,
5606
5607 "#define MAX_DIR_LIGHTS " + parameters.maxDirLights,
5608 "#define MAX_POINT_LIGHTS " + parameters.maxPointLights,
5609 "#define MAX_SPOT_LIGHTS " + parameters.maxSpotLights,
5610 "#define MAX_HEMI_LIGHTS " + parameters.maxHemiLights,
5611
5612 "#define MAX_SHADOWS " + parameters.maxShadows,
5613
5614 parameters.alphaTest ? "#define ALPHATEST " + parameters.alphaTest: "",
5615
5616 _this.gammaInput ? "#define GAMMA_INPUT" : "",
5617 _this.gammaOutput ? "#define GAMMA_OUTPUT" : "",
5618
5619 ( parameters.useFog && parameters.fog ) ? "#define USE_FOG" : "",
5620 ( parameters.useFog && parameters.fogExp ) ? "#define FOG_EXP2" : "",
5621
5622 parameters.map ? "#define USE_MAP" : "",
5623 parameters.envMap ? "#define USE_ENVMAP" : "",
5624 parameters.lightMap ? "#define USE_LIGHTMAP" : "",
5625 parameters.bumpMap ? "#define USE_BUMPMAP" : "",
5626 parameters.normalMap ? "#define USE_NORMALMAP" : "",
5627 parameters.specularMap ? "#define USE_SPECULARMAP" : "",
5628 parameters.vertexColors ? "#define USE_COLOR" : "",
5629
5630 parameters.metal ? "#define METAL" : "",
5631 parameters.perPixel ? "#define PHONG_PER_PIXEL" : "",
5632 parameters.wrapAround ? "#define WRAP_AROUND" : "",
5633 parameters.doubleSided ? "#define DOUBLE_SIDED" : "",
5634 parameters.flipSided ? "#define FLIP_SIDED" : "",
5635
5636 parameters.shadowMapEnabled ? "#define USE_SHADOWMAP" : "",
5637 parameters.shadowMapEnabled ? "#define " + shadowMapTypeDefine : "",
5638 parameters.shadowMapDebug ? "#define SHADOWMAP_DEBUG" : "",
5639 parameters.shadowMapCascade ? "#define SHADOWMAP_CASCADE" : "",
5640
5641 "uniform mat4 viewMatrix;",
5642 "uniform vec3 cameraPosition;",
5643 ""
5644
5645 ].join("\n");
5646
5647 var glVertexShader = getShader( "vertex", prefix_vertex + vertexShader );
5648 var glFragmentShader = getShader( "fragment", prefix_fragment + fragmentShader );
5649
5650 _gl.attachShader( program, glVertexShader );
5651 _gl.attachShader( program, glFragmentShader );
5652
5653 //Force a particular attribute to index 0.
5654 // because potentially expensive emulation is done by browser if attribute 0 is disabled.
5655 //And, color, for example is often automatically bound to index 0 so disabling it
5656 if ( index0AttributeName ) {
5657 _gl.bindAttribLocation( program, 0, index0AttributeName );
5658 }
5659
5660 _gl.linkProgram( program );
5661
5662 if ( !_gl.getProgramParameter( program, _gl.LINK_STATUS ) ) {
5663
5664 console.error( "Could not initialise shader\n" + "VALIDATE_STATUS: " + _gl.getProgramParameter( program, _gl.VALIDATE_STATUS ) + ", gl error [" + _gl.getError() + "]" );
5665 console.error( "Program Info Log: " + _gl.getProgramInfoLog( program ) );
5666 }
5667
5668 // clean up
5669
5670 _gl.deleteShader( glFragmentShader );
5671 _gl.deleteShader( glVertexShader );
5672
5673 // console.log( prefix_fragment + fragmentShader );
5674 // console.log( prefix_vertex + vertexShader );
5675
5676 program.uniforms = {};
5677 program.attributes = {};
5678
5679 var identifiers, u, a, i;
5680
5681 // cache uniform locations
5682
5683 identifiers = [
5684
5685 'viewMatrix', 'modelViewMatrix', 'projectionMatrix', 'normalMatrix', 'modelMatrix', 'cameraPosition',
5686 'morphTargetInfluences'
5687
5688 ];
5689
5690 if ( parameters.useVertexTexture ) {
5691
5692 identifiers.push( 'boneTexture' );
5693 identifiers.push( 'boneTextureWidth' );
5694 identifiers.push( 'boneTextureHeight' );
5695
5696 } else {
5697
5698 identifiers.push( 'boneGlobalMatrices' );
5699
5700 }
5701
5702 for ( u in uniforms ) {
5703
5704 identifiers.push( u );
5705
5706 }
5707
5708 cacheUniformLocations( program, identifiers );
5709
5710 // cache attributes locations
5711
5712 identifiers = [
5713
5714 "position", "normal", "uv", "uv2", "tangent", "color",
5715 "skinIndex", "skinWeight", "lineDistance"
5716
5717 ];
5718
5719 for ( i = 0; i < parameters.maxMorphTargets; i ++ ) {
5720
5721 identifiers.push( "morphTarget" + i );
5722
5723 }
5724
5725 for ( i = 0; i < parameters.maxMorphNormals; i ++ ) {
5726
5727 identifiers.push( "morphNormal" + i );
5728
5729 }
5730
5731 for ( a in attributes ) {
5732
5733 identifiers.push( a );
5734
5735 }
5736
5737 cacheAttributeLocations( program, identifiers );
5738
5739 program.id = _programs_counter ++;
5740
5741 _programs.push( { program: program, code: code, usedTimes: 1 } );
5742
5743 _this.info.memory.programs = _programs.length;
5744
5745 return program;
5746
5747 };
5748
5749 // Shader parameters cache
5750
5751 function cacheUniformLocations ( program, identifiers ) {
5752
5753 var i, l, id;
5754
5755 for( i = 0, l = identifiers.length; i < l; i ++ ) {
5756
5757 id = identifiers[ i ];
5758 program.uniforms[ id ] = _gl.getUniformLocation( program, id );
5759
5760 }
5761
5762 };
5763
5764 function cacheAttributeLocations ( program, identifiers ) {
5765
5766 var i, l, id;
5767
5768 for( i = 0, l = identifiers.length; i < l; i ++ ) {
5769
5770 id = identifiers[ i ];
5771 program.attributes[ id ] = _gl.getAttribLocation( program, id );
5772
5773 }
5774
5775 };
5776
5777 function addLineNumbers ( string ) {
5778
5779 var chunks = string.split( "\n" );
5780
5781 for ( var i = 0, il = chunks.length; i < il; i ++ ) {
5782
5783 // Chrome reports shader errors on lines
5784 // starting counting from 1
5785
5786 chunks[ i ] = ( i + 1 ) + ": " + chunks[ i ];
5787
5788 }
5789
5790 return chunks.join( "\n" );
5791
5792 };
5793
5794 function getShader ( type, string ) {
5795
5796 var shader;
5797
5798 if ( type === "fragment" ) {
5799
5800 shader = _gl.createShader( _gl.FRAGMENT_SHADER );
5801
5802 } else if ( type === "vertex" ) {
5803
5804 shader = _gl.createShader( _gl.VERTEX_SHADER );
5805
5806 }
5807
5808 _gl.shaderSource( shader, string );
5809 _gl.compileShader( shader );
5810
5811 if ( !_gl.getShaderParameter( shader, _gl.COMPILE_STATUS ) ) {
5812
5813 console.error( _gl.getShaderInfoLog( shader ) );
5814 console.error( addLineNumbers( string ) );
5815 return null;
5816
5817 }
5818
5819 return shader;
5820
5821 };
5822
5823 // Textures
5824
5825
5826 function isPowerOfTwo ( value ) {
5827
5828 return ( value & ( value - 1 ) ) === 0;
5829
5830 };
5831
5832 function setTextureParameters ( textureType, texture, isImagePowerOfTwo ) {
5833
5834 if ( isImagePowerOfTwo ) {
5835
5836 _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_S, paramThreeToGL( texture.wrapS ) );
5837 _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_T, paramThreeToGL( texture.wrapT ) );
5838
5839 _gl.texParameteri( textureType, _gl.TEXTURE_MAG_FILTER, paramThreeToGL( texture.magFilter ) );
5840 _gl.texParameteri( textureType, _gl.TEXTURE_MIN_FILTER, paramThreeToGL( texture.minFilter ) );
5841
5842 } else {
5843
5844 _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_S, _gl.CLAMP_TO_EDGE );
5845 _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_T, _gl.CLAMP_TO_EDGE );
5846
5847 _gl.texParameteri( textureType, _gl.TEXTURE_MAG_FILTER, filterFallback( texture.magFilter ) );
5848 _gl.texParameteri( textureType, _gl.TEXTURE_MIN_FILTER, filterFallback( texture.minFilter ) );
5849
5850 }
5851
5852 if ( _glExtensionTextureFilterAnisotropic && texture.type !== THREE.FloatType ) {
5853
5854 if ( texture.anisotropy > 1 || texture.__oldAnisotropy ) {
5855
5856 _gl.texParameterf( textureType, _glExtensionTextureFilterAnisotropic.TEXTURE_MAX_ANISOTROPY_EXT, Math.min( texture.anisotropy, _maxAnisotropy ) );
5857 texture.__oldAnisotropy = texture.anisotropy;
5858
5859 }
5860
5861 }
5862
5863 };
5864
5865 this.setTexture = function ( texture, slot ) {
5866
5867 if ( texture.needsUpdate ) {
5868
5869 if ( ! texture.__webglInit ) {
5870
5871 texture.__webglInit = true;
5872
5873 texture.addEventListener( 'dispose', onTextureDispose );
5874
5875 texture.__webglTexture = _gl.createTexture();
5876
5877 _this.info.memory.textures ++;
5878
5879 }
5880
5881 _gl.activeTexture( _gl.TEXTURE0 + slot );
5882 _gl.bindTexture( _gl.TEXTURE_2D, texture.__webglTexture );
5883
5884 _gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, texture.flipY );
5885 _gl.pixelStorei( _gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultiplyAlpha );
5886 _gl.pixelStorei( _gl.UNPACK_ALIGNMENT, texture.unpackAlignment );
5887
5888 var image = texture.image,
5889 isImagePowerOfTwo = isPowerOfTwo( image.width ) && isPowerOfTwo( image.height ),
5890 glFormat = paramThreeToGL( texture.format ),
5891 glType = paramThreeToGL( texture.type );
5892
5893 setTextureParameters( _gl.TEXTURE_2D, texture, isImagePowerOfTwo );
5894
5895 var mipmap, mipmaps = texture.mipmaps;
5896
5897 if ( texture instanceof THREE.DataTexture ) {
5898
5899 // use manually created mipmaps if available
5900 // if there are no manual mipmaps
5901 // set 0 level mipmap and then use GL to generate other mipmap levels
5902
5903 if ( mipmaps.length > 0 && isImagePowerOfTwo ) {
5904
5905 for ( var i = 0, il = mipmaps.length; i < il; i ++ ) {
5906
5907 mipmap = mipmaps[ i ];
5908 _gl.texImage2D( _gl.TEXTURE_2D, i, glFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data );
5909
5910 }
5911
5912 texture.generateMipmaps = false;
5913
5914 } else {
5915
5916 _gl.texImage2D( _gl.TEXTURE_2D, 0, glFormat, image.width, image.height, 0, glFormat, glType, image.data );
5917
5918 }
5919
5920 } else if ( texture instanceof THREE.CompressedTexture ) {
5921
5922 for( var i = 0, il = mipmaps.length; i < il; i ++ ) {
5923
5924 mipmap = mipmaps[ i ];
5925 if ( texture.format!==THREE.RGBAFormat ) {
5926 _gl.compressedTexImage2D( _gl.TEXTURE_2D, i, glFormat, mipmap.width, mipmap.height, 0, mipmap.data );
5927 } else {
5928 _gl.texImage2D( _gl.TEXTURE_2D, i, glFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data );
5929 }
5930
5931 }
5932
5933 } else { // regular Texture (image, video, canvas)
5934
5935 // use manually created mipmaps if available
5936 // if there are no manual mipmaps
5937 // set 0 level mipmap and then use GL to generate other mipmap levels
5938
5939 if ( mipmaps.length > 0 && isImagePowerOfTwo ) {
5940
5941 for ( var i = 0, il = mipmaps.length; i < il; i ++ ) {
5942
5943 mipmap = mipmaps[ i ];
5944 _gl.texImage2D( _gl.TEXTURE_2D, i, glFormat, glFormat, glType, mipmap );
5945
5946 }
5947
5948 texture.generateMipmaps = false;
5949
5950 } else {
5951
5952 _gl.texImage2D( _gl.TEXTURE_2D, 0, glFormat, glFormat, glType, texture.image );
5953
5954 }
5955
5956 }
5957
5958 if ( texture.generateMipmaps && isImagePowerOfTwo ) _gl.generateMipmap( _gl.TEXTURE_2D );
5959
5960 texture.needsUpdate = false;
5961
5962 if ( texture.onUpdate ) texture.onUpdate();
5963
5964 } else {
5965
5966 _gl.activeTexture( _gl.TEXTURE0 + slot );
5967 _gl.bindTexture( _gl.TEXTURE_2D, texture.__webglTexture );
5968
5969 }
5970
5971 };
5972
5973 function clampToMaxSize ( image, maxSize ) {
5974
5975 if ( image.width <= maxSize && image.height <= maxSize ) {
5976
5977 return image;
5978
5979 }
5980
5981 // Warning: Scaling through the canvas will only work with images that use
5982 // premultiplied alpha.
5983
5984 var maxDimension = Math.max( image.width, image.height );
5985 var newWidth = Math.floor( image.width * maxSize / maxDimension );
5986 var newHeight = Math.floor( image.height * maxSize / maxDimension );
5987
5988 var canvas = document.createElement( 'canvas' );
5989 canvas.width = newWidth;
5990 canvas.height = newHeight;
5991
5992 var ctx = canvas.getContext( "2d" );
5993 ctx.drawImage( image, 0, 0, image.width, image.height, 0, 0, newWidth, newHeight );
5994
5995 return canvas;
5996
5997 }
5998
5999 function setCubeTexture ( texture, slot ) {
6000
6001 if ( texture.image.length === 6 ) {
6002
6003 if ( texture.needsUpdate ) {
6004
6005 if ( ! texture.image.__webglTextureCube ) {
6006
6007 texture.addEventListener( 'dispose', onTextureDispose );
6008
6009 texture.image.__webglTextureCube = _gl.createTexture();
6010
6011 _this.info.memory.textures ++;
6012
6013 }
6014
6015 _gl.activeTexture( _gl.TEXTURE0 + slot );
6016 _gl.bindTexture( _gl.TEXTURE_CUBE_MAP, texture.image.__webglTextureCube );
6017
6018 _gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, texture.flipY );
6019
6020 var isCompressed = texture instanceof THREE.CompressedTexture;
6021
6022 var cubeImage = [];
6023
6024 for ( var i = 0; i < 6; i ++ ) {
6025
6026 if ( _this.autoScaleCubemaps && ! isCompressed ) {
6027
6028 cubeImage[ i ] = clampToMaxSize( texture.image[ i ], _maxCubemapSize );
6029
6030 } else {
6031
6032 cubeImage[ i ] = texture.image[ i ];
6033
6034 }
6035
6036 }
6037
6038 var image = cubeImage[ 0 ],
6039 isImagePowerOfTwo = isPowerOfTwo( image.width ) && isPowerOfTwo( image.height ),
6040 glFormat = paramThreeToGL( texture.format ),
6041 glType = paramThreeToGL( texture.type );
6042
6043 setTextureParameters( _gl.TEXTURE_CUBE_MAP, texture, isImagePowerOfTwo );
6044
6045 for ( var i = 0; i < 6; i ++ ) {
6046
6047 if( !isCompressed ) {
6048
6049 _gl.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glFormat, glFormat, glType, cubeImage[ i ] );
6050
6051 } else {
6052
6053 var mipmap, mipmaps = cubeImage[ i ].mipmaps;
6054
6055 for( var j = 0, jl = mipmaps.length; j < jl; j ++ ) {
6056
6057 mipmap = mipmaps[ j ];
6058 if ( texture.format!==THREE.RGBAFormat ) {
6059
6060 _gl.compressedTexImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glFormat, mipmap.width, mipmap.height, 0, mipmap.data );
6061
6062 } else {
6063 _gl.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data );
6064 }
6065
6066 }
6067 }
6068 }
6069
6070 if ( texture.generateMipmaps && isImagePowerOfTwo ) {
6071
6072 _gl.generateMipmap( _gl.TEXTURE_CUBE_MAP );
6073
6074 }
6075
6076 texture.needsUpdate = false;
6077
6078 if ( texture.onUpdate ) texture.onUpdate();
6079
6080 } else {
6081
6082 _gl.activeTexture( _gl.TEXTURE0 + slot );
6083 _gl.bindTexture( _gl.TEXTURE_CUBE_MAP, texture.image.__webglTextureCube );
6084
6085 }
6086
6087 }
6088
6089 };
6090
6091 function setCubeTextureDynamic ( texture, slot ) {
6092
6093 _gl.activeTexture( _gl.TEXTURE0 + slot );
6094 _gl.bindTexture( _gl.TEXTURE_CUBE_MAP, texture.__webglTexture );
6095
6096 };
6097
6098 // Render targets
6099
6100 function setupFrameBuffer ( framebuffer, renderTarget, textureTarget ) {
6101
6102 _gl.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );
6103 _gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, textureTarget, renderTarget.__webglTexture, 0 );
6104
6105 };
6106
6107 function setupRenderBuffer ( renderbuffer, renderTarget ) {
6108
6109 _gl.bindRenderbuffer( _gl.RENDERBUFFER, renderbuffer );
6110
6111 if ( renderTarget.depthBuffer && ! renderTarget.stencilBuffer ) {
6112
6113 _gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.DEPTH_COMPONENT16, renderTarget.width, renderTarget.height );
6114 _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer );
6115
6116 /* For some reason this is not working. Defaulting to RGBA4.
6117 } else if( ! renderTarget.depthBuffer && renderTarget.stencilBuffer ) {
6118
6119 _gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.STENCIL_INDEX8, renderTarget.width, renderTarget.height );
6120 _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.STENCIL_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer );
6121 */
6122 } else if ( renderTarget.depthBuffer && renderTarget.stencilBuffer ) {
6123
6124 _gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.DEPTH_STENCIL, renderTarget.width, renderTarget.height );
6125 _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer );
6126
6127 } else {
6128
6129 _gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.RGBA4, renderTarget.width, renderTarget.height );
6130
6131 }
6132
6133 };
6134
6135 this.setRenderTarget = function ( renderTarget ) {
6136
6137 var isCube = ( renderTarget instanceof THREE.WebGLRenderTargetCube );
6138
6139 if ( renderTarget && ! renderTarget.__webglFramebuffer ) {
6140
6141 if ( renderTarget.depthBuffer === undefined ) renderTarget.depthBuffer = true;
6142 if ( renderTarget.stencilBuffer === undefined ) renderTarget.stencilBuffer = true;
6143
6144 renderTarget.addEventListener( 'dispose', onRenderTargetDispose );
6145
6146 renderTarget.__webglTexture = _gl.createTexture();
6147
6148 _this.info.memory.textures ++;
6149
6150 // Setup texture, create render and frame buffers
6151
6152 var isTargetPowerOfTwo = isPowerOfTwo( renderTarget.width ) && isPowerOfTwo( renderTarget.height ),
6153 glFormat = paramThreeToGL( renderTarget.format ),
6154 glType = paramThreeToGL( renderTarget.type );
6155
6156 if ( isCube ) {
6157
6158 renderTarget.__webglFramebuffer = [];
6159 renderTarget.__webglRenderbuffer = [];
6160
6161 _gl.bindTexture( _gl.TEXTURE_CUBE_MAP, renderTarget.__webglTexture );
6162 setTextureParameters( _gl.TEXTURE_CUBE_MAP, renderTarget, isTargetPowerOfTwo );
6163
6164 for ( var i = 0; i < 6; i ++ ) {
6165
6166 renderTarget.__webglFramebuffer[ i ] = _gl.createFramebuffer();
6167 renderTarget.__webglRenderbuffer[ i ] = _gl.createRenderbuffer();
6168
6169 _gl.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glFormat, renderTarget.width, renderTarget.height, 0, glFormat, glType, null );
6170
6171 setupFrameBuffer( renderTarget.__webglFramebuffer[ i ], renderTarget, _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i );
6172 setupRenderBuffer( renderTarget.__webglRenderbuffer[ i ], renderTarget );
6173
6174 }
6175
6176 if ( isTargetPowerOfTwo ) _gl.generateMipmap( _gl.TEXTURE_CUBE_MAP );
6177
6178 } else {
6179
6180 renderTarget.__webglFramebuffer = _gl.createFramebuffer();
6181
6182 if ( renderTarget.shareDepthFrom ) {
6183
6184 renderTarget.__webglRenderbuffer = renderTarget.shareDepthFrom.__webglRenderbuffer;
6185
6186 } else {
6187
6188 renderTarget.__webglRenderbuffer = _gl.createRenderbuffer();
6189
6190 }
6191
6192 _gl.bindTexture( _gl.TEXTURE_2D, renderTarget.__webglTexture );
6193 setTextureParameters( _gl.TEXTURE_2D, renderTarget, isTargetPowerOfTwo );
6194
6195 _gl.texImage2D( _gl.TEXTURE_2D, 0, glFormat, renderTarget.width, renderTarget.height, 0, glFormat, glType, null );
6196
6197 setupFrameBuffer( renderTarget.__webglFramebuffer, renderTarget, _gl.TEXTURE_2D );
6198
6199 if ( renderTarget.shareDepthFrom ) {
6200
6201 if ( renderTarget.depthBuffer && ! renderTarget.stencilBuffer ) {
6202
6203 _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.RENDERBUFFER, renderTarget.__webglRenderbuffer );
6204
6205 } else if ( renderTarget.depthBuffer && renderTarget.stencilBuffer ) {
6206
6207 _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.RENDERBUFFER, renderTarget.__webglRenderbuffer );
6208
6209 }
6210
6211 } else {
6212
6213 setupRenderBuffer( renderTarget.__webglRenderbuffer, renderTarget );
6214
6215 }
6216
6217 if ( isTargetPowerOfTwo ) _gl.generateMipmap( _gl.TEXTURE_2D );
6218
6219 }
6220
6221 // Release everything
6222
6223 if ( isCube ) {
6224
6225 _gl.bindTexture( _gl.TEXTURE_CUBE_MAP, null );
6226
6227 } else {
6228
6229 _gl.bindTexture( _gl.TEXTURE_2D, null );
6230
6231 }
6232
6233 _gl.bindRenderbuffer( _gl.RENDERBUFFER, null );
6234 _gl.bindFramebuffer( _gl.FRAMEBUFFER, null );
6235
6236 }
6237
6238 var framebuffer, width, height, vx, vy;
6239
6240 if ( renderTarget ) {
6241
6242 if ( isCube ) {
6243
6244 framebuffer = renderTarget.__webglFramebuffer[ renderTarget.activeCubeFace ];
6245
6246 } else {
6247
6248 framebuffer = renderTarget.__webglFramebuffer;
6249
6250 }
6251
6252 width = renderTarget.width;
6253 height = renderTarget.height;
6254
6255 vx = 0;
6256 vy = 0;
6257
6258 } else {
6259
6260 framebuffer = null;
6261
6262 width = _viewportWidth;
6263 height = _viewportHeight;
6264
6265 vx = _viewportX;
6266 vy = _viewportY;
6267
6268 }
6269
6270 if ( framebuffer !== _currentFramebuffer ) {
6271
6272 _gl.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );
6273 _gl.viewport( vx, vy, width, height );
6274
6275 _currentFramebuffer = framebuffer;
6276
6277 }
6278
6279 _currentWidth = width;
6280 _currentHeight = height;
6281
6282 };
6283
6284 function updateRenderTargetMipmap ( renderTarget ) {
6285
6286 if ( renderTarget instanceof THREE.WebGLRenderTargetCube ) {
6287
6288 _gl.bindTexture( _gl.TEXTURE_CUBE_MAP, renderTarget.__webglTexture );
6289 _gl.generateMipmap( _gl.TEXTURE_CUBE_MAP );
6290 _gl.bindTexture( _gl.TEXTURE_CUBE_MAP, null );
6291
6292 } else {
6293
6294 _gl.bindTexture( _gl.TEXTURE_2D, renderTarget.__webglTexture );
6295 _gl.generateMipmap( _gl.TEXTURE_2D );
6296 _gl.bindTexture( _gl.TEXTURE_2D, null );
6297
6298 }
6299
6300 };
6301
6302 // Fallback filters for non-power-of-2 textures
6303
6304 function filterFallback ( f ) {
6305
6306 if ( f === THREE.NearestFilter || f === THREE.NearestMipMapNearestFilter || f === THREE.NearestMipMapLinearFilter ) {
6307
6308 return _gl.NEAREST;
6309
6310 }
6311
6312 return _gl.LINEAR;
6313
6314 };
6315
6316 // Map three.js constants to WebGL constants
6317
6318 function paramThreeToGL ( p ) {
6319
6320 if ( p === THREE.RepeatWrapping ) return _gl.REPEAT;
6321 if ( p === THREE.ClampToEdgeWrapping ) return _gl.CLAMP_TO_EDGE;
6322 if ( p === THREE.MirroredRepeatWrapping ) return _gl.MIRRORED_REPEAT;
6323
6324 if ( p === THREE.NearestFilter ) return _gl.NEAREST;
6325 if ( p === THREE.NearestMipMapNearestFilter ) return _gl.NEAREST_MIPMAP_NEAREST;
6326 if ( p === THREE.NearestMipMapLinearFilter ) return _gl.NEAREST_MIPMAP_LINEAR;
6327
6328 if ( p === THREE.LinearFilter ) return _gl.LINEAR;
6329 if ( p === THREE.LinearMipMapNearestFilter ) return _gl.LINEAR_MIPMAP_NEAREST;
6330 if ( p === THREE.LinearMipMapLinearFilter ) return _gl.LINEAR_MIPMAP_LINEAR;
6331
6332 if ( p === THREE.UnsignedByteType ) return _gl.UNSIGNED_BYTE;
6333 if ( p === THREE.UnsignedShort4444Type ) return _gl.UNSIGNED_SHORT_4_4_4_4;
6334 if ( p === THREE.UnsignedShort5551Type ) return _gl.UNSIGNED_SHORT_5_5_5_1;
6335 if ( p === THREE.UnsignedShort565Type ) return _gl.UNSIGNED_SHORT_5_6_5;
6336
6337 if ( p === THREE.ByteType ) return _gl.BYTE;
6338 if ( p === THREE.ShortType ) return _gl.SHORT;
6339 if ( p === THREE.UnsignedShortType ) return _gl.UNSIGNED_SHORT;
6340 if ( p === THREE.IntType ) return _gl.INT;
6341 if ( p === THREE.UnsignedIntType ) return _gl.UNSIGNED_INT;
6342 if ( p === THREE.FloatType ) return _gl.FLOAT;
6343
6344 if ( p === THREE.AlphaFormat ) return _gl.ALPHA;
6345 if ( p === THREE.RGBFormat ) return _gl.RGB;
6346 if ( p === THREE.RGBAFormat ) return _gl.RGBA;
6347 if ( p === THREE.LuminanceFormat ) return _gl.LUMINANCE;
6348 if ( p === THREE.LuminanceAlphaFormat ) return _gl.LUMINANCE_ALPHA;
6349
6350 if ( p === THREE.AddEquation ) return _gl.FUNC_ADD;
6351 if ( p === THREE.SubtractEquation ) return _gl.FUNC_SUBTRACT;
6352 if ( p === THREE.ReverseSubtractEquation ) return _gl.FUNC_REVERSE_SUBTRACT;
6353
6354 if ( p === THREE.ZeroFactor ) return _gl.ZERO;
6355 if ( p === THREE.OneFactor ) return _gl.ONE;
6356 if ( p === THREE.SrcColorFactor ) return _gl.SRC_COLOR;
6357 if ( p === THREE.OneMinusSrcColorFactor ) return _gl.ONE_MINUS_SRC_COLOR;
6358 if ( p === THREE.SrcAlphaFactor ) return _gl.SRC_ALPHA;
6359 if ( p === THREE.OneMinusSrcAlphaFactor ) return _gl.ONE_MINUS_SRC_ALPHA;
6360 if ( p === THREE.DstAlphaFactor ) return _gl.DST_ALPHA;
6361 if ( p === THREE.OneMinusDstAlphaFactor ) return _gl.ONE_MINUS_DST_ALPHA;
6362
6363 if ( p === THREE.DstColorFactor ) return _gl.DST_COLOR;
6364 if ( p === THREE.OneMinusDstColorFactor ) return _gl.ONE_MINUS_DST_COLOR;
6365 if ( p === THREE.SrcAlphaSaturateFactor ) return _gl.SRC_ALPHA_SATURATE;
6366
6367 if ( _glExtensionCompressedTextureS3TC !== undefined ) {
6368
6369 if ( p === THREE.RGB_S3TC_DXT1_Format ) return _glExtensionCompressedTextureS3TC.COMPRESSED_RGB_S3TC_DXT1_EXT;
6370 if ( p === THREE.RGBA_S3TC_DXT1_Format ) return _glExtensionCompressedTextureS3TC.COMPRESSED_RGBA_S3TC_DXT1_EXT;
6371 if ( p === THREE.RGBA_S3TC_DXT3_Format ) return _glExtensionCompressedTextureS3TC.COMPRESSED_RGBA_S3TC_DXT3_EXT;
6372 if ( p === THREE.RGBA_S3TC_DXT5_Format ) return _glExtensionCompressedTextureS3TC.COMPRESSED_RGBA_S3TC_DXT5_EXT;
6373
6374 }
6375
6376 return 0;
6377
6378 };
6379
6380 // Allocations
6381
6382 function allocateBones ( object ) {
6383
6384 if ( _supportsBoneTextures && object && object.useVertexTexture ) {
6385
6386 return 1024;
6387
6388 } else {
6389
6390 // default for when object is not specified
6391 // ( for example when prebuilding shader
6392 // to be used with multiple objects )
6393 //
6394 // - leave some extra space for other uniforms
6395 // - limit here is ANGLE's 254 max uniform vectors
6396 // (up to 54 should be safe)
6397
6398 var nVertexUniforms = _gl.getParameter( _gl.MAX_VERTEX_UNIFORM_VECTORS );
6399 var nVertexMatrices = Math.floor( ( nVertexUniforms - 20 ) / 4 );
6400
6401 var maxBones = nVertexMatrices;
6402
6403 if ( object !== undefined && object instanceof THREE.SkinnedMesh ) {
6404
6405 maxBones = Math.min( object.bones.length, maxBones );
6406
6407 if ( maxBones < object.bones.length ) {
6408
6409 console.warn( "WebGLRenderer: too many bones - " + object.bones.length + ", this GPU supports just " + maxBones + " (try OpenGL instead of ANGLE)" );
6410
6411 }
6412
6413 }
6414
6415 return maxBones;
6416
6417 }
6418
6419 };
6420
6421 function allocateLights( lights ) {
6422
6423 var dirLights = 0;
6424 var pointLights = 0;
6425 var spotLights = 0;
6426 var hemiLights = 0;
6427
6428 for ( var l = 0, ll = lights.length; l < ll; l ++ ) {
6429
6430 var light = lights[ l ];
6431
6432 if ( light.onlyShadow ) continue;
6433
6434 if ( light instanceof THREE.DirectionalLight ) dirLights ++;
6435 if ( light instanceof THREE.PointLight ) pointLights ++;
6436 if ( light instanceof THREE.SpotLight ) spotLights ++;
6437 if ( light instanceof THREE.HemisphereLight ) hemiLights ++;
6438
6439 }
6440
6441 return { 'directional' : dirLights, 'point' : pointLights, 'spot': spotLights, 'hemi': hemiLights };
6442
6443 };
6444
6445 function allocateShadows( lights ) {
6446
6447 var maxShadows = 0;
6448
6449 for ( var l = 0, ll = lights.length; l < ll; l++ ) {
6450
6451 var light = lights[ l ];
6452
6453 if ( ! light.castShadow ) continue;
6454
6455 if ( light instanceof THREE.SpotLight ) maxShadows ++;
6456 if ( light instanceof THREE.DirectionalLight && ! light.shadowCascade ) maxShadows ++;
6457
6458 }
6459
6460 return maxShadows;
6461
6462 };
6463
6464 // Initialization
6465
6466 function initGL() {
6467
6468 try {
6469
6470 var attributes = {
6471 alpha: _alpha,
6472 premultipliedAlpha: _premultipliedAlpha,
6473 antialias: _antialias,
6474 stencil: _stencil,
6475 preserveDrawingBuffer: _preserveDrawingBuffer
6476 };
6477
6478 _gl = _canvas.getContext( 'webgl', attributes ) || _canvas.getContext( 'experimental-webgl', attributes );
6479
6480 if ( _gl === null ) {
6481
6482 throw 'Error creating WebGL context.';
6483
6484 }
6485
6486 } catch ( error ) {
6487
6488 console.error( error );
6489
6490 }
6491
6492 _glExtensionTextureFloat = _gl.getExtension( 'OES_texture_float' );
6493 _glExtensionTextureFloatLinear = _gl.getExtension( 'OES_texture_float_linear' );
6494 _glExtensionStandardDerivatives = _gl.getExtension( 'OES_standard_derivatives' );
6495
6496 _glExtensionTextureFilterAnisotropic = _gl.getExtension( 'EXT_texture_filter_anisotropic' ) || _gl.getExtension( 'MOZ_EXT_texture_filter_anisotropic' ) || _gl.getExtension( 'WEBKIT_EXT_texture_filter_anisotropic' );
6497
6498 _glExtensionCompressedTextureS3TC = _gl.getExtension( 'WEBGL_compressed_texture_s3tc' ) || _gl.getExtension( 'MOZ_WEBGL_compressed_texture_s3tc' ) || _gl.getExtension( 'WEBKIT_WEBGL_compressed_texture_s3tc' );
6499
6500 if ( ! _glExtensionTextureFloat ) {
6501
6502 console.log( 'THREE.WebGLRenderer: Float textures not supported.' );
6503
6504 }
6505
6506 if ( ! _glExtensionStandardDerivatives ) {
6507
6508 console.log( 'THREE.WebGLRenderer: Standard derivatives not supported.' );
6509
6510 }
6511
6512 if ( ! _glExtensionTextureFilterAnisotropic ) {
6513
6514 console.log( 'THREE.WebGLRenderer: Anisotropic texture filtering not supported.' );
6515
6516 }
6517
6518 if ( ! _glExtensionCompressedTextureS3TC ) {
6519
6520 console.log( 'THREE.WebGLRenderer: S3TC compressed textures not supported.' );
6521
6522 }
6523
6524 if ( _gl.getShaderPrecisionFormat === undefined ) {
6525
6526 _gl.getShaderPrecisionFormat = function() {
6527
6528 return {
6529 "rangeMin" : 1,
6530 "rangeMax" : 1,
6531 "precision" : 1
6532 };
6533
6534 }
6535 }
6536
6537 };
6538
6539 function setDefaultGLState () {
6540
6541 _gl.clearColor( 0, 0, 0, 1 );
6542 _gl.clearDepth( 1 );
6543 _gl.clearStencil( 0 );
6544
6545 _gl.enable( _gl.DEPTH_TEST );
6546 _gl.depthFunc( _gl.LEQUAL );
6547
6548 _gl.frontFace( _gl.CCW );
6549 _gl.cullFace( _gl.BACK );
6550 _gl.enable( _gl.CULL_FACE );
6551
6552 _gl.enable( _gl.BLEND );
6553 _gl.blendEquation( _gl.FUNC_ADD );
6554 _gl.blendFunc( _gl.SRC_ALPHA, _gl.ONE_MINUS_SRC_ALPHA );
6555
6556 _gl.viewport( _viewportX, _viewportY, _viewportWidth, _viewportHeight );
6557
6558 _gl.clearColor( _clearColor.r, _clearColor.g, _clearColor.b, _clearAlpha );
6559
6560 };
6561
6562 // default plugins (order is important)
6563
6564 this.shadowMapPlugin = new THREE.ShadowMapPlugin();
6565 this.addPrePlugin( this.shadowMapPlugin );
6566
6567 this.addPostPlugin( new THREE.SpritePlugin() );
6568 this.addPostPlugin( new THREE.LensFlarePlugin() );
6569
6570};
Note: See TracBrowser for help on using the repository browser.