提交 1efe37f9 编写于 作者: M Mr.doob

Merge remote-tracking branch 'gero3/dev' into dev

/**
* @author supereggbert / http://www.paulbrunt.co.uk/
* @author mrdoob / http://mrdoob.com/
* @author alteredq / http://alteredqualia.com/
* @author szimek / https://github.com/szimek/
* @author gero3 / https://github.com/gero3/
*/
THREE.WebGLRenderer2 = function ( parameters ) {
console.log( 'THREE.WebGLRenderer', THREE.REVISION );
parameters = parameters || {};
var info = {
memory: {
programs: 0,
geometries: 0,
textures: 0
},
render: {
calls: 0,
vertices: 0,
faces: 0,
points: 0
}
};
var renderer = new THREE.WebGLRenderer2.LowLevelRenderer(parameters);
var meshRenderer = new THREE.WebGLRenderer2.MeshRenderer(renderer, info);
var particleRenderer = new THREE.WebGLRenderer2.ParticleRenderer(renderer, info);
var lineRenderer = new THREE.WebGLRenderer2.LineRenderer(renderer, info);
var ribbonRenderer = new THREE.WebGLRenderer2.RibbonRenderer(renderer, info);
var shaderBuilder = new THREE.WebGLRenderer2.ShaderBuilder(renderer, info);
// clearing
this.autoClear = true;
this.autoClearColor = true;
this.autoClearDepth = true;
this.autoClearStencil = true;
// scene graph
this.sortObjects = true;
this.autoUpdateObjects = true;
this.autoUpdateScene = true;
// physically based shading
this.gammaInput = false;
this.gammaOutput = false;
this.physicallyBasedShading = false;
// shadow map
this.shadowMapEnabled = false;
this.shadowMapAutoUpdate = true;
this.shadowMapType = THREE.PCFShadowMap;
this.shadowMapCullFace = THREE.CullFaceFront;
this.shadowMapDebug = false;
this.shadowMapCascade = false;
// morphs
this.maxMorphTargets = 8;
this.maxMorphNormals = 4;
// flags
this.autoScaleCubemaps = true;
// custom render plugins
this.renderPluginsPre = [];
this.renderPluginsPost = [];
// info
this.info = info;
// internal properties
var _this = this,
// internal state cache
_currentProgram = null,
_currentFramebuffer = null,
_currentMaterialId = -1,
_currentGeometryGroupHash = null,
_currentCamera = null,
_geometryGroupCounter = 0,
_usedTextureUnits = 0,
// GL state
_viewportX = 0,
_viewportY = 0,
_viewportWidth = 0,
_viewportHeight = 0,
_currentWidth = 0,
_currentHeight = 0,
_enabledAttributes = {},
// frustum
_frustum = new THREE.Frustum(),
// camera matrices cache
_projScreenMatrix = new THREE.Matrix4(),
_projScreenMatrixPS = new THREE.Matrix4(),
_vector3 = new THREE.Vector3(),
// light arrays cache
_direction = new THREE.Vector3(),
_lightsNeedUpdate = true,
_lights = {
ambient: [ 0, 0, 0 ],
directional: { length: 0, colors: [], positions: [] },
point: { length: 0, colors: [], positions: [], distances: [] },
spot: { length: 0, colors: [], positions: [], distances: [], directions: [], anglesCos: [], exponents: [] },
hemi: { length: 0, skyColors: [], groundColors: [], positions: [] }
};
// initialize
this.context = renderer.getContext();
this.domElement = renderer.getDomElement();
this.getPrecision = renderer.getPrecision;
// low level API
this.getPrecision = renderer.getPrecision;
this.getContext = renderer.getContext;
this.supportsVertexTextures = renderer.supportsVertexTextures;
this.getMaxAnisotropy = renderer.getMaxAnisotropy;
this.setSize = renderer.setSize;
this.setViewport = renderer.setViewport;
this.setScissor = renderer.setScissor;
this.enableScissorTest = renderer.enableScissorTest;
this.setDepthTest = renderer.setDepthTest;
this.setRenderTarget = renderer.setRenderTarget;
// Clearing
this.setClearColorHex = renderer.setClearColorHex;
this.setClearColor = renderer.setClearColor;
this.getClearColor = renderer.getClearColor;
this.getClearAlpha = renderer.getClearAlpha;
this.clear = renderer.clear;
this.clearTarget = renderer.clearTarget;
// Plugins
this.addPostPlugin = function ( plugin ) {
plugin.init( this );
this.renderPluginsPost.push( plugin );
};
this.addPrePlugin = function ( plugin ) {
plugin.init( this );
this.renderPluginsPre.push( plugin );
};
// Rendering
this.updateShadowMap = function ( scene, camera ) {
_currentProgram = null;
_currentGeometryGroupHash = -1;
_currentMaterialId = -1;
_lightsNeedUpdate = true;
renderer.resetState();
this.shadowMapPlugin.update( scene, camera );
};
// Events
var onGeometryDispose = function ( event ) {
var geometry = event.target;
geometry.removeEventListener( 'dispose', onGeometryDispose );
deallocateGeometry( geometry );
_this.info.memory.geometries --;
};
var onTextureDispose = function ( event ) {
var texture = event.target;
texture.removeEventListener( 'dispose', onTextureDispose );
deallocateTexture( texture );
_this.info.memory.textures --;
};
var onRenderTargetDispose = function ( event ) {
var renderTarget = event.target;
renderTarget.removeEventListener( 'dispose', onRenderTargetDispose );
deallocateRenderTarget( renderTarget );
_this.info.memory.textures --;
};
var onMaterialDispose = function ( event ) {
var material = event.target;
material.removeEventListener( 'dispose', onMaterialDispose );
deallocateMaterial( material );
};
// Buffer deallocation
var deallocateGeometry = function ( geometry ) {
var m,ml;
geometry.__webglInit = undefined;
if ( geometry.__webglVertexBuffer !== undefined ) renderer.deleteBuffer( geometry.__webglVertexBuffer );
if ( geometry.__webglNormalBuffer !== undefined ) renderer.deleteBuffer( geometry.__webglNormalBuffer );
if ( geometry.__webglTangentBuffer !== undefined ) renderer.deleteBuffer( geometry.__webglTangentBuffer );
if ( geometry.__webglColorBuffer !== undefined ) renderer.deleteBuffer( geometry.__webglColorBuffer );
if ( geometry.__webglUVBuffer !== undefined ) renderer.deleteBuffer( geometry.__webglUVBuffer );
if ( geometry.__webglUV2Buffer !== undefined ) renderer.deleteBuffer( geometry.__webglUV2Buffer );
if ( geometry.__webglSkinIndicesBuffer !== undefined ) renderer.deleteBuffer( geometry.__webglSkinIndicesBuffer );
if ( geometry.__webglSkinWeightsBuffer !== undefined ) renderer.deleteBuffer( geometry.__webglSkinWeightsBuffer );
if ( geometry.__webglFaceBuffer !== undefined ) renderer.deleteBuffer( geometry.__webglFaceBuffer );
if ( geometry.__webglLineBuffer !== undefined ) renderer.deleteBuffer( geometry.__webglLineBuffer );
if ( geometry.__webglLineDistanceBuffer !== undefined ) renderer.deleteBuffer( geometry.__webglLineDistanceBuffer );
// geometry groups
if ( geometry.geometryGroups !== undefined ) {
for ( var g in geometry.geometryGroups ) {
var geometryGroup = geometry.geometryGroups[ g ];
if ( geometryGroup.numMorphTargets !== undefined ) {
for ( m = 0, ml = geometryGroup.numMorphTargets; m < ml; m ++ ) {
renderer.deleteBuffer( geometryGroup.__webglMorphTargetsBuffers[ m ] );
}
}
if ( geometryGroup.numMorphNormals !== undefined ) {
for ( m = 0, ml = geometryGroup.numMorphNormals; m < ml; m ++ ) {
renderer.deleteBuffer( geometryGroup.__webglMorphNormalsBuffers[ m ] );
}
}
deleteCustomAttributesBuffers( geometryGroup );
}
}
deleteCustomAttributesBuffers( geometry );
};
var deallocateTexture = function ( texture ) {
if ( texture.image && texture.image.__webglTextureCube ) {
// cube texture
renderer.deleteTexture( texture.image.__webglTextureCube );
} else {
// 2D texture
if ( ! texture.__webglInit ) return;
texture.__webglInit = false;
renderer.deleteTexture( texture.__webglTexture );
}
};
var deallocateRenderTarget = function ( renderTarget ) {
if ( !renderTarget || ! renderTarget.__webglTexture ) return;
renderer.deleteTexture( renderTarget.__webglTexture );
if ( renderTarget instanceof THREE.WebGLRenderTargetCube ) {
for ( var i = 0; i < 6; i ++ ) {
renderer.deleteFramebuffer( renderTarget.__webglFramebuffer[ i ] );
renderer.deleteRenderbuffer( renderTarget.__webglRenderbuffer[ i ] );
}
} else {
renderer.deleteFramebuffer( renderTarget.__webglFramebuffer );
renderer.deleteRenderbuffer( renderTarget.__webglRenderbuffer );
}
};
var deallocateMaterial = function ( material ) {
var program = material.program;
if ( program === undefined ) return;
material.program = undefined;
// only deallocate GL program if this was the last use of shared program
// assumed there is only single copy of any program in the _programs list
// (that's how it's constructed)
shaderBuilder.removeProgram(program)
};
function deleteCustomAttributesBuffers( geometry ) {
if ( geometry.__webglCustomAttributesList ) {
for ( var id in geometry.__webglCustomAttributesList ) {
renderer.deleteBuffer( geometry.__webglCustomAttributesList[ id ].buffer );
}
}
};
// Buffer initialization
function initCustomAttributes ( geometry, object ) {
var nvertices = geometry.vertices.length;
var material = object.material;
if ( material.attributes ) {
if ( geometry.__webglCustomAttributesList === undefined ) {
geometry.__webglCustomAttributesList = [];
}
for ( var a in material.attributes ) {
var attribute = material.attributes[ a ];
if ( !attribute.__webglInitialized || attribute.createUniqueBuffers ) {
attribute.__webglInitialized = true;
var size = 1; // "f" and "i"
if ( attribute.type === "v2" ) size = 2;
else if ( attribute.type === "v3" ) size = 3;
else if ( attribute.type === "v4" ) size = 4;
else if ( attribute.type === "c" ) size = 3;
attribute.size = size;
attribute.array = new Float32Array( nvertices * size );
attribute.buffer = renderer.createBuffer();
attribute.buffer.belongsToAttribute = a;
attribute.needsUpdate = true;
}
geometry.__webglCustomAttributesList.push( attribute );
}
}
};
function getBufferMaterial( object, geometryGroup ) {
return object.material instanceof THREE.MeshFaceMaterial
? object.material.materials[ geometryGroup.materialIndex ]
: object.material;
};
//
function initDirectBuffers( geometry ) {
var a, attribute;
for ( a in geometry.attributes ) {
attribute = geometry.attributes[ a ];
attribute.buffer = renderer.createBuffer();
if ( a === "index" ) {
renderer.setStaticIndexBuffer(attribute.buffer,attribute.array);
} else {
renderer.setStaticArrayBuffer(attribute.buffer,attribute.array);
}
}
};
// Buffer setting
function setDirectBuffers ( geometry, dispose ) {
var attributes = geometry.attributes;
var index = attributes[ "index" ];
var position = attributes[ "position" ];
var normal = attributes[ "normal" ];
var uv = attributes[ "uv" ];
var color = attributes[ "color" ];
var tangent = attributes[ "tangent" ];
if ( geometry.elementsNeedUpdate && index !== undefined ) {
renderer.setDynamicIndexBuffer( index.buffer, index.array);
}
if ( geometry.verticesNeedUpdate && position !== undefined ) {
renderer.setDynamicArrayBuffer( position.buffer, position.array);
}
if ( geometry.normalsNeedUpdate && normal !== undefined ) {
renderer.setDynamicArrayBuffer( normal.buffer, normal.array);
}
if ( geometry.uvsNeedUpdate && uv !== undefined ) {
renderer.setDynamicArrayBuffer( uv.buffer, uv.array);
}
if ( geometry.colorsNeedUpdate && color !== undefined ) {
renderer.setDynamicArrayBuffer( color.buffer, color.array);
}
if ( geometry.tangentsNeedUpdate && tangent !== undefined ) {
renderer.setDynamicArrayBuffer( tangent.buffer, tangent.array);
}
if ( dispose ) {
for ( var i in geometry.attributes ) {
delete geometry.attributes[ i ].array;
}
}
};
// Buffer rendering
this.renderBufferImmediate = function ( object, program, material ) {
if ( object.hasPositions && ! object.__webglVertexBuffer ) object.__webglVertexBuffer = renderer.createBuffer();
if ( object.hasNormals && ! object.__webglNormalBuffer ) object.__webglNormalBuffer = renderer.createBuffer();
if ( object.hasUvs && ! object.__webglUvBuffer ) object.__webglUvBuffer = renderer.createBuffer();
if ( object.hasColors && ! object.__webglColorBuffer ) object.__webglColorBuffer = renderer.createBuffer();
if ( object.hasPositions ) {
renderer.setDynamicArrayBuffer( object.__webglVertexBuffer, object.positionArray);
renderer.setFloatAttribute(program.attributes.position, object.__webglVertexBuffer, 3, 0);
}
if ( object.hasNormals ) {
if ( material.shading === THREE.FlatShading ) {
var nx, ny, nz,
nax, nbx, ncx, nay, nby, ncy, naz, nbz, ncz,
normalArray,
i, il = object.count * 3;
for( i = 0; i < il; i += 9 ) {
normalArray = object.normalArray;
nax = normalArray[ i ];
nay = normalArray[ i + 1 ];
naz = normalArray[ i + 2 ];
nbx = normalArray[ i + 3 ];
nby = normalArray[ i + 4 ];
nbz = normalArray[ i + 5 ];
ncx = normalArray[ i + 6 ];
ncy = normalArray[ i + 7 ];
ncz = normalArray[ i + 8 ];
nx = ( nax + nbx + ncx ) / 3;
ny = ( nay + nby + ncy ) / 3;
nz = ( naz + nbz + ncz ) / 3;
normalArray[ i ] = nx;
normalArray[ i + 1 ] = ny;
normalArray[ i + 2 ] = nz;
normalArray[ i + 3 ] = nx;
normalArray[ i + 4 ] = ny;
normalArray[ i + 5 ] = nz;
normalArray[ i + 6 ] = nx;
normalArray[ i + 7 ] = ny;
normalArray[ i + 8 ] = nz;
}
}
renderer.setDynamicArrayBuffer( object.__webglNormalBuffer, object.normalArray);
renderer.setFloatAttribute(program.attributes.normal, object.__webglNormalBuffer, 3, 0);
}
if ( object.hasUvs && material.map ) {
renderer.setDynamicArrayBuffer( object.__webglUvBuffer, object.uvArray);
renderer.setFloatAttribute(program.attributes.uv, object.__webglUvBuffer, 2, 0);
}
if ( object.hasColors && material.vertexColors !== THREE.NoColors ) {
renderer.setDynamicArrayBuffer( object.__webglColorBuffer, object.colorArray);
renderer.setFloatAttribute(program.attributes.color, object.__webglColorBuffer, 3, 0);
}
renderer.drawTriangles(object.count );
object.count = 0;
};
this.renderBufferDirect = function ( camera, lights, fog, material, geometry, object ) {
if ( material.visible === false ) return;
var program, attributes, linewidth, primitives, a, attribute;
program = setProgram( camera, lights, fog, material, object );
attributes = program.attributes;
var updateBuffers = false,
wireframeBit = material.wireframe ? 1 : 0,
geometryHash = ( geometry.id * 0xffffff ) + ( program.id * 2 ) + wireframeBit;
if ( geometryHash !== _currentGeometryGroupHash ) {
_currentGeometryGroupHash = geometryHash;
updateBuffers = true;
}
if ( updateBuffers ) {
renderer.disableAttributes();
}
// render mesh
if ( object instanceof THREE.Mesh ) {
var index = geometry.attributes[ "index" ];
// indexed triangles
if ( index ) {
var offsets = geometry.offsets;
// if there is more than 1 chunk
// must set attribute pointers to use new offsets for each chunk
// even if geometry and materials didn't change
if ( offsets.length > 1 ) updateBuffers = true;
for ( var i = 0, il = offsets.length; i < il; i ++ ) {
var startIndex = offsets[ i ].index;
if ( updateBuffers ) {
// vertices
var position = geometry.attributes[ "position" ];
var positionSize = position.itemSize;
renderer.setFloatAttribute(attributes.position , position.buffer, positionSize, startIndex * positionSize * 4);
// normals
var normal = geometry.attributes[ "normal" ];
if ( attributes.normal >= 0 && normal ) {
var normalSize = normal.itemSize;
renderer.setFloatAttribute(attributes.normal , normal.buffer, normalSize, startIndex * normalSize * 4);
}
// uvs
var uv = geometry.attributes[ "uv" ];
if ( attributes.uv >= 0 && uv ) {
var uvSize = uv.itemSize;
renderer.setFloatAttribute(attributes.uv , uv.buffer, uvSize, startIndex * uvSize * 4);
}
// colors
var color = geometry.attributes[ "color" ];
if ( attributes.color >= 0 && color ) {
var colorSize = color.itemSize;
renderer.setFloatAttribute(attributes.color , color.buffer, colorSize, startIndex * colorSize * 4);
}
// tangents
var tangent = geometry.attributes[ "tangent" ];
if ( attributes.tangent >= 0 && tangent ) {
var tangentSize = tangent.itemSize;
renderer.setFloatAttribute(attributes.tangent , tangent.buffer, tangentSize, startIndex * tangentSize * 4);
}
}
// render indexed triangles
renderer.drawTriangleElements(index.buffer, offsets[ i ].count, offsets[ i ].start * 2);
_this.info.render.calls ++;
_this.info.render.vertices += offsets[ i ].count; // not really true, here vertices can be shared
_this.info.render.faces += offsets[ i ].count / 3;
}
// non-indexed triangles
} else {
if ( updateBuffers ) {
// vertices
var position = geometry.attributes[ "position" ];
var positionSize = position.itemSize;
renderer.setFloatAttribute(attributes.position , position.buffer, positionSize, 0);
// normals
var normal = geometry.attributes[ "normal" ];
if ( attributes.normal >= 0 && normal ) {
var normalSize = normal.itemSize;
renderer.setFloatAttribute(attributes.normal , normal.buffer, normalSize, 0);
}
// uvs
var uv = geometry.attributes[ "uv" ];
if ( attributes.uv >= 0 && uv ) {
var uvSize = uv.itemSize;
renderer.setFloatAttribute(attributes.uv , uv.buffer, uvSize, 0);
}
// colors
var color = geometry.attributes[ "color" ];
if ( attributes.color >= 0 && color ) {
var colorSize = color.itemSize;
renderer.setFloatAttribute(attributes.color , color.buffer, colorSize, 0);
}
// tangents
var tangent = geometry.attributes[ "tangent" ];
if ( attributes.tangent >= 0 && tangent ) {
var tangentSize = tangent.itemSize;
renderer.setFloatAttribute(attributes.tangent , tangent.buffer, tangentSize, 0);
}
}
// render non-indexed triangles
renderer.drawTriangles( position.numItems / 3)
_this.info.render.calls ++;
_this.info.render.vertices += position.numItems / 3;
_this.info.render.faces += position.numItems / 3 / 3;
}
// render particles
} else if ( object instanceof THREE.ParticleSystem ) {
if ( updateBuffers ) {
// vertices
var position = geometry.attributes[ "position" ];
var positionSize = position.itemSize;
renderer.setFloatAttribute(attributes.position , position.buffer, positionSize, 0);
// colors
var color = geometry.attributes[ "color" ];
if ( attributes.color >= 0 && color ) {
var colorSize = color.itemSize;
renderer.setFloatAttribute(attributes.color , color.buffer, colorSize, 0);
}
// render particles
renderer.drawPoints(position.numItems / 3);
_this.info.render.calls ++;
_this.info.render.points += position.numItems / 3;
}
}
};
this.renderBuffer = function ( camera, lights, fog, material, geometryGroup, object ) {
if ( material.visible === false ) return;
var program, attributes, linewidth, primitives, a, attribute, i, il;
program = setProgram( camera, lights, fog, material, object );
attributes = program.attributes;
var updateBuffers = false,
wireframeBit = material.wireframe ? 1 : 0,
geometryGroupHash = ( geometryGroup.id * 0xffffff ) + ( program.id * 2 ) + wireframeBit;
if ( geometryGroupHash !== _currentGeometryGroupHash ) {
_currentGeometryGroupHash = geometryGroupHash;
updateBuffers = true;
}
if ( updateBuffers ) {
renderer.disableAttributes();
}
// vertices
if ( !material.morphTargets && attributes.position >= 0 ) {
if ( updateBuffers ) {
renderer.setFloatAttribute(attributes.position , geometryGroup.__webglVertexBuffer, 3, 0);
}
} else {
if ( object.morphTargetBase ) {
setupMorphTargets( material, geometryGroup, object );
}
}
if ( updateBuffers ) {
// custom attributes
// Use the per-geometryGroup custom attribute arrays which are setup in initMeshBuffers
if ( geometryGroup.__webglCustomAttributesList ) {
for ( i = 0, il = geometryGroup.__webglCustomAttributesList.length; i < il; i ++ ) {
attribute = geometryGroup.__webglCustomAttributesList[ i ];
if ( attributes[ attribute.buffer.belongsToAttribute ] >= 0 ) {
renderer.setFloatAttribute(attributes[ attribute.buffer.belongsToAttribute ] , attribute.buffer, attribute.size, 0);
}
}
}
// colors
if ( attributes.color >= 0 ) {
renderer.setFloatAttribute(attributes.color , geometryGroup.__webglColorBuffer,3, 0);
}
// normals
if ( attributes.normal >= 0 ) {
renderer.setFloatAttribute(attributes.normal, geometryGroup.__webglNormalBuffer, 3, 0);
}
// tangents
if ( attributes.tangent >= 0 ) {
renderer.setFloatAttribute(attributes.tangent, geometryGroup.__webglTangentBuffer, 4, 0);
}
// uvs
if ( attributes.uv >= 0 ) {
renderer.setFloatAttribute(attributes.uv, geometryGroup.__webglUVBuffer, 2, 0);
}
if ( attributes.uv2 >= 0 ) {
renderer.setFloatAttribute(attributes.uv2, geometryGroup.__webglUV2Buffer, 2, 0);
}
if ( material.skinning &&
attributes.skinIndex >= 0 && attributes.skinWeight >= 0 ) {
renderer.setFloatAttribute(attributes.skinIndex, geometryGroup.__webglSkinIndicesBuffer, 4, 0);
renderer.setFloatAttribute(attributes.skinWeight, geometryGroup.__webglSkinWeightsBuffer, 4, 0);
}
// line distances
if ( attributes.lineDistance >= 0 ) {
renderer.setFloatAttribute(attributes.lineDistance, geometryGroup.__webglLineDistanceBuffer, 1, 0);
}
}
// render mesh
if ( object instanceof THREE.Mesh ) {
// wireframe
if ( material.wireframe ) {
renderer.setLineWidth( material.wireframeLinewidth );
renderer.drawLineElements(geometryGroup.__webglLineBuffer,geometryGroup.__webglLineCount,0);
// triangles
} else {
renderer.drawTriangleElements( geometryGroup.__webglFaceBuffer, geometryGroup.__webglFaceCount, 0);
}
_this.info.render.calls ++;
_this.info.render.vertices += geometryGroup.__webglFaceCount;
_this.info.render.faces += geometryGroup.__webglFaceCount / 3;
// render lines
} else if ( object instanceof THREE.Line ) {
renderer.setLineWidth( material.linewidth );
if (object.type === THREE.LineStrip) {
renderer.drawLineStrip(geometryGroup.__webglLineCount);
} else {
renderer.drawLines(geometryGroup.__webglLineCount);
}
_this.info.render.calls ++;
// render particles
} else if ( object instanceof THREE.ParticleSystem ) {
renderer.drawPoints(geometryGroup.__webglParticleCount);
_this.info.render.calls ++;
_this.info.render.points += geometryGroup.__webglParticleCount;
// render ribbon
} else if ( object instanceof THREE.Ribbon ) {
renderer.drawTriangleStrip(geometryGroup.__webglVertexCount);
_this.info.render.calls ++;
}
};
function setupMorphTargets ( material, geometryGroup, object ) {
// set base
var attributes = material.program.attributes;
if ( object.morphTargetBase !== -1 && attributes.position >= 0 ) {
renderer.setFloatAttribute(attributes.position, geometryGroup.__webglMorphTargetsBuffers[ object.morphTargetBase ], 3, 0);
} else if ( attributes.position >= 0 ) {
renderer.setFloatAttribute(attributes.position, geometryGroup.__webglVertexBuffer, 3, 0);
}
if ( object.morphTargetForcedOrder.length ) {
// set forced order
var m = 0;
var order = object.morphTargetForcedOrder;
var influences = object.morphTargetInfluences;
while ( m < material.numSupportedMorphTargets && m < order.length ) {
if ( attributes[ "morphTarget" + m ] >= 0 ) {
renderer.setFloatAttribute(attributes[ "morphTarget" + m ], geometryGroup.__webglMorphTargetsBuffers[ order[ m ] ], 3, 0);
}
if ( attributes[ "morphNormal" + m ] >= 0 && material.morphNormals ) {
renderer.setFloatAttribute(attributes[ "morphNormal" + m ], geometryGroup.__webglMorphNormalsBuffers[ order[ m ] ], 3, 0);
}
object.__webglMorphTargetInfluences[ m ] = influences[ order[ m ] ];
m ++;
}
} else {
// find the most influencing
var influence, activeInfluenceIndices = [];
var influences = object.morphTargetInfluences;
var i, il = influences.length;
for ( i = 0; i < il; i ++ ) {
influence = influences[ i ];
if ( influence > 0 ) {
activeInfluenceIndices.push( [ influence, i ] );
}
}
if ( activeInfluenceIndices.length > material.numSupportedMorphTargets ) {
activeInfluenceIndices.sort( numericalSort );
activeInfluenceIndices.length = material.numSupportedMorphTargets;
} else if ( activeInfluenceIndices.length > material.numSupportedMorphNormals ) {
activeInfluenceIndices.sort( numericalSort );
} else if ( activeInfluenceIndices.length === 0 ) {
activeInfluenceIndices.push( [ 0, 0 ] );
};
var influenceIndex, m = 0;
while ( m < material.numSupportedMorphTargets ) {
if ( activeInfluenceIndices[ m ] ) {
influenceIndex = activeInfluenceIndices[ m ][ 1 ];
if ( attributes[ "morphTarget" + m ] >= 0 ) {
renderer.setFloatAttribute(attributes[ "morphTarget" + m ], geometryGroup.__webglMorphTargetsBuffers[ influenceIndex ], 3, 0);
}
if ( attributes[ "morphNormal" + m ] >= 0 && material.morphNormals ) {
renderer.setFloatAttribute(attributes[ "morphNormal" + m ], geometryGroup.__webglMorphNormalsBuffers[ influenceIndex ], 3, 0);
}
object.__webglMorphTargetInfluences[ m ] = influences[ influenceIndex ];
} else {
/*
_gl.vertexAttribPointer( attributes[ "morphTarget" + m ], 3, _gl.FLOAT, false, 0, 0 );
if ( material.morphNormals ) {
_gl.vertexAttribPointer( attributes[ "morphNormal" + m ], 3, _gl.FLOAT, false, 0, 0 );
}
*/
object.__webglMorphTargetInfluences[ m ] = 0;
}
m ++;
}
}
// load updated influences uniform
if ( material.program.uniforms.morphTargetInfluences !== null ) {
renderer.uniform1fv( material.program.uniforms.morphTargetInfluences, object.__webglMorphTargetInfluences );
}
};
// Sorting
function painterSortStable ( a, b ) {
if ( a.z !== b.z ) {
return b.z - a.z;
} else {
return b.id - a.id;
}
};
function numericalSort ( a, b ) {
return b[ 0 ] - a[ 0 ];
};
// Rendering
this.render = function ( scene, camera, renderTarget, forceClear ) {
if ( camera instanceof THREE.Camera === false ) {
console.error( 'THREE.WebGLRenderer.render: camera is not an instance of THREE.Camera.' );
return;
}
var i, il,
webglObject, object,
renderList,
lights = scene.__lights,
fog = scene.fog;
// reset caching for this frame
_currentMaterialId = -1;
_lightsNeedUpdate = true;
// update scene graph
if ( this.autoUpdateScene ) scene.updateMatrixWorld();
// update camera matrices and frustum
if ( camera.parent === undefined ) camera.updateMatrixWorld();
camera.matrixWorldInverse.getInverse( camera.matrixWorld );
_projScreenMatrix.multiply( camera.projectionMatrix, camera.matrixWorldInverse );
_frustum.setFromMatrix( _projScreenMatrix );
// update WebGL objects
if ( this.autoUpdateObjects ) this.initWebGLObjects( scene );
// custom render plugins (pre pass)
renderPlugins( this.renderPluginsPre, scene, camera );
//
_this.info.render.calls = 0;
_this.info.render.vertices = 0;
_this.info.render.faces = 0;
_this.info.render.points = 0;
renderer.setRenderTarget( renderTarget );
if ( this.autoClear || forceClear ) {
this.clear( this.autoClearColor, this.autoClearDepth, this.autoClearStencil );
}
// set matrices for regular objects (frustum culled)
renderList = scene.__webglObjects;
for ( i = 0, il = renderList.length; i < il; i ++ ) {
webglObject = renderList[ i ];
object = webglObject.object;
webglObject.render = false;
if ( object.visible ) {
if ( ! ( object instanceof THREE.Mesh || object instanceof THREE.ParticleSystem ) || ! ( object.frustumCulled ) || _frustum.intersectsObject( object ) ) {
setupMatrices( object, camera );
unrollBufferMaterial( webglObject );
webglObject.render = true;
if ( this.sortObjects === true ) {
if ( object.renderDepth !== null ) {
webglObject.z = object.renderDepth;
} else {
_vector3.copy( object.matrixWorld.getPosition() );
_vector3.applyMatrix4(_projScreenMatrix);
webglObject.z = _vector3.z;
}
webglObject.id = object.id;
}
}
}
}
if ( this.sortObjects ) {
renderList.sort( painterSortStable );
}
// set matrices for immediate objects
renderList = scene.__webglObjectsImmediate;
for ( i = 0, il = renderList.length; i < il; i ++ ) {
webglObject = renderList[ i ];
object = webglObject.object;
if ( object.visible ) {
setupMatrices( object, camera );
unrollImmediateBufferMaterial( webglObject );
}
}
if ( scene.overrideMaterial ) {
var material = scene.overrideMaterial;
renderer.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst );
renderer.setDepthTest( material.depthTest );
renderer.setDepthWrite( material.depthWrite );
renderer.setPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits );
renderObjects( scene.__webglObjects, false, "", camera, lights, fog, true, material );
renderObjectsImmediate( scene.__webglObjectsImmediate, "", camera, lights, fog, false, material );
} else {
var material = null;
// opaque pass (front-to-back order)
renderer.setBlending( THREE.NoBlending );
renderObjects( scene.__webglObjects, true, "opaque", camera, lights, fog, false, material );
renderObjectsImmediate( scene.__webglObjectsImmediate, "opaque", camera, lights, fog, false, material );
// transparent pass (back-to-front order)
renderObjects( scene.__webglObjects, false, "transparent", camera, lights, fog, true, material );
renderObjectsImmediate( scene.__webglObjectsImmediate, "transparent", camera, lights, fog, true, material );
}
// custom render plugins (post pass)
renderPlugins( this.renderPluginsPost, scene, camera );
// Generate mipmap if we're using any kind of mipmap filtering
if ( renderTarget && renderTarget.generateMipmaps && renderTarget.minFilter !== THREE.NearestFilter && renderTarget.minFilter !== THREE.LinearFilter ) {
renderer.updateRenderTargetMipmap( renderTarget );
}
// Ensure depth buffer writing is enabled so it can be cleared on next render
renderer.setDepthTest( true );
renderer.setDepthWrite( true );
// _gl.finish();
};
function renderPlugins( plugins, scene, camera ) {
if ( ! plugins.length ) return;
for ( var i = 0, il = plugins.length; i < il; i ++ ) {
// reset state for plugin (to start from clean slate)
_currentProgram = null;
_currentCamera = null;
_currentGeometryGroupHash = -1;
_currentMaterialId = -1;
_lightsNeedUpdate = true;
renderer.resetState();
plugins[ i ].render( scene, camera, renderer.getCurrentWidth(), renderer.getCurrentWidth() );
// reset state after plugin (anything could have changed)
_currentProgram = null;
_currentCamera = null;
_currentGeometryGroupHash = -1;
_currentMaterialId = -1;
_lightsNeedUpdate = true;
renderer.resetState();
}
};
function renderObjects ( renderList, reverse, materialType, camera, lights, fog, useBlending, overrideMaterial ) {
var webglObject, object, buffer, material, start, end, delta;
if ( reverse ) {
start = renderList.length - 1;
end = -1;
delta = -1;
} else {
start = 0;
end = renderList.length;
delta = 1;
}
for ( var i = start; i !== end; i += delta ) {
webglObject = renderList[ i ];
if ( webglObject.render ) {
object = webglObject.object;
buffer = webglObject.buffer;
if ( overrideMaterial ) {
material = overrideMaterial;
} else {
material = webglObject[ materialType ];
if ( ! material ) continue;
if ( useBlending ) renderer.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst );
renderer.setDepthTest( material.depthTest );
renderer.setDepthWrite( material.depthWrite );
renderer.setPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits );
}
renderer.setMaterialFaces( material );
if ( buffer instanceof THREE.BufferGeometry ) {
_this.renderBufferDirect( camera, lights, fog, material, buffer, object );
} else {
_this.renderBuffer( camera, lights, fog, material, buffer, object );
}
}
}
};
function renderObjectsImmediate ( renderList, materialType, camera, lights, fog, useBlending, overrideMaterial ) {
var webglObject, object, material, program;
for ( var i = 0, il = renderList.length; i < il; i ++ ) {
webglObject = renderList[ i ];
object = webglObject.object;
if ( object.visible ) {
if ( overrideMaterial ) {
material = overrideMaterial;
} else {
material = webglObject[ materialType ];
if ( ! material ) continue;
if ( useBlending ) renderer.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst );
renderer.setDepthTest( material.depthTest );
renderer.setDepthWrite( material.depthWrite );
renderer.setPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits );
}
_this.renderImmediateObject( camera, lights, fog, material, object );
}
}
};
this.renderImmediateObject = function ( camera, lights, fog, material, object ) {
var program = setProgram( camera, lights, fog, material, object );
_currentGeometryGroupHash = -1;
renderer.setMaterialFaces( material );
if ( object.immediateRenderCallback ) {
object.immediateRenderCallback( program, renderer.getContext(), _frustum );
} else {
object.render( function( object ) { _this.renderBufferImmediate( object, program, material ); } );
}
};
function unrollImmediateBufferMaterial ( globject ) {
var object = globject.object,
material = object.material;
if ( material.transparent ) {
globject.transparent = material;
globject.opaque = null;
} else {
globject.opaque = material;
globject.transparent = null;
}
};
function unrollBufferMaterial ( globject ) {
var object = globject.object,
buffer = globject.buffer,
material, materialIndex, meshMaterial;
meshMaterial = object.material;
if ( meshMaterial instanceof THREE.MeshFaceMaterial ) {
materialIndex = buffer.materialIndex;
material = meshMaterial.materials[ materialIndex ];
if ( material.transparent ) {
globject.transparent = material;
globject.opaque = null;
} else {
globject.opaque = material;
globject.transparent = null;
}
} else {
material = meshMaterial;
if ( material ) {
if ( material.transparent ) {
globject.transparent = material;
globject.opaque = null;
} else {
globject.opaque = material;
globject.transparent = null;
}
}
}
};
// Geometry splitting
function sortFacesByMaterial ( geometry, material ) {
var f, fl, face, materialIndex, vertices,
groupHash, hash_map = {};
var numMorphTargets = geometry.morphTargets.length;
var numMorphNormals = geometry.morphNormals.length;
var usesFaceMaterial = material instanceof THREE.MeshFaceMaterial;
geometry.geometryGroups = {};
for ( f = 0, fl = geometry.faces.length; f < fl; f ++ ) {
face = geometry.faces[ f ];
materialIndex = usesFaceMaterial ? face.materialIndex : 0;
if ( hash_map[ materialIndex ] === undefined ) {
hash_map[ materialIndex ] = { 'hash': materialIndex, 'counter': 0 };
}
groupHash = hash_map[ materialIndex ].hash + '_' + hash_map[ materialIndex ].counter;
if ( geometry.geometryGroups[ groupHash ] === undefined ) {
geometry.geometryGroups[ groupHash ] = { 'faces3': [], 'faces4': [], 'materialIndex': materialIndex, 'vertices': 0, 'numMorphTargets': numMorphTargets, 'numMorphNormals': numMorphNormals };
}
vertices = face instanceof THREE.Face3 ? 3 : 4;
if ( geometry.geometryGroups[ groupHash ].vertices + vertices > 65535 ) {
hash_map[ materialIndex ].counter += 1;
groupHash = hash_map[ materialIndex ].hash + '_' + hash_map[ materialIndex ].counter;
if ( geometry.geometryGroups[ groupHash ] === undefined ) {
geometry.geometryGroups[ groupHash ] = { 'faces3': [], 'faces4': [], 'materialIndex': materialIndex, 'vertices': 0, 'numMorphTargets': numMorphTargets, 'numMorphNormals': numMorphNormals };
}
}
if ( face instanceof THREE.Face3 ) {
geometry.geometryGroups[ groupHash ].faces3.push( f );
} else {
geometry.geometryGroups[ groupHash ].faces4.push( f );
}
geometry.geometryGroups[ groupHash ].vertices += vertices;
}
geometry.geometryGroupsList = [];
for ( var g in geometry.geometryGroups ) {
geometry.geometryGroups[ g ].id = _geometryGroupCounter ++;
geometry.geometryGroupsList.push( geometry.geometryGroups[ g ] );
}
};
// Objects refresh
this.initWebGLObjects = function ( scene ) {
if ( !scene.__webglObjects ) {
scene.__webglObjects = [];
scene.__webglObjectsImmediate = [];
scene.__webglSprites = [];
scene.__webglFlares = [];
}
while ( scene.__objectsAdded.length ) {
addObject( scene.__objectsAdded[ 0 ], scene );
scene.__objectsAdded.splice( 0, 1 );
}
while ( scene.__objectsRemoved.length ) {
removeObject( scene.__objectsRemoved[ 0 ], scene );
scene.__objectsRemoved.splice( 0, 1 );
}
// update must be called after objects adding / removal
for ( var o = 0, ol = scene.__webglObjects.length; o < ol; o ++ ) {
updateObject( scene.__webglObjects[ o ].object );
}
};
// Objects adding
function addObject ( object, scene ) {
var g, geometry, material, geometryGroup;
if ( ! object.__webglInit ) {
object.__webglInit = true;
object._modelViewMatrix = new THREE.Matrix4();
object._normalMatrix = new THREE.Matrix3();
if ( object.geometry !== undefined && object.geometry.__webglInit === undefined ) {
object.geometry.__webglInit = true;
object.geometry.addEventListener( 'dispose', onGeometryDispose );
}
if ( object instanceof THREE.Mesh ) {
geometry = object.geometry;
material = object.material;
if ( geometry instanceof THREE.Geometry ) {
if ( geometry.geometryGroups === undefined ) {
sortFacesByMaterial( geometry, material );
}
// create separate VBOs per geometry chunk
for ( g in geometry.geometryGroups ) {
geometryGroup = geometry.geometryGroups[ g ];
// initialise VBO on the first access
if ( ! geometryGroup.__webglVertexBuffer ) {
meshRenderer.createBuffers( geometryGroup );
meshRenderer.initBuffers( geometryGroup, object );
geometry.verticesNeedUpdate = true;
geometry.morphTargetsNeedUpdate = true;
geometry.elementsNeedUpdate = true;
geometry.uvsNeedUpdate = true;
geometry.normalsNeedUpdate = true;
geometry.tangentsNeedUpdate = true;
geometry.colorsNeedUpdate = true;
}
}
} else if ( geometry instanceof THREE.BufferGeometry ) {
initDirectBuffers( geometry );
}
} else if ( object instanceof THREE.Ribbon ) {
geometry = object.geometry;
if ( ! geometry.__webglVertexBuffer ) {
ribbonRenderer.createBuffers( geometry );
ribbonRenderer.initBuffers( geometry, object );
geometry.verticesNeedUpdate = true;
geometry.colorsNeedUpdate = true;
geometry.normalsNeedUpdate = true;
}
} else if ( object instanceof THREE.Line ) {
geometry = object.geometry;
if ( ! geometry.__webglVertexBuffer ) {
lineRenderer.createBuffers( geometry );
lineRenderer.initBuffers( geometry, object );
geometry.verticesNeedUpdate = true;
geometry.colorsNeedUpdate = true;
geometry.lineDistancesNeedUpdate = true;
}
} else if ( object instanceof THREE.ParticleSystem ) {
geometry = object.geometry;
if ( ! geometry.__webglVertexBuffer ) {
if ( geometry instanceof THREE.Geometry ) {
particleRenderer.createBuffers( geometry );
particleRenderer.initBuffers( geometry, object );
geometry.verticesNeedUpdate = true;
geometry.colorsNeedUpdate = true;
} else if ( geometry instanceof THREE.BufferGeometry ) {
initDirectBuffers( geometry );
}
}
}
}
if ( ! object.__webglActive ) {
if ( object instanceof THREE.Mesh ) {
geometry = object.geometry;
if ( geometry instanceof THREE.BufferGeometry ) {
addBuffer( scene.__webglObjects, geometry, object );
} else if ( geometry instanceof THREE.Geometry ) {
for ( g in geometry.geometryGroups ) {
geometryGroup = geometry.geometryGroups[ g ];
addBuffer( scene.__webglObjects, geometryGroup, object );
}
}
} else if ( object instanceof THREE.Ribbon ||
object instanceof THREE.Line ||
object instanceof THREE.ParticleSystem ) {
geometry = object.geometry;
addBuffer( scene.__webglObjects, geometry, object );
} else if ( object instanceof THREE.ImmediateRenderObject || object.immediateRenderCallback ) {
addBufferImmediate( scene.__webglObjectsImmediate, object );
} else if ( object instanceof THREE.Sprite ) {
scene.__webglSprites.push( object );
} else if ( object instanceof THREE.LensFlare ) {
scene.__webglFlares.push( object );
}
object.__webglActive = true;
}
};
function addBuffer ( objlist, buffer, object ) {
objlist.push(
{
buffer: buffer,
object: object,
opaque: null,
transparent: null
}
);
};
function addBufferImmediate ( objlist, object ) {
objlist.push(
{
object: object,
opaque: null,
transparent: null
}
);
};
// Objects updates
function updateObject ( object ) {
var geometry = object.geometry,
geometryGroup, customAttributesDirty, material;
if ( object instanceof THREE.Mesh ) {
if ( geometry instanceof THREE.BufferGeometry ) {
if ( geometry.verticesNeedUpdate || geometry.elementsNeedUpdate ||
geometry.uvsNeedUpdate || geometry.normalsNeedUpdate ||
geometry.colorsNeedUpdate || geometry.tangentsNeedUpdate ) {
setDirectBuffers( geometry, !geometry.dynamic );
}
geometry.verticesNeedUpdate = false;
geometry.elementsNeedUpdate = false;
geometry.uvsNeedUpdate = false;
geometry.normalsNeedUpdate = false;
geometry.colorsNeedUpdate = false;
geometry.tangentsNeedUpdate = false;
} else {
// check all geometry groups
for( var i = 0, il = geometry.geometryGroupsList.length; i < il; i ++ ) {
geometryGroup = geometry.geometryGroupsList[ i ];
material = getBufferMaterial( object, geometryGroup );
if ( geometry.buffersNeedUpdate ) {
meshRenderer.initBuffers( geometryGroup, object );
}
customAttributesDirty = material.attributes && areCustomAttributesDirty( material );
if ( geometry.verticesNeedUpdate || geometry.morphTargetsNeedUpdate || geometry.elementsNeedUpdate ||
geometry.uvsNeedUpdate || geometry.normalsNeedUpdate ||
geometry.colorsNeedUpdate || geometry.tangentsNeedUpdate || customAttributesDirty ) {
meshRenderer.setBuffers( geometryGroup, object, !geometry.dynamic, material );
}
}
geometry.verticesNeedUpdate = false;
geometry.morphTargetsNeedUpdate = false;
geometry.elementsNeedUpdate = false;
geometry.uvsNeedUpdate = false;
geometry.normalsNeedUpdate = false;
geometry.colorsNeedUpdate = false;
geometry.tangentsNeedUpdate = false;
geometry.buffersNeedUpdate = false;
material.attributes && clearCustomAttributes( material );
}
} else if ( object instanceof THREE.Ribbon ) {
material = getBufferMaterial( object, geometry );
customAttributesDirty = material.attributes && areCustomAttributesDirty( material );
if ( geometry.verticesNeedUpdate || geometry.colorsNeedUpdate || geometry.normalsNeedUpdate || customAttributesDirty ) {
ribbonRenderer.setBuffers( geometry);
}
geometry.verticesNeedUpdate = false;
geometry.colorsNeedUpdate = false;
geometry.normalsNeedUpdate = false;
material.attributes && clearCustomAttributes( material );
} else if ( object instanceof THREE.Line ) {
material = getBufferMaterial( object, geometry );
customAttributesDirty = material.attributes && areCustomAttributesDirty( material );
if ( geometry.verticesNeedUpdate || geometry.colorsNeedUpdate || geometry.lineDistancesNeedUpdate || customAttributesDirty ) {
lineRenderer.setBuffers( geometry);
}
geometry.verticesNeedUpdate = false;
geometry.colorsNeedUpdate = false;
geometry.lineDistancesNeedUpdate = false;
material.attributes && clearCustomAttributes( material );
} else if ( object instanceof THREE.ParticleSystem ) {
if ( geometry instanceof THREE.BufferGeometry ) {
if ( geometry.verticesNeedUpdate || geometry.colorsNeedUpdate ) {
setDirectBuffers( geometry, !geometry.dynamic );
}
geometry.verticesNeedUpdate = false;
geometry.colorsNeedUpdate = false;
} else {
material = getBufferMaterial( object, geometry );
customAttributesDirty = material.attributes && areCustomAttributesDirty( material );
if ( geometry.verticesNeedUpdate || geometry.colorsNeedUpdate || object.sortParticles || customAttributesDirty ) {
particleRenderer.setBuffers( geometry, object, _projScreenMatrix);
}
geometry.verticesNeedUpdate = false;
geometry.colorsNeedUpdate = false;
material.attributes && clearCustomAttributes( material );
}
}
};
// Objects updates - custom attributes check
function areCustomAttributesDirty ( material ) {
for ( var a in material.attributes ) {
if ( material.attributes[ a ].needsUpdate ) return true;
}
return false;
};
function clearCustomAttributes ( material ) {
for ( var a in material.attributes ) {
material.attributes[ a ].needsUpdate = false;
}
};
// Objects removal
function removeObject ( object, scene ) {
if ( object instanceof THREE.Mesh ||
object instanceof THREE.ParticleSystem ||
object instanceof THREE.Ribbon ||
object instanceof THREE.Line ) {
removeInstances( scene.__webglObjects, object );
} else if ( object instanceof THREE.Sprite ) {
removeInstancesDirect( scene.__webglSprites, object );
} else if ( object instanceof THREE.LensFlare ) {
removeInstancesDirect( scene.__webglFlares, object );
} else if ( object instanceof THREE.ImmediateRenderObject || object.immediateRenderCallback ) {
removeInstances( scene.__webglObjectsImmediate, object );
}
object.__webglActive = false;
};
function removeInstances ( objlist, object ) {
for ( var o = objlist.length - 1; o >= 0; o -- ) {
if ( objlist[ o ].object === object ) {
objlist.splice( o, 1 );
}
}
};
function removeInstancesDirect ( objlist, object ) {
for ( var o = objlist.length - 1; o >= 0; o -- ) {
if ( objlist[ o ] === object ) {
objlist.splice( o, 1 );
}
}
};
// Materials
this.initMaterial = function ( material, lights, fog, object ) {
material.addEventListener( 'dispose', onMaterialDispose );
var u, a, identifiers, i, parameters, maxLightCount, maxBones, maxShadows, shaderID;
if ( material instanceof THREE.MeshDepthMaterial ) {
shaderID = 'depth';
} else if ( material instanceof THREE.MeshNormalMaterial ) {
shaderID = 'normal';
} else if ( material instanceof THREE.MeshBasicMaterial ) {
shaderID = 'basic';
} else if ( material instanceof THREE.MeshLambertMaterial ) {
shaderID = 'lambert';
} else if ( material instanceof THREE.MeshPhongMaterial ) {
shaderID = 'phong';
} else if ( material instanceof THREE.LineBasicMaterial ) {
shaderID = 'basic';
} else if ( material instanceof THREE.LineDashedMaterial ) {
shaderID = 'dashed';
} else if ( material instanceof THREE.ParticleBasicMaterial ) {
shaderID = 'particle_basic';
}
if ( shaderID ) {
setMaterialShaders( material, THREE.ShaderLib[ shaderID ] );
}
// heuristics to create shader parameters according to lights in the scene
// (not to blow over maxLights budget)
maxLightCount = allocateLights( lights );
maxShadows = allocateShadows( lights );
maxBones = allocateBones( object );
parameters = {
map: !!material.map,
envMap: !!material.envMap,
lightMap: !!material.lightMap,
bumpMap: !!material.bumpMap,
normalMap: !!material.normalMap,
specularMap: !!material.specularMap,
vertexColors: material.vertexColors,
fog: fog,
useFog: material.fog,
fogExp: fog instanceof THREE.FogExp2,
sizeAttenuation: material.sizeAttenuation,
skinning: material.skinning,
maxBones: maxBones,
useVertexTexture: renderer.supportsBoneTextures && object && object.useVertexTexture,
boneTextureWidth: object && object.boneTextureWidth,
boneTextureHeight: object && object.boneTextureHeight,
morphTargets: material.morphTargets,
morphNormals: material.morphNormals,
maxMorphTargets: this.maxMorphTargets,
maxMorphNormals: this.maxMorphNormals,
maxDirLights: maxLightCount.directional,
maxPointLights: maxLightCount.point,
maxSpotLights: maxLightCount.spot,
maxHemiLights: maxLightCount.hemi,
maxShadows: maxShadows,
shadowMapEnabled: this.shadowMapEnabled && object.receiveShadow,
shadowMapType: this.shadowMapType,
shadowMapDebug: this.shadowMapDebug,
shadowMapCascade: this.shadowMapCascade,
alphaTest: material.alphaTest,
metal: material.metal,
perPixel: material.perPixel,
wrapAround: material.wrapAround,
doubleSided: material.side === THREE.DoubleSide,
flipSided: material.side === THREE.BackSide,
gammaInput : this.gammaInput,
gammaOutput : this.gammaOutput ,
physicallyBasedShading : this.physicallyBasedShading
};
material.program = shaderBuilder.buildProgram( shaderID, material.fragmentShader, material.vertexShader, material.uniforms, material.attributes, material.defines, parameters );
var attributes = material.program.attributes;
if ( material.morphTargets ) {
material.numSupportedMorphTargets = 0;
var id, base = "morphTarget";
for ( i = 0; i < this.maxMorphTargets; i ++ ) {
id = base + i;
if ( attributes[ id ] >= 0 ) {
material.numSupportedMorphTargets ++;
}
}
}
if ( material.morphNormals ) {
material.numSupportedMorphNormals = 0;
var id, base = "morphNormal";
for ( i = 0; i < this.maxMorphNormals; i ++ ) {
id = base + i;
if ( attributes[ id ] >= 0 ) {
material.numSupportedMorphNormals ++;
}
}
}
material.uniformsList = [];
for ( u in material.uniforms ) {
material.uniformsList.push( [ material.uniforms[ u ], u ] );
}
};
function setMaterialShaders( material, shaders ) {
material.uniforms = THREE.UniformsUtils.clone( shaders.uniforms );
material.vertexShader = shaders.vertexShader;
material.fragmentShader = shaders.fragmentShader;
};
function setProgram( camera, lights, fog, material, object ) {
_usedTextureUnits = 0;
if ( material.needsUpdate ) {
if ( material.program ) deallocateMaterial( material );
_this.initMaterial( material, lights, fog, object );
material.needsUpdate = false;
}
if ( material.morphTargets ) {
if ( ! object.__webglMorphTargetInfluences ) {
object.__webglMorphTargetInfluences = new Float32Array( _this.maxMorphTargets );
}
}
var refreshMaterial = false;
var program = material.program,
p_uniforms = program.uniforms,
m_uniforms = material.uniforms;
if ( program !== _currentProgram ) {
renderer.useProgram( program );
_currentProgram = program;
refreshMaterial = true;
}
if ( material.id !== _currentMaterialId ) {
_currentMaterialId = material.id;
refreshMaterial = true;
}
if ( refreshMaterial || camera !== _currentCamera ) {
renderer.uniformMatrix4fv( p_uniforms.projectionMatrix, camera.projectionMatrix.elements );
if ( camera !== _currentCamera ) _currentCamera = camera;
}
// skinning uniforms must be set even if material didn't change
// auto-setting of texture unit for bone texture must go before other textures
// not sure why, but otherwise weird things happen
if ( material.skinning ) {
if ( renderer.supportsBoneTextures && object.useVertexTexture ) {
if ( p_uniforms.boneTexture !== null ) {
var textureUnit = getTextureUnit();
renderer.uniform1i( p_uniforms.boneTexture, textureUnit );
renderer.setTexture( object.boneTexture, textureUnit );
}
} else {
if ( p_uniforms.boneGlobalMatrices !== null ) {
renderer.uniformMatrix4fv( p_uniforms.boneGlobalMatrices, object.boneMatrices );
}
}
}
if ( refreshMaterial ) {
// refresh uniforms common to several materials
if ( fog && material.fog ) {
refreshUniformsFog( m_uniforms, fog );
}
if ( material instanceof THREE.MeshPhongMaterial ||
material instanceof THREE.MeshLambertMaterial ||
material.lights ) {
if ( _lightsNeedUpdate ) {
setupLights( program, lights );
_lightsNeedUpdate = false;
}
refreshUniformsLights( m_uniforms, _lights );
}
if ( material instanceof THREE.MeshBasicMaterial ||
material instanceof THREE.MeshLambertMaterial ||
material instanceof THREE.MeshPhongMaterial ) {
refreshUniformsCommon( m_uniforms, material );
}
// refresh single material specific uniforms
if ( material instanceof THREE.LineBasicMaterial ) {
refreshUniformsLine( m_uniforms, material );
} else if ( material instanceof THREE.LineDashedMaterial ) {
refreshUniformsLine( m_uniforms, material );
refreshUniformsDash( m_uniforms, material );
} else if ( material instanceof THREE.ParticleBasicMaterial ) {
refreshUniformsParticle( m_uniforms, material );
} else if ( material instanceof THREE.MeshPhongMaterial ) {
refreshUniformsPhong( m_uniforms, material );
} else if ( material instanceof THREE.MeshLambertMaterial ) {
refreshUniformsLambert( m_uniforms, material );
} else if ( material instanceof THREE.MeshDepthMaterial ) {
m_uniforms.mNear.value = camera.near;
m_uniforms.mFar.value = camera.far;
m_uniforms.opacity.value = material.opacity;
} else if ( material instanceof THREE.MeshNormalMaterial ) {
m_uniforms.opacity.value = material.opacity;
}
if ( object.receiveShadow && ! material._shadowPass ) {
refreshUniformsShadow( m_uniforms, lights );
}
// load common uniforms
loadUniformsGeneric( program, material.uniformsList );
// load material specific uniforms
// (shader material also gets them for the sake of genericity)
if ( material instanceof THREE.ShaderMaterial ||
material instanceof THREE.MeshPhongMaterial ||
material.envMap ) {
if ( p_uniforms.cameraPosition !== null ) {
var position = camera.matrixWorld.getPosition();
renderer.uniform3f( p_uniforms.cameraPosition, position.x, position.y, position.z );
}
}
if ( material instanceof THREE.MeshPhongMaterial ||
material instanceof THREE.MeshLambertMaterial ||
material instanceof THREE.ShaderMaterial ||
material.skinning ) {
if ( p_uniforms.viewMatrix !== null ) {
renderer.uniformMatrix4fv( p_uniforms.viewMatrix, camera.matrixWorldInverse.elements );
}
}
}
loadUniformsMatrices( p_uniforms, object );
if ( p_uniforms.modelMatrix !== null ) {
renderer.uniformMatrix4fv( p_uniforms.modelMatrix, object.matrixWorld.elements );
}
return program;
};
// Uniforms (refresh uniforms objects)
function refreshUniformsCommon ( uniforms, material ) {
uniforms.opacity.value = material.opacity;
if ( _this.gammaInput ) {
uniforms.diffuse.value.copyGammaToLinear( material.color );
} else {
uniforms.diffuse.value = material.color;
}
uniforms.map.value = material.map;
uniforms.lightMap.value = material.lightMap;
uniforms.specularMap.value = material.specularMap;
if ( material.bumpMap ) {
uniforms.bumpMap.value = material.bumpMap;
uniforms.bumpScale.value = material.bumpScale;
}
if ( material.normalMap ) {
uniforms.normalMap.value = material.normalMap;
uniforms.normalScale.value.copy( material.normalScale );
}
// uv repeat and offset setting priorities
// 1. color map
// 2. specular map
// 3. normal map
// 4. bump map
var uvScaleMap;
if ( material.map ) {
uvScaleMap = material.map;
} else if ( material.specularMap ) {
uvScaleMap = material.specularMap;
} else if ( material.normalMap ) {
uvScaleMap = material.normalMap;
} else if ( material.bumpMap ) {
uvScaleMap = material.bumpMap;
}
if ( uvScaleMap !== undefined ) {
var offset = uvScaleMap.offset;
var repeat = uvScaleMap.repeat;
uniforms.offsetRepeat.value.set( offset.x, offset.y, repeat.x, repeat.y );
}
uniforms.envMap.value = material.envMap;
uniforms.flipEnvMap.value = ( material.envMap instanceof THREE.WebGLRenderTargetCube ) ? 1 : -1;
if ( _this.gammaInput ) {
//uniforms.reflectivity.value = material.reflectivity * material.reflectivity;
uniforms.reflectivity.value = material.reflectivity;
} else {
uniforms.reflectivity.value = material.reflectivity;
}
uniforms.refractionRatio.value = material.refractionRatio;
uniforms.combine.value = material.combine;
uniforms.useRefract.value = material.envMap && material.envMap.mapping instanceof THREE.CubeRefractionMapping;
};
function refreshUniformsLine ( uniforms, material ) {
uniforms.diffuse.value = material.color;
uniforms.opacity.value = material.opacity;
};
function refreshUniformsDash ( uniforms, material ) {
uniforms.dashSize.value = material.dashSize;
uniforms.totalSize.value = material.dashSize + material.gapSize;
uniforms.scale.value = material.scale;
};
function refreshUniformsParticle ( uniforms, material ) {
uniforms.psColor.value = material.color;
uniforms.opacity.value = material.opacity;
uniforms.size.value = material.size;
uniforms.scale.value = renderer.getDomElement().height / 2.0; // TODO: Cache this.
uniforms.map.value = material.map;
};
function refreshUniformsFog ( uniforms, fog ) {
uniforms.fogColor.value = fog.color;
if ( fog instanceof THREE.Fog ) {
uniforms.fogNear.value = fog.near;
uniforms.fogFar.value = fog.far;
} else if ( fog instanceof THREE.FogExp2 ) {
uniforms.fogDensity.value = fog.density;
}
};
function refreshUniformsPhong ( uniforms, material ) {
uniforms.shininess.value = material.shininess;
if ( _this.gammaInput ) {
uniforms.ambient.value.copyGammaToLinear( material.ambient );
uniforms.emissive.value.copyGammaToLinear( material.emissive );
uniforms.specular.value.copyGammaToLinear( material.specular );
} else {
uniforms.ambient.value = material.ambient;
uniforms.emissive.value = material.emissive;
uniforms.specular.value = material.specular;
}
if ( material.wrapAround ) {
uniforms.wrapRGB.value.copy( material.wrapRGB );
}
};
function refreshUniformsLambert ( uniforms, material ) {
if ( _this.gammaInput ) {
uniforms.ambient.value.copyGammaToLinear( material.ambient );
uniforms.emissive.value.copyGammaToLinear( material.emissive );
} else {
uniforms.ambient.value = material.ambient;
uniforms.emissive.value = material.emissive;
}
if ( material.wrapAround ) {
uniforms.wrapRGB.value.copy( material.wrapRGB );
}
};
function refreshUniformsLights ( uniforms, lights ) {
uniforms.ambientLightColor.value = lights.ambient;
uniforms.directionalLightColor.value = lights.directional.colors;
uniforms.directionalLightDirection.value = lights.directional.positions;
uniforms.pointLightColor.value = lights.point.colors;
uniforms.pointLightPosition.value = lights.point.positions;
uniforms.pointLightDistance.value = lights.point.distances;
uniforms.spotLightColor.value = lights.spot.colors;
uniforms.spotLightPosition.value = lights.spot.positions;
uniforms.spotLightDistance.value = lights.spot.distances;
uniforms.spotLightDirection.value = lights.spot.directions;
uniforms.spotLightAngleCos.value = lights.spot.anglesCos;
uniforms.spotLightExponent.value = lights.spot.exponents;
uniforms.hemisphereLightSkyColor.value = lights.hemi.skyColors;
uniforms.hemisphereLightGroundColor.value = lights.hemi.groundColors;
uniforms.hemisphereLightDirection.value = lights.hemi.positions;
};
function refreshUniformsShadow ( uniforms, lights ) {
if ( uniforms.shadowMatrix ) {
var j = 0;
for ( var i = 0, il = lights.length; i < il; i ++ ) {
var light = lights[ i ];
if ( ! light.castShadow ) continue;
if ( light instanceof THREE.SpotLight || ( light instanceof THREE.DirectionalLight && ! light.shadowCascade ) ) {
uniforms.shadowMap.value[ j ] = light.shadowMap;
uniforms.shadowMapSize.value[ j ] = light.shadowMapSize;
uniforms.shadowMatrix.value[ j ] = light.shadowMatrix;
uniforms.shadowDarkness.value[ j ] = light.shadowDarkness;
uniforms.shadowBias.value[ j ] = light.shadowBias;
j ++;
}
}
}
};
// Uniforms (load to GPU)
function loadUniformsMatrices ( uniforms, object ) {
renderer.uniformMatrix4fv( uniforms.modelViewMatrix, object._modelViewMatrix.elements );
if ( uniforms.normalMatrix ) {
renderer.uniformMatrix3fv( uniforms.normalMatrix, object._normalMatrix.elements );
}
};
function getTextureUnit() {
var textureUnit = _usedTextureUnits;
if ( textureUnit >= renderer.maxTextures ) {
console.warn( "WebGLRenderer: trying to use " + textureUnit + " texture units while this GPU supports only " + renderer.maxTextures );
}
_usedTextureUnits += 1;
return textureUnit;
};
function loadUniformsGeneric ( program, uniforms ) {
var uniform, value, type, location, texture, textureUnit, i, il, j, jl, offset;
for ( j = 0, jl = uniforms.length; j < jl; j ++ ) {
location = program.uniforms[ uniforms[ j ][ 1 ] ];
if ( !location ) continue;
uniform = uniforms[ j ][ 0 ];
type = uniform.type;
value = uniform.value;
if ( type === "i" ) { // single integer
renderer.uniform1i( location, value );
} else if ( type === "f" ) { // single float
renderer.uniform1f( location, value );
} else if ( type === "v2" ) { // single THREE.Vector2
renderer.uniform2f( location, value.x, value.y );
} else if ( type === "v3" ) { // single THREE.Vector3
renderer.uniform3f( location, value.x, value.y, value.z );
} else if ( type === "v4" ) { // single THREE.Vector4
renderer.uniform4f( location, value.x, value.y, value.z, value.w );
} else if ( type === "c" ) { // single THREE.Color
renderer.uniform3f( location, value.r, value.g, value.b );
} else if ( type === "iv1" ) { // flat array of integers (JS or typed array)
renderer.uniform1iv( location, value );
} else if ( type === "iv" ) { // flat array of integers with 3 x N size (JS or typed array)
renderer.uniform3iv( location, value );
} else if ( type === "fv1" ) { // flat array of floats (JS or typed array)
renderer.uniform1fv( location, value );
} else if ( type === "fv" ) { // flat array of floats with 3 x N size (JS or typed array)
renderer.uniform3fv( location, value );
} else if ( type === "v2v" ) { // array of THREE.Vector2
if ( uniform._array === undefined ) {
uniform._array = new Float32Array( 2 * value.length );
}
for ( i = 0, il = value.length; i < il; i ++ ) {
offset = i * 2;
uniform._array[ offset ] = value[ i ].x;
uniform._array[ offset + 1 ] = value[ i ].y;
}
renderer.uniform2fv( location, uniform._array );
} else if ( type === "v3v" ) { // array of THREE.Vector3
if ( uniform._array === undefined ) {
uniform._array = new Float32Array( 3 * value.length );
}
for ( i = 0, il = value.length; i < il; i ++ ) {
offset = i * 3;
uniform._array[ offset ] = value[ i ].x;
uniform._array[ offset + 1 ] = value[ i ].y;
uniform._array[ offset + 2 ] = value[ i ].z;
}
renderer.uniform3fv( location, uniform._array );
} else if ( type === "v4v" ) { // array of THREE.Vector4
if ( uniform._array === undefined ) {
uniform._array = new Float32Array( 4 * value.length );
}
for ( i = 0, il = value.length; i < il; i ++ ) {
offset = i * 4;
uniform._array[ offset ] = value[ i ].x;
uniform._array[ offset + 1 ] = value[ i ].y;
uniform._array[ offset + 2 ] = value[ i ].z;
uniform._array[ offset + 3 ] = value[ i ].w;
}
renderer.uniform4fv( location, uniform._array );
} else if ( type === "m4") { // single THREE.Matrix4
if ( uniform._array === undefined ) {
uniform._array = new Float32Array( 16 );
}
value.flattenToArray( uniform._array );
renderer.uniformMatrix4fv( location, uniform._array );
} else if ( type === "m4v" ) { // array of THREE.Matrix4
if ( uniform._array === undefined ) {
uniform._array = new Float32Array( 16 * value.length );
}
for ( i = 0, il = value.length; i < il; i ++ ) {
value[ i ].flattenToArrayOffset( uniform._array, i * 16 );
}
renderer.uniformMatrix4fv( location, uniform._array );
} else if ( type === "t" ) { // single THREE.Texture (2d or cube)
texture = value;
textureUnit = getTextureUnit();
renderer.uniform1i( location, textureUnit );
if ( !texture ) continue;
if ( texture.image instanceof Array && texture.image.length === 6 ) {
renderer.setCubeTexture( texture, textureUnit );
} else if ( texture instanceof THREE.WebGLRenderTargetCube ) {
renderer.setCubeTextureDynamic( texture, textureUnit );
} else {
renderer.setTexture( texture, textureUnit );
}
} else if ( type === "tv" ) { // array of THREE.Texture (2d)
if ( uniform._array === undefined ) {
uniform._array = [];
}
for( i = 0, il = uniform.value.length; i < il; i ++ ) {
uniform._array[ i ] = getTextureUnit();
}
renderer.uniform1iv( location, uniform._array );
for( i = 0, il = uniform.value.length; i < il; i ++ ) {
texture = uniform.value[ i ];
textureUnit = uniform._array[ i ];
if ( !texture ) continue;
renderer.setTexture( texture, textureUnit );
}
}
}
};
function setupMatrices ( object, camera ) {
object._modelViewMatrix.multiply( camera.matrixWorldInverse, object.matrixWorld );
object._normalMatrix.getInverse( object._modelViewMatrix );
object._normalMatrix.transpose();
};
//
function setColorGamma( array, offset, color, intensitySq ) {
array[ offset ] = color.r * color.r * intensitySq;
array[ offset + 1 ] = color.g * color.g * intensitySq;
array[ offset + 2 ] = color.b * color.b * intensitySq;
};
function setColorLinear( array, offset, color, intensity ) {
array[ offset ] = color.r * intensity;
array[ offset + 1 ] = color.g * intensity;
array[ offset + 2 ] = color.b * intensity;
};
function setupLights ( program, lights ) {
var l, ll, light, n,
r = 0, g = 0, b = 0,
color, skyColor, groundColor,
intensity, intensitySq,
position,
distance,
zlights = _lights,
dirColors = zlights.directional.colors,
dirPositions = zlights.directional.positions,
pointColors = zlights.point.colors,
pointPositions = zlights.point.positions,
pointDistances = zlights.point.distances,
spotColors = zlights.spot.colors,
spotPositions = zlights.spot.positions,
spotDistances = zlights.spot.distances,
spotDirections = zlights.spot.directions,
spotAnglesCos = zlights.spot.anglesCos,
spotExponents = zlights.spot.exponents,
hemiSkyColors = zlights.hemi.skyColors,
hemiGroundColors = zlights.hemi.groundColors,
hemiPositions = zlights.hemi.positions,
dirLength = 0,
pointLength = 0,
spotLength = 0,
hemiLength = 0,
dirCount = 0,
pointCount = 0,
spotCount = 0,
hemiCount = 0,
dirOffset = 0,
pointOffset = 0,
spotOffset = 0,
hemiOffset = 0;
for ( l = 0, ll = lights.length; l < ll; l ++ ) {
light = lights[ l ];
if ( light.onlyShadow ) continue;
color = light.color;
intensity = light.intensity;
distance = light.distance;
if ( light instanceof THREE.AmbientLight ) {
if ( ! light.visible ) continue;
if ( _this.gammaInput ) {
r += color.r * color.r;
g += color.g * color.g;
b += color.b * color.b;
} else {
r += color.r;
g += color.g;
b += color.b;
}
} else if ( light instanceof THREE.DirectionalLight ) {
dirCount += 1;
if ( ! light.visible ) continue;
_direction.copy( light.matrixWorld.getPosition() );
_direction.subSelf( light.target.matrixWorld.getPosition() );
_direction.normalize();
// skip lights with undefined direction
// these create troubles in OpenGL (making pixel black)
if ( _direction.x === 0 && _direction.y === 0 && _direction.z === 0 ) continue;
dirOffset = dirLength * 3;
dirPositions[ dirOffset ] = _direction.x;
dirPositions[ dirOffset + 1 ] = _direction.y;
dirPositions[ dirOffset + 2 ] = _direction.z;
if ( _this.gammaInput ) {
setColorGamma( dirColors, dirOffset, color, intensity * intensity );
} else {
setColorLinear( dirColors, dirOffset, color, intensity );
}
dirLength += 1;
} else if ( light instanceof THREE.PointLight ) {
pointCount += 1;
if ( ! light.visible ) continue;
pointOffset = pointLength * 3;
if ( _this.gammaInput ) {
setColorGamma( pointColors, pointOffset, color, intensity * intensity );
} else {
setColorLinear( pointColors, pointOffset, color, intensity );
}
position = light.matrixWorld.getPosition();
pointPositions[ pointOffset ] = position.x;
pointPositions[ pointOffset + 1 ] = position.y;
pointPositions[ pointOffset + 2 ] = position.z;
pointDistances[ pointLength ] = distance;
pointLength += 1;
} else if ( light instanceof THREE.SpotLight ) {
spotCount += 1;
if ( ! light.visible ) continue;
spotOffset = spotLength * 3;
if ( _this.gammaInput ) {
setColorGamma( spotColors, spotOffset, color, intensity * intensity );
} else {
setColorLinear( spotColors, spotOffset, color, intensity );
}
position = light.matrixWorld.getPosition();
spotPositions[ spotOffset ] = position.x;
spotPositions[ spotOffset + 1 ] = position.y;
spotPositions[ spotOffset + 2 ] = position.z;
spotDistances[ spotLength ] = distance;
_direction.copy( position );
_direction.subSelf( light.target.matrixWorld.getPosition() );
_direction.normalize();
spotDirections[ spotOffset ] = _direction.x;
spotDirections[ spotOffset + 1 ] = _direction.y;
spotDirections[ spotOffset + 2 ] = _direction.z;
spotAnglesCos[ spotLength ] = Math.cos( light.angle );
spotExponents[ spotLength ] = light.exponent;
spotLength += 1;
} else if ( light instanceof THREE.HemisphereLight ) {
hemiCount += 1;
if ( ! light.visible ) continue;
_direction.copy( light.matrixWorld.getPosition() );
_direction.normalize();
// skip lights with undefined direction
// these create troubles in OpenGL (making pixel black)
if ( _direction.x === 0 && _direction.y === 0 && _direction.z === 0 ) continue;
hemiOffset = hemiLength * 3;
hemiPositions[ hemiOffset ] = _direction.x;
hemiPositions[ hemiOffset + 1 ] = _direction.y;
hemiPositions[ hemiOffset + 2 ] = _direction.z;
skyColor = light.color;
groundColor = light.groundColor;
if ( _this.gammaInput ) {
intensitySq = intensity * intensity;
setColorGamma( hemiSkyColors, hemiOffset, skyColor, intensitySq );
setColorGamma( hemiGroundColors, hemiOffset, groundColor, intensitySq );
} else {
setColorLinear( hemiSkyColors, hemiOffset, skyColor, intensity );
setColorLinear( hemiGroundColors, hemiOffset, groundColor, intensity );
}
hemiLength += 1;
}
}
// null eventual remains from removed lights
// (this is to avoid if in shader)
for ( l = dirLength * 3, ll = Math.max( dirColors.length, dirCount * 3 ); l < ll; l ++ ) dirColors[ l ] = 0.0;
for ( l = pointLength * 3, ll = Math.max( pointColors.length, pointCount * 3 ); l < ll; l ++ ) pointColors[ l ] = 0.0;
for ( l = spotLength * 3, ll = Math.max( spotColors.length, spotCount * 3 ); l < ll; l ++ ) spotColors[ l ] = 0.0;
for ( l = hemiLength * 3, ll = Math.max( hemiSkyColors.length, hemiCount * 3 ); l < ll; l ++ ) hemiSkyColors[ l ] = 0.0;
for ( l = hemiLength * 3, ll = Math.max( hemiGroundColors.length, hemiCount * 3 ); l < ll; l ++ ) hemiGroundColors[ l ] = 0.0;
zlights.directional.length = dirLength;
zlights.point.length = pointLength;
zlights.spot.length = spotLength;
zlights.hemi.length = hemiLength;
zlights.ambient[ 0 ] = r;
zlights.ambient[ 1 ] = g;
zlights.ambient[ 2 ] = b;
};
// Allocations
function allocateBones ( object ) {
if ( renderer.supportsBoneTextures && object && object.useVertexTexture ) {
return 1024;
} else {
// default for when object is not specified
// ( for example when prebuilding shader
// to be used with multiple objects )
//
// - leave some extra space for other uniforms
// - limit here is ANGLE's 254 max uniform vectors
// (up to 54 should be safe)
var nVertexUniforms = renderer.maxVertexUniformVectors
var nVertexMatrices = Math.floor( ( nVertexUniforms - 20 ) / 4 );
var maxBones = nVertexMatrices;
if ( object !== undefined && object instanceof THREE.SkinnedMesh ) {
maxBones = Math.min( object.bones.length, maxBones );
if ( maxBones < object.bones.length ) {
console.warn( "WebGLRenderer: too many bones - " + object.bones.length + ", this GPU supports just " + maxBones + " (try OpenGL instead of ANGLE)" );
}
}
return maxBones;
}
};
function allocateLights ( lights ) {
var l, ll, light, dirLights, pointLights, spotLights, hemiLights;
dirLights = pointLights = spotLights = hemiLights = 0;
for ( l = 0, ll = lights.length; l < ll; l ++ ) {
light = lights[ l ];
if ( light.onlyShadow ) continue;
if ( light instanceof THREE.DirectionalLight ) dirLights ++;
if ( light instanceof THREE.PointLight ) pointLights ++;
if ( light instanceof THREE.SpotLight ) spotLights ++;
if ( light instanceof THREE.HemisphereLight ) hemiLights ++;
}
return { 'directional' : dirLights, 'point' : pointLights, 'spot': spotLights, 'hemi': hemiLights };
};
function allocateShadows ( lights ) {
var l, ll, light, maxShadows = 0;
for ( l = 0, ll = lights.length; l < ll; l++ ) {
light = lights[ l ];
if ( ! light.castShadow ) continue;
if ( light instanceof THREE.SpotLight ) maxShadows ++;
if ( light instanceof THREE.DirectionalLight && ! light.shadowCascade ) maxShadows ++;
}
return maxShadows;
};
// default plugins (order is important)
this.shadowMapPlugin = new THREE.ShadowMapPlugin();
this.addPrePlugin( this.shadowMapPlugin );
this.addPostPlugin( new THREE.SpritePlugin() );
this.addPostPlugin( new THREE.LensFlarePlugin() );
};
/*global THREE:false */
THREE.WebGLRenderer2.LowLevelRenderer = function(parameters){
parameters = parameters || {};
var _canvas = parameters.canvas !== undefined ? parameters.canvas : document.createElement( 'canvas' ),
_precision = parameters.precision !== undefined ? parameters.precision : 'highp',
_alpha = parameters.alpha !== undefined ? parameters.alpha : true,
_premultipliedAlpha = parameters.premultipliedAlpha !== undefined ? parameters.premultipliedAlpha : true,
_antialias = parameters.antialias !== undefined ? parameters.antialias : false,
_stencil = parameters.stencil !== undefined ? parameters.stencil : true,
_preserveDrawingBuffer = parameters.preserveDrawingBuffer !== undefined ? parameters.preserveDrawingBuffer : false,
_clearColor = parameters.clearColor !== undefined ? new THREE.Color( parameters.clearColor ) : new THREE.Color( 0x000000 ),
_clearAlpha = parameters.clearAlpha !== undefined ? parameters.clearAlpha : 0,
_autoScaleCubemaps = true;
this.devicePixelRatio = parameters.devicePixelRatio !== undefined ? parameters.devicePixelRatio : window.devicePixelRatio !== undefined ? window.devicePixelRatio : 1;
var _currentWidth = 0,
_currentHeight = 0;
var _gl;
var _glExtensionTextureFloat;
var _glExtensionStandardDerivatives;
var _glExtensionTextureFilterAnisotropic;
var _glExtensionCompressedTextureS3TC;
initGL();
setDefaultGLState();
var _maxTextures = _gl.getParameter( _gl.MAX_TEXTURE_IMAGE_UNITS );
var _maxVertexTextures = _gl.getParameter( _gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS );
var _maxTextureSize = _gl.getParameter( _gl.MAX_TEXTURE_SIZE );
var _maxCubemapSize = _gl.getParameter( _gl.MAX_CUBE_MAP_TEXTURE_SIZE );
var _maxAnisotropy = _glExtensionTextureFilterAnisotropic ? _gl.getParameter( _glExtensionTextureFilterAnisotropic.MAX_TEXTURE_MAX_ANISOTROPY_EXT ) : 0;
var _supportsVertexTextures = ( _maxVertexTextures > 0 );
var _supportsBoneTextures = _supportsVertexTextures && _glExtensionTextureFloat;
var _compressedTextureFormats = _glExtensionCompressedTextureS3TC ? _gl.getParameter( _gl.COMPRESSED_TEXTURE_FORMATS ) : [];
var _vertexShaderPrecisionHighpFloat = _gl.getShaderPrecisionFormat( _gl.VERTEX_SHADER, _gl.HIGH_FLOAT );
var _vertexShaderPrecisionMediumpFloat = _gl.getShaderPrecisionFormat( _gl.VERTEX_SHADER, _gl.MEDIUM_FLOAT );
var _vertexShaderPrecisionLowpFloat = _gl.getShaderPrecisionFormat( _gl.VERTEX_SHADER, _gl.LOW_FLOAT );
var _fragmentShaderPrecisionHighpFloat = _gl.getShaderPrecisionFormat( _gl.FRAGMENT_SHADER, _gl.HIGH_FLOAT );
var _fragmentShaderPrecisionMediumpFloat = _gl.getShaderPrecisionFormat( _gl.FRAGMENT_SHADER, _gl.MEDIUM_FLOAT );
var _fragmentShaderPrecisionLowpFloat = _gl.getShaderPrecisionFormat( _gl.FRAGMENT_SHADER, _gl.LOW_FLOAT );
var _vertexShaderPrecisionHighpInt = _gl.getShaderPrecisionFormat( _gl.VERTEX_SHADER, _gl.HIGH_INT );
var _vertexShaderPrecisionMediumpInt = _gl.getShaderPrecisionFormat( _gl.VERTEX_SHADER, _gl.MEDIUM_INT );
var _vertexShaderPrecisionLowpInt = _gl.getShaderPrecisionFormat( _gl.VERTEX_SHADER, _gl.LOW_INT );
var _fragmentShaderPrecisionHighpInt = _gl.getShaderPrecisionFormat( _gl.FRAGMENT_SHADER, _gl.HIGH_INT );
var _fragmentShaderPrecisionMediumpInt = _gl.getShaderPrecisionFormat( _gl.FRAGMENT_SHADER, _gl.MEDIUM_INT );
var _fragmentShaderPrecisionLowpInt = _gl.getShaderPrecisionFormat( _gl.FRAGMENT_SHADER, _gl.LOW_INT );
// clamp precision to maximum available
var highpAvailable = _vertexShaderPrecisionHighpFloat.precision > 0 && _fragmentShaderPrecisionHighpFloat.precision > 0;
var mediumpAvailable = _vertexShaderPrecisionMediumpFloat.precision > 0 && _fragmentShaderPrecisionMediumpFloat.precision > 0;
if ( _precision === "highp" && ! highpAvailable ) {
if ( mediumpAvailable ) {
_precision = "mediump";
console.warn( "WebGLRenderer: highp not supported, using mediump" );
} else {
_precision = "lowp";
console.warn( "WebGLRenderer: highp and mediump not supported, using lowp" );
}
}
if ( _precision === "mediump" && ! mediumpAvailable ) {
_precision = "lowp";
console.warn( "WebGLRenderer: mediump not supported, using lowp" );
}
var _enabledAttributes = {},
_oldBlending,
_oldBlendEquation,
_oldBlendSrc,
_oldBlendDst,
_oldDoubleSided = -1,
_oldFlipSided = -1,
_oldDepthTest = -1,
_oldDepthWrite = -1,
_oldLineWidth = -1,
_viewportX = 0,
_viewportY = 0,
_viewportWidth = 0,
_viewportHeight = 0,
// GL state cache
_oldPolygonOffset = null,
_oldPolygonOffsetFactor = null,
_oldPolygonOffsetUnits = null,
_currentFramebuffer = null;
function initGL () {
try {
if ( ! ( _gl = _canvas.getContext( 'experimental-webgl', { alpha: _alpha, premultipliedAlpha: _premultipliedAlpha, antialias: _antialias, stencil: _stencil, preserveDrawingBuffer: _preserveDrawingBuffer } ) ) ) {
throw 'Error creating WebGL context.';
}
} catch ( error ) {
console.error( error );
}
_glExtensionTextureFloat = _gl.getExtension( 'OES_texture_float' );
_glExtensionStandardDerivatives = _gl.getExtension( 'OES_standard_derivatives' );
_glExtensionTextureFilterAnisotropic = _gl.getExtension( 'EXT_texture_filter_anisotropic' ) ||
_gl.getExtension( 'MOZ_EXT_texture_filter_anisotropic' ) ||
_gl.getExtension( 'WEBKIT_EXT_texture_filter_anisotropic' );
_glExtensionCompressedTextureS3TC = _gl.getExtension( 'WEBGL_compressed_texture_s3tc' ) ||
_gl.getExtension( 'MOZ_WEBGL_compressed_texture_s3tc' ) ||
_gl.getExtension( 'WEBKIT_WEBGL_compressed_texture_s3tc' );
if ( ! _glExtensionTextureFloat ) {
console.log( 'THREE.WebGLRenderer: Float textures not supported.' );
}
if ( ! _glExtensionStandardDerivatives ) {
console.log( 'THREE.WebGLRenderer: Standard derivatives not supported.' );
}
if ( ! _glExtensionTextureFilterAnisotropic ) {
console.log( 'THREE.WebGLRenderer: Anisotropic texture filtering not supported.' );
}
if ( ! _glExtensionCompressedTextureS3TC ) {
console.log( 'THREE.WebGLRenderer: S3TC compressed textures not supported.' );
}
};
function setDefaultGLState () {
_gl.clearColor( 0, 0, 0, 1 );
_gl.clearDepth( 1 );
_gl.clearStencil( 0 );
_gl.enable( _gl.DEPTH_TEST );
_gl.depthFunc( _gl.LEQUAL );
_gl.frontFace( _gl.CCW );
_gl.cullFace( _gl.BACK );
_gl.enable( _gl.CULL_FACE );
_gl.enable( _gl.BLEND );
_gl.blendEquation( _gl.FUNC_ADD );
_gl.blendFunc( _gl.SRC_ALPHA, _gl.ONE_MINUS_SRC_ALPHA );
_gl.clearColor( _clearColor.r, _clearColor.g, _clearColor.b, _clearAlpha );
};
// Fallback filters for non-power-of-2 textures
function filterFallback ( f ) {
if ( f === THREE.NearestFilter || f === THREE.NearestMipMapNearestFilter || f === THREE.NearestMipMapLinearFilter ) {
return _gl.NEAREST;
}
return _gl.LINEAR;
};
function getContext() {
return _gl;
};
function getDomElement(){
return _canvas;
};
function getPrecision() {
return _precision;
};
function getCurrentWidth(){
return _currentWidth;
};
function getCurrentHeight(){
return _currentHeight;
};
function supportsVertexTextures() {
return _supportsVertexTextures;
};
function getMaxAnisotropy() {
return _maxAnisotropy;
};
function setSize( width, height ) {
_canvas.width = width;
_canvas.height = height;
setViewport( 0, 0, _canvas.width, _canvas.height );
};
function setViewport( x, y, width, height ) {
_viewportX = x !== undefined ? x : 0;
_viewportY = y !== undefined ? y : 0;
_viewportWidth = width !== undefined ? width : _canvas.width;
_viewportHeight = height !== undefined ? height : _canvas.height;
_gl.viewport( _viewportX, _viewportY, _viewportWidth, _viewportHeight );
};
function setScissor( x, y, width, height ) {
_gl.scissor( x, y, width, height );
};
function enableScissorTest( enable ) {
enable ? _gl.enable( _gl.SCISSOR_TEST ) : _gl.disable( _gl.SCISSOR_TEST );
};
// Clearing
function setClearColorHex( hex, alpha ) {
_clearColor.setHex( hex );
_clearAlpha = alpha;
_gl.clearColor( _clearColor.r, _clearColor.g, _clearColor.b, _clearAlpha );
};
function setClearColor( color, alpha ) {
_clearColor.copy( color );
_clearAlpha = alpha;
_gl.clearColor( _clearColor.r, _clearColor.g, _clearColor.b, _clearAlpha );
};
function getClearColor() {
return _clearColor;
};
function getClearAlpha() {
return _clearAlpha;
};
function clear( color, depth, stencil ) {
var bits = 0;
if ( color === undefined || color ) bits |= _gl.COLOR_BUFFER_BIT;
if ( depth === undefined || depth ) bits |= _gl.DEPTH_BUFFER_BIT;
if ( stencil === undefined || stencil ) bits |= _gl.STENCIL_BUFFER_BIT;
_gl.clear( bits );
};
function clearTarget( renderTarget, color, depth, stencil ) {
setRenderTarget( renderTarget );
clear( color, depth, stencil );
};
function deleteBuffer(buffer){
_gl.deleteBuffer(buffer);
};
function deleteTexture(texture){
_gl.deleteTexture( texture );
};
function deleteFramebuffer(Framebuffer){
_gl.deleteFramebuffer(Framebuffer);
};
function deleteRenderbuffer(RenderBuffer){
_gl.deleteRenderbuffer(RenderBuffer);
};
function deleteProgram(RenderBuffer){
_gl.deleteProgram(RenderBuffer);
};
function createBuffer(){
return _gl.createBuffer();
};
function setStaticArrayBuffer(buffer,data){
bindArrayBuffer( buffer );
_gl.bufferData( _gl.ARRAY_BUFFER, data, _gl.STATIC_DRAW );
};
function setStaticIndexBuffer(buffer,data){
bindElementArrayBuffer( buffer );
_gl.bufferData( _gl.ELEMENT_ARRAY_BUFFER, data, _gl.STATIC_DRAW );
};
function setDynamicArrayBuffer(buffer,data){
bindArrayBuffer( buffer );
_gl.bufferData( _gl.ARRAY_BUFFER, data, _gl.DYNAMIC_DRAW );
};
function setDynamicIndexBuffer(buffer,data){
bindElementArrayBuffer( buffer );
_gl.bufferData( _gl.ELEMENT_ARRAY_BUFFER, data, _gl.DYNAMIC_DRAW );
};
function drawTriangles(count){
_gl.drawArrays( _gl.TRIANGLES, 0, count );
};
function drawTriangleStrip(count){
_gl.drawArrays( _gl.TRIANGLE_STRIP, 0, count );
};
function drawLines(count){
_gl.drawArrays( _gl.LINES, 0, count );
};
function drawLineStrip(count){
_gl.drawArrays( _gl.LINE_STRIP, 0, count );
};
function drawPoints(count){
_gl.drawArrays( _gl.POINTS, 0, count );
};
function drawTriangleElements(buffer,count,offset){
bindElementArrayBuffer( buffer );
_gl.drawElements( _gl.TRIANGLES, count, _gl.UNSIGNED_SHORT, offset ); // 2 bytes per Uint16
};
function drawLineElements(buffer,count,offset){
bindElementArrayBuffer( buffer );
_gl.drawElements( _gl.LINES, count, _gl.UNSIGNED_SHORT, offset ); // 2 bytes per Uint16
};
var _boundBuffer;
function bindArrayBuffer(buffer){
if (_boundBuffer != buffer){
_gl.bindBuffer( _gl.ARRAY_BUFFER, buffer );
_boundBuffer = buffer;
}
};
function bindElementArrayBuffer(buffer){
if (_boundBuffer != buffer){
_gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, buffer );
_boundBuffer = buffer;
}
};
function enableAttribute( attribute ) {
if ( ! _enabledAttributes[ attribute ] ) {
_gl.enableVertexAttribArray( attribute );
_enabledAttributes[ attribute ] = true;
}
};
function disableAttributes() {
for ( var attribute in _enabledAttributes ) {
if ( _enabledAttributes[ attribute ] ) {
_gl.disableVertexAttribArray( attribute );
_enabledAttributes[ attribute ] = false;
}
}
};
function getAttribLocation( program, id ){
return _gl.getAttribLocation( program, id );
}
function setFloatAttribute(index,buffer,size,offset){
bindArrayBuffer( buffer );
enableAttribute( index );
_gl.vertexAttribPointer( index, size, _gl.FLOAT, false, 0, offset );
};
function getUniformLocation( program, id ){
return _gl.getUniformLocation( program, id );
}
function uniform1i(uniform,value){
_gl.uniform1i( uniform, value );
};
function uniform1f(uniform,value){
_gl.uniform1f( uniform, value );
};
function uniform2f(uniform,value1, value2){
_gl.uniform2f( uniform, value1, value2 );
};
function uniform3f(uniform, value1, value2, value3){
_gl.uniform3f( uniform, value1, value2, value3 );
};
function uniform4f(uniform, value1, value2, value3, value4){
_gl.uniform4f( uniform, value1, value2, value3, value4);
};
function uniform1iv(uniform,value){
_gl.uniform1iv( uniform, value );
};
function uniform2iv(uniform,value){
_gl.uniform2iv( uniform, value );
};
function uniform3iv(uniform,value){
_gl.uniform3iv( uniform, value );
};
function uniform1fv(uniform,value){
_gl.uniform1fv( uniform, value );
};
function uniform2fv(uniform,value){
_gl.uniform2fv( uniform, value );
};
function uniform3fv(uniform,value){
_gl.uniform3fv( uniform, value );
};
function uniform4fv(uniform,value){
_gl.uniform3fv( uniform, value );
};
function uniformMatrix3fv(location,value){
_gl.uniformMatrix3fv( location, false, value );
};
function uniformMatrix4fv(location,value){
_gl.uniformMatrix4fv( location, false, value );
};
function useProgram(program){
_gl.useProgram( program );
};
function setFaceCulling( cullFace, frontFaceDirection ) {
if ( cullFace === THREE.CullFaceNone ) {
_gl.disable( _gl.CULL_FACE );
} else {
if ( frontFaceDirection === THREE.FrontFaceDirectionCW ) {
_gl.frontFace( _gl.CW );
} else {
_gl.frontFace( _gl.CCW );
}
if ( cullFace === THREE.CullFaceBack ) {
_gl.cullFace( _gl.BACK );
} else if ( cullFace === THREE.CullFaceFront ) {
_gl.cullFace( _gl.FRONT );
} else {
_gl.cullFace( _gl.FRONT_AND_BACK );
}
_gl.enable( _gl.CULL_FACE );
}
};
function setMaterialFaces( material ) {
var doubleSided = material.side === THREE.DoubleSide;
var flipSided = material.side === THREE.BackSide;
if ( _oldDoubleSided !== doubleSided ) {
if ( doubleSided ) {
_gl.disable( _gl.CULL_FACE );
} else {
_gl.enable( _gl.CULL_FACE );
}
_oldDoubleSided = doubleSided;
}
if ( _oldFlipSided !== flipSided ) {
if ( flipSided ) {
_gl.frontFace( _gl.CW );
} else {
_gl.frontFace( _gl.CCW );
}
_oldFlipSided = flipSided;
}
};
function setPolygonOffset ( polygonoffset, factor, units ) {
if ( _oldPolygonOffset !== polygonoffset ) {
if ( polygonoffset ) {
_gl.enable( _gl.POLYGON_OFFSET_FILL );
} else {
_gl.disable( _gl.POLYGON_OFFSET_FILL );
}
_oldPolygonOffset = polygonoffset;
}
if ( polygonoffset && ( _oldPolygonOffsetFactor !== factor || _oldPolygonOffsetUnits !== units ) ) {
_gl.polygonOffset( factor, units );
_oldPolygonOffsetFactor = factor;
_oldPolygonOffsetUnits = units;
}
};
function setBlending( blending, blendEquation, blendSrc, blendDst ) {
if ( blending !== _oldBlending ) {
if ( blending === THREE.NoBlending ) {
_gl.disable( _gl.BLEND );
} else if ( blending === THREE.AdditiveBlending ) {
_gl.enable( _gl.BLEND );
_gl.blendEquation( _gl.FUNC_ADD );
_gl.blendFunc( _gl.SRC_ALPHA, _gl.ONE );
} else if ( blending === THREE.SubtractiveBlending ) {
// TODO: Find blendFuncSeparate() combination
_gl.enable( _gl.BLEND );
_gl.blendEquation( _gl.FUNC_ADD );
_gl.blendFunc( _gl.ZERO, _gl.ONE_MINUS_SRC_COLOR );
} else if ( blending === THREE.MultiplyBlending ) {
// TODO: Find blendFuncSeparate() combination
_gl.enable( _gl.BLEND );
_gl.blendEquation( _gl.FUNC_ADD );
_gl.blendFunc( _gl.ZERO, _gl.SRC_COLOR );
} else if ( blending === THREE.CustomBlending ) {
_gl.enable( _gl.BLEND );
} else {
_gl.enable( _gl.BLEND );
_gl.blendEquationSeparate( _gl.FUNC_ADD, _gl.FUNC_ADD );
_gl.blendFuncSeparate( _gl.SRC_ALPHA, _gl.ONE_MINUS_SRC_ALPHA, _gl.ONE, _gl.ONE_MINUS_SRC_ALPHA );
}
_oldBlending = blending;
}
if ( blending === THREE.CustomBlending ) {
if ( blendEquation !== _oldBlendEquation ) {
_gl.blendEquation( paramThreeToGL( blendEquation ) );
_oldBlendEquation = blendEquation;
}
if ( blendSrc !== _oldBlendSrc || blendDst !== _oldBlendDst ) {
_gl.blendFunc( paramThreeToGL( blendSrc ), paramThreeToGL( blendDst ) );
_oldBlendSrc = blendSrc;
_oldBlendDst = blendDst;
}
} else {
_oldBlendEquation = null;
_oldBlendSrc = null;
_oldBlendDst = null;
}
};
function setDepthTest( depthTest ) {
if ( _oldDepthTest !== depthTest ) {
if ( depthTest ) {
_gl.enable( _gl.DEPTH_TEST );
} else {
_gl.disable( _gl.DEPTH_TEST );
}
_oldDepthTest = depthTest;
}
};
function setDepthWrite( depthWrite ) {
if ( _oldDepthWrite !== depthWrite ) {
_gl.depthMask( depthWrite );
_oldDepthWrite = depthWrite;
}
};
function setTexture( texture, slot ) {
if ( texture.needsUpdate ) {
if ( ! texture.__webglInit ) {
texture.__webglInit = true;
//texture.addEventListener( 'dispose', onTextureDispose );
texture.__webglTexture = _gl.createTexture();
//_this.info.memory.textures ++;
}
_gl.activeTexture( _gl.TEXTURE0 + slot );
_gl.bindTexture( _gl.TEXTURE_2D, texture.__webglTexture );
_gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, texture.flipY );
_gl.pixelStorei( _gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultiplyAlpha );
_gl.pixelStorei( _gl.UNPACK_ALIGNMENT, texture.unpackAlignment );
var image = texture.image,
isImagePowerOfTwo = isPowerOfTwo( image.width ) && isPowerOfTwo( image.height ),
glFormat = paramThreeToGL( texture.format ),
glType = paramThreeToGL( texture.type );
setTextureParameters( _gl.TEXTURE_2D, texture, isImagePowerOfTwo );
var mipmap, mipmaps = texture.mipmaps;
if ( texture instanceof THREE.DataTexture ) {
// use manually created mipmaps if available
// if there are no manual mipmaps
// set 0 level mipmap and then use GL to generate other mipmap levels
if ( mipmaps.length > 0 && isImagePowerOfTwo ) {
for ( var i = 0, il = mipmaps.length; i < il; i ++ ) {
mipmap = mipmaps[ i ];
_gl.texImage2D( _gl.TEXTURE_2D, i, glFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data );
}
texture.generateMipmaps = false;
} else {
_gl.texImage2D( _gl.TEXTURE_2D, 0, glFormat, image.width, image.height, 0, glFormat, glType, image.data );
}
} else if ( texture instanceof THREE.CompressedTexture ) {
// compressed textures can only use manually created mipmaps
// WebGL can't generate mipmaps for DDS textures
for( var i = 0, il = mipmaps.length; i < il; i ++ ) {
mipmap = mipmaps[ i ];
_gl.compressedTexImage2D( _gl.TEXTURE_2D, i, glFormat, mipmap.width, mipmap.height, 0, mipmap.data );
}
} else { // regular Texture (image, video, canvas)
// use manually created mipmaps if available
// if there are no manual mipmaps
// set 0 level mipmap and then use GL to generate other mipmap levels
if ( mipmaps.length > 0 && isImagePowerOfTwo ) {
for ( var i = 0, il = mipmaps.length; i < il; i ++ ) {
mipmap = mipmaps[ i ];
_gl.texImage2D( _gl.TEXTURE_2D, i, glFormat, glFormat, glType, mipmap );
}
texture.generateMipmaps = false;
} else {
_gl.texImage2D( _gl.TEXTURE_2D, 0, glFormat, glFormat, glType, texture.image );
}
}
if ( texture.generateMipmaps && isImagePowerOfTwo ) _gl.generateMipmap( _gl.TEXTURE_2D );
texture.needsUpdate = false;
if ( texture.onUpdate ) texture.onUpdate();
} else {
_gl.activeTexture( _gl.TEXTURE0 + slot );
_gl.bindTexture( _gl.TEXTURE_2D, texture.__webglTexture );
}
};
function setCubeTexture ( texture, slot ) {
if ( texture.image.length === 6 ) {
if ( texture.needsUpdate ) {
if ( ! texture.image.__webglTextureCube ) {
texture.image.__webglTextureCube = _gl.createTexture();
}
_gl.activeTexture( _gl.TEXTURE0 + slot );
_gl.bindTexture( _gl.TEXTURE_CUBE_MAP, texture.image.__webglTextureCube );
_gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, texture.flipY );
var isCompressed = texture instanceof THREE.CompressedTexture;
var cubeImage = [];
for ( var i = 0; i < 6; i ++ ) {
if ( _autoScaleCubemaps && ! isCompressed ) {
cubeImage[ i ] = clampToMaxSize( texture.image[ i ], _maxCubemapSize );
} else {
cubeImage[ i ] = texture.image[ i ];
}
}
var image = cubeImage[ 0 ],
isImagePowerOfTwo = isPowerOfTwo( image.width ) && isPowerOfTwo( image.height ),
glFormat = paramThreeToGL( texture.format ),
glType = paramThreeToGL( texture.type );
setTextureParameters( _gl.TEXTURE_CUBE_MAP, texture, isImagePowerOfTwo );
for ( var i = 0; i < 6; i ++ ) {
if ( isCompressed ) {
var mipmap, mipmaps = cubeImage[ i ].mipmaps;
for( var j = 0, jl = mipmaps.length; j < jl; j ++ ) {
mipmap = mipmaps[ j ];
_gl.compressedTexImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glFormat, mipmap.width, mipmap.height, 0, mipmap.data );
}
} else {
_gl.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glFormat, glFormat, glType, cubeImage[ i ] );
}
}
if ( texture.generateMipmaps && isImagePowerOfTwo ) {
_gl.generateMipmap( _gl.TEXTURE_CUBE_MAP );
}
texture.needsUpdate = false;
if ( texture.onUpdate ) texture.onUpdate();
} else {
_gl.activeTexture( _gl.TEXTURE0 + slot );
_gl.bindTexture( _gl.TEXTURE_CUBE_MAP, texture.image.__webglTextureCube );
}
}
};
// Textures
function isPowerOfTwo ( value ) {
return ( value & ( value - 1 ) ) === 0;
};
function setTextureParameters ( textureType, texture, isImagePowerOfTwo ) {
if ( isImagePowerOfTwo ) {
_gl.texParameteri( textureType, _gl.TEXTURE_WRAP_S, paramThreeToGL( texture.wrapS ) );
_gl.texParameteri( textureType, _gl.TEXTURE_WRAP_T, paramThreeToGL( texture.wrapT ) );
_gl.texParameteri( textureType, _gl.TEXTURE_MAG_FILTER, paramThreeToGL( texture.magFilter ) );
_gl.texParameteri( textureType, _gl.TEXTURE_MIN_FILTER, paramThreeToGL( texture.minFilter ) );
} else {
_gl.texParameteri( textureType, _gl.TEXTURE_WRAP_S, _gl.CLAMP_TO_EDGE );
_gl.texParameteri( textureType, _gl.TEXTURE_WRAP_T, _gl.CLAMP_TO_EDGE );
_gl.texParameteri( textureType, _gl.TEXTURE_MAG_FILTER, filterFallback( texture.magFilter ) );
_gl.texParameteri( textureType, _gl.TEXTURE_MIN_FILTER, filterFallback( texture.minFilter ) );
}
if ( _glExtensionTextureFilterAnisotropic && texture.type !== THREE.FloatType ) {
if ( texture.anisotropy > 1 || texture.__oldAnisotropy ) {
_gl.texParameterf( textureType, _glExtensionTextureFilterAnisotropic.TEXTURE_MAX_ANISOTROPY_EXT, Math.min( texture.anisotropy, _maxAnisotropy ) );
texture.__oldAnisotropy = texture.anisotropy;
}
}
};
function setupFrameBuffer ( framebuffer, renderTarget, textureTarget ) {
_gl.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );
_gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, textureTarget, renderTarget.__webglTexture, 0 );
};
function setupRenderBuffer ( renderbuffer, renderTarget ) {
_gl.bindRenderbuffer( _gl.RENDERBUFFER, renderbuffer );
if ( renderTarget.depthBuffer && ! renderTarget.stencilBuffer ) {
_gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.DEPTH_COMPONENT16, renderTarget.width, renderTarget.height );
_gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer );
/* For some reason this is not working. Defaulting to RGBA4.
} else if( ! renderTarget.depthBuffer && renderTarget.stencilBuffer ) {
_gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.STENCIL_INDEX8, renderTarget.width, renderTarget.height );
_gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.STENCIL_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer );
*/
} else if( renderTarget.depthBuffer && renderTarget.stencilBuffer ) {
_gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.DEPTH_STENCIL, renderTarget.width, renderTarget.height );
_gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer );
} else {
_gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.RGBA4, renderTarget.width, renderTarget.height );
}
};
function setRenderTarget( renderTarget ) {
var isCube = ( renderTarget instanceof THREE.WebGLRenderTargetCube );
if ( renderTarget && ! renderTarget.__webglFramebuffer ) {
if ( renderTarget.depthBuffer === undefined ) renderTarget.depthBuffer = true;
if ( renderTarget.stencilBuffer === undefined ) renderTarget.stencilBuffer = true;
//renderTarget.addEventListener( 'dispose', onRenderTargetDispose );
renderTarget.__webglTexture = _gl.createTexture();
//_this.info.memory.textures ++;
// Setup texture, create render and frame buffers
var isTargetPowerOfTwo = isPowerOfTwo( renderTarget.width ) && isPowerOfTwo( renderTarget.height ),
glFormat = paramThreeToGL( renderTarget.format ),
glType = paramThreeToGL( renderTarget.type );
if ( isCube ) {
renderTarget.__webglFramebuffer = [];
renderTarget.__webglRenderbuffer = [];
_gl.bindTexture( _gl.TEXTURE_CUBE_MAP, renderTarget.__webglTexture );
setTextureParameters( _gl.TEXTURE_CUBE_MAP, renderTarget, isTargetPowerOfTwo );
for ( var i = 0; i < 6; i ++ ) {
renderTarget.__webglFramebuffer[ i ] = _gl.createFramebuffer();
renderTarget.__webglRenderbuffer[ i ] = _gl.createRenderbuffer();
_gl.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glFormat, renderTarget.width, renderTarget.height, 0, glFormat, glType, null );
setupFrameBuffer( renderTarget.__webglFramebuffer[ i ], renderTarget, _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i );
setupRenderBuffer( renderTarget.__webglRenderbuffer[ i ], renderTarget );
}
if ( isTargetPowerOfTwo ) _gl.generateMipmap( _gl.TEXTURE_CUBE_MAP );
} else {
renderTarget.__webglFramebuffer = _gl.createFramebuffer();
if ( renderTarget.shareDepthFrom ) {
renderTarget.__webglRenderbuffer = renderTarget.shareDepthFrom.__webglRenderbuffer;
} else {
renderTarget.__webglRenderbuffer = _gl.createRenderbuffer();
}
_gl.bindTexture( _gl.TEXTURE_2D, renderTarget.__webglTexture );
setTextureParameters( _gl.TEXTURE_2D, renderTarget, isTargetPowerOfTwo );
_gl.texImage2D( _gl.TEXTURE_2D, 0, glFormat, renderTarget.width, renderTarget.height, 0, glFormat, glType, null );
setupFrameBuffer( renderTarget.__webglFramebuffer, renderTarget, _gl.TEXTURE_2D );
if ( renderTarget.shareDepthFrom ) {
if ( renderTarget.depthBuffer && ! renderTarget.stencilBuffer ) {
_gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.RENDERBUFFER, renderTarget.__webglRenderbuffer );
} else if ( renderTarget.depthBuffer && renderTarget.stencilBuffer ) {
_gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.RENDERBUFFER, renderTarget.__webglRenderbuffer );
}
} else {
setupRenderBuffer( renderTarget.__webglRenderbuffer, renderTarget );
}
if ( isTargetPowerOfTwo ) _gl.generateMipmap( _gl.TEXTURE_2D );
}
// Release everything
if ( isCube ) {
_gl.bindTexture( _gl.TEXTURE_CUBE_MAP, null );
} else {
_gl.bindTexture( _gl.TEXTURE_2D, null );
}
_gl.bindRenderbuffer( _gl.RENDERBUFFER, null );
_gl.bindFramebuffer( _gl.FRAMEBUFFER, null );
}
var framebuffer, width, height, vx, vy;
if ( renderTarget ) {
if ( isCube ) {
framebuffer = renderTarget.__webglFramebuffer[ renderTarget.activeCubeFace ];
} else {
framebuffer = renderTarget.__webglFramebuffer;
}
width = renderTarget.width;
height = renderTarget.height;
vx = 0;
vy = 0;
} else {
framebuffer = null;
width = _viewportWidth;
height = _viewportHeight;
vx = _viewportX;
vy = _viewportY;
}
if ( framebuffer !== _currentFramebuffer ) {
_gl.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );
_gl.viewport( vx, vy, width, height );
_currentFramebuffer = framebuffer;
}
_currentWidth = width;
_currentHeight = height;
};
function clampToMaxSize ( image, maxSize ) {
if ( image.width <= maxSize && image.height <= maxSize ) {
return image;
}
// Warning: Scaling through the canvas will only work with images that use
// premultiplied alpha.
var maxDimension = Math.max( image.width, image.height );
var newWidth = Math.floor( image.width * maxSize / maxDimension );
var newHeight = Math.floor( image.height * maxSize / maxDimension );
var canvas = document.createElement( 'canvas' );
canvas.width = newWidth;
canvas.height = newHeight;
var ctx = canvas.getContext( "2d" );
ctx.drawImage( image, 0, 0, image.width, image.height, 0, 0, newWidth, newHeight );
return canvas;
};
function updateRenderTargetMipmap ( renderTarget ) {
if ( renderTarget instanceof THREE.WebGLRenderTargetCube ) {
_gl.bindTexture( _gl.TEXTURE_CUBE_MAP, renderTarget.__webglTexture );
_gl.generateMipmap( _gl.TEXTURE_CUBE_MAP );
_gl.bindTexture( _gl.TEXTURE_CUBE_MAP, null );
} else {
_gl.bindTexture( _gl.TEXTURE_2D, renderTarget.__webglTexture );
_gl.generateMipmap( _gl.TEXTURE_2D );
_gl.bindTexture( _gl.TEXTURE_2D, null );
}
};
function setCubeTextureDynamic ( texture, slot ) {
_gl.activeTexture( _gl.TEXTURE0 + slot );
_gl.bindTexture( _gl.TEXTURE_CUBE_MAP, texture.__webglTexture );
};
// Map three.js constants to WebGL constants
function paramThreeToGL ( p ) {
if ( p === THREE.RepeatWrapping ) return _gl.REPEAT;
if ( p === THREE.ClampToEdgeWrapping ) return _gl.CLAMP_TO_EDGE;
if ( p === THREE.MirroredRepeatWrapping ) return _gl.MIRRORED_REPEAT;
if ( p === THREE.NearestFilter ) return _gl.NEAREST;
if ( p === THREE.NearestMipMapNearestFilter ) return _gl.NEAREST_MIPMAP_NEAREST;
if ( p === THREE.NearestMipMapLinearFilter ) return _gl.NEAREST_MIPMAP_LINEAR;
if ( p === THREE.LinearFilter ) return _gl.LINEAR;
if ( p === THREE.LinearMipMapNearestFilter ) return _gl.LINEAR_MIPMAP_NEAREST;
if ( p === THREE.LinearMipMapLinearFilter ) return _gl.LINEAR_MIPMAP_LINEAR;
if ( p === THREE.UnsignedByteType ) return _gl.UNSIGNED_BYTE;
if ( p === THREE.UnsignedShort4444Type ) return _gl.UNSIGNED_SHORT_4_4_4_4;
if ( p === THREE.UnsignedShort5551Type ) return _gl.UNSIGNED_SHORT_5_5_5_1;
if ( p === THREE.UnsignedShort565Type ) return _gl.UNSIGNED_SHORT_5_6_5;
if ( p === THREE.ByteType ) return _gl.BYTE;
if ( p === THREE.ShortType ) return _gl.SHORT;
if ( p === THREE.UnsignedShortType ) return _gl.UNSIGNED_SHORT;
if ( p === THREE.IntType ) return _gl.INT;
if ( p === THREE.UnsignedIntType ) return _gl.UNSIGNED_INT;
if ( p === THREE.FloatType ) return _gl.FLOAT;
if ( p === THREE.AlphaFormat ) return _gl.ALPHA;
if ( p === THREE.RGBFormat ) return _gl.RGB;
if ( p === THREE.RGBAFormat ) return _gl.RGBA;
if ( p === THREE.LuminanceFormat ) return _gl.LUMINANCE;
if ( p === THREE.LuminanceAlphaFormat ) return _gl.LUMINANCE_ALPHA;
if ( p === THREE.AddEquation ) return _gl.FUNC_ADD;
if ( p === THREE.SubtractEquation ) return _gl.FUNC_SUBTRACT;
if ( p === THREE.ReverseSubtractEquation ) return _gl.FUNC_REVERSE_SUBTRACT;
if ( p === THREE.ZeroFactor ) return _gl.ZERO;
if ( p === THREE.OneFactor ) return _gl.ONE;
if ( p === THREE.SrcColorFactor ) return _gl.SRC_COLOR;
if ( p === THREE.OneMinusSrcColorFactor ) return _gl.ONE_MINUS_SRC_COLOR;
if ( p === THREE.SrcAlphaFactor ) return _gl.SRC_ALPHA;
if ( p === THREE.OneMinusSrcAlphaFactor ) return _gl.ONE_MINUS_SRC_ALPHA;
if ( p === THREE.DstAlphaFactor ) return _gl.DST_ALPHA;
if ( p === THREE.OneMinusDstAlphaFactor ) return _gl.ONE_MINUS_DST_ALPHA;
if ( p === THREE.DstColorFactor ) return _gl.DST_COLOR;
if ( p === THREE.OneMinusDstColorFactor ) return _gl.ONE_MINUS_DST_COLOR;
if ( p === THREE.SrcAlphaSaturateFactor ) return _gl.SRC_ALPHA_SATURATE;
if ( _glExtensionCompressedTextureS3TC !== undefined ) {
if ( p === THREE.RGB_S3TC_DXT1_Format ) return _glExtensionCompressedTextureS3TC.COMPRESSED_RGB_S3TC_DXT1_EXT;
if ( p === THREE.RGBA_S3TC_DXT1_Format ) return _glExtensionCompressedTextureS3TC.COMPRESSED_RGBA_S3TC_DXT1_EXT;
if ( p === THREE.RGBA_S3TC_DXT3_Format ) return _glExtensionCompressedTextureS3TC.COMPRESSED_RGBA_S3TC_DXT3_EXT;
if ( p === THREE.RGBA_S3TC_DXT5_Format ) return _glExtensionCompressedTextureS3TC.COMPRESSED_RGBA_S3TC_DXT5_EXT;
}
return 0;
};
function compileShader(vertexShader, fragmentShader){
var program = _gl.createProgram();
var glFragmentShader = getShader( "fragment", fragmentShader );
var glVertexShader = getShader( "vertex", vertexShader );
_gl.attachShader( program, glVertexShader );
_gl.attachShader( program, glFragmentShader );
_gl.linkProgram( program );
if ( !_gl.getProgramParameter( program, _gl.LINK_STATUS ) ) {
console.error( "Could not initialise shader\n" + "VALIDATE_STATUS: " + _gl.getProgramParameter( program, _gl.VALIDATE_STATUS ) + ", gl error [" + _gl.getError() + "]" );
}
// clean up
_gl.deleteShader( glFragmentShader );
_gl.deleteShader( glVertexShader );
return program;
};
function resetState(){
_oldBlending = -1;
_oldDepthTest = -1;
_oldDepthWrite = -1;
_oldDoubleSided = -1;
_oldFlipSided = -1;
}
function getShader ( type, string ) {
var shader;
if ( type === "fragment" ) {
shader = _gl.createShader( _gl.FRAGMENT_SHADER );
} else if ( type === "vertex" ) {
shader = _gl.createShader( _gl.VERTEX_SHADER );
}
_gl.shaderSource( shader, string );
_gl.compileShader( shader );
if ( !_gl.getShaderParameter( shader, _gl.COMPILE_STATUS ) ) {
console.error( _gl.getShaderInfoLog( shader ) );
console.error( addLineNumbers( string ) );
return null;
}
return shader;
};
function addLineNumbers ( string ) {
var chunks = string.split( "\n" );
for ( var i = 0, il = chunks.length; i < il; i ++ ) {
// Chrome reports shader errors on lines
// starting counting from 1
chunks[ i ] = ( i + 1 ) + ": " + chunks[ i ];
}
return chunks.join( "\n" );
};
function setLineWidth ( width ) {
if ( width !== _oldLineWidth ) {
_gl.lineWidth( width );
_oldLineWidth = width;
}
};
this.context = _gl;
this.autoScaleCubemaps = _autoScaleCubemaps;
this.supportsBoneTextures = _supportsBoneTextures;
this.precision = _precision;
this.maxVertexUniformVectors = _gl.getParameter( _gl.MAX_VERTEX_UNIFORM_VECTORS );
// Methods
this.getContext = getContext;
this.getDomElement = getDomElement;
this.getPrecision = getPrecision;
this.getCurrentWidth = getCurrentWidth;
this.getCurrentHeight = getCurrentHeight;
this.supportsVertexTextures = supportsVertexTextures;
this.getMaxAnisotropy = getMaxAnisotropy;
this.setRenderTarget = setRenderTarget;
this.setSize = setSize;
this.setViewport = setViewport;
this.setScissor = setScissor;
this.enableScissorTest = enableScissorTest;
this.setClearColorHex = setClearColorHex;
this.setClearColor = setClearColor;
this.getClearColor = getClearColor;
this.getClearAlpha = getClearAlpha;
this.clear = clear;
this.clearTarget = clearTarget;
this.deleteBuffer = deleteBuffer;
this.deleteTexture = deleteTexture;
this.deleteFramebuffer = deleteFramebuffer;
this.deleteRenderbuffer = deleteRenderbuffer;
this.deleteProgram = deleteProgram;
this.createBuffer = createBuffer;
this.setStaticArrayBuffer = setStaticArrayBuffer;
this.setStaticIndexBuffer = setStaticIndexBuffer;
this.setDynamicArrayBuffer = setDynamicArrayBuffer;
this.setDynamicIndexBuffer = setDynamicIndexBuffer;
this.drawTriangles = drawTriangles;
this.drawTriangleStrip = drawTriangleStrip;
this.drawLines = drawLines;
this.drawLineStrip = drawLineStrip;
this.drawPoints = drawPoints;
this.drawTriangleElements = drawTriangleElements;
this.drawLineElements = drawLineElements;
this.bindArrayBuffer = bindArrayBuffer;
this.bindElementArrayBuffer = bindElementArrayBuffer;
this.enableAttribute = enableAttribute;
this.disableAttributes = disableAttributes;
this.getAttribLocation = getAttribLocation;
this.setFloatAttribute = setFloatAttribute;
this.getUniformLocation= getUniformLocation;
this.uniform1i = uniform1i;
this.uniform1f = uniform1f;
this.uniform2f = uniform2f;
this.uniform3f = uniform3f;
this.uniform4f = uniform4f;
this.uniform1iv = uniform1iv;
this.uniform2iv = uniform2iv;
this.uniform3iv = uniform3iv;
this.uniform1fv = uniform1fv;
this.uniform2fv = uniform2fv;
this.uniform3fv = uniform3fv;
this.uniform4fv = uniform4fv;
this.uniformMatrix3fv = uniformMatrix3fv;
this.uniformMatrix4fv = uniformMatrix4fv;
this.useProgram = useProgram;
this.compileShader = compileShader;
this.setFaceCulling = setFaceCulling;
this.setMaterialFaces = setMaterialFaces;
this.setPolygonOffset = setPolygonOffset;
this.setBlending = setBlending;
this.setDepthTest = setDepthTest;
this.setDepthWrite = setDepthWrite;
this.setTexture = setTexture;
this.setCubeTexture = setCubeTexture;
this.updateRenderTargetMipmap = updateRenderTargetMipmap;
this.setCubeTextureDynamic = setCubeTextureDynamic;
this.paramThreeToGL = paramThreeToGL;
this.setLineWidth = setLineWidth;
this.resetState = resetState;
};
THREE.WebGLRenderer2.ShaderBuilder = function(renderer,info){
this.renderer = renderer;
this.info = info;
this.programs = [],
this.programs_counter = 0;
}
THREE.WebGLRenderer2.ShaderBuilder.prototype.buildProgram = function ( shaderID, fragmentShader, vertexShader, uniforms, attributes, defines, parameters ) {
var renderer = this.renderer;
var p, pl, d, program, code;
var chunks = [];
// Generate code
if ( shaderID ) {
chunks.push( shaderID );
} else {
chunks.push( fragmentShader );
chunks.push( vertexShader );
}
for ( d in defines ) {
chunks.push( d );
chunks.push( defines[ d ] );
}
for ( p in parameters ) {
chunks.push( p );
chunks.push( parameters[ p ] );
}
code = chunks.join();
// Check if code has been already compiled
for ( p = 0, pl = this.programs.length; p < pl; p ++ ) {
var programInfo = this.programs[ p ];
if ( programInfo.code === code ) {
//console.log( "Code already compiled." /*: \n\n" + code*/ );
programInfo.usedTimes ++;
return programInfo.program;
}
}
var shadowMapTypeDefine = "SHADOWMAP_TYPE_BASIC";
if ( parameters.shadowMapType === THREE.PCFShadowMap ) {
shadowMapTypeDefine = "SHADOWMAP_TYPE_PCF";
} else if ( parameters.shadowMapType === THREE.PCFSoftShadowMap ) {
shadowMapTypeDefine = "SHADOWMAP_TYPE_PCF_SOFT";
}
//console.log( "building new program " );
//
var customDefines = this.generateDefines( defines );
//
var prefix_vertex = [
"precision " + renderer.precision + " float;",
customDefines,
renderer.supportsVertexTextures ? "#define VERTEX_TEXTURES" : "",
parameters.gammaInput ? "#define GAMMA_INPUT" : "",
parameters.gammaOutput ? "#define GAMMA_OUTPUT" : "",
parameters.physicallyBasedShading ? "#define PHYSICALLY_BASED_SHADING" : "",
"#define MAX_DIR_LIGHTS " + parameters.maxDirLights,
"#define MAX_POINT_LIGHTS " + parameters.maxPointLights,
"#define MAX_SPOT_LIGHTS " + parameters.maxSpotLights,
"#define MAX_HEMI_LIGHTS " + parameters.maxHemiLights,
"#define MAX_SHADOWS " + parameters.maxShadows,
"#define MAX_BONES " + parameters.maxBones,
parameters.map ? "#define USE_MAP" : "",
parameters.envMap ? "#define USE_ENVMAP" : "",
parameters.lightMap ? "#define USE_LIGHTMAP" : "",
parameters.bumpMap ? "#define USE_BUMPMAP" : "",
parameters.normalMap ? "#define USE_NORMALMAP" : "",
parameters.specularMap ? "#define USE_SPECULARMAP" : "",
parameters.vertexColors ? "#define USE_COLOR" : "",
parameters.skinning ? "#define USE_SKINNING" : "",
parameters.useVertexTexture ? "#define BONE_TEXTURE" : "",
parameters.boneTextureWidth ? "#define N_BONE_PIXEL_X " + parameters.boneTextureWidth.toFixed( 1 ) : "",
parameters.boneTextureHeight ? "#define N_BONE_PIXEL_Y " + parameters.boneTextureHeight.toFixed( 1 ) : "",
parameters.morphTargets ? "#define USE_MORPHTARGETS" : "",
parameters.morphNormals ? "#define USE_MORPHNORMALS" : "",
parameters.perPixel ? "#define PHONG_PER_PIXEL" : "",
parameters.wrapAround ? "#define WRAP_AROUND" : "",
parameters.doubleSided ? "#define DOUBLE_SIDED" : "",
parameters.flipSided ? "#define FLIP_SIDED" : "",
parameters.shadowMapEnabled ? "#define USE_SHADOWMAP" : "",
parameters.shadowMapEnabled ? "#define " + shadowMapTypeDefine : "",
parameters.shadowMapDebug ? "#define SHADOWMAP_DEBUG" : "",
parameters.shadowMapCascade ? "#define SHADOWMAP_CASCADE" : "",
parameters.sizeAttenuation ? "#define USE_SIZEATTENUATION" : "",
"uniform mat4 modelMatrix;",
"uniform mat4 modelViewMatrix;",
"uniform mat4 projectionMatrix;",
"uniform mat4 viewMatrix;",
"uniform mat3 normalMatrix;",
"uniform vec3 cameraPosition;",
"attribute vec3 position;",
"attribute vec3 normal;",
"attribute vec2 uv;",
"attribute vec2 uv2;",
"#ifdef USE_COLOR",
"attribute vec3 color;",
"#endif",
"#ifdef USE_MORPHTARGETS",
"attribute vec3 morphTarget0;",
"attribute vec3 morphTarget1;",
"attribute vec3 morphTarget2;",
"attribute vec3 morphTarget3;",
"#ifdef USE_MORPHNORMALS",
"attribute vec3 morphNormal0;",
"attribute vec3 morphNormal1;",
"attribute vec3 morphNormal2;",
"attribute vec3 morphNormal3;",
"#else",
"attribute vec3 morphTarget4;",
"attribute vec3 morphTarget5;",
"attribute vec3 morphTarget6;",
"attribute vec3 morphTarget7;",
"#endif",
"#endif",
"#ifdef USE_SKINNING",
"attribute vec4 skinIndex;",
"attribute vec4 skinWeight;",
"#endif",
""
].join("\n");
var prefix_fragment = [
"precision " + renderer.precision + " float;",
( parameters.bumpMap || parameters.normalMap ) ? "#extension GL_OES_standard_derivatives : enable" : "",
customDefines,
"#define MAX_DIR_LIGHTS " + parameters.maxDirLights,
"#define MAX_POINT_LIGHTS " + parameters.maxPointLights,
"#define MAX_SPOT_LIGHTS " + parameters.maxSpotLights,
"#define MAX_HEMI_LIGHTS " + parameters.maxHemiLights,
"#define MAX_SHADOWS " + parameters.maxShadows,
parameters.alphaTest ? "#define ALPHATEST " + parameters.alphaTest: "",
parameters.gammaInput ? "#define GAMMA_INPUT" : "",
parameters.gammaOutput ? "#define GAMMA_OUTPUT" : "",
( parameters.useFog && parameters.fog ) ? "#define USE_FOG" : "",
( parameters.useFog && parameters.fogExp ) ? "#define FOG_EXP2" : "",
parameters.map ? "#define USE_MAP" : "",
parameters.envMap ? "#define USE_ENVMAP" : "",
parameters.lightMap ? "#define USE_LIGHTMAP" : "",
parameters.bumpMap ? "#define USE_BUMPMAP" : "",
parameters.normalMap ? "#define USE_NORMALMAP" : "",
parameters.specularMap ? "#define USE_SPECULARMAP" : "",
parameters.vertexColors ? "#define USE_COLOR" : "",
parameters.metal ? "#define METAL" : "",
parameters.perPixel ? "#define PHONG_PER_PIXEL" : "",
parameters.wrapAround ? "#define WRAP_AROUND" : "",
parameters.doubleSided ? "#define DOUBLE_SIDED" : "",
parameters.flipSided ? "#define FLIP_SIDED" : "",
parameters.shadowMapEnabled ? "#define USE_SHADOWMAP" : "",
parameters.shadowMapEnabled ? "#define " + shadowMapTypeDefine : "",
parameters.shadowMapDebug ? "#define SHADOWMAP_DEBUG" : "",
parameters.shadowMapCascade ? "#define SHADOWMAP_CASCADE" : "",
"uniform mat4 viewMatrix;",
"uniform vec3 cameraPosition;",
""
].join("\n");
program = renderer.compileShader(prefix_vertex + vertexShader, prefix_fragment + fragmentShader);
//console.log( prefix_fragment + fragmentShader );
//console.log( prefix_vertex + vertexShader );
program.uniforms = {};
program.attributes = {};
var identifiers, u, a, i;
// cache uniform locations
identifiers = [
'viewMatrix', 'modelViewMatrix', 'projectionMatrix', 'normalMatrix', 'modelMatrix', 'cameraPosition',
'morphTargetInfluences'
];
if ( parameters.useVertexTexture ) {
identifiers.push( 'boneTexture' );
} else {
identifiers.push( 'boneGlobalMatrices' );
}
for ( u in uniforms ) {
identifiers.push( u );
}
this.cacheUniformLocations( program, identifiers );
// cache attributes locations
identifiers = [
"position", "normal", "uv", "uv2", "tangent", "color",
"skinIndex", "skinWeight", "lineDistance"
];
for ( i = 0; i < parameters.maxMorphTargets; i ++ ) {
identifiers.push( "morphTarget" + i );
}
for ( i = 0; i < parameters.maxMorphNormals; i ++ ) {
identifiers.push( "morphNormal" + i );
}
for ( a in attributes ) {
identifiers.push( a );
}
this.cacheAttributeLocations( program, identifiers );
program.id = this.programs_counter ++;
this.programs.push( { program: program, code: code, usedTimes: 1 } );
this.info.memory.programs = this.programs.length;
return program;
};
THREE.WebGLRenderer2.ShaderBuilder.prototype.generateDefines = function( defines ) {
var value, chunk, chunks = [];
for ( var d in defines ) {
value = defines[ d ];
if ( value === false ) continue;
chunk = "#define " + d + " " + value;
chunks.push( chunk );
}
return chunks.join( "\n" );
};
// Shader parameters cache
THREE.WebGLRenderer2.ShaderBuilder.prototype.cacheUniformLocations = function( program, identifiers ) {
var i, l, id, renderer = this.renderer;
for( i = 0, l = identifiers.length; i < l; i ++ ) {
id = identifiers[ i ];
program.uniforms[ id ] = renderer.getUniformLocation( program, id );
}
};
THREE.WebGLRenderer2.ShaderBuilder.prototype.cacheAttributeLocations = function( program, identifiers ) {
var i, l, id, renderer = this.renderer;
for( i = 0, l = identifiers.length; i < l; i ++ ) {
id = identifiers[ i ];
program.attributes[ id ] = renderer.getAttribLocation( program, id );
}
};
THREE.WebGLRenderer2.ShaderBuilder.prototype.removeProgram = function( program ) {
var i, il, programInfo;
var deleteProgram = false;
var programs = this.programs;
for ( i = 0, il = programs.length; i < il; i ++ ) {
programInfo = programs[ i ];
if ( programInfo.program === program ) {
programInfo.usedTimes --;
if ( programInfo.usedTimes === 0 ) {
deleteProgram = true;
}
break;
}
}
if ( deleteProgram === true ) {
// avoid using array.splice, this is costlier than creating new array from scratch
var newPrograms = [];
for ( i = 0, il = programs.length; i < il; i ++ ) {
programInfo = programs[ i ];
if ( programInfo.program !== program ) {
newPrograms.push( programInfo );
}
}
programs = newPrograms;
this.renderer.deleteProgram( program );
this.info.memory.programs --;
}
}
\ No newline at end of file
THREE.WebGLRenderer2.LineRenderer = function(lowlevelrenderer, info){
THREE.WebGLRenderer2.Object3DObjectRenderer.call( this, lowlevelrenderer, info );
};
THREE.WebGLRenderer2.LineRenderer.prototype = Object.create( THREE.WebGLRenderer2.Object3DObjectRenderer.prototype );
THREE.WebGLRenderer2.LineRenderer.prototype.createBuffers = function( geometry ) {
var renderer = this.renderer;
geometry.__webglVertexBuffer = renderer.createBuffer();
geometry.__webglColorBuffer = renderer.createBuffer();
geometry.__webglLineDistanceBuffer = renderer.createBuffer();
this.info.memory.geometries ++;
};
THREE.WebGLRenderer2.LineRenderer.prototype.initBuffers = function( geometry, object ) {
var nvertices = geometry.vertices.length;
geometry.__vertexArray = new Float32Array( nvertices * 3 );
geometry.__colorArray = new Float32Array( nvertices * 3 );
geometry.__lineDistanceArray = new Float32Array( nvertices * 1 );
geometry.__webglLineCount = nvertices;
this.initCustomAttributes ( geometry, object );
};
THREE.WebGLRenderer2.LineRenderer.prototype.setBuffers = function( geometry, object) {
var renderer = this.renderer;
var v, c, d, vertex, offset, color,
vertices = geometry.vertices,
colors = geometry.colors,
lineDistances = geometry.lineDistances,
vl = vertices.length,
cl = colors.length,
dl = lineDistances.length,
vertexArray = geometry.__vertexArray,
colorArray = geometry.__colorArray,
lineDistanceArray = geometry.__lineDistanceArray,
dirtyVertices = geometry.verticesNeedUpdate,
dirtyColors = geometry.colorsNeedUpdate,
dirtyLineDistances = geometry.lineDistancesNeedUpdate,
customAttributes = geometry.__webglCustomAttributesList,
i, il,
a, ca, cal, value,
customAttribute;
if ( dirtyVertices ) {
for ( v = 0; v < vl; v ++ ) {
vertex = vertices[ v ];
offset = v * 3;
vertexArray[ offset ] = vertex.x;
vertexArray[ offset + 1 ] = vertex.y;
vertexArray[ offset + 2 ] = vertex.z;
}
renderer.setDynamicArrayBuffer(geometry.__webglVertexBuffer,vertexArray);
}
if ( dirtyColors ) {
for ( c = 0; c < cl; c ++ ) {
color = colors[ c ];
offset = c * 3;
colorArray[ offset ] = color.r;
colorArray[ offset + 1 ] = color.g;
colorArray[ offset + 2 ] = color.b;
}
renderer.setDynamicArrayBuffer(geometry.__webglColorBuffer,colorArray);
}
if ( dirtyLineDistances ) {
for ( d = 0; d < dl; d ++ ) {
lineDistanceArray[ d ] = lineDistances[ d ];
}
renderer.setDynamicArrayBuffer( geometry.__webglLineDistanceBuffer,lineDistanceArray);
}
if ( customAttributes ) {
for ( i = 0, il = customAttributes.length; i < il; i ++ ) {
customAttribute = customAttributes[ i ];
if ( customAttribute.needsUpdate &&
( customAttribute.boundTo === undefined ||
customAttribute.boundTo === "vertices" ) ) {
offset = 0;
cal = customAttribute.value.length;
if ( customAttribute.size === 1 ) {
for ( ca = 0; ca < cal; ca ++ ) {
customAttribute.array[ ca ] = customAttribute.value[ ca ];
}
} else if ( customAttribute.size === 2 ) {
for ( ca = 0; ca < cal; ca ++ ) {
value = customAttribute.value[ ca ];
customAttribute.array[ offset ] = value.x;
customAttribute.array[ offset + 1 ] = value.y;
offset += 2;
}
} else if ( customAttribute.size === 3 ) {
if ( customAttribute.type === "c" ) {
for ( ca = 0; ca < cal; ca ++ ) {
value = customAttribute.value[ ca ];
customAttribute.array[ offset ] = value.r;
customAttribute.array[ offset + 1 ] = value.g;
customAttribute.array[ offset + 2 ] = value.b;
offset += 3;
}
} else {
for ( ca = 0; ca < cal; ca ++ ) {
value = customAttribute.value[ ca ];
customAttribute.array[ offset ] = value.x;
customAttribute.array[ offset + 1 ] = value.y;
customAttribute.array[ offset + 2 ] = value.z;
offset += 3;
}
}
} else if ( customAttribute.size === 4 ) {
for ( ca = 0; ca < cal; ca ++ ) {
value = customAttribute.value[ ca ];
customAttribute.array[ offset ] = value.x;
customAttribute.array[ offset + 1 ] = value.y;
customAttribute.array[ offset + 2 ] = value.z;
customAttribute.array[ offset + 3 ] = value.w;
offset += 4;
}
}
renderer.setDynamicArrayBuffer( customAttribute.buffer,customAttribute.array);
}
}
}
};
\ No newline at end of file
THREE.WebGLRenderer2.MeshRenderer = function(lowlevelrenderer, info){
THREE.WebGLRenderer2.Object3DObjectRenderer.call( this, lowlevelrenderer, info );
};
THREE.WebGLRenderer2.MeshRenderer.prototype = Object.create( THREE.WebGLRenderer2.Object3DObjectRenderer.prototype );
THREE.WebGLRenderer2.MeshRenderer.prototype.createBuffers = function( geometryGroup ) {
var renderer = this.renderer;
geometryGroup.__webglVertexBuffer = renderer.createBuffer();
geometryGroup.__webglNormalBuffer = renderer.createBuffer();
geometryGroup.__webglTangentBuffer = renderer.createBuffer();
geometryGroup.__webglColorBuffer = renderer.createBuffer();
geometryGroup.__webglUVBuffer = renderer.createBuffer();
geometryGroup.__webglUV2Buffer = renderer.createBuffer();
geometryGroup.__webglSkinIndicesBuffer = renderer.createBuffer();
geometryGroup.__webglSkinWeightsBuffer = renderer.createBuffer();
geometryGroup.__webglFaceBuffer = renderer.createBuffer();
geometryGroup.__webglLineBuffer = renderer.createBuffer();
var m, ml;
if ( geometryGroup.numMorphTargets ) {
geometryGroup.__webglMorphTargetsBuffers = [];
for ( m = 0, ml = geometryGroup.numMorphTargets; m < ml; m ++ ) {
geometryGroup.__webglMorphTargetsBuffers.push( renderer.createBuffer() );
}
}
if ( geometryGroup.numMorphNormals ) {
geometryGroup.__webglMorphNormalsBuffers = [];
for ( m = 0, ml = geometryGroup.numMorphNormals; m < ml; m ++ ) {
geometryGroup.__webglMorphNormalsBuffers.push( renderer.createBuffer() );
}
}
this.info.memory.geometries ++;
};
THREE.WebGLRenderer2.MeshRenderer.prototype.initBuffers = function( geometryGroup, object ) {
var geometry = object.geometry,
faces3 = geometryGroup.faces3,
faces4 = geometryGroup.faces4,
nvertices = faces3.length * 3 + faces4.length * 4,
ntris = faces3.length * 1 + faces4.length * 2,
nlines = faces3.length * 3 + faces4.length * 4,
material = this.getBufferMaterial( object, geometryGroup ),
uvType = this.bufferGuessUVType( material ),
normalType = this.bufferGuessNormalType( material ),
vertexColorType = this.bufferGuessVertexColorType( material );
//console.log( "uvType", uvType, "normalType", normalType, "vertexColorType", vertexColorType, object, geometryGroup, material );
geometryGroup.__vertexArray = new Float32Array( nvertices * 3 );
if ( normalType ) {
geometryGroup.__normalArray = new Float32Array( nvertices * 3 );
}
if ( geometry.hasTangents ) {
geometryGroup.__tangentArray = new Float32Array( nvertices * 4 );
}
if ( vertexColorType ) {
geometryGroup.__colorArray = new Float32Array( nvertices * 3 );
}
if ( uvType ) {
if ( geometry.faceUvs.length > 0 || geometry.faceVertexUvs.length > 0 ) {
geometryGroup.__uvArray = new Float32Array( nvertices * 2 );
}
if ( geometry.faceUvs.length > 1 || geometry.faceVertexUvs.length > 1 ) {
geometryGroup.__uv2Array = new Float32Array( nvertices * 2 );
}
}
if ( object.geometry.skinWeights.length && object.geometry.skinIndices.length ) {
geometryGroup.__skinIndexArray = new Float32Array( nvertices * 4 );
geometryGroup.__skinWeightArray = new Float32Array( nvertices * 4 );
}
geometryGroup.__faceArray = new Uint16Array( ntris * 3 );
geometryGroup.__lineArray = new Uint16Array( nlines * 2 );
var m, ml;
if ( geometryGroup.numMorphTargets ) {
geometryGroup.__morphTargetsArrays = [];
for ( m = 0, ml = geometryGroup.numMorphTargets; m < ml; m ++ ) {
geometryGroup.__morphTargetsArrays.push( new Float32Array( nvertices * 3 ) );
}
}
if ( geometryGroup.numMorphNormals ) {
geometryGroup.__morphNormalsArrays = [];
for ( m = 0, ml = geometryGroup.numMorphNormals; m < ml; m ++ ) {
geometryGroup.__morphNormalsArrays.push( new Float32Array( nvertices * 3 ) );
}
}
geometryGroup.__webglFaceCount = ntris * 3;
geometryGroup.__webglLineCount = nlines * 2;
// custom attributes
if ( material.attributes ) {
if ( geometryGroup.__webglCustomAttributesList === undefined ) {
geometryGroup.__webglCustomAttributesList = [];
}
for ( var a in material.attributes ) {
// Do a shallow copy of the attribute object so different geometryGroup chunks use different
// attribute buffers which are correctly indexed in the setMeshBuffers function
var originalAttribute = material.attributes[ a ];
var attribute = {};
for ( var property in originalAttribute ) {
attribute[ property ] = originalAttribute[ property ];
}
if ( !attribute.__webglInitialized || attribute.createUniqueBuffers ) {
attribute.__webglInitialized = true;
var size = 1; // "f" and "i"
if( attribute.type === "v2" ) size = 2;
else if( attribute.type === "v3" ) size = 3;
else if( attribute.type === "v4" ) size = 4;
else if( attribute.type === "c" ) size = 3;
attribute.size = size;
attribute.array = new Float32Array( nvertices * size );
attribute.buffer = this.renderer.createBuffer();
attribute.buffer.belongsToAttribute = a;
originalAttribute.needsUpdate = true;
attribute.__original = originalAttribute;
}
geometryGroup.__webglCustomAttributesList.push( attribute );
}
}
geometryGroup.__inittedArrays = true;
};
THREE.WebGLRenderer2.MeshRenderer.prototype.setBuffers = function( geometryGroup, object, dispose, material ) {
if ( ! geometryGroup.__inittedArrays ) {
return;
}
var renderer = this.renderer;
var normalType = this.bufferGuessNormalType( material ),
vertexColorType = this.bufferGuessVertexColorType( material ),
uvType = this.bufferGuessUVType( material ),
needsSmoothNormals = ( normalType === THREE.SmoothShading );
var f, fl, fi, face,
vertexNormals, faceNormal, normal,
vertexColors, faceColor,
vertexTangents,
uv, uv2, v1, v2, v3, v4, t1, t2, t3, t4, n1, n2, n3, n4,
c1, c2, c3, c4,
sw1, sw2, sw3, sw4,
si1, si2, si3, si4,
sa1, sa2, sa3, sa4,
sb1, sb2, sb3, sb4,
m, ml, i, il,
vn, uvi, uv2i,
vk, vkl, vka,
nka, chf, faceVertexNormals,
a,
vertexIndex = 0,
offset = 0,
offset_uv = 0,
offset_uv2 = 0,
offset_face = 0,
offset_normal = 0,
offset_tangent = 0,
offset_line = 0,
offset_color = 0,
offset_skin = 0,
offset_morphTarget = 0,
offset_custom = 0,
offset_customSrc = 0,
value,
vertexArray = geometryGroup.__vertexArray,
uvArray = geometryGroup.__uvArray,
uv2Array = geometryGroup.__uv2Array,
normalArray = geometryGroup.__normalArray,
tangentArray = geometryGroup.__tangentArray,
colorArray = geometryGroup.__colorArray,
skinIndexArray = geometryGroup.__skinIndexArray,
skinWeightArray = geometryGroup.__skinWeightArray,
morphTargetsArrays = geometryGroup.__morphTargetsArrays,
morphNormalsArrays = geometryGroup.__morphNormalsArrays,
customAttributes = geometryGroup.__webglCustomAttributesList,
customAttribute,
faceArray = geometryGroup.__faceArray,
lineArray = geometryGroup.__lineArray,
geometry = object.geometry, // this is shared for all chunks
dirtyVertices = geometry.verticesNeedUpdate,
dirtyElements = geometry.elementsNeedUpdate,
dirtyUvs = geometry.uvsNeedUpdate,
dirtyNormals = geometry.normalsNeedUpdate,
dirtyTangents = geometry.tangentsNeedUpdate,
dirtyColors = geometry.colorsNeedUpdate,
dirtyMorphTargets = geometry.morphTargetsNeedUpdate,
vertices = geometry.vertices,
chunk_faces3 = geometryGroup.faces3,
chunk_faces4 = geometryGroup.faces4,
obj_faces = geometry.faces,
obj_uvs = geometry.faceVertexUvs[ 0 ],
obj_uvs2 = geometry.faceVertexUvs[ 1 ],
obj_colors = geometry.colors,
obj_skinIndices = geometry.skinIndices,
obj_skinWeights = geometry.skinWeights,
morphTargets = geometry.morphTargets,
morphNormals = geometry.morphNormals;
if ( dirtyVertices ) {
for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
face = obj_faces[ chunk_faces3[ f ] ];
v1 = vertices[ face.a ];
v2 = vertices[ face.b ];
v3 = vertices[ face.c ];
vertexArray[ offset ] = v1.x;
vertexArray[ offset + 1 ] = v1.y;
vertexArray[ offset + 2 ] = v1.z;
vertexArray[ offset + 3 ] = v2.x;
vertexArray[ offset + 4 ] = v2.y;
vertexArray[ offset + 5 ] = v2.z;
vertexArray[ offset + 6 ] = v3.x;
vertexArray[ offset + 7 ] = v3.y;
vertexArray[ offset + 8 ] = v3.z;
offset += 9;
}
for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) {
face = obj_faces[ chunk_faces4[ f ] ];
v1 = vertices[ face.a ];
v2 = vertices[ face.b ];
v3 = vertices[ face.c ];
v4 = vertices[ face.d ];
vertexArray[ offset ] = v1.x;
vertexArray[ offset + 1 ] = v1.y;
vertexArray[ offset + 2 ] = v1.z;
vertexArray[ offset + 3 ] = v2.x;
vertexArray[ offset + 4 ] = v2.y;
vertexArray[ offset + 5 ] = v2.z;
vertexArray[ offset + 6 ] = v3.x;
vertexArray[ offset + 7 ] = v3.y;
vertexArray[ offset + 8 ] = v3.z;
vertexArray[ offset + 9 ] = v4.x;
vertexArray[ offset + 10 ] = v4.y;
vertexArray[ offset + 11 ] = v4.z;
offset += 12;
}
renderer.setDynamicArrayBuffer( geometryGroup.__webglVertexBuffer, vertexArray);
}
if ( dirtyMorphTargets ) {
for ( vk = 0, vkl = morphTargets.length; vk < vkl; vk ++ ) {
offset_morphTarget = 0;
for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
chf = chunk_faces3[ f ];
face = obj_faces[ chf ];
// morph positions
v1 = morphTargets[ vk ].vertices[ face.a ];
v2 = morphTargets[ vk ].vertices[ face.b ];
v3 = morphTargets[ vk ].vertices[ face.c ];
vka = morphTargetsArrays[ vk ];
vka[ offset_morphTarget ] = v1.x;
vka[ offset_morphTarget + 1 ] = v1.y;
vka[ offset_morphTarget + 2 ] = v1.z;
vka[ offset_morphTarget + 3 ] = v2.x;
vka[ offset_morphTarget + 4 ] = v2.y;
vka[ offset_morphTarget + 5 ] = v2.z;
vka[ offset_morphTarget + 6 ] = v3.x;
vka[ offset_morphTarget + 7 ] = v3.y;
vka[ offset_morphTarget + 8 ] = v3.z;
// morph normals
if ( material.morphNormals ) {
if ( needsSmoothNormals ) {
faceVertexNormals = morphNormals[ vk ].vertexNormals[ chf ];
n1 = faceVertexNormals.a;
n2 = faceVertexNormals.b;
n3 = faceVertexNormals.c;
} else {
n1 = morphNormals[ vk ].faceNormals[ chf ];
n2 = n1;
n3 = n1;
}
nka = morphNormalsArrays[ vk ];
nka[ offset_morphTarget ] = n1.x;
nka[ offset_morphTarget + 1 ] = n1.y;
nka[ offset_morphTarget + 2 ] = n1.z;
nka[ offset_morphTarget + 3 ] = n2.x;
nka[ offset_morphTarget + 4 ] = n2.y;
nka[ offset_morphTarget + 5 ] = n2.z;
nka[ offset_morphTarget + 6 ] = n3.x;
nka[ offset_morphTarget + 7 ] = n3.y;
nka[ offset_morphTarget + 8 ] = n3.z;
}
//
offset_morphTarget += 9;
}
for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) {
chf = chunk_faces4[ f ];
face = obj_faces[ chf ];
// morph positions
v1 = morphTargets[ vk ].vertices[ face.a ];
v2 = morphTargets[ vk ].vertices[ face.b ];
v3 = morphTargets[ vk ].vertices[ face.c ];
v4 = morphTargets[ vk ].vertices[ face.d ];
vka = morphTargetsArrays[ vk ];
vka[ offset_morphTarget ] = v1.x;
vka[ offset_morphTarget + 1 ] = v1.y;
vka[ offset_morphTarget + 2 ] = v1.z;
vka[ offset_morphTarget + 3 ] = v2.x;
vka[ offset_morphTarget + 4 ] = v2.y;
vka[ offset_morphTarget + 5 ] = v2.z;
vka[ offset_morphTarget + 6 ] = v3.x;
vka[ offset_morphTarget + 7 ] = v3.y;
vka[ offset_morphTarget + 8 ] = v3.z;
vka[ offset_morphTarget + 9 ] = v4.x;
vka[ offset_morphTarget + 10 ] = v4.y;
vka[ offset_morphTarget + 11 ] = v4.z;
// morph normals
if ( material.morphNormals ) {
if ( needsSmoothNormals ) {
faceVertexNormals = morphNormals[ vk ].vertexNormals[ chf ];
n1 = faceVertexNormals.a;
n2 = faceVertexNormals.b;
n3 = faceVertexNormals.c;
n4 = faceVertexNormals.d;
} else {
n1 = morphNormals[ vk ].faceNormals[ chf ];
n2 = n1;
n3 = n1;
n4 = n1;
}
nka = morphNormalsArrays[ vk ];
nka[ offset_morphTarget ] = n1.x;
nka[ offset_morphTarget + 1 ] = n1.y;
nka[ offset_morphTarget + 2 ] = n1.z;
nka[ offset_morphTarget + 3 ] = n2.x;
nka[ offset_morphTarget + 4 ] = n2.y;
nka[ offset_morphTarget + 5 ] = n2.z;
nka[ offset_morphTarget + 6 ] = n3.x;
nka[ offset_morphTarget + 7 ] = n3.y;
nka[ offset_morphTarget + 8 ] = n3.z;
nka[ offset_morphTarget + 9 ] = n4.x;
nka[ offset_morphTarget + 10 ] = n4.y;
nka[ offset_morphTarget + 11 ] = n4.z;
}
//
offset_morphTarget += 12;
}
this.renderer.setDynamicArrayBuffer( geometryGroup.__webglMorphTargetsBuffers[ vk ], morphTargetsArrays[ vk ]);
if ( material.morphNormals ) {
this.renderer.setDynamicArrayBuffer( geometryGroup.__webglMorphNormalsBuffers[ vk ], morphNormalsArrays[ vk ]);
}
}
}
if ( obj_skinWeights.length ) {
for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
face = obj_faces[ chunk_faces3[ f ] ];
// weights
sw1 = obj_skinWeights[ face.a ];
sw2 = obj_skinWeights[ face.b ];
sw3 = obj_skinWeights[ face.c ];
skinWeightArray[ offset_skin ] = sw1.x;
skinWeightArray[ offset_skin + 1 ] = sw1.y;
skinWeightArray[ offset_skin + 2 ] = sw1.z;
skinWeightArray[ offset_skin + 3 ] = sw1.w;
skinWeightArray[ offset_skin + 4 ] = sw2.x;
skinWeightArray[ offset_skin + 5 ] = sw2.y;
skinWeightArray[ offset_skin + 6 ] = sw2.z;
skinWeightArray[ offset_skin + 7 ] = sw2.w;
skinWeightArray[ offset_skin + 8 ] = sw3.x;
skinWeightArray[ offset_skin + 9 ] = sw3.y;
skinWeightArray[ offset_skin + 10 ] = sw3.z;
skinWeightArray[ offset_skin + 11 ] = sw3.w;
// indices
si1 = obj_skinIndices[ face.a ];
si2 = obj_skinIndices[ face.b ];
si3 = obj_skinIndices[ face.c ];
skinIndexArray[ offset_skin ] = si1.x;
skinIndexArray[ offset_skin + 1 ] = si1.y;
skinIndexArray[ offset_skin + 2 ] = si1.z;
skinIndexArray[ offset_skin + 3 ] = si1.w;
skinIndexArray[ offset_skin + 4 ] = si2.x;
skinIndexArray[ offset_skin + 5 ] = si2.y;
skinIndexArray[ offset_skin + 6 ] = si2.z;
skinIndexArray[ offset_skin + 7 ] = si2.w;
skinIndexArray[ offset_skin + 8 ] = si3.x;
skinIndexArray[ offset_skin + 9 ] = si3.y;
skinIndexArray[ offset_skin + 10 ] = si3.z;
skinIndexArray[ offset_skin + 11 ] = si3.w;
offset_skin += 12;
}
for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) {
face = obj_faces[ chunk_faces4[ f ] ];
// weights
sw1 = obj_skinWeights[ face.a ];
sw2 = obj_skinWeights[ face.b ];
sw3 = obj_skinWeights[ face.c ];
sw4 = obj_skinWeights[ face.d ];
skinWeightArray[ offset_skin ] = sw1.x;
skinWeightArray[ offset_skin + 1 ] = sw1.y;
skinWeightArray[ offset_skin + 2 ] = sw1.z;
skinWeightArray[ offset_skin + 3 ] = sw1.w;
skinWeightArray[ offset_skin + 4 ] = sw2.x;
skinWeightArray[ offset_skin + 5 ] = sw2.y;
skinWeightArray[ offset_skin + 6 ] = sw2.z;
skinWeightArray[ offset_skin + 7 ] = sw2.w;
skinWeightArray[ offset_skin + 8 ] = sw3.x;
skinWeightArray[ offset_skin + 9 ] = sw3.y;
skinWeightArray[ offset_skin + 10 ] = sw3.z;
skinWeightArray[ offset_skin + 11 ] = sw3.w;
skinWeightArray[ offset_skin + 12 ] = sw4.x;
skinWeightArray[ offset_skin + 13 ] = sw4.y;
skinWeightArray[ offset_skin + 14 ] = sw4.z;
skinWeightArray[ offset_skin + 15 ] = sw4.w;
// indices
si1 = obj_skinIndices[ face.a ];
si2 = obj_skinIndices[ face.b ];
si3 = obj_skinIndices[ face.c ];
si4 = obj_skinIndices[ face.d ];
skinIndexArray[ offset_skin ] = si1.x;
skinIndexArray[ offset_skin + 1 ] = si1.y;
skinIndexArray[ offset_skin + 2 ] = si1.z;
skinIndexArray[ offset_skin + 3 ] = si1.w;
skinIndexArray[ offset_skin + 4 ] = si2.x;
skinIndexArray[ offset_skin + 5 ] = si2.y;
skinIndexArray[ offset_skin + 6 ] = si2.z;
skinIndexArray[ offset_skin + 7 ] = si2.w;
skinIndexArray[ offset_skin + 8 ] = si3.x;
skinIndexArray[ offset_skin + 9 ] = si3.y;
skinIndexArray[ offset_skin + 10 ] = si3.z;
skinIndexArray[ offset_skin + 11 ] = si3.w;
skinIndexArray[ offset_skin + 12 ] = si4.x;
skinIndexArray[ offset_skin + 13 ] = si4.y;
skinIndexArray[ offset_skin + 14 ] = si4.z;
skinIndexArray[ offset_skin + 15 ] = si4.w;
offset_skin += 16;
}
if ( offset_skin > 0 ) {
renderer.setDynamicArrayBuffer( geometryGroup.__webglSkinIndicesBuffer, skinIndexArray);
renderer.setDynamicArrayBuffer( geometryGroup.__webglSkinWeightsBuffer, skinWeightArray);
}
}
if ( dirtyColors && vertexColorType ) {
for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
face = obj_faces[ chunk_faces3[ f ] ];
vertexColors = face.vertexColors;
faceColor = face.color;
if ( vertexColors.length === 3 && vertexColorType === THREE.VertexColors ) {
c1 = vertexColors[ 0 ];
c2 = vertexColors[ 1 ];
c3 = vertexColors[ 2 ];
} else {
c1 = faceColor;
c2 = faceColor;
c3 = faceColor;
}
colorArray[ offset_color ] = c1.r;
colorArray[ offset_color + 1 ] = c1.g;
colorArray[ offset_color + 2 ] = c1.b;
colorArray[ offset_color + 3 ] = c2.r;
colorArray[ offset_color + 4 ] = c2.g;
colorArray[ offset_color + 5 ] = c2.b;
colorArray[ offset_color + 6 ] = c3.r;
colorArray[ offset_color + 7 ] = c3.g;
colorArray[ offset_color + 8 ] = c3.b;
offset_color += 9;
}
for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) {
face = obj_faces[ chunk_faces4[ f ] ];
vertexColors = face.vertexColors;
faceColor = face.color;
if ( vertexColors.length === 4 && vertexColorType === THREE.VertexColors ) {
c1 = vertexColors[ 0 ];
c2 = vertexColors[ 1 ];
c3 = vertexColors[ 2 ];
c4 = vertexColors[ 3 ];
} else {
c1 = faceColor;
c2 = faceColor;
c3 = faceColor;
c4 = faceColor;
}
colorArray[ offset_color ] = c1.r;
colorArray[ offset_color + 1 ] = c1.g;
colorArray[ offset_color + 2 ] = c1.b;
colorArray[ offset_color + 3 ] = c2.r;
colorArray[ offset_color + 4 ] = c2.g;
colorArray[ offset_color + 5 ] = c2.b;
colorArray[ offset_color + 6 ] = c3.r;
colorArray[ offset_color + 7 ] = c3.g;
colorArray[ offset_color + 8 ] = c3.b;
colorArray[ offset_color + 9 ] = c4.r;
colorArray[ offset_color + 10 ] = c4.g;
colorArray[ offset_color + 11 ] = c4.b;
offset_color += 12;
}
if ( offset_color > 0 ) {
renderer.setDynamicArrayBuffer( geometryGroup.__webglColorBuffer, colorArray);
}
}
if ( dirtyTangents && geometry.hasTangents ) {
for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
face = obj_faces[ chunk_faces3[ f ] ];
vertexTangents = face.vertexTangents;
t1 = vertexTangents[ 0 ];
t2 = vertexTangents[ 1 ];
t3 = vertexTangents[ 2 ];
tangentArray[ offset_tangent ] = t1.x;
tangentArray[ offset_tangent + 1 ] = t1.y;
tangentArray[ offset_tangent + 2 ] = t1.z;
tangentArray[ offset_tangent + 3 ] = t1.w;
tangentArray[ offset_tangent + 4 ] = t2.x;
tangentArray[ offset_tangent + 5 ] = t2.y;
tangentArray[ offset_tangent + 6 ] = t2.z;
tangentArray[ offset_tangent + 7 ] = t2.w;
tangentArray[ offset_tangent + 8 ] = t3.x;
tangentArray[ offset_tangent + 9 ] = t3.y;
tangentArray[ offset_tangent + 10 ] = t3.z;
tangentArray[ offset_tangent + 11 ] = t3.w;
offset_tangent += 12;
}
for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) {
face = obj_faces[ chunk_faces4[ f ] ];
vertexTangents = face.vertexTangents;
t1 = vertexTangents[ 0 ];
t2 = vertexTangents[ 1 ];
t3 = vertexTangents[ 2 ];
t4 = vertexTangents[ 3 ];
tangentArray[ offset_tangent ] = t1.x;
tangentArray[ offset_tangent + 1 ] = t1.y;
tangentArray[ offset_tangent + 2 ] = t1.z;
tangentArray[ offset_tangent + 3 ] = t1.w;
tangentArray[ offset_tangent + 4 ] = t2.x;
tangentArray[ offset_tangent + 5 ] = t2.y;
tangentArray[ offset_tangent + 6 ] = t2.z;
tangentArray[ offset_tangent + 7 ] = t2.w;
tangentArray[ offset_tangent + 8 ] = t3.x;
tangentArray[ offset_tangent + 9 ] = t3.y;
tangentArray[ offset_tangent + 10 ] = t3.z;
tangentArray[ offset_tangent + 11 ] = t3.w;
tangentArray[ offset_tangent + 12 ] = t4.x;
tangentArray[ offset_tangent + 13 ] = t4.y;
tangentArray[ offset_tangent + 14 ] = t4.z;
tangentArray[ offset_tangent + 15 ] = t4.w;
offset_tangent += 16;
}
renderer.setDynamicArrayBuffer( geometryGroup.__webglTangentBuffer, tangentArray);
}
if ( dirtyNormals && normalType ) {
for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
face = obj_faces[ chunk_faces3[ f ] ];
vertexNormals = face.vertexNormals;
faceNormal = face.normal;
if ( vertexNormals.length === 3 && needsSmoothNormals ) {
for ( i = 0; i < 3; i ++ ) {
vn = vertexNormals[ i ];
normalArray[ offset_normal ] = vn.x;
normalArray[ offset_normal + 1 ] = vn.y;
normalArray[ offset_normal + 2 ] = vn.z;
offset_normal += 3;
}
} else {
for ( i = 0; i < 3; i ++ ) {
normalArray[ offset_normal ] = faceNormal.x;
normalArray[ offset_normal + 1 ] = faceNormal.y;
normalArray[ offset_normal + 2 ] = faceNormal.z;
offset_normal += 3;
}
}
}
for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) {
face = obj_faces[ chunk_faces4[ f ] ];
vertexNormals = face.vertexNormals;
faceNormal = face.normal;
if ( vertexNormals.length === 4 && needsSmoothNormals ) {
for ( i = 0; i < 4; i ++ ) {
vn = vertexNormals[ i ];
normalArray[ offset_normal ] = vn.x;
normalArray[ offset_normal + 1 ] = vn.y;
normalArray[ offset_normal + 2 ] = vn.z;
offset_normal += 3;
}
} else {
for ( i = 0; i < 4; i ++ ) {
normalArray[ offset_normal ] = faceNormal.x;
normalArray[ offset_normal + 1 ] = faceNormal.y;
normalArray[ offset_normal + 2 ] = faceNormal.z;
offset_normal += 3;
}
}
}
renderer.setDynamicArrayBuffer( geometryGroup.__webglNormalBuffer, normalArray);
}
if ( dirtyUvs && obj_uvs && uvType ) {
for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
fi = chunk_faces3[ f ];
uv = obj_uvs[ fi ];
if ( uv === undefined ) continue;
for ( i = 0; i < 3; i ++ ) {
uvi = uv[ i ];
uvArray[ offset_uv ] = uvi.x;
uvArray[ offset_uv + 1 ] = uvi.y;
offset_uv += 2;
}
}
for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) {
fi = chunk_faces4[ f ];
uv = obj_uvs[ fi ];
if ( uv === undefined ) continue;
for ( i = 0; i < 4; i ++ ) {
uvi = uv[ i ];
uvArray[ offset_uv ] = uvi.x;
uvArray[ offset_uv + 1 ] = uvi.y;
offset_uv += 2;
}
}
if ( offset_uv > 0 ) {
renderer.setDynamicArrayBuffer( geometryGroup.__webglUVBuffer, uvArray);
}
}
if ( dirtyUvs && obj_uvs2 && uvType ) {
for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
fi = chunk_faces3[ f ];
uv2 = obj_uvs2[ fi ];
if ( uv2 === undefined ) continue;
for ( i = 0; i < 3; i ++ ) {
uv2i = uv2[ i ];
uv2Array[ offset_uv2 ] = uv2i.x;
uv2Array[ offset_uv2 + 1 ] = uv2i.y;
offset_uv2 += 2;
}
}
for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) {
fi = chunk_faces4[ f ];
uv2 = obj_uvs2[ fi ];
if ( uv2 === undefined ) continue;
for ( i = 0; i < 4; i ++ ) {
uv2i = uv2[ i ];
uv2Array[ offset_uv2 ] = uv2i.x;
uv2Array[ offset_uv2 + 1 ] = uv2i.y;
offset_uv2 += 2;
}
}
if ( offset_uv2 > 0 ) {
renderer.setDynamicArrayBuffer( geometryGroup.__webglUV2Buffer, uv2Array);
}
}
if ( dirtyElements ) {
for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
faceArray[ offset_face ] = vertexIndex;
faceArray[ offset_face + 1 ] = vertexIndex + 1;
faceArray[ offset_face + 2 ] = vertexIndex + 2;
offset_face += 3;
lineArray[ offset_line ] = vertexIndex;
lineArray[ offset_line + 1 ] = vertexIndex + 1;
lineArray[ offset_line + 2 ] = vertexIndex;
lineArray[ offset_line + 3 ] = vertexIndex + 2;
lineArray[ offset_line + 4 ] = vertexIndex + 1;
lineArray[ offset_line + 5 ] = vertexIndex + 2;
offset_line += 6;
vertexIndex += 3;
}
for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) {
faceArray[ offset_face ] = vertexIndex;
faceArray[ offset_face + 1 ] = vertexIndex + 1;
faceArray[ offset_face + 2 ] = vertexIndex + 3;
faceArray[ offset_face + 3 ] = vertexIndex + 1;
faceArray[ offset_face + 4 ] = vertexIndex + 2;
faceArray[ offset_face + 5 ] = vertexIndex + 3;
offset_face += 6;
lineArray[ offset_line ] = vertexIndex;
lineArray[ offset_line + 1 ] = vertexIndex + 1;
lineArray[ offset_line + 2 ] = vertexIndex;
lineArray[ offset_line + 3 ] = vertexIndex + 3;
lineArray[ offset_line + 4 ] = vertexIndex + 1;
lineArray[ offset_line + 5 ] = vertexIndex + 2;
lineArray[ offset_line + 6 ] = vertexIndex + 2;
lineArray[ offset_line + 7 ] = vertexIndex + 3;
offset_line += 8;
vertexIndex += 4;
}
renderer.setDynamicIndexBuffer( geometryGroup.__webglFaceBuffer, faceArray);
renderer.setDynamicIndexBuffer( geometryGroup.__webglLineBuffer, lineArray);
}
if ( customAttributes ) {
for ( i = 0, il = customAttributes.length; i < il; i ++ ) {
customAttribute = customAttributes[ i ];
if ( ! customAttribute.__original.needsUpdate ) continue;
offset_custom = 0;
offset_customSrc = 0;
if ( customAttribute.size === 1 ) {
if ( customAttribute.boundTo === undefined || customAttribute.boundTo === "vertices" ) {
for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
face = obj_faces[ chunk_faces3[ f ] ];
customAttribute.array[ offset_custom ] = customAttribute.value[ face.a ];
customAttribute.array[ offset_custom + 1 ] = customAttribute.value[ face.b ];
customAttribute.array[ offset_custom + 2 ] = customAttribute.value[ face.c ];
offset_custom += 3;
}
for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) {
face = obj_faces[ chunk_faces4[ f ] ];
customAttribute.array[ offset_custom ] = customAttribute.value[ face.a ];
customAttribute.array[ offset_custom + 1 ] = customAttribute.value[ face.b ];
customAttribute.array[ offset_custom + 2 ] = customAttribute.value[ face.c ];
customAttribute.array[ offset_custom + 3 ] = customAttribute.value[ face.d ];
offset_custom += 4;
}
} else if ( customAttribute.boundTo === "faces" ) {
for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
value = customAttribute.value[ chunk_faces3[ f ] ];
customAttribute.array[ offset_custom ] = value;
customAttribute.array[ offset_custom + 1 ] = value;
customAttribute.array[ offset_custom + 2 ] = value;
offset_custom += 3;
}
for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) {
value = customAttribute.value[ chunk_faces4[ f ] ];
customAttribute.array[ offset_custom ] = value;
customAttribute.array[ offset_custom + 1 ] = value;
customAttribute.array[ offset_custom + 2 ] = value;
customAttribute.array[ offset_custom + 3 ] = value;
offset_custom += 4;
}
}
} else if ( customAttribute.size === 2 ) {
if ( customAttribute.boundTo === undefined || customAttribute.boundTo === "vertices" ) {
for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
face = obj_faces[ chunk_faces3[ f ] ];
v1 = customAttribute.value[ face.a ];
v2 = customAttribute.value[ face.b ];
v3 = customAttribute.value[ face.c ];
customAttribute.array[ offset_custom ] = v1.x;
customAttribute.array[ offset_custom + 1 ] = v1.y;
customAttribute.array[ offset_custom + 2 ] = v2.x;
customAttribute.array[ offset_custom + 3 ] = v2.y;
customAttribute.array[ offset_custom + 4 ] = v3.x;
customAttribute.array[ offset_custom + 5 ] = v3.y;
offset_custom += 6;
}
for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) {
face = obj_faces[ chunk_faces4[ f ] ];
v1 = customAttribute.value[ face.a ];
v2 = customAttribute.value[ face.b ];
v3 = customAttribute.value[ face.c ];
v4 = customAttribute.value[ face.d ];
customAttribute.array[ offset_custom ] = v1.x;
customAttribute.array[ offset_custom + 1 ] = v1.y;
customAttribute.array[ offset_custom + 2 ] = v2.x;
customAttribute.array[ offset_custom + 3 ] = v2.y;
customAttribute.array[ offset_custom + 4 ] = v3.x;
customAttribute.array[ offset_custom + 5 ] = v3.y;
customAttribute.array[ offset_custom + 6 ] = v4.x;
customAttribute.array[ offset_custom + 7 ] = v4.y;
offset_custom += 8;
}
} else if ( customAttribute.boundTo === "faces" ) {
for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
value = customAttribute.value[ chunk_faces3[ f ] ];
v1 = value;
v2 = value;
v3 = value;
customAttribute.array[ offset_custom ] = v1.x;
customAttribute.array[ offset_custom + 1 ] = v1.y;
customAttribute.array[ offset_custom + 2 ] = v2.x;
customAttribute.array[ offset_custom + 3 ] = v2.y;
customAttribute.array[ offset_custom + 4 ] = v3.x;
customAttribute.array[ offset_custom + 5 ] = v3.y;
offset_custom += 6;
}
for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) {
value = customAttribute.value[ chunk_faces4[ f ] ];
v1 = value;
v2 = value;
v3 = value;
v4 = value;
customAttribute.array[ offset_custom ] = v1.x;
customAttribute.array[ offset_custom + 1 ] = v1.y;
customAttribute.array[ offset_custom + 2 ] = v2.x;
customAttribute.array[ offset_custom + 3 ] = v2.y;
customAttribute.array[ offset_custom + 4 ] = v3.x;
customAttribute.array[ offset_custom + 5 ] = v3.y;
customAttribute.array[ offset_custom + 6 ] = v4.x;
customAttribute.array[ offset_custom + 7 ] = v4.y;
offset_custom += 8;
}
}
} else if ( customAttribute.size === 3 ) {
var pp;
if ( customAttribute.type === "c" ) {
pp = [ "r", "g", "b" ];
} else {
pp = [ "x", "y", "z" ];
}
if ( customAttribute.boundTo === undefined || customAttribute.boundTo === "vertices" ) {
for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
face = obj_faces[ chunk_faces3[ f ] ];
v1 = customAttribute.value[ face.a ];
v2 = customAttribute.value[ face.b ];
v3 = customAttribute.value[ face.c ];
customAttribute.array[ offset_custom ] = v1[ pp[ 0 ] ];
customAttribute.array[ offset_custom + 1 ] = v1[ pp[ 1 ] ];
customAttribute.array[ offset_custom + 2 ] = v1[ pp[ 2 ] ];
customAttribute.array[ offset_custom + 3 ] = v2[ pp[ 0 ] ];
customAttribute.array[ offset_custom + 4 ] = v2[ pp[ 1 ] ];
customAttribute.array[ offset_custom + 5 ] = v2[ pp[ 2 ] ];
customAttribute.array[ offset_custom + 6 ] = v3[ pp[ 0 ] ];
customAttribute.array[ offset_custom + 7 ] = v3[ pp[ 1 ] ];
customAttribute.array[ offset_custom + 8 ] = v3[ pp[ 2 ] ];
offset_custom += 9;
}
for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) {
face = obj_faces[ chunk_faces4[ f ] ];
v1 = customAttribute.value[ face.a ];
v2 = customAttribute.value[ face.b ];
v3 = customAttribute.value[ face.c ];
v4 = customAttribute.value[ face.d ];
customAttribute.array[ offset_custom ] = v1[ pp[ 0 ] ];
customAttribute.array[ offset_custom + 1 ] = v1[ pp[ 1 ] ];
customAttribute.array[ offset_custom + 2 ] = v1[ pp[ 2 ] ];
customAttribute.array[ offset_custom + 3 ] = v2[ pp[ 0 ] ];
customAttribute.array[ offset_custom + 4 ] = v2[ pp[ 1 ] ];
customAttribute.array[ offset_custom + 5 ] = v2[ pp[ 2 ] ];
customAttribute.array[ offset_custom + 6 ] = v3[ pp[ 0 ] ];
customAttribute.array[ offset_custom + 7 ] = v3[ pp[ 1 ] ];
customAttribute.array[ offset_custom + 8 ] = v3[ pp[ 2 ] ];
customAttribute.array[ offset_custom + 9 ] = v4[ pp[ 0 ] ];
customAttribute.array[ offset_custom + 10 ] = v4[ pp[ 1 ] ];
customAttribute.array[ offset_custom + 11 ] = v4[ pp[ 2 ] ];
offset_custom += 12;
}
} else if ( customAttribute.boundTo === "faces" ) {
for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
value = customAttribute.value[ chunk_faces3[ f ] ];
v1 = value;
v2 = value;
v3 = value;
customAttribute.array[ offset_custom ] = v1[ pp[ 0 ] ];
customAttribute.array[ offset_custom + 1 ] = v1[ pp[ 1 ] ];
customAttribute.array[ offset_custom + 2 ] = v1[ pp[ 2 ] ];
customAttribute.array[ offset_custom + 3 ] = v2[ pp[ 0 ] ];
customAttribute.array[ offset_custom + 4 ] = v2[ pp[ 1 ] ];
customAttribute.array[ offset_custom + 5 ] = v2[ pp[ 2 ] ];
customAttribute.array[ offset_custom + 6 ] = v3[ pp[ 0 ] ];
customAttribute.array[ offset_custom + 7 ] = v3[ pp[ 1 ] ];
customAttribute.array[ offset_custom + 8 ] = v3[ pp[ 2 ] ];
offset_custom += 9;
}
for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) {
value = customAttribute.value[ chunk_faces4[ f ] ];
v1 = value;
v2 = value;
v3 = value;
v4 = value;
customAttribute.array[ offset_custom ] = v1[ pp[ 0 ] ];
customAttribute.array[ offset_custom + 1 ] = v1[ pp[ 1 ] ];
customAttribute.array[ offset_custom + 2 ] = v1[ pp[ 2 ] ];
customAttribute.array[ offset_custom + 3 ] = v2[ pp[ 0 ] ];
customAttribute.array[ offset_custom + 4 ] = v2[ pp[ 1 ] ];
customAttribute.array[ offset_custom + 5 ] = v2[ pp[ 2 ] ];
customAttribute.array[ offset_custom + 6 ] = v3[ pp[ 0 ] ];
customAttribute.array[ offset_custom + 7 ] = v3[ pp[ 1 ] ];
customAttribute.array[ offset_custom + 8 ] = v3[ pp[ 2 ] ];
customAttribute.array[ offset_custom + 9 ] = v4[ pp[ 0 ] ];
customAttribute.array[ offset_custom + 10 ] = v4[ pp[ 1 ] ];
customAttribute.array[ offset_custom + 11 ] = v4[ pp[ 2 ] ];
offset_custom += 12;
}
} else if ( customAttribute.boundTo === "faceVertices" ) {
for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
value = customAttribute.value[ chunk_faces3[ f ] ];
v1 = value[ 0 ];
v2 = value[ 1 ];
v3 = value[ 2 ];
customAttribute.array[ offset_custom ] = v1[ pp[ 0 ] ];
customAttribute.array[ offset_custom + 1 ] = v1[ pp[ 1 ] ];
customAttribute.array[ offset_custom + 2 ] = v1[ pp[ 2 ] ];
customAttribute.array[ offset_custom + 3 ] = v2[ pp[ 0 ] ];
customAttribute.array[ offset_custom + 4 ] = v2[ pp[ 1 ] ];
customAttribute.array[ offset_custom + 5 ] = v2[ pp[ 2 ] ];
customAttribute.array[ offset_custom + 6 ] = v3[ pp[ 0 ] ];
customAttribute.array[ offset_custom + 7 ] = v3[ pp[ 1 ] ];
customAttribute.array[ offset_custom + 8 ] = v3[ pp[ 2 ] ];
offset_custom += 9;
}
for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) {
value = customAttribute.value[ chunk_faces4[ f ] ];
v1 = value[ 0 ];
v2 = value[ 1 ];
v3 = value[ 2 ];
v4 = value[ 3 ];
customAttribute.array[ offset_custom ] = v1[ pp[ 0 ] ];
customAttribute.array[ offset_custom + 1 ] = v1[ pp[ 1 ] ];
customAttribute.array[ offset_custom + 2 ] = v1[ pp[ 2 ] ];
customAttribute.array[ offset_custom + 3 ] = v2[ pp[ 0 ] ];
customAttribute.array[ offset_custom + 4 ] = v2[ pp[ 1 ] ];
customAttribute.array[ offset_custom + 5 ] = v2[ pp[ 2 ] ];
customAttribute.array[ offset_custom + 6 ] = v3[ pp[ 0 ] ];
customAttribute.array[ offset_custom + 7 ] = v3[ pp[ 1 ] ];
customAttribute.array[ offset_custom + 8 ] = v3[ pp[ 2 ] ];
customAttribute.array[ offset_custom + 9 ] = v4[ pp[ 0 ] ];
customAttribute.array[ offset_custom + 10 ] = v4[ pp[ 1 ] ];
customAttribute.array[ offset_custom + 11 ] = v4[ pp[ 2 ] ];
offset_custom += 12;
}
}
} else if ( customAttribute.size === 4 ) {
if ( customAttribute.boundTo === undefined || customAttribute.boundTo === "vertices" ) {
for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
face = obj_faces[ chunk_faces3[ f ] ];
v1 = customAttribute.value[ face.a ];
v2 = customAttribute.value[ face.b ];
v3 = customAttribute.value[ face.c ];
customAttribute.array[ offset_custom ] = v1.x;
customAttribute.array[ offset_custom + 1 ] = v1.y;
customAttribute.array[ offset_custom + 2 ] = v1.z;
customAttribute.array[ offset_custom + 3 ] = v1.w;
customAttribute.array[ offset_custom + 4 ] = v2.x;
customAttribute.array[ offset_custom + 5 ] = v2.y;
customAttribute.array[ offset_custom + 6 ] = v2.z;
customAttribute.array[ offset_custom + 7 ] = v2.w;
customAttribute.array[ offset_custom + 8 ] = v3.x;
customAttribute.array[ offset_custom + 9 ] = v3.y;
customAttribute.array[ offset_custom + 10 ] = v3.z;
customAttribute.array[ offset_custom + 11 ] = v3.w;
offset_custom += 12;
}
for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) {
face = obj_faces[ chunk_faces4[ f ] ];
v1 = customAttribute.value[ face.a ];
v2 = customAttribute.value[ face.b ];
v3 = customAttribute.value[ face.c ];
v4 = customAttribute.value[ face.d ];
customAttribute.array[ offset_custom ] = v1.x;
customAttribute.array[ offset_custom + 1 ] = v1.y;
customAttribute.array[ offset_custom + 2 ] = v1.z;
customAttribute.array[ offset_custom + 3 ] = v1.w;
customAttribute.array[ offset_custom + 4 ] = v2.x;
customAttribute.array[ offset_custom + 5 ] = v2.y;
customAttribute.array[ offset_custom + 6 ] = v2.z;
customAttribute.array[ offset_custom + 7 ] = v2.w;
customAttribute.array[ offset_custom + 8 ] = v3.x;
customAttribute.array[ offset_custom + 9 ] = v3.y;
customAttribute.array[ offset_custom + 10 ] = v3.z;
customAttribute.array[ offset_custom + 11 ] = v3.w;
customAttribute.array[ offset_custom + 12 ] = v4.x;
customAttribute.array[ offset_custom + 13 ] = v4.y;
customAttribute.array[ offset_custom + 14 ] = v4.z;
customAttribute.array[ offset_custom + 15 ] = v4.w;
offset_custom += 16;
}
} else if ( customAttribute.boundTo === "faces" ) {
for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
value = customAttribute.value[ chunk_faces3[ f ] ];
v1 = value;
v2 = value;
v3 = value;
customAttribute.array[ offset_custom ] = v1.x;
customAttribute.array[ offset_custom + 1 ] = v1.y;
customAttribute.array[ offset_custom + 2 ] = v1.z;
customAttribute.array[ offset_custom + 3 ] = v1.w;
customAttribute.array[ offset_custom + 4 ] = v2.x;
customAttribute.array[ offset_custom + 5 ] = v2.y;
customAttribute.array[ offset_custom + 6 ] = v2.z;
customAttribute.array[ offset_custom + 7 ] = v2.w;
customAttribute.array[ offset_custom + 8 ] = v3.x;
customAttribute.array[ offset_custom + 9 ] = v3.y;
customAttribute.array[ offset_custom + 10 ] = v3.z;
customAttribute.array[ offset_custom + 11 ] = v3.w;
offset_custom += 12;
}
for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) {
value = customAttribute.value[ chunk_faces4[ f ] ];
v1 = value;
v2 = value;
v3 = value;
v4 = value;
customAttribute.array[ offset_custom ] = v1.x;
customAttribute.array[ offset_custom + 1 ] = v1.y;
customAttribute.array[ offset_custom + 2 ] = v1.z;
customAttribute.array[ offset_custom + 3 ] = v1.w;
customAttribute.array[ offset_custom + 4 ] = v2.x;
customAttribute.array[ offset_custom + 5 ] = v2.y;
customAttribute.array[ offset_custom + 6 ] = v2.z;
customAttribute.array[ offset_custom + 7 ] = v2.w;
customAttribute.array[ offset_custom + 8 ] = v3.x;
customAttribute.array[ offset_custom + 9 ] = v3.y;
customAttribute.array[ offset_custom + 10 ] = v3.z;
customAttribute.array[ offset_custom + 11 ] = v3.w;
customAttribute.array[ offset_custom + 12 ] = v4.x;
customAttribute.array[ offset_custom + 13 ] = v4.y;
customAttribute.array[ offset_custom + 14 ] = v4.z;
customAttribute.array[ offset_custom + 15 ] = v4.w;
offset_custom += 16;
}
} else if ( customAttribute.boundTo === "faceVertices" ) {
for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
value = customAttribute.value[ chunk_faces3[ f ] ];
v1 = value[ 0 ];
v2 = value[ 1 ];
v3 = value[ 2 ];
customAttribute.array[ offset_custom ] = v1.x;
customAttribute.array[ offset_custom + 1 ] = v1.y;
customAttribute.array[ offset_custom + 2 ] = v1.z;
customAttribute.array[ offset_custom + 3 ] = v1.w;
customAttribute.array[ offset_custom + 4 ] = v2.x;
customAttribute.array[ offset_custom + 5 ] = v2.y;
customAttribute.array[ offset_custom + 6 ] = v2.z;
customAttribute.array[ offset_custom + 7 ] = v2.w;
customAttribute.array[ offset_custom + 8 ] = v3.x;
customAttribute.array[ offset_custom + 9 ] = v3.y;
customAttribute.array[ offset_custom + 10 ] = v3.z;
customAttribute.array[ offset_custom + 11 ] = v3.w;
offset_custom += 12;
}
for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) {
value = customAttribute.value[ chunk_faces4[ f ] ];
v1 = value[ 0 ];
v2 = value[ 1 ];
v3 = value[ 2 ];
v4 = value[ 3 ];
customAttribute.array[ offset_custom ] = v1.x;
customAttribute.array[ offset_custom + 1 ] = v1.y;
customAttribute.array[ offset_custom + 2 ] = v1.z;
customAttribute.array[ offset_custom + 3 ] = v1.w;
customAttribute.array[ offset_custom + 4 ] = v2.x;
customAttribute.array[ offset_custom + 5 ] = v2.y;
customAttribute.array[ offset_custom + 6 ] = v2.z;
customAttribute.array[ offset_custom + 7 ] = v2.w;
customAttribute.array[ offset_custom + 8 ] = v3.x;
customAttribute.array[ offset_custom + 9 ] = v3.y;
customAttribute.array[ offset_custom + 10 ] = v3.z;
customAttribute.array[ offset_custom + 11 ] = v3.w;
customAttribute.array[ offset_custom + 12 ] = v4.x;
customAttribute.array[ offset_custom + 13 ] = v4.y;
customAttribute.array[ offset_custom + 14 ] = v4.z;
customAttribute.array[ offset_custom + 15 ] = v4.w;
offset_custom += 16;
}
}
}
renderer.setDynamicArrayBuffer( customAttribute.buffer, customAttribute.array);
}
}
if ( dispose ) {
delete geometryGroup.__inittedArrays;
delete geometryGroup.__colorArray;
delete geometryGroup.__normalArray;
delete geometryGroup.__tangentArray;
delete geometryGroup.__uvArray;
delete geometryGroup.__uv2Array;
delete geometryGroup.__faceArray;
delete geometryGroup.__vertexArray;
delete geometryGroup.__lineArray;
delete geometryGroup.__skinIndexArray;
delete geometryGroup.__skinWeightArray;
}
};
\ No newline at end of file
THREE.WebGLRenderer2.Object3DRenderer = function(lowlevelrenderer, info){
this.renderer = lowlevelrenderer;
this.info = info;
};
THREE.WebGLRenderer2.Object3DRenderer.prototype.getBufferMaterial = function( object, geometryGroup ) {
return object.material instanceof THREE.MeshFaceMaterial
? object.material.materials[ geometryGroup.materialIndex ]
: object.material;
};
THREE.WebGLRenderer2.Object3DRenderer.prototype.bufferGuessUVType = function( material ) {
// material must use some texture to require uvs
if ( material.map || material.lightMap || material.bumpMap || material.normalMap || material.specularMap || material instanceof THREE.ShaderMaterial ) {
return true;
}
return false;
};
THREE.WebGLRenderer2.Object3DRenderer.prototype.bufferGuessNormalType = function ( material ) {
// only MeshBasicMaterial and MeshDepthMaterial don't need normals
if ( ( material instanceof THREE.MeshBasicMaterial && !material.envMap ) || material instanceof THREE.MeshDepthMaterial ) {
return false;
}
if ( this.materialNeedsSmoothNormals( material ) ) {
return THREE.SmoothShading;
} else {
return THREE.FlatShading;
}
};
THREE.WebGLRenderer2.Object3DRenderer.prototype.materialNeedsSmoothNormals = function ( material ) {
return material && material.shading !== undefined && material.shading === THREE.SmoothShading;
};
THREE.WebGLRenderer2.Object3DRenderer.prototype.bufferGuessVertexColorType = function ( material ) {
if ( material.vertexColors ) {
return material.vertexColors;
}
return false;
};
THREE.WebGLRenderer2.Object3DRenderer.prototype.initCustomAttributes = function( geometry, object ) {
var nvertices = geometry.vertices.length;
var material = object.material;
if ( material.attributes ) {
if ( geometry.__webglCustomAttributesList === undefined ) {
geometry.__webglCustomAttributesList = [];
}
for ( var a in material.attributes ) {
var attribute = material.attributes[ a ];
if ( !attribute.__webglInitialized || attribute.createUniqueBuffers ) {
attribute.__webglInitialized = true;
var size = 1; // "f" and "i"
if ( attribute.type === "v2" ) size = 2;
else if ( attribute.type === "v3" ) size = 3;
else if ( attribute.type === "v4" ) size = 4;
else if ( attribute.type === "c" ) size = 3;
attribute.size = size;
attribute.array = new Float32Array( nvertices * size );
attribute.buffer = this.renderer.createBuffer();
attribute.buffer.belongsToAttribute = a;
attribute.needsUpdate = true;
}
geometry.__webglCustomAttributesList.push( attribute );
}
}
};
THREE.WebGLRenderer2.Object3DRenderer.prototype.numericalSort = function( a, b ) {
return b[ 0 ] - a[ 0 ];
};
\ No newline at end of file
THREE.WebGLRenderer2.ParticleRenderer = function(lowlevelrenderer, info){
THREE.WebGLRenderer2.Object3DObjectRenderer.call( this, lowlevelrenderer, info );
};
THREE.WebGLRenderer2.ParticleRenderer.prototype = Object.create( THREE.WebGLRenderer2.Object3DObjectRenderer.prototype );
THREE.WebGLRenderer2.ParticleRenderer.prototype.createBuffers = function( geometry ) {
var renderer = this.renderer;
geometry.__webglVertexBuffer = renderer.createBuffer();
geometry.__webglColorBuffer = renderer.createBuffer();
this.info.memory.geometries ++;
};
THREE.WebGLRenderer2.ParticleRenderer.prototype.initBuffers = function( geometry, object ) {
var nvertices = geometry.vertices.length;
geometry.__vertexArray = new Float32Array( nvertices * 3 );
geometry.__colorArray = new Float32Array( nvertices * 3 );
geometry.__sortArray = [];
geometry.__webglParticleCount = nvertices;
this.initCustomAttributes ( geometry, object );
};
THREE.WebGLRenderer2.ParticleRenderer.prototype.setBuffers = function( geometry, object , projectionScreenMatrix) {
var renderer = this.renderer;
var v, c, vertex, offset, index, color,
vertices = geometry.vertices,
vl = vertices.length,
colors = geometry.colors,
cl = colors.length,
vertexArray = geometry.__vertexArray,
colorArray = geometry.__colorArray,
sortArray = geometry.__sortArray,
dirtyVertices = geometry.verticesNeedUpdate,
dirtyElements = geometry.elementsNeedUpdate,
dirtyColors = geometry.colorsNeedUpdate,
customAttributes = geometry.__webglCustomAttributesList,
i, il,
a, ca, cal, value,
customAttribute;
var _projScreenMatrixPS = THREE.WebGLRenderer2.ParticleRenderer._m1,
_vector3 = THREE.WebGLRenderer2.ParticleRenderer._v1;
if ( object.sortParticles ) {
_projScreenMatrixPS.copy( projectionScreenMatrix );
_projScreenMatrixPS.multiplySelf( object.matrixWorld );
for ( v = 0; v < vl; v ++ ) {
vertex = vertices[ v ];
_vector3.copy( vertex );
_vector3.applyMatrix4(_projScreenMatrixPS);
sortArray[ v ] = [ _vector3.z, v ];
}
sortArray.sort( this.numericalSort );
for ( v = 0; v < vl; v ++ ) {
vertex = vertices[ sortArray[v][1] ];
offset = v * 3;
vertexArray[ offset ] = vertex.x;
vertexArray[ offset + 1 ] = vertex.y;
vertexArray[ offset + 2 ] = vertex.z;
}
for ( c = 0; c < cl; c ++ ) {
offset = c * 3;
color = colors[ sortArray[c][1] ];
colorArray[ offset ] = color.r;
colorArray[ offset + 1 ] = color.g;
colorArray[ offset + 2 ] = color.b;
}
if ( customAttributes ) {
for ( i = 0, il = customAttributes.length; i < il; i ++ ) {
customAttribute = customAttributes[ i ];
if ( ! ( customAttribute.boundTo === undefined || customAttribute.boundTo === "vertices" ) ) continue;
offset = 0;
cal = customAttribute.value.length;
if ( customAttribute.size === 1 ) {
for ( ca = 0; ca < cal; ca ++ ) {
index = sortArray[ ca ][ 1 ];
customAttribute.array[ ca ] = customAttribute.value[ index ];
}
} else if ( customAttribute.size === 2 ) {
for ( ca = 0; ca < cal; ca ++ ) {
index = sortArray[ ca ][ 1 ];
value = customAttribute.value[ index ];
customAttribute.array[ offset ] = value.x;
customAttribute.array[ offset + 1 ] = value.y;
offset += 2;
}
} else if ( customAttribute.size === 3 ) {
if ( customAttribute.type === "c" ) {
for ( ca = 0; ca < cal; ca ++ ) {
index = sortArray[ ca ][ 1 ];
value = customAttribute.value[ index ];
customAttribute.array[ offset ] = value.r;
customAttribute.array[ offset + 1 ] = value.g;
customAttribute.array[ offset + 2 ] = value.b;
offset += 3;
}
} else {
for ( ca = 0; ca < cal; ca ++ ) {
index = sortArray[ ca ][ 1 ];
value = customAttribute.value[ index ];
customAttribute.array[ offset ] = value.x;
customAttribute.array[ offset + 1 ] = value.y;
customAttribute.array[ offset + 2 ] = value.z;
offset += 3;
}
}
} else if ( customAttribute.size === 4 ) {
for ( ca = 0; ca < cal; ca ++ ) {
index = sortArray[ ca ][ 1 ];
value = customAttribute.value[ index ];
customAttribute.array[ offset ] = value.x;
customAttribute.array[ offset + 1 ] = value.y;
customAttribute.array[ offset + 2 ] = value.z;
customAttribute.array[ offset + 3 ] = value.w;
offset += 4;
}
}
}
}
} else {
if ( dirtyVertices ) {
for ( v = 0; v < vl; v ++ ) {
vertex = vertices[ v ];
offset = v * 3;
vertexArray[ offset ] = vertex.x;
vertexArray[ offset + 1 ] = vertex.y;
vertexArray[ offset + 2 ] = vertex.z;
}
}
if ( dirtyColors ) {
for ( c = 0; c < cl; c ++ ) {
color = colors[ c ];
offset = c * 3;
colorArray[ offset ] = color.r;
colorArray[ offset + 1 ] = color.g;
colorArray[ offset + 2 ] = color.b;
}
}
if ( customAttributes ) {
for ( i = 0, il = customAttributes.length; i < il; i ++ ) {
customAttribute = customAttributes[ i ];
if ( customAttribute.needsUpdate &&
( customAttribute.boundTo === undefined ||
customAttribute.boundTo === "vertices") ) {
cal = customAttribute.value.length;
offset = 0;
if ( customAttribute.size === 1 ) {
for ( ca = 0; ca < cal; ca ++ ) {
customAttribute.array[ ca ] = customAttribute.value[ ca ];
}
} else if ( customAttribute.size === 2 ) {
for ( ca = 0; ca < cal; ca ++ ) {
value = customAttribute.value[ ca ];
customAttribute.array[ offset ] = value.x;
customAttribute.array[ offset + 1 ] = value.y;
offset += 2;
}
} else if ( customAttribute.size === 3 ) {
if ( customAttribute.type === "c" ) {
for ( ca = 0; ca < cal; ca ++ ) {
value = customAttribute.value[ ca ];
customAttribute.array[ offset ] = value.r;
customAttribute.array[ offset + 1 ] = value.g;
customAttribute.array[ offset + 2 ] = value.b;
offset += 3;
}
} else {
for ( ca = 0; ca < cal; ca ++ ) {
value = customAttribute.value[ ca ];
customAttribute.array[ offset ] = value.x;
customAttribute.array[ offset + 1 ] = value.y;
customAttribute.array[ offset + 2 ] = value.z;
offset += 3;
}
}
} else if ( customAttribute.size === 4 ) {
for ( ca = 0; ca < cal; ca ++ ) {
value = customAttribute.value[ ca ];
customAttribute.array[ offset ] = value.x;
customAttribute.array[ offset + 1 ] = value.y;
customAttribute.array[ offset + 2 ] = value.z;
customAttribute.array[ offset + 3 ] = value.w;
offset += 4;
}
}
}
}
}
}
if ( dirtyVertices || object.sortParticles ) {
renderer.setDynamicArrayBuffer(geometry.__webglVertexBuffer,vertexArray);
}
if ( dirtyColors || object.sortParticles ) {
renderer.setDynamicArrayBuffer(geometry.__webglColorBuffer,colorArray);
}
if ( customAttributes ) {
for ( i = 0, il = customAttributes.length; i < il; i ++ ) {
customAttribute = customAttributes[ i ];
if ( customAttribute.needsUpdate || object.sortParticles ) {
renderer.setDynamicArrayBuffer(customAttribute.buffer,customAttribute.array);
}
}
}
};
THREE.WebGLRenderer2.ParticleRenderer._m1 = new THREE.Matrix4();
THREE.WebGLRenderer2.ParticleRenderer._v1 = new THREE.Vector3();
\ No newline at end of file
THREE.WebGLRenderer2.RibbonRenderer = function(lowlevelrenderer, info){
THREE.WebGLRenderer2.Object3DObjectRenderer.call( this, lowlevelrenderer, info );
};
THREE.WebGLRenderer2.RibbonRenderer.prototype = Object.create( THREE.WebGLRenderer2.Object3DObjectRenderer.prototype );
THREE.WebGLRenderer2.RibbonRenderer.prototype.createBuffers = function( geometry ) {
var renderer = this.renderer;
geometry.__webglVertexBuffer = renderer.createBuffer();
geometry.__webglColorBuffer = renderer.createBuffer();
geometry.__webglNormalBuffer = renderer.createBuffer();
this.info.memory.geometries ++;
};
THREE.WebGLRenderer2.RibbonRenderer.prototype.initBuffers = function( geometry, object ) {
var nvertices = geometry.vertices.length;
geometry.__vertexArray = new Float32Array( nvertices * 3 );
geometry.__colorArray = new Float32Array( nvertices * 3 );
geometry.__normalArray = new Float32Array( nvertices * 3 );
geometry.__webglVertexCount = nvertices;
this.initCustomAttributes ( geometry, object );
};
THREE.WebGLRenderer2.RibbonRenderer.prototype.setBuffers = function( geometry, object , projectionScreenMatrix) {
var renderer = this.renderer;
var v, c, n, vertex, offset, color, normal,
i, il, ca, cal, customAttribute, value,
vertices = geometry.vertices,
colors = geometry.colors,
normals = geometry.normals,
vl = vertices.length,
cl = colors.length,
nl = normals.length,
vertexArray = geometry.__vertexArray,
colorArray = geometry.__colorArray,
normalArray = geometry.__normalArray,
dirtyVertices = geometry.verticesNeedUpdate,
dirtyColors = geometry.colorsNeedUpdate,
dirtyNormals = geometry.normalsNeedUpdate,
customAttributes = geometry.__webglCustomAttributesList;
if ( dirtyVertices ) {
for ( v = 0; v < vl; v ++ ) {
vertex = vertices[ v ];
offset = v * 3;
vertexArray[ offset ] = vertex.x;
vertexArray[ offset + 1 ] = vertex.y;
vertexArray[ offset + 2 ] = vertex.z;
}
renderer.setDynamicArrayBuffer( geometry.__webglVertexBuffer,vertexArray);
}
if ( dirtyColors ) {
for ( c = 0; c < cl; c ++ ) {
color = colors[ c ];
offset = c * 3;
colorArray[ offset ] = color.r;
colorArray[ offset + 1 ] = color.g;
colorArray[ offset + 2 ] = color.b;
}
renderer.setDynamicArrayBuffer( geometry.__webglColorBuffer, colorArray);
}
if ( dirtyNormals ) {
for ( n = 0; n < nl; n ++ ) {
normal = normals[ n ];
offset = n * 3;
normalArray[ offset ] = normal.x;
normalArray[ offset + 1 ] = normal.y;
normalArray[ offset + 2 ] = normal.z;
}
renderer.setDynamicArrayBuffer( geometry.__webglNormalBuffer, normalArray);
}
if ( customAttributes ) {
for ( i = 0, il = customAttributes.length; i < il; i ++ ) {
customAttribute = customAttributes[ i ];
if ( customAttribute.needsUpdate &&
( customAttribute.boundTo === undefined ||
customAttribute.boundTo === "vertices" ) ) {
offset = 0;
cal = customAttribute.value.length;
if ( customAttribute.size === 1 ) {
for ( ca = 0; ca < cal; ca ++ ) {
customAttribute.array[ ca ] = customAttribute.value[ ca ];
}
} else if ( customAttribute.size === 2 ) {
for ( ca = 0; ca < cal; ca ++ ) {
value = customAttribute.value[ ca ];
customAttribute.array[ offset ] = value.x;
customAttribute.array[ offset + 1 ] = value.y;
offset += 2;
}
} else if ( customAttribute.size === 3 ) {
if ( customAttribute.type === "c" ) {
for ( ca = 0; ca < cal; ca ++ ) {
value = customAttribute.value[ ca ];
customAttribute.array[ offset ] = value.r;
customAttribute.array[ offset + 1 ] = value.g;
customAttribute.array[ offset + 2 ] = value.b;
offset += 3;
}
} else {
for ( ca = 0; ca < cal; ca ++ ) {
value = customAttribute.value[ ca ];
customAttribute.array[ offset ] = value.x;
customAttribute.array[ offset + 1 ] = value.y;
customAttribute.array[ offset + 2 ] = value.z;
offset += 3;
}
}
} else if ( customAttribute.size === 4 ) {
for ( ca = 0; ca < cal; ca ++ ) {
value = customAttribute.value[ ca ];
customAttribute.array[ offset ] = value.x;
customAttribute.array[ offset + 1 ] = value.y;
customAttribute.array[ offset + 2 ] = value.z;
customAttribute.array[ offset + 3 ] = value.w;
offset += 4;
}
}
renderer.setDynamicArrayBuffer( customAttribute.buffer, customAttribute.array);
}
}
}
};
\ No newline at end of file
...@@ -73,8 +73,16 @@ ...@@ -73,8 +73,16 @@
"../src/scenes/Fog.js", "../src/scenes/Fog.js",
"../src/scenes/FogExp2.js", "../src/scenes/FogExp2.js",
"../src/renderers/CanvasRenderer.js", "../src/renderers/CanvasRenderer.js",
"../src/renderers/WebGLShaders.js",
"../src/renderers/WebGLRenderer.js", "../src/renderers/WebGLRenderer.js",
"../src/renderers/WebGLShaders.js",
"../src/renderers/WebGLRenderer2.js",
"../src/renderers/webgl/LowLevelRenderer.js",
"../src/renderers/webgl/ShaderBuilder.js",
"../src/renderers/webgl/objects/Object3DRenderer.js",
"../src/renderers/webgl/objects/MeshRenderer.js",
"../src/renderers/webgl/objects/ParticleRenderer.js",
"../src/renderers/webgl/objects/LineRenderer.js",
"../src/renderers/webgl/objects/RibbonRenderer.js",
"../src/renderers/WebGLRenderTarget.js", "../src/renderers/WebGLRenderTarget.js",
"../src/renderers/WebGLRenderTargetCube.js", "../src/renderers/WebGLRenderTargetCube.js",
"../src/renderers/renderables/RenderableVertex.js", "../src/renderers/renderables/RenderableVertex.js",
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册