From 330ab778365180eb3f6c9a044068c5cf0214aaf8 Mon Sep 17 00:00:00 2001 From: "Mr.doob" Date: Sun, 16 Oct 2011 11:36:09 +0200 Subject: [PATCH] WIP WebGLRenderer refactoring --- examples/js/Stats.js | 16 +-- src/core/Projector.js | 105 +++++++++------ src/renderers/WebGLRenderer.js | 237 ++++++++++++++++----------------- 3 files changed, 188 insertions(+), 170 deletions(-) diff --git a/examples/js/Stats.js b/examples/js/Stats.js index 356b7ab5..6cdeeb36 100644 --- a/examples/js/Stats.js +++ b/examples/js/Stats.js @@ -1,10 +1,8 @@ -// stats.js r7 - http://github.com/mrdoob/stats.js -var Stats=function(){function s(a,g,d){var f,c,e;for(c=0;c<30;c++)for(f=0;f<73;f++)e=(f+c*74)*4,a[e]=a[e+4],a[e+1]=a[e+5],a[e+2]=a[e+6];for(c=0;c<30;c++)e=(73+c*74)*4,c'+n+" MS ("+z+"-"+A+")";o.putImageData(B,0,0);F=j;if(j>v+1E3){l= -Math.round(u*1E3/(j-v));w=Math.min(w,l);x=Math.max(x,l);s(y.data,Math.min(30,30-l/100*30),"fps");d.innerHTML=''+l+" FPS ("+w+"-"+x+")";m.putImageData(y,0,0);if(t==3)p=performance.memory.usedJSHeapSize*9.54E-7,C=Math.min(C,p),D=Math.max(D,p),s(E.data,Math.min(30,30-p/2),"mb"),i.innerHTML=''+Math.round(p)+" MB ("+Math.round(C)+"-"+Math.round(D)+")",q.putImageData(E,0,0);v=j;u=0}}}}; +// stats.js r8 - http://github.com/mrdoob/stats.js +var Stats=function(){var h,a,n=0,o=0,i=Date.now(),u=i,p=i,l=0,q=1E3,r=0,e,j,f,b=[[16,16,48],[0,255,255]],m=0,s=1E3,t=0,d,k,g,c=[[16,48,16],[0,255,0]];h=document.createElement("div");h.style.cursor="pointer";h.style.width="80px";h.style.opacity="0.9";h.style.zIndex="10001";h.addEventListener("mousedown",function(a){a.preventDefault();n=(n+1)%2;n==0?(e.style.display="block",d.style.display="none"):(e.style.display="none",d.style.display="block")},!1);e=document.createElement("div");e.style.textAlign= +"left";e.style.lineHeight="1.2em";e.style.backgroundColor="rgb("+Math.floor(b[0][0]/2)+","+Math.floor(b[0][1]/2)+","+Math.floor(b[0][2]/2)+")";e.style.padding="0 0 3px 3px";h.appendChild(e);j=document.createElement("div");j.style.fontFamily="Helvetica, Arial, sans-serif";j.style.fontSize="9px";j.style.color="rgb("+b[1][0]+","+b[1][1]+","+b[1][2]+")";j.style.fontWeight="bold";j.innerHTML="FPS";e.appendChild(j);f=document.createElement("div");f.style.position="relative";f.style.width="74px";f.style.height= +"30px";f.style.backgroundColor="rgb("+b[1][0]+","+b[1][1]+","+b[1][2]+")";for(e.appendChild(f);f.children.length<74;)a=document.createElement("span"),a.style.width="1px",a.style.height="30px",a.style.cssFloat="left",a.style.backgroundColor="rgb("+b[0][0]+","+b[0][1]+","+b[0][2]+")",f.appendChild(a);d=document.createElement("div");d.style.textAlign="left";d.style.lineHeight="1.2em";d.style.backgroundColor="rgb("+Math.floor(c[0][0]/2)+","+Math.floor(c[0][1]/2)+","+Math.floor(c[0][2]/2)+")";d.style.padding= +"0 0 3px 3px";d.style.display="none";h.appendChild(d);k=document.createElement("div");k.style.fontFamily="Helvetica, Arial, sans-serif";k.style.fontSize="9px";k.style.color="rgb("+c[1][0]+","+c[1][1]+","+c[1][2]+")";k.style.fontWeight="bold";k.innerHTML="MS";d.appendChild(k);g=document.createElement("div");g.style.position="relative";g.style.width="74px";g.style.height="30px";g.style.backgroundColor="rgb("+c[1][0]+","+c[1][1]+","+c[1][2]+")";for(d.appendChild(g);g.children.length<74;)a=document.createElement("span"), +a.style.width="1px",a.style.height=Math.random()*30+"px",a.style.cssFloat="left",a.style.backgroundColor="rgb("+c[0][0]+","+c[0][1]+","+c[0][2]+")",g.appendChild(a);return{domElement:h,update:function(){i=Date.now();m=i-u;s=Math.min(s,m);t=Math.max(t,m);k.textContent=m+" MS ("+s+"-"+t+")";var a=Math.min(30,30-m/200*30);g.appendChild(g.firstChild).style.height=a+"px";u=i;o++;if(i>p+1E3)l=Math.round(o*1E3/(i-p)),q=Math.min(q,l),r=Math.max(r,l),j.textContent=l+" FPS ("+q+"-"+r+")",a=Math.min(30,30-l/ +100*30),f.appendChild(f.firstChild).style.height=a+"px",p=i,o=0}}}; diff --git a/src/core/Projector.js b/src/core/Projector.js index ed9d8ac6..c2c927da 100644 --- a/src/core/Projector.js +++ b/src/core/Projector.js @@ -11,13 +11,13 @@ THREE.Projector = function() { _line, _lineCount, _linePool = [], _particle, _particleCount, _particlePool = [], - _renderData = { objects: [], lights: [], elements: [] }, + _renderData = { objects: [], lines: [], sprites: [], lights: [], elements: [] }, _vector3 = new THREE.Vector3(), _vector4 = new THREE.Vector4(), _projScreenMatrix = new THREE.Matrix4(), - _projScreenObjectMatrix = new THREE.Matrix4(), + _projScreenobjectMatrixWorld = new THREE.Matrix4(), _frustum = [ new THREE.Vector4(), @@ -33,6 +33,23 @@ THREE.Projector = function() { _face3VertexNormals; + this.computeFrustum = function ( m ) { + + _frustum[ 0 ].set( m.n41 - m.n11, m.n42 - m.n12, m.n43 - m.n13, m.n44 - m.n14 ); + _frustum[ 1 ].set( m.n41 + m.n11, m.n42 + m.n12, m.n43 + m.n13, m.n44 + m.n14 ); + _frustum[ 2 ].set( m.n41 + m.n21, m.n42 + m.n22, m.n43 + m.n23, m.n44 + m.n24 ); + _frustum[ 3 ].set( m.n41 - m.n21, m.n42 - m.n22, m.n43 - m.n23, m.n44 - m.n24 ); + _frustum[ 4 ].set( m.n41 - m.n31, m.n42 - m.n32, m.n43 - m.n33, m.n44 - m.n34 ); + _frustum[ 5 ].set( m.n41 + m.n31, m.n42 + m.n32, m.n43 + m.n33, m.n44 + m.n34 ); + + for ( var i = 0; i < 6; i ++ ) { + + var plane = _frustum[ i ]; + plane.divideScalar( Math.sqrt( plane.x * plane.x + plane.y * plane.y + plane.z * plane.z ) ); + + } + + } this.projectVector = function ( vector, camera ) { @@ -83,17 +100,26 @@ THREE.Projector = function() { this.projectGraph = function ( object ) { _renderData.objects.length = 0; + _renderData.lines.length = 0; + _renderData.sprites.length = 0; _renderData.lights.length = 0; var projectObject = function ( object ) { if ( object.visible == false ) return; - if ( object instanceof THREE.Particle || object instanceof THREE.Line || - ( object instanceof THREE.Mesh && ( !object.frustumCulled || isInFrustum( object ) ) ) ) { + if ( ( object instanceof THREE.Mesh ) && ( object.frustumCulled == false || isInFrustum( object ) ) ) { _renderData.objects.push( object ); + } else if ( object instanceof THREE.Line ) { + + _renderData.lines.push( object ); + + } else if ( object instanceof THREE.Sprite || object instanceof THREE.Particle ) { + + _renderData.sprites.push( object ); + } else if ( object instanceof THREE.Light ) { _renderData.lights.push( object ); @@ -118,7 +144,7 @@ THREE.Projector = function() { var near = camera.near, far = camera.far, o, ol, v, vl, f, fl, n, nl, c, cl, u, ul, object, - objectMatrix, objectMatrixRotation, objectMaterials, objectOverdraw, + objectMatrixWorld, objectMatrixWorldRotation, objectMaterials, objectOverdraw, geometry, vertices, vertex, vertexPositionScreen, faces, face, faceVertexNormals, normal, faceVertexUvs, uvs, v1, v2, v3, v4; @@ -143,7 +169,7 @@ THREE.Projector = function() { _projScreenMatrix.multiply( camera.projectionMatrix, camera.matrixWorldInverse ); - computeFrustum( _projScreenMatrix ); + this.computeFrustum( _projScreenMatrix ); _renderData = this.projectGraph( scene ); @@ -151,8 +177,7 @@ THREE.Projector = function() { object = _renderData.objects[ o ]; - objectMatrix = object.matrixWorld; - + objectMatrixWorld = object.matrixWorld; objectMaterials = object.materials; objectOverdraw = object.overdraw; @@ -165,14 +190,14 @@ THREE.Projector = function() { faces = geometry.faces; faceVertexUvs = geometry.faceVertexUvs; - objectMatrixRotation = object.matrixRotationWorld.extractRotation( object.matrixWorld ); + objectMatrixWorldRotation = object.matrixRotationWorld.extractRotation( objectMatrixWorld ); for ( v = 0, vl = vertices.length; v < vl; v ++ ) { _vertex = getNextVertexInPool(); _vertex.positionWorld.copy( vertices[ v ].position ); - objectMatrix.multiplyVector3( _vertex.positionWorld ); + objectMatrixWorld.multiplyVector3( _vertex.positionWorld ); _vertex.positionScreen.copy( _vertex.positionWorld ); _projScreenMatrix.multiplyVector4( _vertex.positionScreen ); @@ -241,10 +266,10 @@ THREE.Projector = function() { } _face.normalWorld.copy( face.normal ); - objectMatrixRotation.multiplyVector3( _face.normalWorld ); + objectMatrixWorldRotation.multiplyVector3( _face.normalWorld ); _face.centroidWorld.copy( face.centroid ); - objectMatrix.multiplyVector3( _face.centroidWorld ); + objectMatrixWorld.multiplyVector3( _face.centroidWorld ); _face.centroidScreen.copy( _face.centroidWorld ); _projScreenMatrix.multiplyVector3( _face.centroidScreen ); @@ -255,7 +280,7 @@ THREE.Projector = function() { normal = _face.vertexNormalsWorld[ n ]; normal.copy( faceVertexNormals[ n ] ); - objectMatrixRotation.multiplyVector3( normal ); + objectMatrixWorldRotation.multiplyVector3( normal ); } @@ -283,21 +308,34 @@ THREE.Projector = function() { } - } else if ( object instanceof THREE.Line ) { + } - _projScreenObjectMatrix.multiply( _projScreenMatrix, objectMatrix ); + } + + for ( o = 0, ol = _renderData.lines.length; o < ol; o++ ) { + + object = _renderData.lines[ o ]; + + objectMatrixWorld = object.matrixWorld; + objectMaterials = object.materials; + + _vertexCount = 0; + + if ( object instanceof THREE.Line ) { + + _projScreenobjectMatrixWorld.multiply( _projScreenMatrix, objectMatrixWorld ); vertices = object.geometry.vertices; v1 = getNextVertexInPool(); v1.positionScreen.copy( vertices[ 0 ].position ); - _projScreenObjectMatrix.multiplyVector4( v1.positionScreen ); + _projScreenobjectMatrixWorld.multiplyVector4( v1.positionScreen ); for ( v = 1, vl = vertices.length; v < vl; v++ ) { v1 = getNextVertexInPool(); v1.positionScreen.copy( vertices[ v ].position ); - _projScreenObjectMatrix.multiplyVector4( v1.positionScreen ); + _projScreenobjectMatrixWorld.multiplyVector4( v1.positionScreen ); v2 = _vertexPool[ _vertexCount - 2 ]; @@ -316,16 +354,25 @@ THREE.Projector = function() { _line.z = Math.max( _clippedVertex1PositionScreen.z, _clippedVertex2PositionScreen.z ); - _line.materials = object.materials; + _line.materials = objectMaterials; _renderData.elements.push( _line ); } } - } else if ( object instanceof THREE.Particle ) { + } + } - _vector4.set( object.matrixWorld.n14, object.matrixWorld.n24, object.matrixWorld.n34, 1 ); + for ( o = 0, ol = _renderData.sprites.length; o < ol; o++ ) { + + object = _renderData.sprites[ o ]; + + objectMatrixWorld = object.matrixWorld; + + if ( object instanceof THREE.Particle ) { + + _vector4.set( objectMatrixWorld.n14, objectMatrixWorld.n24, objectMatrixWorld.n34, 1 ); _projScreenMatrix.multiplyVector4( _vector4 ); _vector4.z /= _vector4.w; @@ -416,24 +463,6 @@ THREE.Projector = function() { } - function computeFrustum( m ) { - - _frustum[ 0 ].set( m.n41 - m.n11, m.n42 - m.n12, m.n43 - m.n13, m.n44 - m.n14 ); - _frustum[ 1 ].set( m.n41 + m.n11, m.n42 + m.n12, m.n43 + m.n13, m.n44 + m.n14 ); - _frustum[ 2 ].set( m.n41 + m.n21, m.n42 + m.n22, m.n43 + m.n23, m.n44 + m.n24 ); - _frustum[ 3 ].set( m.n41 - m.n21, m.n42 - m.n22, m.n43 - m.n23, m.n44 - m.n24 ); - _frustum[ 4 ].set( m.n41 - m.n31, m.n42 - m.n32, m.n43 - m.n33, m.n44 - m.n34 ); - _frustum[ 5 ].set( m.n41 + m.n31, m.n42 + m.n32, m.n43 + m.n33, m.n44 + m.n34 ); - - for ( var i = 0; i < 6; i ++ ) { - - var plane = _frustum[ i ]; - plane.divideScalar( Math.sqrt( plane.x * plane.x + plane.y * plane.y + plane.z * plane.z ) ); - - } - - } - function isInFrustum( object ) { var distance, matrix = object.matrixWorld, diff --git a/src/renderers/WebGLRenderer.js b/src/renderers/WebGLRenderer.js index 05596ad7..1820a6fe 100644 --- a/src/renderers/WebGLRenderer.js +++ b/src/renderers/WebGLRenderer.js @@ -19,6 +19,10 @@ THREE.WebGLRenderer = function ( parameters ) { _currentGeometryGroupHash = null, _geometryGroupCounter = 0, + _object, _objects = [], + _renderData, _projector = new THREE.Projector(), + _vertexBuffers = [], _textureBuffers = [], + // gl state cache _oldDoubleSided = null, @@ -177,7 +181,7 @@ THREE.WebGLRenderer = function ( parameters ) { // - this.context = _gl; + // this.context = _gl; var _supportsVertexTextures = ( maxVertexTextures() > 0 ); @@ -250,6 +254,12 @@ THREE.WebGLRenderer = function ( parameters ) { var _spriteAttributesEnabled = false; + this.getContext = function () { + + return _gl; + + }; + this.setSize = function ( width, height ) { _canvas.width = width; @@ -325,12 +335,6 @@ THREE.WebGLRenderer = function ( parameters ) { }; - this.getContext = function () { - - return _gl; - - }; - this.deallocateObject = function ( object ) { if ( ! object.__webglInit ) return; @@ -708,7 +712,7 @@ THREE.WebGLRenderer = function ( parameters ) { }; - function initMeshBuffers ( geometryGroup, object ) { + function initMeshBuffers( geometryGroup, object ) { var f, fl, fi, face, m, ml, size, @@ -3373,42 +3377,6 @@ THREE.WebGLRenderer = function ( parameters ) { }; - function computeFrustum( m ) { - - _frustum[ 0 ].set( m.n41 - m.n11, m.n42 - m.n12, m.n43 - m.n13, m.n44 - m.n14 ); - _frustum[ 1 ].set( m.n41 + m.n11, m.n42 + m.n12, m.n43 + m.n13, m.n44 + m.n14 ); - _frustum[ 2 ].set( m.n41 + m.n21, m.n42 + m.n22, m.n43 + m.n23, m.n44 + m.n24 ); - _frustum[ 3 ].set( m.n41 - m.n21, m.n42 - m.n22, m.n43 - m.n23, m.n44 - m.n24 ); - _frustum[ 4 ].set( m.n41 - m.n31, m.n42 - m.n32, m.n43 - m.n33, m.n44 - m.n34 ); - _frustum[ 5 ].set( m.n41 + m.n31, m.n42 + m.n32, m.n43 + m.n33, m.n44 + m.n34 ); - - var i, plane; - - for ( i = 0; i < 6; i ++ ) { - - plane = _frustum[ i ]; - plane.divideScalar( Math.sqrt( plane.x * plane.x + plane.y * plane.y + plane.z * plane.z ) ); - - } - - }; - - function isInFrustum( object ) { - - var distance, matrix = object.matrixWorld, - radius = - object.geometry.boundingSphere.radius * Math.max( object.scale.x, Math.max( object.scale.y, object.scale.z ) ); - - for ( var i = 0; i < 6; i ++ ) { - - distance = _frustum[ i ].x * matrix.n14 + _frustum[ i ].y * matrix.n24 + _frustum[ i ].z * matrix.n34 + _frustum[ i ].w; - if ( distance <= radius ) return false; - - } - - return true; - - }; - function addToFixedArray( where, what ) { where.list[ where.count ] = what; @@ -3709,6 +3677,12 @@ THREE.WebGLRenderer = function ( parameters ) { _this.info.render.vertices = 0; _this.info.render.faces = 0; + if ( this.autoClear || forceClear ) { + + this.clear( this.autoClearColor, this.autoClearDepth, this.autoClearStencil ); + + } + if ( camera.parent == null ) { console.warn( "Camera is not on the Scene. Adding it..." ); @@ -3724,20 +3698,35 @@ THREE.WebGLRenderer = function ( parameters ) { camera.projectionMatrix.flattenToArray( _projectionMatrixArray ); _projScreenMatrix.multiply( camera.projectionMatrix, camera.matrixWorldInverse ); - computeFrustum( _projScreenMatrix ); + _projector.computeFrustum( _projScreenMatrix ); - this.initWebGLObjects( scene ); + _renderData = _projector.projectGraph( scene ); - lights = scene.__webglLights; + // lights = scene.__webglLights; - setRenderTarget( renderTarget ); + setRenderTarget( renderTarget ); // TODO: A bit obfuscated - if ( this.autoClear || forceClear ) { + ol = _renderData.objects.length; + + for ( o = 0; o < ol; o ++ ) { + + object = _renderData.objects[ o ]; + + _object = _objects[ object.id ] || initObject( object ); + + object.matrixWorld.flattenToArray( _object.objectMatrixArray ); + + // setupMatrices() + + _object.modelViewMatrix.multiplyToArray( camera.matrixWorldInverse, object.matrixWorld, _object.modelViewMatrixArray ); + THREE.Matrix4.makeInvert3x3( _object.modelViewMatrix ).transposeIntoArray( _object.normalMatrixArray ); - this.clear( this.autoClearColor, this.autoClearDepth, this.autoClearStencil ); } + + /* + // set matrices ol = scene.__webglObjects.length; @@ -4019,9 +4008,11 @@ THREE.WebGLRenderer = function ( parameters ) { } + */ + // render 2d - if ( scene.__webglSprites.length ) { + if ( _renderData.sprites.length ) { renderSprites( scene, camera ); @@ -4234,103 +4225,103 @@ THREE.WebGLRenderer = function ( parameters ) { }; - function addObject( object, scene ) { + function initObject( object ) { - var g, geometry, geometryGroup; + _object = _objects[ object.id ] = {}; - if ( ! object.__webglInit ) { + _object.modelViewMatrix = new THREE.Matrix4(); - object.__webglInit = true; + _object.normalMatrixArray = new Float32Array( 9 ); + _object.modelViewMatrixArray = new Float32Array( 16 ); + _object.objectMatrixArray = new Float32Array( 16 ); - object._modelViewMatrix = new THREE.Matrix4(); + object.matrixWorld.flattenToArray( _object.objectMatrixArray ); - object._normalMatrixArray = new Float32Array( 9 ); - object._modelViewMatrixArray = new Float32Array( 16 ); - object._objectMatrixArray = new Float32Array( 16 ); + if ( object instanceof THREE.Mesh ) { - object.matrixWorld.flattenToArray( object._objectMatrixArray ); + var geometry = object.geometry; - if ( object instanceof THREE.Mesh ) { + if ( geometry.geometryGroups == undefined ) { - geometry = object.geometry; + sortFacesByMaterial( geometry ); - if ( geometry.geometryGroups == undefined ) { + } - sortFacesByMaterial( geometry ); + // create separate VBOs per geometry chunk - } + for ( var g in geometry.geometryGroups ) { - // create separate VBOs per geometry chunk + var geometryGroup = geometry.geometryGroups[ g ]; - for ( g in geometry.geometryGroups ) { + // initialise VBO on the first access - geometryGroup = geometry.geometryGroups[ g ]; + if ( ! geometryGroup.__webglVertexBuffer ) { - // initialise VBO on the first access - - if ( ! geometryGroup.__webglVertexBuffer ) { - - createMeshBuffers( geometryGroup ); - initMeshBuffers( geometryGroup, object ); - - geometry.__dirtyVertices = true; - geometry.__dirtyMorphTargets = true; - geometry.__dirtyElements = true; - geometry.__dirtyUvs = true; - geometry.__dirtyNormals = true; - geometry.__dirtyTangents = true; - geometry.__dirtyColors = true; - - } - - } - - } else if ( object instanceof THREE.Ribbon ) { - - geometry = object.geometry; - - if( ! geometry.__webglVertexBuffer ) { - - createRibbonBuffers( geometry ); - initRibbonBuffers( geometry ); - - geometry.__dirtyVertices = true; - geometry.__dirtyColors = true; - - } - - } else if ( object instanceof THREE.Line ) { - - geometry = object.geometry; - - if( ! geometry.__webglVertexBuffer ) { - - createLineBuffers( geometry ); - initLineBuffers( geometry ); - - geometry.__dirtyVertices = true; - geometry.__dirtyColors = true; - - } - - } else if ( object instanceof THREE.ParticleSystem ) { - - geometry = object.geometry; - - if ( ! geometry.__webglVertexBuffer ) { - - createParticleBuffers( geometry ); - initParticleBuffers( geometry, object ); + createMeshBuffers( geometryGroup ); + initMeshBuffers( geometryGroup, object ); geometry.__dirtyVertices = true; + geometry.__dirtyMorphTargets = true; + geometry.__dirtyElements = true; + geometry.__dirtyUvs = true; + geometry.__dirtyNormals = true; + geometry.__dirtyTangents = true; geometry.__dirtyColors = true; } } + } else if ( object instanceof THREE.Ribbon ) { + + geometry = object.geometry; + + if( ! geometry.__webglVertexBuffer ) { + + createRibbonBuffers( geometry ); + initRibbonBuffers( geometry ); + + geometry.__dirtyVertices = true; + geometry.__dirtyColors = true; + + } + + } else if ( object instanceof THREE.Line ) { + + geometry = object.geometry; + + if( ! geometry.__webglVertexBuffer ) { + + createLineBuffers( geometry ); + initLineBuffers( geometry ); + + geometry.__dirtyVertices = true; + geometry.__dirtyColors = true; + + } + + } else if ( object instanceof THREE.ParticleSystem ) { + + geometry = object.geometry; + + if ( ! geometry.__webglVertexBuffer ) { + + createParticleBuffers( geometry ); + initParticleBuffers( geometry, object ); + + geometry.__dirtyVertices = true; + geometry.__dirtyColors = true; + + } + } + return _object; + + } + + function addObject( object, scene ) { + if ( ! object.__webglActive ) { if ( object instanceof THREE.Mesh ) {