提交 c0e30b2c 编写于 作者: A alteredq

Made VBOs reusable.

The most tangible practical effect is that demos with multiple Lucys / Walts are now initialized much faster ;).

Reuse is achieved mostly by moving mesh chunks / VBOs (formerly called materialFaceGroups) from Mesh into Geometry.

This means sorting of geometry by face materials + breaking large geometries into chunks now has to be done after construction of geometry.

It becomes a step in the usual sequence:

    geometry.computeNormals();
    geometry.computeCentroids();
    geometry.sortFacesByMaterial();

If geometry is constructed programmatically (e.g. with GeometryUtils.merge), this has to be called afterwards.

Also of note: single geometry cannot be reused both for flat and smooth shading, as only one stream of normals is baked into VBO.
上级 d7ba66ea
此差异已折叠。
此差异已折叠。
此差异已折叠。
......@@ -95,6 +95,7 @@
GeometryUtils.merge( geometry, sphere );
}
geometry.sortFacesByMaterial();
var path = "textures/cube/pisa/";
var format = '.png';
......
......@@ -94,6 +94,7 @@
GeometryUtils.merge( geometry, sphere );
}
geometry.sortFacesByMaterial();
var path = "textures/cube/skybox/";
var format = '.jpg';
......
......@@ -66,10 +66,6 @@
}
// Spheres
var geometry1 = new Sphere( 70, 32, 16, true );
var generatedTexture = new THREE.Texture( generateTexture() );
generatedTexture.image.loaded = 1;
......@@ -89,13 +85,15 @@
materials.push( { material: new THREE.MeshBasicMaterial( { map: generatedTexture } ), overdraw: true, doubleSided: false } );
materials.push( { material: new THREE.MeshLambertMaterial( { map: generatedTexture } ), overdraw: true, doubleSided: false } );
// Extra mesh to be broken down for MeshFaceMaterial
var geometry2 = new Sphere( 70, 32, 16, true );
// Spheres geometry
var geometry_smooth = new Sphere( 70, 32, 16, true );
var geometry_flat = new Sphere( 70, 32, 16, false );
var geometry_pieces = new Sphere( 70, 32, 16, true ); // Extra geometry to be broken down for MeshFaceMaterial
for ( var i = 0, l = geometry2.faces.length; i < l; i ++ ) {
for ( var i = 0, l = geometry_pieces.faces.length; i < l; i ++ ) {
var face = geometry2.faces[ i ];
var face = geometry_pieces.faces[ i ];
if ( Math.random() > 0.7 ) face.material = [ materials[ Math.floor( Math.random() * materials.length ) ].material ];
}
......@@ -104,16 +102,19 @@
objects = [];
var sphere, geometry;
var sphere, geometry, material;
for ( var i = 0, l = materials.length; i < l; i ++ ) {
geometry = materials[ i ].material instanceof THREE.MeshFaceMaterial ? geometry2 : geometry1;
sphere = new THREE.Mesh( geometry, materials[ i ].material );
material = materials[ i ].material;
geometry = material instanceof THREE.MeshFaceMaterial ? geometry_pieces :
( material.shading == THREE.FlatShading ? geometry_flat : geometry_smooth );
sphere = new THREE.Mesh( geometry, material );
sphere.overdraw = materials[ i ].overdraw;
sphere.doubleSided = materials[ i ].doubleSided;
sphere.overdraw = material.overdraw;
sphere.doubleSided = material.doubleSided;
sphere.position.x = ( i % 4 ) * 200 - 400;
sphere.position.z = Math.floor( i / 4 ) * 200 - 200;
......
......@@ -92,7 +92,8 @@
GeometryUtils.merge( geometry, sphere );
}
geometry.sortFacesByMaterial();
var path = "textures/cube/Park2/";
var format = '.jpg';
var urls = [
......
......@@ -20,6 +20,10 @@ var Bird = function () {
f3( 4, 7, 6 );
f3( 5, 6, 7 );
this.computeCentroids();
this.computeNormals();
this.sortFacesByMaterial();
function v( x, y, z ) {
scope.vertices.push( new THREE.Vertex( new THREE.Vector3( x, y, z ) ) );
......
......@@ -1435,6 +1435,7 @@ var Qrcode = function () {
this.computeCentroids();
this.computeNormals();
this.sortFacesByMaterial();
function v( x, y, z ) {
......
......@@ -4885,6 +4885,7 @@ var WaltHead = function () {
this.computeCentroids();
this.computeNormals();
this.sortFacesByMaterial();
function v( x, y, z ) {
......
......@@ -175,6 +175,7 @@
geometry.computeNormals();
geometry.computeCentroids();
geometry.sortFacesByMaterial();
mesh = new THREE.Mesh( geometry, [ new THREE.MeshFaceMaterial(), new THREE.MeshBasicMaterial( { color: 0xff0000, opacity: 0.5, wireframe: true, wireframe_linewidth: 10 } ) ] );
mesh.doubleSided = true;
......
/**
* @author mr.doob / http://mrdoob.com/
* @author kile / http://kile.stravaganza.org/
* @author alteredq / http://alteredqualia.com/
*/
THREE.Geometry = function () {
......@@ -9,6 +10,8 @@ THREE.Geometry = function () {
this.faces = [];
this.uvs = [];
this.geometryChunks = {};
};
THREE.Geometry.prototype = {
......@@ -89,7 +92,7 @@ THREE.Geometry.prototype = {
if ( !cb.isZero() ) {
cb.normalize();
cb.normalize();
}
......@@ -149,6 +152,80 @@ THREE.Geometry.prototype = {
},
sortFacesByMaterial: function () {
// TODO
// Should optimize by grouping faces with ColorFill / ColorStroke materials
// which could then use vertex color attributes instead of each being
// in its separate VBO
var i, l, f, fl, face, material, vertices, mhash, ghash, hash_map = {};
function materialHash( material ) {
var hash_array = [];
for ( i = 0, l = material.length; i < l; i++ ) {
if ( material[ i ] == undefined ) {
hash_array.push( "undefined" );
} else {
hash_array.push( material[ i ].toString() );
}
}
return hash_array.join( '_' );
}
for ( f = 0, fl = this.faces.length; f < fl; f++ ) {
face = this.faces[ f ];
material = face.material;
mhash = materialHash( material );
if ( hash_map[ mhash ] == undefined ) {
hash_map[ mhash ] = { 'hash': mhash, 'counter': 0 };
}
ghash = hash_map[ mhash ].hash + '_' + hash_map[ mhash ].counter;
if ( this.geometryChunks[ ghash ] == undefined ) {
this.geometryChunks[ ghash ] = { 'faces': [], 'material': material, 'vertices': 0 };
}
vertices = face instanceof THREE.Face3 ? 3 : 4;
if ( this.geometryChunks[ ghash ].vertices + vertices > 65535 ) {
hash_map[ mhash ].counter += 1;
ghash = hash_map[ mhash ].hash + '_' + hash_map[ mhash ].counter;
if ( this.geometryChunks[ ghash ] == undefined ) {
this.geometryChunks[ ghash ] = { 'faces': [], 'material': material, 'vertices': 0 };
}
}
this.geometryChunks[ ghash ].faces.push( f );
this.geometryChunks[ ghash ].vertices += vertices;
}
},
toString: function () {
return 'THREE.Geometry ( vertices: ' + this.vertices + ', faces: ' + this.faces + ' )';
......
......@@ -245,6 +245,7 @@ THREE.Loader.prototype = {
this.computeCentroids();
this.computeNormals();
this.sortFacesByMaterial();
//var e = (new Date).getTime();
......@@ -706,6 +707,7 @@ THREE.Loader.prototype = {
this.computeCentroids();
this.computeNormals();
this.sortFacesByMaterial();
function init_vertices() {
......
......@@ -158,6 +158,7 @@ var Cube = function ( width, height, depth, segments_width, segments_height, mat
this.computeCentroids();
this.computeNormals();
this.sortFacesByMaterial();
}
......
......@@ -67,6 +67,7 @@ var Cylinder = function (numSegs, topRad, botRad, height, topOffset, botOffset)
this.computeCentroids();
this.computeNormals();
this.sortFacesByMaterial();
function v(x, y, z) {
......
......@@ -54,6 +54,7 @@ var Plane = function ( width, height, segments_width, segments_height ) {
this.computeCentroids();
this.computeNormals();
this.sortFacesByMaterial();
}
......
......@@ -105,6 +105,8 @@ var Sphere = function ( radius, segments_width, segments_height ) {
this.computeCentroids();
this.computeNormals();
this.sortFacesByMaterial();
}
Sphere.prototype = new THREE.Geometry();
......
/**
* @author mr.doob / http://mrdoob.com/
* @author alteredq / http://alteredqualia.com/
*/
THREE.Mesh = function ( geometry, material, normUVs ) {
......@@ -14,8 +15,6 @@ THREE.Mesh = function ( geometry, material, normUVs ) {
this.overdraw = false;
this.materialFaceGroup = {};
this.sortFacesByMaterial();
if ( normUVs ) this.normalizeUVs();
this.geometry.computeBoundingBox();
......@@ -25,81 +24,6 @@ THREE.Mesh = function ( geometry, material, normUVs ) {
THREE.Mesh.prototype = new THREE.Object3D();
THREE.Mesh.prototype.constructor = THREE.Mesh;
THREE.Mesh.prototype.sortFacesByMaterial = function () {
// TODO
// Should optimize by grouping faces with ColorFill / ColorStroke materials
// which could then use vertex color attributes instead of each being
// in its separate VBO
var i, l, f, fl, face, material, vertices, mhash, ghash, hash_map = {};
function materialHash( material ) {
var hash_array = [];
for ( i = 0, l = material.length; i < l; i++ ) {
if ( material[ i ] == undefined ) {
hash_array.push( "undefined" );
} else {
hash_array.push( material[ i ].toString() );
}
}
return hash_array.join( '_' );
}
for ( f = 0, fl = this.geometry.faces.length; f < fl; f++ ) {
face = this.geometry.faces[ f ];
material = face.material;
mhash = materialHash( material );
if ( hash_map[ mhash ] == undefined ) {
hash_map[ mhash ] = { 'hash': mhash, 'counter': 0 };
}
ghash = hash_map[ mhash ].hash + '_' + hash_map[ mhash ].counter;
if ( this.materialFaceGroup[ ghash ] == undefined ) {
this.materialFaceGroup[ ghash ] = { 'faces': [], 'material': material, 'vertices': 0 };
}
vertices = face instanceof THREE.Face3 ? 3 : 4;
if ( this.materialFaceGroup[ ghash ].vertices + vertices > 65535 ) {
hash_map[ mhash ].counter += 1;
ghash = hash_map[ mhash ].hash + '_' + hash_map[ mhash ].counter;
if ( this.materialFaceGroup[ ghash ] == undefined ) {
this.materialFaceGroup[ ghash ] = { 'faces': [], 'material': material, 'vertices': 0 };
}
}
this.materialFaceGroup[ ghash ].faces.push( f );
this.materialFaceGroup[ ghash ].vertices += vertices;
}
};
THREE.Mesh.prototype.normalizeUVs = function () {
var i, il, j, jl, uvs;
......
......@@ -4,6 +4,8 @@
THREE.Object3D = function ( material ) {
this.id = THREE.Object3DCounter.value ++;
this.position = new THREE.Vector3();
this.rotation = new THREE.Vector3();
this.scale = new THREE.Vector3( 1, 1, 1 );
......@@ -35,3 +37,5 @@ THREE.Object3D = function ( material ) {
};
};
THREE.Object3DCounter = { value: 0 };
......@@ -155,7 +155,7 @@ THREE.WebGLRenderer = function ( scene ) {
};
this.createBuffers = function ( object, mf ) {
this.createBuffers = function ( object, g ) {
var f, fl, fi, face, vertexNormals, normal, uv, v1, v2, v3, v4, m, ml, i,
......@@ -168,13 +168,13 @@ THREE.WebGLRenderer = function ( scene ) {
vertexIndex = 0,
materialFaceGroup = object.materialFaceGroup[ mf ],
geometryChunk = object.geometry.geometryChunks[ g ],
needsSmoothNormals = bufferNeedsSmoothNormals ( materialFaceGroup, object );
needsSmoothNormals = bufferNeedsSmoothNormals ( geometryChunk, object );
for ( f = 0, fl = materialFaceGroup.faces.length; f < fl; f++ ) {
for ( f = 0, fl = geometryChunk.faces.length; f < fl; f++ ) {
fi = materialFaceGroup.faces[f];
fi = geometryChunk.faces[ f ];
face = object.geometry.faces[ fi ];
vertexNormals = face.vertexNormals;
......@@ -283,6 +283,7 @@ THREE.WebGLRenderer = function ( scene ) {
vertexIndex += 4;
}
}
if ( !vertexArray.length ) {
......@@ -291,32 +292,32 @@ THREE.WebGLRenderer = function ( scene ) {
}
materialFaceGroup.__webGLVertexBuffer = _gl.createBuffer();
_gl.bindBuffer( _gl.ARRAY_BUFFER, materialFaceGroup.__webGLVertexBuffer );
geometryChunk.__webGLVertexBuffer = _gl.createBuffer();
_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryChunk.__webGLVertexBuffer );
_gl.bufferData( _gl.ARRAY_BUFFER, new Float32Array( vertexArray ), _gl.STATIC_DRAW );
materialFaceGroup.__webGLNormalBuffer = _gl.createBuffer();
_gl.bindBuffer( _gl.ARRAY_BUFFER, materialFaceGroup.__webGLNormalBuffer );
geometryChunk.__webGLNormalBuffer = _gl.createBuffer();
_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryChunk.__webGLNormalBuffer );
_gl.bufferData( _gl.ARRAY_BUFFER, new Float32Array( normalArray ), _gl.STATIC_DRAW );
materialFaceGroup.__webGLUVBuffer = _gl.createBuffer();
_gl.bindBuffer( _gl.ARRAY_BUFFER, materialFaceGroup.__webGLUVBuffer );
geometryChunk.__webGLUVBuffer = _gl.createBuffer();
_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryChunk.__webGLUVBuffer );
_gl.bufferData( _gl.ARRAY_BUFFER, new Float32Array( uvArray ), _gl.STATIC_DRAW );
materialFaceGroup.__webGLFaceBuffer = _gl.createBuffer();
_gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, materialFaceGroup.__webGLFaceBuffer );
geometryChunk.__webGLFaceBuffer = _gl.createBuffer();
_gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, geometryChunk.__webGLFaceBuffer );
_gl.bufferData( _gl.ELEMENT_ARRAY_BUFFER, new Uint16Array( faceArray ), _gl.STATIC_DRAW );
materialFaceGroup.__webGLLineBuffer = _gl.createBuffer();
_gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, materialFaceGroup.__webGLLineBuffer );
geometryChunk.__webGLLineBuffer = _gl.createBuffer();
_gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, geometryChunk.__webGLLineBuffer );
_gl.bufferData( _gl.ELEMENT_ARRAY_BUFFER, new Uint16Array( lineArray ), _gl.STATIC_DRAW );
materialFaceGroup.__webGLFaceCount = faceArray.length;
materialFaceGroup.__webGLLineCount = lineArray.length;
geometryChunk.__webGLFaceCount = faceArray.length;
geometryChunk.__webGLLineCount = lineArray.length;
};
this.renderBuffer = function ( camera, material, materialFaceGroup ) {
this.renderBuffer = function ( camera, material, geometryChunk ) {
var mColor, mOpacity, mReflectivity,
mWireframe, mLineWidth, mBlending,
......@@ -356,6 +357,9 @@ THREE.WebGLRenderer = function ( scene ) {
if ( material instanceof THREE.MeshShaderMaterial ) {
mWireframe = material.wireframe;
mLineWidth = material.wireframe_linewidth;
setUniforms( program, material.uniforms );
this.loadCamera( program, camera );
this.loadMatrices( program );
......@@ -471,19 +475,19 @@ THREE.WebGLRenderer = function ( scene ) {
// vertices
_gl.bindBuffer( _gl.ARRAY_BUFFER, materialFaceGroup.__webGLVertexBuffer );
_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryChunk.__webGLVertexBuffer );
_gl.vertexAttribPointer( program.position, 3, _gl.FLOAT, false, 0, 0 );
// normals
_gl.bindBuffer( _gl.ARRAY_BUFFER, materialFaceGroup.__webGLNormalBuffer );
_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryChunk.__webGLNormalBuffer );
_gl.vertexAttribPointer( program.normal, 3, _gl.FLOAT, false, 0, 0 );
// uvs
if ( mMap ) {
_gl.bindBuffer( _gl.ARRAY_BUFFER, materialFaceGroup.__webGLUVBuffer );
_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryChunk.__webGLUVBuffer );
_gl.enableVertexAttribArray( program.uv );
_gl.vertexAttribPointer( program.uv, 2, _gl.FLOAT, false, 0, 0 );
......@@ -498,22 +502,22 @@ THREE.WebGLRenderer = function ( scene ) {
if ( ! mWireframe ) {
_gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, materialFaceGroup.__webGLFaceBuffer );
_gl.drawElements( _gl.TRIANGLES, materialFaceGroup.__webGLFaceCount, _gl.UNSIGNED_SHORT, 0 );
_gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, geometryChunk.__webGLFaceBuffer );
_gl.drawElements( _gl.TRIANGLES, geometryChunk.__webGLFaceCount, _gl.UNSIGNED_SHORT, 0 );
// render lines
} else {
_gl.lineWidth( mLineWidth );
_gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, materialFaceGroup.__webGLLineBuffer );
_gl.drawElements( _gl.LINES, materialFaceGroup.__webGLLineCount, _gl.UNSIGNED_SHORT, 0 );
_gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, geometryChunk.__webGLLineBuffer );
_gl.drawElements( _gl.LINES, geometryChunk.__webGLLineCount, _gl.UNSIGNED_SHORT, 0 );
}
};
this.renderPass = function ( camera, object, materialFaceGroup, blending, transparent ) {
this.renderPass = function ( camera, object, geometryChunk, blending, transparent ) {
var i, l, m, ml, material, meshMaterial;
......@@ -523,13 +527,13 @@ THREE.WebGLRenderer = function ( scene ) {
if ( meshMaterial instanceof THREE.MeshFaceMaterial ) {
for ( i = 0, l = materialFaceGroup.material.length; i < l; i++ ) {
for ( i = 0, l = geometryChunk.material.length; i < l; i++ ) {
material = materialFaceGroup.material[ i ];
material = geometryChunk.material[ i ];
if ( material && material.blending == blending && ( material.opacity < 1.0 == transparent ) ) {
this.setBlending( material.blending );
this.renderBuffer( camera, material, materialFaceGroup );
this.renderBuffer( camera, material, geometryChunk );
}
......@@ -541,7 +545,7 @@ THREE.WebGLRenderer = function ( scene ) {
if ( material && material.blending == blending && ( material.opacity < 1.0 == transparent ) ) {
this.setBlending( material.blending );
this.renderBuffer( camera, material, materialFaceGroup );
this.renderBuffer( camera, material, geometryChunk );
}
......@@ -553,7 +557,7 @@ THREE.WebGLRenderer = function ( scene ) {
this.render = function( scene, camera ) {
var o, ol;
var o, ol, webGLObject, object, buffer;
this.initWebGLObjects( scene );
......@@ -574,11 +578,14 @@ THREE.WebGLRenderer = function ( scene ) {
webGLObject = scene.__webGLObjects[ o ];
if ( webGLObject.__object.visible ) {
object = webGLObject.object;
buffer = webGLObject.buffer;
if ( object.visible ) {
this.setupMatrices( webGLObject.__object, camera );
this.setupMatrices( object, camera );
this.loadMatrices( _program );
this.renderPass( camera, webGLObject.__object, webGLObject, THREE.NormalBlending, false );
this.renderPass( camera, object, buffer, THREE.NormalBlending, false );
}
......@@ -590,24 +597,27 @@ THREE.WebGLRenderer = function ( scene ) {
webGLObject = scene.__webGLObjects[ o ];
if ( webGLObject.__object.visible ) {
object = webGLObject.object;
buffer = webGLObject.buffer;
if ( object.visible ) {
this.setupMatrices( webGLObject.__object, camera );
this.setupMatrices( object, camera );
this.loadMatrices( _program );
// opaque blended materials
this.renderPass( camera, webGLObject.__object, webGLObject, THREE.AdditiveBlending, false );
this.renderPass( camera, webGLObject.__object, webGLObject, THREE.SubtractiveBlending, false );
this.renderPass( camera, object, buffer, THREE.AdditiveBlending, false );
this.renderPass( camera, object, buffer, THREE.SubtractiveBlending, false );
// transparent blended materials
this.renderPass( camera, webGLObject.__object, webGLObject, THREE.AdditiveBlending, true );
this.renderPass( camera, webGLObject.__object, webGLObject, THREE.SubtractiveBlending, true );
this.renderPass( camera, object, buffer, THREE.AdditiveBlending, true );
this.renderPass( camera, object, buffer, THREE.SubtractiveBlending, true );
// transparent normal materials
this.renderPass( camera, webGLObject.__object, webGLObject, THREE.NormalBlending, true );
this.renderPass( camera, object, buffer, THREE.NormalBlending, true );
}
......@@ -617,11 +627,12 @@ THREE.WebGLRenderer = function ( scene ) {
this.initWebGLObjects = function( scene ) {
var o, ol, object, mf, materialFaceGroup;
var o, ol, object, globject, g, geometryChunk, objmap;
if ( !scene.__webGLObjects ) {
scene.__webGLObjects = [];
scene.__webGLObjectsMap = {};
}
......@@ -629,23 +640,40 @@ THREE.WebGLRenderer = function ( scene ) {
object = scene.objects[ o ];
if ( scene.__webGLObjectsMap[ object.id ] == undefined ) {
scene.__webGLObjectsMap[ object.id ] = {};
}
objmap = scene.__webGLObjectsMap[ object.id ];
if ( object instanceof THREE.Mesh ) {
// create separate VBOs per material
// create separate VBOs per geometry chunk
for ( mf in object.materialFaceGroup ) {
for ( g in object.geometry.geometryChunks ) {
materialFaceGroup = object.materialFaceGroup[ mf ];
geometryChunk = object.geometry.geometryChunks[ g ];
// initialise buffers on the first access
// initialise VBO on the first access
if( ! materialFaceGroup.__webGLVertexBuffer ) {
if( ! geometryChunk.__webGLVertexBuffer ) {
this.createBuffers( object, mf );
materialFaceGroup.__object = object;
scene.__webGLObjects.push( materialFaceGroup );
this.createBuffers( object, g );
}
// create separate wrapper per each use of VBO
if ( objmap[ g ] == undefined ) {
globject = { buffer: geometryChunk, object: object };
scene.__webGLObjects.push( globject );
objmap[ g ] = 1;
}
}
......@@ -665,7 +693,7 @@ THREE.WebGLRenderer = function ( scene ) {
for ( o = scene.__webGLObjects.length - 1; o >= 0; o-- ) {
zobject = scene.__webGLObjects[ o ].__object;
zobject = scene.__webGLObjects[ o ].object;
if ( object == zobject ) {
......@@ -1296,7 +1324,7 @@ THREE.WebGLRenderer = function ( scene ) {
function initUbershader( maxDirLights, maxPointLights ) {
var vertex_shader = generateVertexShader( maxDirLights, maxPointLights ),
fragment_shader = generateFragmentShader( maxDirLights, maxPointLights );
fragment_shader = generateFragmentShader( maxDirLights, maxPointLights );
//log ( vertex_shader );
//log ( fragment_shader );
......@@ -1401,7 +1429,7 @@ THREE.WebGLRenderer = function ( scene ) {
};
function bufferNeedsSmoothNormals( materialFaceGroup, object ) {
function bufferNeedsSmoothNormals( geometryChunk, object ) {
var m, ml, i, l, needsSmoothNormals = false;
......@@ -1411,9 +1439,9 @@ THREE.WebGLRenderer = function ( scene ) {
if ( meshMaterial instanceof THREE.MeshFaceMaterial ) {
for ( i = 0, l = materialFaceGroup.material.length; i < l; i++ ) {
for ( i = 0, l = geometryChunk.material.length; i < l; i++ ) {
if ( materialNeedsSmoothNormals( materialFaceGroup.material[ i ] ) ) {
if ( materialNeedsSmoothNormals( geometryChunk.material[ i ] ) ) {
needsSmoothNormals = true;
break;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册