Created
July 28, 2015 10:14
-
-
Save gidili/61515feabf9dbb2d5dc3 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
define(function(require) { | |
THREE.WebGLRenderer = function ( parameters ) { | |
console.log('THREE.WormWebGLRenderer'); | |
parameters = parameters || {}; | |
var _canvas = parameters.canvas !== undefined ? parameters.canvas : document.createElement( 'canvas' ), | |
_context = parameters.context !== undefined ? parameters.context : null, | |
_precision = parameters.precision !== undefined ? parameters.precision : 'highp', | |
_alpha = parameters.alpha !== undefined ? parameters.alpha : false, | |
_depth = parameters.depth !== undefined ? parameters.depth : true, | |
_stencil = parameters.stencil !== undefined ? parameters.stencil : true, | |
_antialias = parameters.antialias !== undefined ? parameters.antialias : false, | |
_premultipliedAlpha = parameters.premultipliedAlpha !== undefined ? parameters.premultipliedAlpha : true, | |
_preserveDrawingBuffer = parameters.preserveDrawingBuffer !== undefined ? parameters.preserveDrawingBuffer : false, | |
_logarithmicDepthBuffer = parameters.logarithmicDepthBuffer !== undefined ? parameters.logarithmicDepthBuffer : false, | |
_clearColor = new THREE.Color( 0x000000 ), | |
_clearAlpha = 0; | |
var lights = []; | |
var _webglObjects = {}; | |
var _webglObjectsImmediate = []; | |
var opaqueObjects = []; | |
var transparentObjects = []; | |
var sprites = []; | |
var lensFlares = []; | |
// public properties | |
this.domElement = _canvas; | |
this.context = null; | |
this.devicePixelRatio = parameters.devicePixelRatio !== undefined | |
? parameters.devicePixelRatio | |
: self.devicePixelRatio !== undefined | |
? self.devicePixelRatio | |
: 1; | |
// clearing | |
this.autoClear = true; | |
this.autoClearColor = true; | |
this.autoClearDepth = true; | |
this.autoClearStencil = true; | |
// scene graph | |
this.sortObjects = true; | |
// physically based shading | |
this.gammaInput = false; | |
this.gammaOutput = false; | |
// shadow map | |
this.shadowMapEnabled = false; | |
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; | |
// info | |
this.info = { | |
memory: { | |
programs: 0, | |
geometries: 0, | |
textures: 0 | |
}, | |
render: { | |
calls: 0, | |
vertices: 0, | |
faces: 0, | |
points: 0 | |
} | |
}; | |
// internal properties | |
var _this = this, | |
_programs = [], | |
// internal state cache | |
_currentProgram = null, | |
_currentFramebuffer = null, | |
_currentMaterialId = - 1, | |
_currentGeometryGroupHash = - 1, | |
_currentCamera = null, | |
_usedTextureUnits = 0, | |
// GL state cache | |
_oldDoubleSided = - 1, | |
_oldFlipSided = - 1, | |
_oldBlending = - 1, | |
_oldBlendEquation = - 1, | |
_oldBlendSrc = - 1, | |
_oldBlendDst = - 1, | |
_oldDepthTest = - 1, | |
_oldDepthWrite = - 1, | |
_oldPolygonOffset = null, | |
_oldPolygonOffsetFactor = null, | |
_oldPolygonOffsetUnits = null, | |
_oldLineWidth = null, | |
_viewportX = 0, | |
_viewportY = 0, | |
_viewportWidth = _canvas.width, | |
_viewportHeight = _canvas.height, | |
_currentWidth = 0, | |
_currentHeight = 0, | |
_newAttributes = new Uint8Array( 16 ), | |
_enabledAttributes = new Uint8Array( 16 ), | |
// 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: [] } | |
}; | |
var timestep; | |
var currentMatrix = new Array(); | |
this.setTimestep = function setTimestep(ts) { | |
timestep = ts; | |
} | |
this.setCurrentMatrix = function setCurrentMatrix(m) { | |
currentMatrix = m; | |
} | |
// initialize | |
var _gl; | |
try { | |
var attributes = { | |
alpha: _alpha, | |
depth: _depth, | |
stencil: _stencil, | |
antialias: _antialias, | |
premultipliedAlpha: _premultipliedAlpha, | |
preserveDrawingBuffer: _preserveDrawingBuffer | |
}; | |
_gl = _context || _canvas.getContext( 'webgl', attributes ) || _canvas.getContext( 'experimental-webgl', attributes ); | |
if ( _gl === null ) { | |
if ( _canvas.getContext( 'webgl') !== null ) { | |
throw 'Error creating WebGL context with your selected attributes.'; | |
} else { | |
throw 'Error creating WebGL context.'; | |
} | |
} | |
} catch ( error ) { | |
console.error( error ); | |
} | |
if ( _gl.getShaderPrecisionFormat === undefined ) { | |
_gl.getShaderPrecisionFormat = function () { | |
return { | |
'rangeMin': 1, | |
'rangeMax': 1, | |
'precision': 1 | |
}; | |
} | |
} | |
var extensions = new THREE.WebGLExtensions( _gl ); | |
extensions.get( 'OES_texture_float' ); | |
extensions.get( 'OES_texture_float_linear' ); | |
extensions.get( 'OES_standard_derivatives' ); | |
if ( _logarithmicDepthBuffer ) { | |
extensions.get( 'EXT_frag_depth' ); | |
} | |
// | |
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.viewport( _viewportX, _viewportY, _viewportWidth, _viewportHeight ); | |
_gl.clearColor( _clearColor.r, _clearColor.g, _clearColor.b, _clearAlpha ); | |
} | |
setDefaultGLState(); | |
this.context = _gl; | |
// GPU capabilities | |
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 _supportsVertexTextures = _maxVertexTextures > 0; | |
var _supportsBoneTextures = _supportsVertexTextures && extensions.get( 'OES_texture_float' ); | |
// | |
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 getCompressedTextureFormats = ( function () { | |
var array; | |
return function () { | |
if ( array !== undefined ) { | |
return array; | |
} | |
array = []; | |
if ( extensions.get( 'WEBGL_compressed_texture_pvrtc' ) || extensions.get( 'WEBGL_compressed_texture_s3tc' ) ) { | |
var formats = _gl.getParameter( _gl.COMPRESSED_TEXTURE_FORMATS ); | |
for ( var i = 0; i < formats.length; i ++ ){ | |
array.push( formats[ i ] ); | |
} | |
} | |
return array; | |
}; | |
} )(); | |
// 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( 'THREE.WebGLRenderer: highp not supported, using mediump.' ); | |
} else { | |
_precision = 'lowp'; | |
console.warn( 'THREE.WebGLRenderer: highp and mediump not supported, using lowp.' ); | |
} | |
} | |
if ( _precision === 'mediump' && ! mediumpAvailable ) { | |
_precision = 'lowp'; | |
console.warn( 'THREE.WebGLRenderer: mediump not supported, using lowp.' ); | |
} | |
// Plugins | |
var shadowMapPlugin = new THREE.ShadowMapPlugin( this, lights, _webglObjects, _webglObjectsImmediate ); | |
var spritePlugin = new THREE.SpritePlugin( this, sprites ); | |
var lensFlarePlugin = new THREE.LensFlarePlugin( this, lensFlares ); | |
// API | |
this.getContext = function () { | |
return _gl; | |
}; | |
this.supportsVertexTextures = function () { | |
return _supportsVertexTextures; | |
}; | |
this.supportsFloatTextures = function () { | |
return extensions.get( 'OES_texture_float' ); | |
}; | |
this.supportsStandardDerivatives = function () { | |
return extensions.get( 'OES_standard_derivatives' ); | |
}; | |
this.supportsCompressedTextureS3TC = function () { | |
return extensions.get( 'WEBGL_compressed_texture_s3tc' ); | |
}; | |
this.supportsCompressedTexturePVRTC = function () { | |
return extensions.get( 'WEBGL_compressed_texture_pvrtc' ); | |
}; | |
this.supportsBlendMinMax = function () { | |
return extensions.get( 'EXT_blend_minmax' ); | |
}; | |
this.getMaxAnisotropy = ( function () { | |
var value; | |
return function () { | |
if ( value !== undefined ) { | |
return value; | |
} | |
var extension = extensions.get( 'EXT_texture_filter_anisotropic' ); | |
value = extension !== null ? _gl.getParameter( extension.MAX_TEXTURE_MAX_ANISOTROPY_EXT ) : 0; | |
return value; | |
} | |
} )(); | |
this.getPrecision = function () { | |
return _precision; | |
}; | |
this.setSize = function ( width, height, updateStyle ) { | |
_canvas.width = width * this.devicePixelRatio; | |
_canvas.height = height * this.devicePixelRatio; | |
if ( updateStyle !== false ) { | |
_canvas.style.width = width + 'px'; | |
_canvas.style.height = height + 'px'; | |
} | |
this.setViewport( 0, 0, width, height ); | |
}; | |
this.setViewport = function ( x, y, width, height ) { | |
_viewportX = x * this.devicePixelRatio; | |
_viewportY = y * this.devicePixelRatio; | |
_viewportWidth = width * this.devicePixelRatio; | |
_viewportHeight = height * this.devicePixelRatio; | |
_gl.viewport( _viewportX, _viewportY, _viewportWidth, _viewportHeight ); | |
}; | |
this.setScissor = function ( x, y, width, height ) { | |
_gl.scissor( | |
x * this.devicePixelRatio, | |
y * this.devicePixelRatio, | |
width * this.devicePixelRatio, | |
height * this.devicePixelRatio | |
); | |
}; | |
this.enableScissorTest = function ( enable ) { | |
enable ? _gl.enable( _gl.SCISSOR_TEST ) : _gl.disable( _gl.SCISSOR_TEST ); | |
}; | |
// Clearing | |
this.setClearColor = function ( color, alpha ) { | |
_clearColor.set( color ); | |
_clearAlpha = alpha !== undefined ? alpha : 1; | |
_gl.clearColor( _clearColor.r, _clearColor.g, _clearColor.b, _clearAlpha ); | |
}; | |
this.setClearColorHex = function ( hex, alpha ) { | |
console.warn( 'THREE.WebGLRenderer: .setClearColorHex() is being removed. Use .setClearColor() instead.' ); | |
this.setClearColor( hex, alpha ); | |
}; | |
this.getClearColor = function () { | |
return _clearColor; | |
}; | |
this.getClearAlpha = function () { | |
return _clearAlpha; | |
}; | |
this.clear = function ( 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 ); | |
}; | |
this.clearColor = function () { | |
_gl.clear( _gl.COLOR_BUFFER_BIT ); | |
}; | |
this.clearDepth = function () { | |
_gl.clear( _gl.DEPTH_BUFFER_BIT ); | |
}; | |
this.clearStencil = function () { | |
_gl.clear( _gl.STENCIL_BUFFER_BIT ); | |
}; | |
this.clearTarget = function ( renderTarget, color, depth, stencil ) { | |
this.setRenderTarget( renderTarget ); | |
this.clear( color, depth, stencil ); | |
}; | |
// Reset | |
this.resetGLState = function () { | |
_currentProgram = null; | |
_currentCamera = null; | |
_oldBlending = - 1; | |
_oldDepthTest = - 1; | |
_oldDepthWrite = - 1; | |
_oldDoubleSided = - 1; | |
_oldFlipSided = - 1; | |
_currentGeometryGroupHash = - 1; | |
_currentMaterialId = - 1; | |
_lightsNeedUpdate = true; | |
}; | |
// Buffer allocation | |
function createParticleBuffers ( geometry ) { | |
geometry.__webglVertexBuffer = _gl.createBuffer(); | |
geometry.__webglColorBuffer = _gl.createBuffer(); | |
_this.info.memory.geometries ++; | |
}; | |
function createLineBuffers ( geometry ) { | |
geometry.__webglVertexBuffer = _gl.createBuffer(); | |
geometry.__webglColorBuffer = _gl.createBuffer(); | |
geometry.__webglLineDistanceBuffer = _gl.createBuffer(); | |
_this.info.memory.geometries ++; | |
}; | |
function createMeshBuffers ( geometryGroup ) { | |
geometryGroup.__webglVertexBuffer = _gl.createBuffer(); | |
geometryGroup.__webglNormalBuffer = _gl.createBuffer(); | |
geometryGroup.__webglTangentBuffer = _gl.createBuffer(); | |
geometryGroup.__webglColorBuffer = _gl.createBuffer(); | |
geometryGroup.__webglUVBuffer = _gl.createBuffer(); | |
geometryGroup.__webglUV2Buffer = _gl.createBuffer(); | |
geometryGroup.__webglSkinIndicesBuffer = _gl.createBuffer(); | |
geometryGroup.__webglSkinWeightsBuffer = _gl.createBuffer(); | |
geometryGroup.__webglFaceBuffer = _gl.createBuffer(); | |
geometryGroup.__webglLineBuffer = _gl.createBuffer(); | |
var m, ml; | |
if ( geometryGroup.numMorphTargets ) { | |
geometryGroup.__webglMorphTargetsBuffers = []; | |
for ( m = 0, ml = geometryGroup.numMorphTargets; m < ml; m ++ ) { | |
geometryGroup.__webglMorphTargetsBuffers.push( _gl.createBuffer() ); | |
} | |
} | |
if ( geometryGroup.numMorphNormals ) { | |
geometryGroup.__webglMorphNormalsBuffers = []; | |
for ( m = 0, ml = geometryGroup.numMorphNormals; m < ml; m ++ ) { | |
geometryGroup.__webglMorphNormalsBuffers.push( _gl.createBuffer() ); | |
} | |
} | |
_this.info.memory.geometries ++; | |
}; | |
// Events | |
var onObjectRemoved = function ( event ) { | |
var object = event.target; | |
object.traverse( function ( child ) { | |
child.removeEventListener( 'remove', onObjectRemoved ); | |
removeObject( child ); | |
} ); | |
}; | |
var onGeometryDispose = function ( event ) { | |
var geometry = event.target; | |
geometry.removeEventListener( 'dispose', onGeometryDispose ); | |
deallocateGeometry( geometry ); | |
}; | |
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 deleteBuffers = function ( geometry ) { | |
var buffers = [ | |
'__webglVertexBuffer', | |
'__webglNormalBuffer', | |
'__webglTangentBuffer', | |
'__webglColorBuffer', | |
'__webglUVBuffer', | |
'__webglUV2Buffer', | |
'__webglSkinIndicesBuffer', | |
'__webglSkinWeightsBuffer', | |
'__webglFaceBuffer', | |
'__webglLineBuffer', | |
'__webglLineDistanceBuffer' | |
]; | |
for ( var i = 0, l = buffers.length; i < l; i ++ ) { | |
var name = buffers[ i ]; | |
if ( geometry[ name ] !== undefined ) { | |
_gl.deleteBuffer( geometry[ name ] ); | |
delete geometry[ name ]; | |
} | |
} | |
// custom attributes | |
if ( geometry.__webglCustomAttributesList !== undefined ) { | |
for ( var name in geometry.__webglCustomAttributesList ) { | |
_gl.deleteBuffer( geometry.__webglCustomAttributesList[ name ].buffer ); | |
} | |
delete geometry.__webglCustomAttributesList; | |
} | |
_this.info.memory.geometries --; | |
}; | |
var deallocateGeometry = function ( geometry ) { | |
delete geometry.__webglInit; | |
if ( geometry instanceof THREE.BufferGeometry ) { | |
for ( var name in geometry.attributes ) { | |
var attribute = geometry.attributes[ name ]; | |
if ( attribute.buffer !== undefined ) { | |
_gl.deleteBuffer( attribute.buffer ); | |
delete attribute.buffer; | |
} | |
} | |
_this.info.memory.geometries --; | |
} else { | |
var geometryGroupsList = geometryGroups[ geometry.id ]; | |
if ( geometryGroupsList !== undefined ) { | |
for ( var i = 0,l = geometryGroupsList.length; i < l; i ++ ) { | |
var geometryGroup = geometryGroupsList[ i ]; | |
if ( geometryGroup.numMorphTargets !== undefined ) { | |
for ( var m = 0, ml = geometryGroup.numMorphTargets; m < ml; m ++ ) { | |
_gl.deleteBuffer( geometryGroup.__webglMorphTargetsBuffers[ m ] ); | |
} | |
delete geometryGroup.__webglMorphTargetsBuffers; | |
} | |
if ( geometryGroup.numMorphNormals !== undefined ) { | |
for ( var m = 0, ml = geometryGroup.numMorphNormals; m < ml; m ++ ) { | |
_gl.deleteBuffer( geometryGroup.__webglMorphNormalsBuffers[ m ] ); | |
} | |
delete geometryGroup.__webglMorphNormalsBuffers; | |
} | |
deleteBuffers( geometryGroup ); | |
} | |
delete geometryGroups[ geometry.id ]; | |
} else { | |
deleteBuffers( geometry ); | |
} | |
} | |
// TOFIX: Workaround for deleted geometry being currently bound | |
_currentGeometryGroupHash = - 1; | |
}; | |
var deallocateTexture = function ( texture ) { | |
if ( texture.image && texture.image.__webglTextureCube ) { | |
// cube texture | |
_gl.deleteTexture( texture.image.__webglTextureCube ); | |
delete texture.image.__webglTextureCube; | |
} else { | |
// 2D texture | |
if ( texture.__webglInit === undefined ) return; | |
_gl.deleteTexture( texture.__webglTexture ); | |
delete texture.__webglTexture; | |
delete texture.__webglInit; | |
} | |
}; | |
var deallocateRenderTarget = function ( renderTarget ) { | |
if ( ! renderTarget || renderTarget.__webglTexture === undefined ) return; | |
_gl.deleteTexture( renderTarget.__webglTexture ); | |
delete renderTarget.__webglTexture; | |
if ( renderTarget instanceof THREE.WebGLRenderTargetCube ) { | |
for ( var i = 0; i < 6; i ++ ) { | |
_gl.deleteFramebuffer( renderTarget.__webglFramebuffer[ i ] ); | |
_gl.deleteRenderbuffer( renderTarget.__webglRenderbuffer[ i ] ); | |
} | |
} else { | |
_gl.deleteFramebuffer( renderTarget.__webglFramebuffer ); | |
_gl.deleteRenderbuffer( renderTarget.__webglRenderbuffer ); | |
} | |
delete renderTarget.__webglFramebuffer; | |
delete renderTarget.__webglRenderbuffer; | |
}; | |
var deallocateMaterial = function ( material ) { | |
var program = material.program.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) | |
var i, il, programInfo; | |
var deleteProgram = false; | |
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; | |
_gl.deleteProgram( program ); | |
_this.info.memory.programs --; | |
} | |
}; | |
// Buffer initialization | |
function initCustomAttributes ( object ) { | |
var geometry = object.geometry; | |
var material = object.material; | |
var nvertices = geometry.vertices.length; | |
if ( material.attributes ) { | |
if ( geometry.__webglCustomAttributesList === undefined ) { | |
geometry.__webglCustomAttributesList = []; | |
} | |
for ( var name in material.attributes ) { | |
var attribute = material.attributes[ name ]; | |
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 = _gl.createBuffer(); | |
attribute.buffer.belongsToAttribute = name; | |
attribute.needsUpdate = true; | |
} | |
geometry.__webglCustomAttributesList.push( attribute ); | |
} | |
} | |
}; | |
function initParticleBuffers ( geometry, object ) { | |
var nvertices = geometry.vertices.length; | |
geometry.__vertexArray = new Float32Array( nvertices * 3 ); | |
geometry.__colorArray = new Float32Array( nvertices * 3 ); | |
geometry.__sortArray = []; | |
geometry.__webglParticleCount = nvertices; | |
initCustomAttributes( object ); | |
}; | |
function initLineBuffers ( 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; | |
initCustomAttributes( object ); | |
}; | |
function initMeshBuffers ( geometryGroup, object ) { | |
var geometry = object.geometry, | |
faces3 = geometryGroup.faces3, | |
nvertices = faces3.length * 3, | |
ntris = faces3.length * 1, | |
nlines = faces3.length * 3, | |
material = getBufferMaterial( object, geometryGroup ); | |
geometryGroup.__vertexArray = new Float32Array( nvertices * 3 ); | |
geometryGroup.__normalArray = new Float32Array( nvertices * 3 ); | |
geometryGroup.__colorArray = new Float32Array( nvertices * 3 ); | |
geometryGroup.__uvArray = new Float32Array( nvertices * 2 ); | |
if ( geometry.faceVertexUvs.length > 1 ) { | |
geometryGroup.__uv2Array = new Float32Array( nvertices * 2 ); | |
} | |
if ( geometry.hasTangents ) { | |
geometryGroup.__tangentArray = new Float32Array( nvertices * 4 ); | |
} | |
if ( object.geometry.skinWeights.length && object.geometry.skinIndices.length ) { | |
geometryGroup.__skinIndexArray = new Float32Array( nvertices * 4 ); | |
geometryGroup.__skinWeightArray = new Float32Array( nvertices * 4 ); | |
} | |
var UintArray = extensions.get( 'OES_element_index_uint' ) !== null && ntris > 21845 ? Uint32Array : Uint16Array; // 65535 / 3 | |
geometryGroup.__typeArray = UintArray; | |
geometryGroup.__faceArray = new UintArray( ntris * 3 ); | |
geometryGroup.__lineArray = new UintArray( 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 name 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[ name ]; | |
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 = _gl.createBuffer(); | |
attribute.buffer.belongsToAttribute = name; | |
originalAttribute.needsUpdate = true; | |
attribute.__original = originalAttribute; | |
} | |
geometryGroup.__webglCustomAttributesList.push( attribute ); | |
} | |
} | |
geometryGroup.__inittedArrays = true; | |
}; | |
function getBufferMaterial( object, geometryGroup ) { | |
return object.material instanceof THREE.MeshFaceMaterial | |
? object.material.materials[ geometryGroup.materialIndex ] | |
: object.material; | |
}; | |
function materialNeedsSmoothNormals ( material ) { | |
return material && material.shading !== undefined && material.shading === THREE.SmoothShading; | |
}; | |
// Buffer setting | |
function setParticleBuffers ( geometry, hint, object ) { | |
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; | |
if ( object.sortParticles ) { | |
_projScreenMatrixPS.copy( _projScreenMatrix ); | |
_projScreenMatrixPS.multiply( object.matrixWorld ); | |
for ( v = 0; v < vl; v ++ ) { | |
vertex = vertices[ v ]; | |
_vector3.copy( vertex ); | |
_vector3.applyProjection( _projScreenMatrixPS ); | |
sortArray[ v ] = [ _vector3.z, v ]; | |
} | |
sortArray.sort( 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 ) { | |
_gl.bindBuffer( _gl.ARRAY_BUFFER, geometry.__webglVertexBuffer ); | |
_gl.bufferData( _gl.ARRAY_BUFFER, vertexArray, hint ); | |
} | |
if ( dirtyColors || object.sortParticles ) { | |
_gl.bindBuffer( _gl.ARRAY_BUFFER, geometry.__webglColorBuffer ); | |
_gl.bufferData( _gl.ARRAY_BUFFER, colorArray, hint ); | |
} | |
if ( customAttributes ) { | |
for ( i = 0, il = customAttributes.length; i < il; i ++ ) { | |
customAttribute = customAttributes[ i ]; | |
if ( customAttribute.needsUpdate || object.sortParticles ) { | |
_gl.bindBuffer( _gl.ARRAY_BUFFER, customAttribute.buffer ); | |
_gl.bufferData( _gl.ARRAY_BUFFER, customAttribute.array, hint ); | |
} | |
} | |
} | |
} | |
function setLineBuffers ( geometry, hint ) { | |
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; | |
} | |
_gl.bindBuffer( _gl.ARRAY_BUFFER, geometry.__webglVertexBuffer ); | |
_gl.bufferData( _gl.ARRAY_BUFFER, vertexArray, hint ); | |
} | |
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; | |
} | |
_gl.bindBuffer( _gl.ARRAY_BUFFER, geometry.__webglColorBuffer ); | |
_gl.bufferData( _gl.ARRAY_BUFFER, colorArray, hint ); | |
} | |
if ( dirtyLineDistances ) { | |
for ( d = 0; d < dl; d ++ ) { | |
lineDistanceArray[ d ] = lineDistances[ d ]; | |
} | |
_gl.bindBuffer( _gl.ARRAY_BUFFER, geometry.__webglLineDistanceBuffer ); | |
_gl.bufferData( _gl.ARRAY_BUFFER, lineDistanceArray, hint ); | |
} | |
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; | |
} | |
} | |
_gl.bindBuffer( _gl.ARRAY_BUFFER, customAttribute.buffer ); | |
_gl.bufferData( _gl.ARRAY_BUFFER, customAttribute.array, hint ); | |
} | |
} | |
} | |
} | |
function setMeshBuffers( geometryGroup, object, hint, dispose, material ) { | |
if ( ! geometryGroup.__inittedArrays ) { | |
return; | |
} | |
var needsSmoothNormals = materialNeedsSmoothNormals( material ); | |
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, | |
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, | |
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; | |
} | |
_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglVertexBuffer ); | |
_gl.bufferData( _gl.ARRAY_BUFFER, vertexArray, hint ); | |
} | |
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; | |
} | |
_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphTargetsBuffers[ vk ] ); | |
_gl.bufferData( _gl.ARRAY_BUFFER, morphTargetsArrays[ vk ], hint ); | |
if ( material.morphNormals ) { | |
_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphNormalsBuffers[ vk ] ); | |
_gl.bufferData( _gl.ARRAY_BUFFER, morphNormalsArrays[ vk ], hint ); | |
} | |
} | |
} | |
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; | |
} | |
if ( offset_skin > 0 ) { | |
_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglSkinIndicesBuffer ); | |
_gl.bufferData( _gl.ARRAY_BUFFER, skinIndexArray, hint ); | |
_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglSkinWeightsBuffer ); | |
_gl.bufferData( _gl.ARRAY_BUFFER, skinWeightArray, hint ); | |
} | |
} | |
if ( dirtyColors ) { | |
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 && material.vertexColors === 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; | |
} | |
if ( offset_color > 0 ) { | |
_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglColorBuffer ); | |
_gl.bufferData( _gl.ARRAY_BUFFER, colorArray, hint ); | |
} | |
} | |
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; | |
} | |
_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglTangentBuffer ); | |
_gl.bufferData( _gl.ARRAY_BUFFER, tangentArray, hint ); | |
} | |
if ( dirtyNormals ) { | |
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; | |
} | |
} | |
} | |
_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglNormalBuffer ); | |
_gl.bufferData( _gl.ARRAY_BUFFER, normalArray, hint ); | |
} | |
if ( dirtyUvs && obj_uvs ) { | |
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; | |
} | |
} | |
if ( offset_uv > 0 ) { | |
_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglUVBuffer ); | |
_gl.bufferData( _gl.ARRAY_BUFFER, uvArray, hint ); | |
} | |
} | |
if ( dirtyUvs && obj_uvs2 ) { | |
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; | |
} | |
} | |
if ( offset_uv2 > 0 ) { | |
_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglUV2Buffer ); | |
_gl.bufferData( _gl.ARRAY_BUFFER, uv2Array, hint ); | |
} | |
} | |
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; | |
} | |
_gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, geometryGroup.__webglFaceBuffer ); | |
_gl.bufferData( _gl.ELEMENT_ARRAY_BUFFER, faceArray, hint ); | |
_gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, geometryGroup.__webglLineBuffer ); | |
_gl.bufferData( _gl.ELEMENT_ARRAY_BUFFER, lineArray, hint ); | |
} | |
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; | |
} | |
} 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; | |
} | |
} | |
} 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; | |
} | |
} 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; | |
} | |
} | |
} 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; | |
} | |
} 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; | |
} | |
} 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; | |
} | |
} | |
} 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; | |
} | |
} 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; | |
} | |
} 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; | |
} | |
} | |
} | |
_gl.bindBuffer( _gl.ARRAY_BUFFER, customAttribute.buffer ); | |
_gl.bufferData( _gl.ARRAY_BUFFER, customAttribute.array, hint ); | |
} | |
} | |
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; | |
} | |
}; | |
function setDirectBuffers( geometry ) { | |
var attributes = geometry.attributes; | |
var attributesKeys = geometry.attributesKeys; | |
for ( var i = 0, l = attributesKeys.length; i < l; i ++ ) { | |
var key = attributesKeys[ i ]; | |
var attribute = attributes[ key ]; | |
if ( attribute.buffer === undefined ) { | |
attribute.buffer = _gl.createBuffer(); | |
attribute.needsUpdate = true; | |
} | |
if ( attribute.needsUpdate === true ) { | |
var bufferType = ( key === 'index' ) ? _gl.ELEMENT_ARRAY_BUFFER : _gl.ARRAY_BUFFER; | |
_gl.bindBuffer( bufferType, attribute.buffer ); | |
_gl.bufferData( bufferType, attribute.array, _gl.STATIC_DRAW ); | |
attribute.needsUpdate = false; | |
} | |
} | |
} | |
// Buffer rendering | |
this.renderBufferImmediate = function ( object, program, material ) { | |
initAttributes(); | |
if ( object.hasPositions && ! object.__webglVertexBuffer ) object.__webglVertexBuffer = _gl.createBuffer(); | |
if ( object.hasNormals && ! object.__webglNormalBuffer ) object.__webglNormalBuffer = _gl.createBuffer(); | |
if ( object.hasUvs && ! object.__webglUvBuffer ) object.__webglUvBuffer = _gl.createBuffer(); | |
if ( object.hasColors && ! object.__webglColorBuffer ) object.__webglColorBuffer = _gl.createBuffer(); | |
if ( object.hasPositions ) { | |
_gl.bindBuffer( _gl.ARRAY_BUFFER, object.__webglVertexBuffer ); | |
_gl.bufferData( _gl.ARRAY_BUFFER, object.positionArray, _gl.DYNAMIC_DRAW ); | |
enableAttribute( program.attributes.position ); | |
_gl.vertexAttribPointer( program.attributes.position, 3, _gl.FLOAT, false, 0, 0 ); | |
} | |
if ( object.hasNormals ) { | |
_gl.bindBuffer( _gl.ARRAY_BUFFER, object.__webglNormalBuffer ); | |
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; | |
} | |
} | |
_gl.bufferData( _gl.ARRAY_BUFFER, object.normalArray, _gl.DYNAMIC_DRAW ); | |
enableAttribute( program.attributes.normal ); | |
_gl.vertexAttribPointer( program.attributes.normal, 3, _gl.FLOAT, false, 0, 0 ); | |
} | |
if ( object.hasUvs && material.map ) { | |
_gl.bindBuffer( _gl.ARRAY_BUFFER, object.__webglUvBuffer ); | |
_gl.bufferData( _gl.ARRAY_BUFFER, object.uvArray, _gl.DYNAMIC_DRAW ); | |
enableAttribute( program.attributes.uv ); | |
_gl.vertexAttribPointer( program.attributes.uv, 2, _gl.FLOAT, false, 0, 0 ); | |
} | |
if ( object.hasColors && material.vertexColors !== THREE.NoColors ) { | |
_gl.bindBuffer( _gl.ARRAY_BUFFER, object.__webglColorBuffer ); | |
_gl.bufferData( _gl.ARRAY_BUFFER, object.colorArray, _gl.DYNAMIC_DRAW ); | |
enableAttribute( program.attributes.color ); | |
_gl.vertexAttribPointer( program.attributes.color, 3, _gl.FLOAT, false, 0, 0 ); | |
} | |
disableUnusedAttributes(); | |
_gl.drawArrays( _gl.TRIANGLES, 0, object.count ); | |
object.count = 0; | |
}; | |
function setupVertexAttributes( material, program, geometry, startIndex ) { | |
var geometryAttributes = geometry.attributes; | |
var programAttributes = program.attributes; | |
var programAttributesKeys = program.attributesKeys; | |
for ( var i = 0, l = programAttributesKeys.length; i < l; i ++ ) { | |
var key = programAttributesKeys[ i ]; | |
var programAttribute = programAttributes[ key ]; | |
if ( programAttribute >= 0 ) { | |
var geometryAttribute = geometryAttributes[ key ]; | |
if ( geometryAttribute !== undefined ) { | |
var size = geometryAttribute.itemSize; | |
_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryAttribute.buffer ); | |
enableAttribute( programAttribute ); | |
_gl.vertexAttribPointer( programAttribute, size, _gl.FLOAT, false, 0, startIndex * size * 4 ); // 4 bytes per Float32 | |
} else if ( material.defaultAttributeValues !== undefined ) { | |
if ( material.defaultAttributeValues[ key ].length === 2 ) { | |
_gl.vertexAttrib2fv( programAttribute, material.defaultAttributeValues[ key ] ); | |
} else if ( material.defaultAttributeValues[ key ].length === 3 ) { | |
_gl.vertexAttrib3fv( programAttribute, material.defaultAttributeValues[ key ] ); | |
} | |
} | |
} | |
} | |
disableUnusedAttributes(); | |
} | |
this.renderBufferDirect = function ( camera, lights, fog, material, geometry, object ) { | |
if ( material.visible === false ) return; | |
console.log("renderBufferDirect"); | |
var program = setProgram( camera, lights, fog, material, object ); | |
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 ) { | |
initAttributes(); | |
} | |
// render mesh | |
if ( object instanceof THREE.Mesh ) { | |
var mode = material.wireframe === true ? _gl.LINES : _gl.TRIANGLES; | |
var index = geometry.attributes.index; | |
if ( index ) { | |
// indexed triangles | |
var type, size; | |
if ( index.array instanceof Uint32Array && extensions.get( 'OES_element_index_uint' ) ) { | |
type = _gl.UNSIGNED_INT; | |
size = 4; | |
} else { | |
type = _gl.UNSIGNED_SHORT; | |
size = 2; | |
} | |
var offsets = geometry.offsets; | |
if ( offsets.length === 0 ) { | |
if ( updateBuffers ) { | |
setupVertexAttributes( material, program, geometry, 0 ); | |
_gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, index.buffer ); | |
} | |
_gl.drawElements( mode, index.array.length, type, 0 ); | |
_this.info.render.calls ++; | |
_this.info.render.vertices += index.array.length; // not really true, here vertices can be shared | |
_this.info.render.faces += index.array.length / 3; | |
} else { | |
// 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 | |
updateBuffers = true; | |
for ( var i = 0, il = offsets.length; i < il; i ++ ) { | |
var startIndex = offsets[ i ].index; | |
if ( updateBuffers ) { | |
setupVertexAttributes( material, program, geometry, startIndex ); | |
_gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, index.buffer ); | |
} | |
// render indexed triangles | |
_gl.drawElements( mode, offsets[ i ].count, type, offsets[ i ].start * size ); | |
_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; | |
} | |
} | |
} else { | |
// non-indexed triangles | |
if ( updateBuffers ) { | |
setupVertexAttributes( material, program, geometry, 0 ); | |
} | |
var position = geometry.attributes[ 'position' ]; | |
// render non-indexed triangles | |
_gl.drawArrays( mode, 0, position.array.length / 3 ); | |
_this.info.render.calls ++; | |
_this.info.render.vertices += position.array.length / 3; | |
_this.info.render.faces += position.array.length / 9; | |
} | |
} else if ( object instanceof THREE.PointCloud ) { | |
// render particles | |
if ( updateBuffers ) { | |
setupVertexAttributes( material, program, geometry, 0 ); | |
} | |
var position = geometry.attributes.position; | |
// render particles | |
_gl.drawArrays( _gl.POINTS, 0, position.array.length / 3 ); | |
_this.info.render.calls ++; | |
_this.info.render.points += position.array.length / 3; | |
} else if ( object instanceof THREE.Line ) { | |
var mode = ( object.mode === THREE.LineStrip ) ? _gl.LINE_STRIP : _gl.LINES; | |
setLineWidth( material.linewidth ); | |
var index = geometry.attributes.index; | |
if ( index ) { | |
// indexed lines | |
var type, size; | |
if ( index.array instanceof Uint32Array ) { | |
type = _gl.UNSIGNED_INT; | |
size = 4; | |
} else { | |
type = _gl.UNSIGNED_SHORT; | |
size = 2; | |
} | |
var offsets = geometry.offsets; | |
if ( offsets.length === 0 ) { | |
if ( updateBuffers ) { | |
setupVertexAttributes( material, program, geometry, 0 ); | |
_gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, index.buffer ); | |
} | |
_gl.drawElements( mode, index.array.length, type, 0 ); // 2 bytes per Uint16Array | |
_this.info.render.calls ++; | |
_this.info.render.vertices += index.array.length; // not really true, here vertices can be shared | |
} else { | |
// 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 ) { | |
setupVertexAttributes( material, program, geometry, startIndex ); | |
_gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, index.buffer ); | |
} | |
// render indexed lines | |
_gl.drawElements( mode, offsets[ i ].count, type, offsets[ i ].start * size ); // 2 bytes per Uint16Array | |
_this.info.render.calls ++; | |
_this.info.render.vertices += offsets[ i ].count; // not really true, here vertices can be shared | |
} | |
} | |
} else { | |
// non-indexed lines | |
if ( updateBuffers ) { | |
setupVertexAttributes( material, program, geometry, 0 ); | |
} | |
var position = geometry.attributes.position; | |
_gl.drawArrays( mode, 0, position.array.length / 3 ); | |
_this.info.render.calls ++; | |
_this.info.render.points += position.array.length / 3; | |
} | |
} | |
}; | |
this.renderBuffer = function ( camera, lights, fog, material, geometryGroup, object ) { | |
if ( material.visible === false ) return; | |
//console.log("renderBuffer"); | |
var program = setProgram( camera, lights, fog, material, object ); | |
var 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 ) { | |
initAttributes(); | |
} | |
// vertices | |
if ( ! material.morphTargets && attributes.position >= 0 ) { | |
if ( updateBuffers ) { | |
_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglVertexBuffer ); | |
enableAttribute( attributes.position ); | |
_gl.vertexAttribPointer( attributes.position, 3, _gl.FLOAT, false, 0, 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 ( var i = 0, il = geometryGroup.__webglCustomAttributesList.length; i < il; i ++ ) { | |
var attribute = geometryGroup.__webglCustomAttributesList[ i ]; | |
if ( attributes[ attribute.buffer.belongsToAttribute ] >= 0 ) { | |
_gl.bindBuffer( _gl.ARRAY_BUFFER, attribute.buffer ); | |
enableAttribute( attributes[ attribute.buffer.belongsToAttribute ] ); | |
_gl.vertexAttribPointer( attributes[ attribute.buffer.belongsToAttribute ], attribute.size, _gl.FLOAT, false, 0, 0 ); | |
} | |
} | |
} | |
// colors | |
if ( attributes.color >= 0 ) { | |
if ( object.geometry.colors.length > 0 || object.geometry.faces.length > 0 ) { | |
_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglColorBuffer ); | |
enableAttribute( attributes.color ); | |
_gl.vertexAttribPointer( attributes.color, 3, _gl.FLOAT, false, 0, 0 ); | |
} else if ( material.defaultAttributeValues !== undefined ) { | |
_gl.vertexAttrib3fv( attributes.color, material.defaultAttributeValues.color ); | |
} | |
} | |
// normals | |
if ( attributes.normal >= 0 ) { | |
_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglNormalBuffer ); | |
enableAttribute( attributes.normal ); | |
_gl.vertexAttribPointer( attributes.normal, 3, _gl.FLOAT, false, 0, 0 ); | |
} | |
// tangents | |
if ( attributes.tangent >= 0 ) { | |
_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglTangentBuffer ); | |
enableAttribute( attributes.tangent ); | |
_gl.vertexAttribPointer( attributes.tangent, 4, _gl.FLOAT, false, 0, 0 ); | |
} | |
// uvs | |
if ( attributes.uv >= 0 ) { | |
if ( object.geometry.faceVertexUvs[ 0 ] ) { | |
_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglUVBuffer ); | |
enableAttribute( attributes.uv ); | |
_gl.vertexAttribPointer( attributes.uv, 2, _gl.FLOAT, false, 0, 0 ); | |
} else if ( material.defaultAttributeValues !== undefined ) { | |
_gl.vertexAttrib2fv( attributes.uv, material.defaultAttributeValues.uv ); | |
} | |
} | |
if ( attributes.uv2 >= 0 ) { | |
if ( object.geometry.faceVertexUvs[ 1 ] ) { | |
_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglUV2Buffer ); | |
enableAttribute( attributes.uv2 ); | |
_gl.vertexAttribPointer( attributes.uv2, 2, _gl.FLOAT, false, 0, 0 ); | |
} else if ( material.defaultAttributeValues !== undefined ) { | |
_gl.vertexAttrib2fv( attributes.uv2, material.defaultAttributeValues.uv2 ); | |
} | |
} | |
if ( material.skinning && | |
attributes.skinIndex >= 0 && attributes.skinWeight >= 0 ) { | |
_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglSkinIndicesBuffer ); | |
enableAttribute( attributes.skinIndex ); | |
_gl.vertexAttribPointer( attributes.skinIndex, 4, _gl.FLOAT, false, 0, 0 ); | |
_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglSkinWeightsBuffer ); | |
enableAttribute( attributes.skinWeight ); | |
_gl.vertexAttribPointer( attributes.skinWeight, 4, _gl.FLOAT, false, 0, 0 ); | |
} | |
// line distances | |
if ( attributes.lineDistance >= 0 ) { | |
_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglLineDistanceBuffer ); | |
enableAttribute( attributes.lineDistance ); | |
_gl.vertexAttribPointer( attributes.lineDistance, 1, _gl.FLOAT, false, 0, 0 ); | |
} | |
} | |
disableUnusedAttributes(); | |
// render mesh | |
if ( object instanceof THREE.Mesh ) { | |
var type = geometryGroup.__typeArray === Uint32Array ? _gl.UNSIGNED_INT : _gl.UNSIGNED_SHORT; | |
// wireframe | |
if ( material.wireframe ) { | |
setLineWidth( material.wireframeLinewidth ); | |
if ( updateBuffers ) _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, geometryGroup.__webglLineBuffer ); | |
_gl.drawElements( _gl.LINES, geometryGroup.__webglLineCount, type, 0 ); | |
// triangles | |
} else { | |
if ( updateBuffers ) _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, geometryGroup.__webglFaceBuffer ); | |
_gl.drawElements( _gl.TRIANGLES, geometryGroup.__webglFaceCount, type, 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 ) { | |
var mode = ( object.mode === THREE.LineStrip ) ? _gl.LINE_STRIP : _gl.LINES; | |
setLineWidth( material.linewidth ); | |
_gl.drawArrays( mode, 0, geometryGroup.__webglLineCount ); | |
_this.info.render.calls ++; | |
// render particles | |
} else if ( object instanceof THREE.PointCloud ) { | |
_gl.drawArrays( _gl.POINTS, 0, geometryGroup.__webglParticleCount ); | |
_this.info.render.calls ++; | |
_this.info.render.points += geometryGroup.__webglParticleCount; | |
} | |
}; | |
function initAttributes() { | |
for ( var i = 0, l = _newAttributes.length; i < l; i ++ ) { | |
_newAttributes[ i ] = 0; | |
} | |
} | |
function enableAttribute( attribute ) { | |
_newAttributes[ attribute ] = 1; | |
if ( _enabledAttributes[ attribute ] === 0 ) { | |
_gl.enableVertexAttribArray( attribute ); | |
_enabledAttributes[ attribute ] = 1; | |
} | |
} | |
function disableUnusedAttributes() { | |
for ( var i = 0, l = _enabledAttributes.length; i < l; i ++ ) { | |
if ( _enabledAttributes[ i ] !== _newAttributes[ i ] ) { | |
_gl.disableVertexAttribArray( i ); | |
_enabledAttributes[ i ] = 0; | |
} | |
} | |
} | |
function setupMorphTargets ( material, geometryGroup, object ) { | |
// set base | |
var attributes = material.program.attributes; | |
if ( object.morphTargetBase !== - 1 && attributes.position >= 0 ) { | |
_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphTargetsBuffers[ object.morphTargetBase ] ); | |
enableAttribute( attributes.position ); | |
_gl.vertexAttribPointer( attributes.position, 3, _gl.FLOAT, false, 0, 0 ); | |
} else if ( attributes.position >= 0 ) { | |
_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglVertexBuffer ); | |
enableAttribute( attributes.position ); | |
_gl.vertexAttribPointer( attributes.position, 3, _gl.FLOAT, false, 0, 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 ) { | |
_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphTargetsBuffers[ order[ m ] ] ); | |
enableAttribute( attributes[ 'morphTarget' + m ] ); | |
_gl.vertexAttribPointer( attributes[ 'morphTarget' + m ], 3, _gl.FLOAT, false, 0, 0 ); | |
} | |
if ( attributes[ 'morphNormal' + m ] >= 0 && material.morphNormals ) { | |
_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphNormalsBuffers[ order[ m ] ] ); | |
enableAttribute( attributes[ 'morphNormal' + m ] ); | |
_gl.vertexAttribPointer( attributes[ 'morphNormal' + m ], 3, _gl.FLOAT, false, 0, 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 ) { | |
_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphTargetsBuffers[ influenceIndex ] ); | |
enableAttribute( attributes[ 'morphTarget' + m ] ); | |
_gl.vertexAttribPointer( attributes[ 'morphTarget' + m ], 3, _gl.FLOAT, false, 0, 0 ); | |
} | |
if ( attributes[ 'morphNormal' + m ] >= 0 && material.morphNormals ) { | |
_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphNormalsBuffers[ influenceIndex ] ); | |
enableAttribute( attributes[ 'morphNormal' + m ] ); | |
_gl.vertexAttribPointer( attributes[ 'morphNormal' + m ], 3, _gl.FLOAT, false, 0, 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 ) { | |
_gl.uniform1fv( material.program.uniforms.morphTargetInfluences, object.__webglMorphTargetInfluences ); | |
} | |
} | |
// Sorting | |
function painterSortStable ( a, b ) { | |
if ( a.material.id !== b.material.id ) { | |
return b.material.id - a.material.id; | |
} else if ( a.z !== b.z ) { | |
return b.z - a.z; | |
} else { | |
return a.id - b.id; | |
} | |
} | |
function reversePainterSortStable ( a, b ) { | |
if ( a.z !== b.z ) { | |
return a.z - b.z; | |
} else { | |
return a.id - b.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 fog = scene.fog; | |
// reset caching for this frame | |
_currentGeometryGroupHash = - 1; | |
_currentMaterialId = - 1; | |
_currentCamera = null; | |
_lightsNeedUpdate = true; | |
// update scene graph | |
if ( scene.autoUpdate === true ) scene.updateMatrixWorld(); | |
// update camera matrices and frustum | |
if ( camera.parent === undefined ) camera.updateMatrixWorld(); | |
// update Skeleton objects | |
scene.traverse( function ( object ) { | |
if ( object instanceof THREE.SkinnedMesh ) { | |
object.skeleton.update(); | |
} | |
} ); | |
camera.matrixWorldInverse.getInverse( camera.matrixWorld ); | |
_projScreenMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse ); | |
_frustum.setFromMatrix( _projScreenMatrix ); | |
lights.length = 0; | |
opaqueObjects.length = 0; | |
transparentObjects.length = 0; | |
sprites.length = 0; | |
lensFlares.length = 0; | |
projectObject( scene, scene ); | |
if ( _this.sortObjects === true ) { | |
opaqueObjects.sort( painterSortStable ); | |
transparentObjects.sort( reversePainterSortStable ); | |
} | |
// custom render plugins (pre pass) | |
shadowMapPlugin.render( scene, camera ); | |
// | |
_this.info.render.calls = 0; | |
_this.info.render.vertices = 0; | |
_this.info.render.faces = 0; | |
_this.info.render.points = 0; | |
this.setRenderTarget( renderTarget ); | |
if ( this.autoClear || forceClear ) { | |
this.clear( this.autoClearColor, this.autoClearDepth, this.autoClearStencil ); | |
} | |
// set matrices for immediate objects | |
for ( var i = 0, il = _webglObjectsImmediate.length; i < il; i ++ ) { | |
var webglObject = _webglObjectsImmediate[ i ]; | |
var object = webglObject.object; | |
if ( object.visible ) { | |
setupMatrices( object, camera ); | |
unrollImmediateBufferMaterial( webglObject ); | |
} | |
} | |
if ( scene.overrideMaterial ) { | |
var material = scene.overrideMaterial; | |
this.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst ); | |
this.setDepthTest( material.depthTest ); | |
this.setDepthWrite( material.depthWrite ); | |
setPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits ); | |
renderObjects( opaqueObjects, camera, lights, fog, true, material ); | |
renderObjects( transparentObjects, camera, lights, fog, true, material ); | |
renderObjectsImmediate( _webglObjectsImmediate, '', camera, lights, fog, false, material ); | |
} else { | |
var material = null; | |
// opaque pass (front-to-back order) | |
this.setBlending( THREE.NoBlending ); | |
renderObjects( opaqueObjects, camera, lights, fog, false, material ); | |
renderObjectsImmediate( _webglObjectsImmediate, 'opaque', camera, lights, fog, false, material ); | |
// transparent pass (back-to-front order) | |
renderObjects( transparentObjects, camera, lights, fog, true, material ); | |
renderObjectsImmediate( _webglObjectsImmediate, 'transparent', camera, lights, fog, true, material ); | |
} | |
// custom render plugins (post pass) | |
spritePlugin.render( scene, camera ); | |
lensFlarePlugin.render( scene, camera, _currentWidth, _currentHeight ); | |
// Generate mipmap if we're using any kind of mipmap filtering | |
if ( renderTarget && renderTarget.generateMipmaps && renderTarget.minFilter !== THREE.NearestFilter && renderTarget.minFilter !== THREE.LinearFilter ) { | |
updateRenderTargetMipmap( renderTarget ); | |
} | |
// Ensure depth buffer writing is enabled so it can be cleared on next render | |
this.setDepthTest( true ); | |
this.setDepthWrite( true ); | |
// _gl.finish(); | |
}; | |
function projectObject( scene, object ) { | |
if ( object.visible === false ) return; | |
if ( object instanceof THREE.Scene || object instanceof THREE.Group ) { | |
// skip | |
} else { | |
initObject( object, scene ); | |
if ( object instanceof THREE.Light ) { | |
lights.push( object ); | |
} else if ( object instanceof THREE.Sprite ) { | |
sprites.push( object ); | |
} else if ( object instanceof THREE.LensFlare ) { | |
lensFlares.push( object ); | |
} else { | |
var webglObjects = _webglObjects[ object.id ]; | |
if ( webglObjects && ( object.frustumCulled === false || _frustum.intersectsObject( object ) === true ) ) { | |
updateObject( object, scene ); | |
for ( var i = 0, l = webglObjects.length; i < l; i ++ ) { | |
var webglObject = webglObjects[i]; | |
unrollBufferMaterial( webglObject ); | |
webglObject.render = true; | |
if ( _this.sortObjects === true ) { | |
if ( object.renderDepth !== null ) { | |
webglObject.z = object.renderDepth; | |
} else { | |
_vector3.setFromMatrixPosition( object.matrixWorld ); | |
_vector3.applyProjection( _projScreenMatrix ); | |
webglObject.z = _vector3.z; | |
} | |
} | |
} | |
} | |
} | |
} | |
for ( var i = 0, l = object.children.length; i < l; i ++ ) { | |
projectObject( scene, object.children[ i ] ); | |
} | |
} | |
function renderObjects( renderList, camera, lights, fog, useBlending, overrideMaterial ) { | |
var material; | |
//console.log("renderObjects"); | |
for ( var i = renderList.length - 1; i !== - 1; i -- ) { | |
var webglObject = renderList[ i ]; | |
var object = webglObject.object; | |
var buffer = webglObject.buffer; | |
setupMatrices( object, camera ); | |
if ( overrideMaterial ) { | |
material = overrideMaterial; | |
} else { | |
material = webglObject.material; | |
if ( ! material ) continue; | |
if ( useBlending ) _this.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst ); | |
_this.setDepthTest( material.depthTest ); | |
_this.setDepthWrite( material.depthWrite ); | |
setPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits ); | |
} | |
_this.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 material; | |
for ( var i = 0, il = renderList.length; i < il; i ++ ) { | |
var webglObject = renderList[ i ]; | |
var object = webglObject.object; | |
if ( object.visible ) { | |
if ( overrideMaterial ) { | |
material = overrideMaterial; | |
} else { | |
material = webglObject[ materialType ]; | |
if ( ! material ) continue; | |
if ( useBlending ) _this.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst ); | |
_this.setDepthTest( material.depthTest ); | |
_this.setDepthWrite( material.depthWrite ); | |
setPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits ); | |
} | |
_this.renderImmediateObject( camera, lights, fog, material, object ); | |
} | |
} | |
} | |
this.renderImmediateObject = function ( camera, lights, fog, material, object ) { | |
console.log("renderImmediateObject"); | |
var program = setProgram( camera, lights, fog, material, object ); | |
_currentGeometryGroupHash = - 1; | |
_this.setMaterialFaces( material ); | |
if ( object.immediateRenderCallback ) { | |
object.immediateRenderCallback( program, _gl, _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; | |
var buffer = globject.buffer; | |
var geometry = object.geometry; | |
var material = object.material; | |
if ( material instanceof THREE.MeshFaceMaterial ) { | |
var materialIndex = geometry instanceof THREE.BufferGeometry ? 0 : buffer.materialIndex; | |
material = material.materials[ materialIndex ]; | |
globject.material = material; | |
if ( material.transparent ) { | |
transparentObjects.push( globject ); | |
} else { | |
opaqueObjects.push( globject ); | |
} | |
} else if ( material ) { | |
globject.material = material; | |
if ( material.transparent ) { | |
transparentObjects.push( globject ); | |
} else { | |
opaqueObjects.push( globject ); | |
} | |
} | |
} | |
function initObject( object, scene ) { | |
if ( object.__webglInit === undefined ) { | |
object.__webglInit = true; | |
object._modelViewMatrix = new THREE.Matrix4(); | |
object._normalMatrix = new THREE.Matrix3(); | |
object.addEventListener( 'removed', onObjectRemoved ); | |
} | |
var geometry = object.geometry; | |
if ( geometry === undefined ) { | |
// ImmediateRenderObject | |
} else if ( geometry.__webglInit === undefined ) { | |
geometry.__webglInit = true; | |
geometry.addEventListener( 'dispose', onGeometryDispose ); | |
if ( geometry instanceof THREE.BufferGeometry ) { | |
// | |
} else if ( object instanceof THREE.Mesh ) { | |
initGeometryGroups( scene, object, geometry ); | |
} else if ( object instanceof THREE.Line ) { | |
if ( geometry.__webglVertexBuffer === undefined ) { | |
createLineBuffers( geometry ); | |
initLineBuffers( geometry, object ); | |
geometry.verticesNeedUpdate = true; | |
geometry.colorsNeedUpdate = true; | |
geometry.lineDistancesNeedUpdate = true; | |
} | |
} else if ( object instanceof THREE.PointCloud ) { | |
if ( geometry.__webglVertexBuffer === undefined ) { | |
createParticleBuffers( geometry ); | |
initParticleBuffers( geometry, object ); | |
geometry.verticesNeedUpdate = true; | |
geometry.colorsNeedUpdate = true; | |
} | |
} | |
} | |
if ( object.__webglActive === undefined) { | |
object.__webglActive = true; | |
if ( object instanceof THREE.Mesh ) { | |
if ( geometry instanceof THREE.BufferGeometry ) { | |
addBuffer( _webglObjects, geometry, object ); | |
} else if ( geometry instanceof THREE.Geometry ) { | |
var geometryGroupsList = geometryGroups[ geometry.id ]; | |
for ( var i = 0,l = geometryGroupsList.length; i < l; i ++ ) { | |
addBuffer( _webglObjects, geometryGroupsList[ i ], object ); | |
} | |
} | |
} else if ( object instanceof THREE.Line || object instanceof THREE.PointCloud ) { | |
addBuffer( _webglObjects, geometry, object ); | |
} else if ( object instanceof THREE.ImmediateRenderObject || object.immediateRenderCallback ) { | |
addBufferImmediate( _webglObjectsImmediate, object ); | |
} | |
} | |
} | |
// Geometry splitting | |
var geometryGroups = {}; | |
var geometryGroupCounter = 0; | |
function makeGroups( geometry, usesFaceMaterial ) { | |
var maxVerticesInGroup = extensions.get( 'OES_element_index_uint' ) ? 4294967296 : 65535; | |
var groupHash, hash_map = {}; | |
var numMorphTargets = geometry.morphTargets.length; | |
var numMorphNormals = geometry.morphNormals.length; | |
var group; | |
var groups = {}; | |
var groupsList = []; | |
for ( var f = 0, fl = geometry.faces.length; f < fl; f ++ ) { | |
var face = geometry.faces[ f ]; | |
var materialIndex = usesFaceMaterial ? face.materialIndex : 0; | |
if ( ! ( materialIndex in hash_map ) ) { | |
hash_map[ materialIndex ] = { hash: materialIndex, counter: 0 }; | |
} | |
groupHash = hash_map[ materialIndex ].hash + '_' + hash_map[ materialIndex ].counter; | |
if ( ! ( groupHash in groups ) ) { | |
group = { | |
id: geometryGroupCounter ++, | |
faces3: [], | |
materialIndex: materialIndex, | |
vertices: 0, | |
numMorphTargets: numMorphTargets, | |
numMorphNormals: numMorphNormals | |
}; | |
groups[ groupHash ] = group; | |
groupsList.push( group ); | |
} | |
if ( groups[ groupHash ].vertices + 3 > maxVerticesInGroup ) { | |
hash_map[ materialIndex ].counter += 1; | |
groupHash = hash_map[ materialIndex ].hash + '_' + hash_map[ materialIndex ].counter; | |
if ( ! ( groupHash in groups ) ) { | |
group = { | |
id: geometryGroupCounter ++, | |
faces3: [], | |
materialIndex: materialIndex, | |
vertices: 0, | |
numMorphTargets: numMorphTargets, | |
numMorphNormals: numMorphNormals | |
}; | |
groups[ groupHash ] = group; | |
groupsList.push( group ); | |
} | |
} | |
groups[ groupHash ].faces3.push( f ); | |
groups[ groupHash ].vertices += 3; | |
} | |
return groupsList; | |
} | |
function initGeometryGroups( scene, object, geometry ) { | |
var material = object.material, addBuffers = false; | |
if ( geometryGroups[ geometry.id ] === undefined || geometry.groupsNeedUpdate === true ) { | |
delete _webglObjects[ object.id ]; | |
geometryGroups[ geometry.id ] = makeGroups( geometry, material instanceof THREE.MeshFaceMaterial ); | |
geometry.groupsNeedUpdate = false; | |
} | |
var geometryGroupsList = geometryGroups[ geometry.id ]; | |
// create separate VBOs per geometry chunk | |
for ( var i = 0, il = geometryGroupsList.length; i < il; i ++ ) { | |
var geometryGroup = geometryGroupsList[ i ]; | |
// initialise VBO on the first access | |
if ( geometryGroup.__webglVertexBuffer === undefined ) { | |
createMeshBuffers( geometryGroup ); | |
initMeshBuffers( geometryGroup, object ); | |
geometry.verticesNeedUpdate = true; | |
geometry.morphTargetsNeedUpdate = true; | |
geometry.elementsNeedUpdate = true; | |
geometry.uvsNeedUpdate = true; | |
geometry.normalsNeedUpdate = true; | |
geometry.tangentsNeedUpdate = true; | |
geometry.colorsNeedUpdate = true; | |
addBuffers = true; | |
} else { | |
addBuffers = false; | |
} | |
if ( addBuffers || object.__webglActive === undefined ) { | |
addBuffer( _webglObjects, geometryGroup, object ); | |
} | |
} | |
object.__webglActive = true; | |
} | |
function addBuffer( objlist, buffer, object ) { | |
var id = object.id; | |
objlist[id] = objlist[id] || []; | |
objlist[id].push( | |
{ | |
id: id, | |
buffer: buffer, | |
object: object, | |
material: null, | |
z: 0 | |
} | |
); | |
}; | |
function addBufferImmediate( objlist, object ) { | |
objlist.push( | |
{ | |
id: null, | |
object: object, | |
opaque: null, | |
transparent: null, | |
z: 0 | |
} | |
); | |
}; | |
// Objects updates | |
function updateObject( object, scene ) { | |
var geometry = object.geometry, customAttributesDirty, material; | |
if ( geometry instanceof THREE.BufferGeometry ) { | |
setDirectBuffers( geometry ); | |
} else if ( object instanceof THREE.Mesh ) { | |
// check all geometry groups | |
if ( geometry.groupsNeedUpdate === true ) { | |
initGeometryGroups( scene, object, geometry ); | |
} | |
var geometryGroupsList = geometryGroups[ geometry.id ]; | |
for ( var i = 0, il = geometryGroupsList.length; i < il; i ++ ) { | |
var geometryGroup = geometryGroupsList[ i ]; | |
material = getBufferMaterial( object, geometryGroup ); | |
if ( geometry.groupsNeedUpdate === true ) { | |
initMeshBuffers( geometryGroup, object ); | |
} | |
customAttributesDirty = material.attributes && areCustomAttributesDirty( material ); | |
if ( geometry.verticesNeedUpdate || geometry.morphTargetsNeedUpdate || geometry.elementsNeedUpdate || | |
geometry.uvsNeedUpdate || geometry.normalsNeedUpdate || | |
geometry.colorsNeedUpdate || geometry.tangentsNeedUpdate || customAttributesDirty ) { | |
setMeshBuffers( geometryGroup, object, _gl.DYNAMIC_DRAW, ! geometry.dynamic, material ); | |
} | |
} | |
geometry.verticesNeedUpdate = false; | |
geometry.morphTargetsNeedUpdate = false; | |
geometry.elementsNeedUpdate = false; | |
geometry.uvsNeedUpdate = false; | |
geometry.normalsNeedUpdate = false; | |
geometry.colorsNeedUpdate = false; | |
geometry.tangentsNeedUpdate = 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 ) { | |
setLineBuffers( geometry, _gl.DYNAMIC_DRAW ); | |
} | |
geometry.verticesNeedUpdate = false; | |
geometry.colorsNeedUpdate = false; | |
geometry.lineDistancesNeedUpdate = false; | |
material.attributes && clearCustomAttributes( material ); | |
} else if ( object instanceof THREE.PointCloud ) { | |
material = getBufferMaterial( object, geometry ); | |
customAttributesDirty = material.attributes && areCustomAttributesDirty( material ); | |
if ( geometry.verticesNeedUpdate || geometry.colorsNeedUpdate || object.sortParticles || customAttributesDirty ) { | |
setParticleBuffers( geometry, _gl.DYNAMIC_DRAW, object ); | |
} | |
geometry.verticesNeedUpdate = false; | |
geometry.colorsNeedUpdate = false; | |
material.attributes && clearCustomAttributes( material ); | |
} | |
} | |
// Objects updates - custom attributes check | |
function areCustomAttributesDirty( material ) { | |
for ( var name in material.attributes ) { | |
if ( material.attributes[ name ].needsUpdate ) return true; | |
} | |
return false; | |
} | |
function clearCustomAttributes( material ) { | |
for ( var name in material.attributes ) { | |
material.attributes[ name ].needsUpdate = false; | |
} | |
} | |
// Objects removal | |
function removeObject( object ) { | |
if ( object instanceof THREE.Mesh || | |
object instanceof THREE.PointCloud || | |
object instanceof THREE.Line ) { | |
delete _webglObjects[ object.id ]; | |
} else if ( object instanceof THREE.ImmediateRenderObject || object.immediateRenderCallback ) { | |
removeInstances( _webglObjectsImmediate, object ); | |
} | |
delete object.__webglInit; | |
delete object._modelViewMatrix; | |
delete object._normalMatrix; | |
delete object.__webglActive; | |
} | |
function removeInstances( objlist, object ) { | |
for ( var o = objlist.length - 1; o >= 0; o -- ) { | |
if ( objlist[ o ].object === object ) { | |
objlist.splice( o, 1 ); | |
} | |
} | |
} | |
// Materials | |
function initMaterial( material, lights, fog, object ) { | |
material.addEventListener( 'dispose', onMaterialDispose ); | |
var 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.PointCloudMaterial ) { | |
shaderID = 'particle_basic'; | |
} | |
if ( shaderID ) { | |
var shader = THREE.ShaderLib[ shaderID ]; | |
material.__webglShader = { | |
uniforms: THREE.UniformsUtils.clone( shader.uniforms ), | |
vertexShader: shader.vertexShader, | |
fragmentShader: shader.fragmentShader | |
} | |
} else { | |
material.__webglShader = { | |
uniforms: material.uniforms, | |
vertexShader: material.vertexShader, | |
fragmentShader: material.fragmentShader | |
} | |
} | |
// heuristics to create shader parameters according to lights in the scene | |
// (not to blow over maxLights budget) | |
var maxLightCount = allocateLights( lights ); | |
var maxShadows = allocateShadows( lights ); | |
var maxBones = allocateBones( object ); | |
var parameters = { | |
precision: _precision, | |
supportsVertexTextures: _supportsVertexTextures, | |
map: !! material.map, | |
envMap: !! material.envMap, | |
lightMap: !! material.lightMap, | |
bumpMap: !! material.bumpMap, | |
normalMap: !! material.normalMap, | |
specularMap: !! material.specularMap, | |
alphaMap: !! material.alphaMap, | |
vertexColors: material.vertexColors, | |
fog: fog, | |
useFog: material.fog, | |
fogExp: fog instanceof THREE.FogExp2, | |
sizeAttenuation: material.sizeAttenuation, | |
logarithmicDepthBuffer: _logarithmicDepthBuffer, | |
skinning: material.skinning, | |
maxBones: maxBones, | |
useVertexTexture: _supportsBoneTextures && object && object.skeleton && object.skeleton.useVertexTexture, | |
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 && maxShadows > 0, | |
shadowMapType: _this.shadowMapType, | |
shadowMapDebug: _this.shadowMapDebug, | |
shadowMapCascade: _this.shadowMapCascade, | |
alphaTest: material.alphaTest, | |
metal: material.metal, | |
wrapAround: material.wrapAround, | |
doubleSided: material.side === THREE.DoubleSide, | |
flipSided: material.side === THREE.BackSide | |
}; | |
// Generate code | |
var chunks = []; | |
if ( shaderID ) { | |
chunks.push( shaderID ); | |
} else { | |
chunks.push( material.fragmentShader ); | |
chunks.push( material.vertexShader ); | |
} | |
if ( material.defines !== undefined ) { | |
for ( var name in material.defines ) { | |
chunks.push( name ); | |
chunks.push( material.defines[ name ] ); | |
} | |
} | |
for ( var name in parameters ) { | |
chunks.push( name ); | |
chunks.push( parameters[ name ] ); | |
} | |
var code = chunks.join(); | |
var program; | |
// Check if code has been already compiled | |
for ( var p = 0, pl = _programs.length; p < pl; p ++ ) { | |
var programInfo = _programs[ p ]; | |
if ( programInfo.code === code ) { | |
program = programInfo; | |
program.usedTimes ++; | |
break; | |
} | |
} | |
if ( program === undefined ) { | |
program = new THREE.WebGLProgram( _this, code, material, parameters ); | |
_programs.push( program ); | |
_this.info.memory.programs = _programs.length; | |
} | |
material.program = program; | |
var attributes = program.attributes; | |
if ( material.morphTargets ) { | |
material.numSupportedMorphTargets = 0; | |
var id, base = 'morphTarget'; | |
for ( var 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 ( var u in material.__webglShader.uniforms ) { | |
var location = material.program.uniforms[ u ]; | |
if ( location ) { | |
material.uniformsList.push( [ material.__webglShader.uniforms[ u ], location ] ); | |
} | |
} | |
} | |
function setProgram( camera, lights, fog, material, object ) { | |
_usedTextureUnits = 0; | |
if ( material.needsUpdate ) { | |
if ( material.program ) deallocateMaterial( material ); | |
initMaterial( material, lights, fog, object ); | |
material.needsUpdate = false; | |
} | |
if ( material.morphTargets ) { | |
if ( ! object.__webglMorphTargetInfluences ) { | |
object.__webglMorphTargetInfluences = new Float32Array( _this.maxMorphTargets ); | |
} | |
} | |
var refreshProgram = false; | |
var refreshMaterial = false; | |
var refreshLights = false; | |
var program = material.program, | |
p_uniforms = program.uniforms, | |
m_uniforms = material.__webglShader.uniforms; | |
if ( program.id !== _currentProgram ) { | |
_gl.useProgram( program.program ); | |
_currentProgram = program.id; | |
refreshProgram = true; | |
refreshMaterial = true; | |
refreshLights = true; | |
} | |
if ( material.id !== _currentMaterialId ) { | |
if ( _currentMaterialId === -1 ) refreshLights = true; | |
_currentMaterialId = material.id; | |
refreshMaterial = true; | |
} | |
if ( refreshProgram || camera !== _currentCamera ) { | |
_gl.uniformMatrix4fv( p_uniforms.projectionMatrix, false, camera.projectionMatrix.elements ); | |
if ( _logarithmicDepthBuffer ) { | |
_gl.uniform1f( p_uniforms.logDepthBufFC, 2.0 / ( Math.log( camera.far + 1.0 ) / Math.LN2 ) ); | |
} | |
if ( camera !== _currentCamera ) _currentCamera = camera; | |
// 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 ) { | |
_vector3.setFromMatrixPosition( camera.matrixWorld ); | |
_gl.uniform3f( p_uniforms.cameraPosition, _vector3.x, _vector3.y, _vector3.z ); | |
} | |
} | |
if ( material instanceof THREE.MeshPhongMaterial || | |
material instanceof THREE.MeshLambertMaterial || | |
material instanceof THREE.ShaderMaterial || | |
material.skinning ) { | |
if ( p_uniforms.viewMatrix !== null ) { | |
_gl.uniformMatrix4fv( p_uniforms.viewMatrix, false, camera.matrixWorldInverse.elements ); | |
} | |
} | |
} | |
// 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 ( object.bindMatrix && p_uniforms.bindMatrix !== null ) { | |
_gl.uniformMatrix4fv( p_uniforms.bindMatrix, false, object.bindMatrix.elements ); | |
} | |
if ( object.bindMatrixInverse && p_uniforms.bindMatrixInverse !== null ) { | |
_gl.uniformMatrix4fv( p_uniforms.bindMatrixInverse, false, object.bindMatrixInverse.elements ); | |
} | |
if ( _supportsBoneTextures && object.skeleton && object.skeleton.useVertexTexture ) { | |
if ( p_uniforms.boneTexture !== null ) { | |
var textureUnit = getTextureUnit(); | |
_gl.uniform1i( p_uniforms.boneTexture, textureUnit ); | |
_this.setTexture( object.skeleton.boneTexture, textureUnit ); | |
} | |
if ( p_uniforms.boneTextureWidth !== null ) { | |
_gl.uniform1i( p_uniforms.boneTextureWidth, object.skeleton.boneTextureWidth ); | |
} | |
if ( p_uniforms.boneTextureHeight !== null ) { | |
_gl.uniform1i( p_uniforms.boneTextureHeight, object.skeleton.boneTextureHeight ); | |
} | |
} else if ( object.skeleton && object.skeleton.boneMatrices ) { | |
//console.log(object.skeleton); | |
if ( p_uniforms.boneGlobalMatrices !== null ) { | |
var modelMatrix = new Array(); | |
for (var n = 0; n < 16; n++){ | |
modelMatrix[n] = object.skeleton.boneMatrices[n]; | |
} | |
var newMatrix = new Array(); | |
if (currentMatrix.length == 0){ | |
newMatrix = modelMatrix; | |
} else { | |
var mModel = new THREE.Matrix4(); | |
mModel.set(modelMatrix[0], modelMatrix[4], modelMatrix[8], modelMatrix[12], | |
modelMatrix[1], modelMatrix[5], modelMatrix[9], modelMatrix[13], | |
modelMatrix[2], modelMatrix[6], modelMatrix[10], modelMatrix[14], | |
modelMatrix[3], modelMatrix[7], modelMatrix[11], modelMatrix[15]); | |
for (var m = 0; m < (currentMatrix.length / 16); m++){ | |
var mCurrent = new THREE.Matrix4(); | |
mCurrent.set(currentMatrix[m * 16 + 0], currentMatrix[m * 16 + 4], currentMatrix[m * 16 + 8], currentMatrix[m * 16 + 12], | |
currentMatrix[m * 16 + 1], currentMatrix[m * 16 + 5], currentMatrix[m * 16 + 9], currentMatrix[m * 16 + 13], | |
currentMatrix[m * 16 + 2], currentMatrix[m * 16 + 6], currentMatrix[m * 16 + 10], currentMatrix[m * 16 + 14], | |
currentMatrix[m * 16 + 3], currentMatrix[m * 16 + 7], currentMatrix[m * 16 + 11], currentMatrix[m * 16 + 15]); | |
var mNew = new THREE.Matrix4(); | |
mNew.multiplyMatrices(mModel, mCurrent); | |
for (var n = 0; n < 16; n++){ | |
newMatrix.push(mNew.elements[n]); | |
} | |
} | |
} | |
_gl.uniformMatrix4fv( p_uniforms.boneGlobalMatrices, false, newMatrix ); | |
//_gl.uniformMatrix4fv( p_uniforms.boneGlobalMatrices, false, object.skeleton.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 ) { | |
refreshLights = true; | |
setupLights( lights ); | |
_lightsNeedUpdate = false; | |
} | |
if ( refreshLights ) { | |
refreshUniformsLights( m_uniforms, _lights ); | |
markUniformsLightsNeedsUpdate( m_uniforms, true ); | |
} else { | |
markUniformsLightsNeedsUpdate( m_uniforms, false ); | |
} | |
} | |
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.PointCloudMaterial ) { | |
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( material.uniformsList ); | |
} | |
loadUniformsMatrices( p_uniforms, object ); | |
if ( p_uniforms.modelMatrix !== null ) { | |
_gl.uniformMatrix4fv( p_uniforms.modelMatrix, false, 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; | |
uniforms.alphaMap.value = material.alphaMap; | |
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 | |
// 5. alpha 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; | |
} else if ( material.alphaMap ) { | |
uvScaleMap = material.alphaMap; | |
} | |
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; | |
if(uniforms.combine) if(uniforms.combine.value) uniforms.combine.value = material.combine; | |
if(uniforms.useRefract) if(uniforms.useRefract.value) 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 = _canvas.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 { | |
if(uniforms.ambient) uniforms.ambient.value = material.ambient; | |
if(uniforms.emissive) 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; | |
} | |
// If uniforms are marked as clean, they don't need to be loaded to the GPU. | |
function markUniformsLightsNeedsUpdate ( uniforms, boolean ) { | |
uniforms.ambientLightColor.needsUpdate = boolean; | |
uniforms.directionalLightColor.needsUpdate = boolean; | |
uniforms.directionalLightDirection.needsUpdate = boolean; | |
uniforms.pointLightColor.needsUpdate = boolean; | |
uniforms.pointLightPosition.needsUpdate = boolean; | |
uniforms.pointLightDistance.needsUpdate = boolean; | |
uniforms.spotLightColor.needsUpdate = boolean; | |
uniforms.spotLightPosition.needsUpdate = boolean; | |
uniforms.spotLightDistance.needsUpdate = boolean; | |
uniforms.spotLightDirection.needsUpdate = boolean; | |
uniforms.spotLightAngleCos.needsUpdate = boolean; | |
uniforms.spotLightExponent.needsUpdate = boolean; | |
uniforms.hemisphereLightSkyColor.needsUpdate = boolean; | |
uniforms.hemisphereLightGroundColor.needsUpdate = boolean; | |
uniforms.hemisphereLightDirection.needsUpdate = boolean; | |
} | |
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 ) { | |
_gl.uniformMatrix4fv( uniforms.modelViewMatrix, false, object._modelViewMatrix.elements ); | |
if ( uniforms.normalMatrix ) { | |
_gl.uniformMatrix3fv( uniforms.normalMatrix, false, object._normalMatrix.elements ); | |
} | |
} | |
function getTextureUnit() { | |
var textureUnit = _usedTextureUnits; | |
if ( textureUnit >= _maxTextures ) { | |
console.warn( 'WebGLRenderer: trying to use ' + textureUnit + ' texture units while this GPU supports only ' + _maxTextures ); | |
} | |
_usedTextureUnits += 1; | |
return textureUnit; | |
} | |
function loadUniformsGeneric ( uniforms ) { | |
var texture, textureUnit, offset; | |
for ( var j = 0, jl = uniforms.length; j < jl; j ++ ) { | |
var uniform = uniforms[ j ][ 0 ]; | |
// needsUpdate property is not added to all uniforms. | |
if ( uniform.needsUpdate === false ) continue; | |
var type = uniform.type; | |
var value = uniform.value; | |
var location = uniforms[ j ][ 1 ]; | |
switch ( type ) { | |
case '1i': | |
_gl.uniform1i( location, value ); | |
break; | |
case '1f': | |
_gl.uniform1f( location, value ); | |
break; | |
case '2f': | |
_gl.uniform2f( location, value[ 0 ], value[ 1 ] ); | |
break; | |
case '3f': | |
_gl.uniform3f( location, value[ 0 ], value[ 1 ], value[ 2 ] ); | |
break; | |
case '4f': | |
_gl.uniform4f( location, value[ 0 ], value[ 1 ], value[ 2 ], value[ 3 ] ); | |
break; | |
case '1iv': | |
_gl.uniform1iv( location, value ); | |
break; | |
case '3iv': | |
_gl.uniform3iv( location, value ); | |
break; | |
case '1fv': | |
_gl.uniform1fv( location, value ); | |
break; | |
case '2fv': | |
_gl.uniform2fv( location, value ); | |
break; | |
case '3fv': | |
_gl.uniform3fv( location, value ); | |
break; | |
case '4fv': | |
_gl.uniform4fv( location, value ); | |
break; | |
case 'Matrix3fv': | |
_gl.uniformMatrix3fv( location, false, value ); | |
break; | |
case 'Matrix4fv': | |
_gl.uniformMatrix4fv( location, false, value ); | |
break; | |
// | |
case 'i': | |
// single integer | |
_gl.uniform1i( location, value ); | |
break; | |
case 'f': | |
// single float | |
_gl.uniform1f( location, value ); | |
break; | |
case 'v2': | |
// single THREE.Vector2 | |
_gl.uniform2f( location, value.x, value.y ); | |
break; | |
case 'v3': | |
// single THREE.Vector3 | |
_gl.uniform3f( location, value.x, value.y, value.z ); | |
break; | |
case 'v4': | |
// single THREE.Vector4 | |
_gl.uniform4f( location, value.x, value.y, value.z, value.w ); | |
break; | |
case 'c': | |
// single THREE.Color | |
_gl.uniform3f( location, value.r, value.g, value.b ); | |
break; | |
case 'iv1': | |
// flat array of integers (JS or typed array) | |
_gl.uniform1iv( location, value ); | |
break; | |
case 'iv': | |
// flat array of integers with 3 x N size (JS or typed array) | |
_gl.uniform3iv( location, value ); | |
break; | |
case 'fv1': | |
// flat array of floats (JS or typed array) | |
_gl.uniform1fv( location, value ); | |
break; | |
case 'fv': | |
// flat array of floats with 3 x N size (JS or typed array) | |
_gl.uniform3fv( location, value ); | |
break; | |
case 'v2v': | |
// array of THREE.Vector2 | |
if ( uniform._array === undefined ) { | |
uniform._array = new Float32Array( 2 * value.length ); | |
} | |
for ( var i = 0, il = value.length; i < il; i ++ ) { | |
offset = i * 2; | |
uniform._array[ offset ] = value[ i ].x; | |
uniform._array[ offset + 1 ] = value[ i ].y; | |
} | |
_gl.uniform2fv( location, uniform._array ); | |
break; | |
case 'v3v': | |
// array of THREE.Vector3 | |
if ( uniform._array === undefined ) { | |
uniform._array = new Float32Array( 3 * value.length ); | |
} | |
for ( var 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; | |
} | |
_gl.uniform3fv( location, uniform._array ); | |
break; | |
case 'v4v': | |
// array of THREE.Vector4 | |
if ( uniform._array === undefined ) { | |
uniform._array = new Float32Array( 4 * value.length ); | |
} | |
for ( var 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; | |
} | |
_gl.uniform4fv( location, uniform._array ); | |
break; | |
case 'm3': | |
// single THREE.Matrix3 | |
_gl.uniformMatrix3fv( location, false, value.elements ); | |
break; | |
case 'm3v': | |
// array of THREE.Matrix3 | |
if ( uniform._array === undefined ) { | |
uniform._array = new Float32Array( 9 * value.length ); | |
} | |
for ( var i = 0, il = value.length; i < il; i ++ ) { | |
value[ i ].flattenToArrayOffset( uniform._array, i * 9 ); | |
} | |
_gl.uniformMatrix3fv( location, false, uniform._array ); | |
break; | |
case 'm4': | |
// single THREE.Matrix4 | |
_gl.uniformMatrix4fv( location, false, value.elements ); | |
break; | |
case 'm4v': | |
// array of THREE.Matrix4 | |
if ( uniform._array === undefined ) { | |
uniform._array = new Float32Array( 16 * value.length ); | |
} | |
for ( var i = 0, il = value.length; i < il; i ++ ) { | |
value[ i ].flattenToArrayOffset( uniform._array, i * 16 ); | |
} | |
_gl.uniformMatrix4fv( location, false, uniform._array ); | |
break; | |
case 't': | |
// single THREE.Texture (2d or cube) | |
texture = value; | |
textureUnit = getTextureUnit(); | |
_gl.uniform1i( location, textureUnit ); | |
if ( ! texture ) continue; | |
if ( texture instanceof THREE.CubeTexture || | |
( texture.image instanceof Array && texture.image.length === 6 ) ) { // CompressedTexture can have Array in image :/ | |
setCubeTexture( texture, textureUnit ); | |
} else if ( texture instanceof THREE.WebGLRenderTargetCube ) { | |
setCubeTextureDynamic( texture, textureUnit ); | |
} else { | |
_this.setTexture( texture, textureUnit ); | |
} | |
break; | |
case 'tv': | |
// array of THREE.Texture (2d) | |
if ( uniform._array === undefined ) { | |
uniform._array = []; | |
} | |
for ( var i = 0, il = uniform.value.length; i < il; i ++ ) { | |
uniform._array[ i ] = getTextureUnit(); | |
} | |
_gl.uniform1iv( location, uniform._array ); | |
for ( var i = 0, il = uniform.value.length; i < il; i ++ ) { | |
texture = uniform.value[ i ]; | |
textureUnit = uniform._array[ i ]; | |
if ( ! texture ) continue; | |
_this.setTexture( texture, textureUnit ); | |
} | |
break; | |
default: | |
console.warn( 'THREE.WebGLRenderer: Unknown uniform type: ' + type ); | |
} | |
} | |
} | |
function setupMatrices ( object, camera ) { | |
object._modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, object.matrixWorld ); | |
object._normalMatrix.getNormalMatrix( object._modelViewMatrix ); | |
} | |
// | |
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 ( 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.setFromMatrixPosition( light.matrixWorld ); | |
_vector3.setFromMatrixPosition( light.target.matrixWorld ); | |
_direction.sub( _vector3 ); | |
_direction.normalize(); | |
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 ); | |
} | |
_vector3.setFromMatrixPosition( light.matrixWorld ); | |
pointPositions[ pointOffset ] = _vector3.x; | |
pointPositions[ pointOffset + 1 ] = _vector3.y; | |
pointPositions[ pointOffset + 2 ] = _vector3.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 ); | |
} | |
_direction.setFromMatrixPosition( light.matrixWorld ); | |
spotPositions[ spotOffset ] = _direction.x; | |
spotPositions[ spotOffset + 1 ] = _direction.y; | |
spotPositions[ spotOffset + 2 ] = _direction.z; | |
spotDistances[ spotLength ] = distance; | |
_vector3.setFromMatrixPosition( light.target.matrixWorld ); | |
_direction.sub( _vector3 ); | |
_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.setFromMatrixPosition( light.matrixWorld ); | |
_direction.normalize(); | |
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; | |
} | |
// GL state setting | |
this.setFaceCulling = function ( 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 ); | |
} | |
}; | |
this.setMaterialFaces = function ( 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; | |
} | |
}; | |
this.setDepthTest = function ( depthTest ) { | |
if ( _oldDepthTest !== depthTest ) { | |
if ( depthTest ) { | |
_gl.enable( _gl.DEPTH_TEST ); | |
} else { | |
_gl.disable( _gl.DEPTH_TEST ); | |
} | |
_oldDepthTest = depthTest; | |
} | |
}; | |
this.setDepthWrite = function ( depthWrite ) { | |
if ( _oldDepthWrite !== depthWrite ) { | |
_gl.depthMask( depthWrite ); | |
_oldDepthWrite = depthWrite; | |
} | |
}; | |
function setLineWidth ( width ) { | |
if ( width !== _oldLineWidth ) { | |
_gl.lineWidth( width ); | |
_oldLineWidth = width; | |
} | |
} | |
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; | |
} | |
} | |
this.setBlending = function ( 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; | |
} | |
}; | |
// Textures | |
function setTextureParameters ( textureType, texture, isImagePowerOfTwo ) { | |
var extension; | |
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 ) ); | |
} | |
extension = extensions.get( 'EXT_texture_filter_anisotropic' ); | |
if ( extension && texture.type !== THREE.FloatType ) { | |
if ( texture.anisotropy > 1 || texture.__oldAnisotropy ) { | |
_gl.texParameterf( textureType, extension.TEXTURE_MAX_ANISOTROPY_EXT, Math.min( texture.anisotropy, _this.getMaxAnisotropy() ) ); | |
texture.__oldAnisotropy = texture.anisotropy; | |
} | |
} | |
} | |
this.uploadTexture = function ( texture ) { | |
if ( texture.__webglInit === undefined ) { | |
texture.__webglInit = true; | |
texture.addEventListener( 'dispose', onTextureDispose ); | |
texture.__webglTexture = _gl.createTexture(); | |
_this.info.memory.textures ++; | |
} | |
_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 ); | |
texture.image = clampToMaxSize( texture.image, _maxTextureSize ); | |
var image = texture.image, | |
isImagePowerOfTwo = THREE.Math.isPowerOfTwo( image.width ) && THREE.Math.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 ) { | |
for ( var i = 0, il = mipmaps.length; i < il; i ++ ) { | |
mipmap = mipmaps[ i ]; | |
if ( texture.format !== THREE.RGBAFormat && texture.format !== THREE.RGBFormat ) { | |
if ( getCompressedTextureFormats().indexOf( glFormat ) > -1 ) { | |
_gl.compressedTexImage2D( _gl.TEXTURE_2D, i, glFormat, mipmap.width, mipmap.height, 0, mipmap.data ); | |
} else { | |
console.warn( "Attempt to load unsupported compressed texture format" ); | |
} | |
} else { | |
_gl.texImage2D( _gl.TEXTURE_2D, i, glFormat, mipmap.width, mipmap.height, 0, glFormat, glType, 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(); | |
}; | |
this.setTexture = function ( texture, slot ) { | |
_gl.activeTexture( _gl.TEXTURE0 + slot ); | |
if ( texture.needsUpdate ) { | |
_this.uploadTexture( texture ); | |
} else { | |
_gl.bindTexture( _gl.TEXTURE_2D, texture.__webglTexture ); | |
} | |
}; | |
function clampToMaxSize ( image, maxSize ) { | |
if ( image.width > maxSize || image.height > maxSize ) { | |
// Warning: Scaling through the canvas will only work with images that use | |
// premultiplied alpha. | |
var scale = maxSize / Math.max( image.width, image.height ); | |
var canvas = document.createElement( 'canvas' ); | |
canvas.width = Math.floor( image.width * scale ); | |
canvas.height = Math.floor( image.height * scale ); | |
var context = canvas.getContext( '2d' ); | |
context.drawImage( image, 0, 0, image.width, image.height, 0, 0, canvas.width, canvas.height ); | |
console.log( 'THREE.WebGLRenderer:', image, 'is too big (' + image.width + 'x' + image.height + '). Resized to ' + canvas.width + 'x' + canvas.height + '.' ); | |
return canvas; | |
} | |
return image; | |
} | |
function setCubeTexture ( texture, slot ) { | |
if ( texture.image.length === 6 ) { | |
if ( texture.needsUpdate ) { | |
if ( ! texture.image.__webglTextureCube ) { | |
texture.addEventListener( 'dispose', onTextureDispose ); | |
texture.image.__webglTextureCube = _gl.createTexture(); | |
_this.info.memory.textures ++; | |
} | |
_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 isDataTexture = texture.image[ 0 ] instanceof THREE.DataTexture; | |
var cubeImage = []; | |
for ( var i = 0; i < 6; i ++ ) { | |
if ( _this.autoScaleCubemaps && ! isCompressed && ! isDataTexture ) { | |
cubeImage[ i ] = clampToMaxSize( texture.image[ i ], _maxCubemapSize ); | |
} else { | |
cubeImage[ i ] = isDataTexture ? texture.image[ i ].image : texture.image[ i ]; | |
} | |
} | |
var image = cubeImage[ 0 ], | |
isImagePowerOfTwo = THREE.Math.isPowerOfTwo( image.width ) && THREE.Math.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 ) { | |
if ( isDataTexture ) { | |
_gl.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glFormat, cubeImage[ i ].width, cubeImage[ i ].height, 0, glFormat, glType, cubeImage[ i ].data ); | |
} else { | |
_gl.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glFormat, glFormat, glType, cubeImage[ i ] ); | |
} | |
} else { | |
var mipmap, mipmaps = cubeImage[ i ].mipmaps; | |
for ( var j = 0, jl = mipmaps.length; j < jl; j ++ ) { | |
mipmap = mipmaps[ j ]; | |
if ( texture.format !== THREE.RGBAFormat && texture.format !== THREE.RGBFormat ) { | |
if ( getCompressedTextureFormats().indexOf( glFormat ) > -1 ) { | |
_gl.compressedTexImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glFormat, mipmap.width, mipmap.height, 0, mipmap.data ); | |
} else { | |
console.warn( "Attempt to load unsupported compressed texture format" ); | |
} | |
} else { | |
_gl.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data ); | |
} | |
} | |
} | |
} | |
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 ); | |
} | |
} | |
} | |
function setCubeTextureDynamic ( texture, slot ) { | |
_gl.activeTexture( _gl.TEXTURE0 + slot ); | |
_gl.bindTexture( _gl.TEXTURE_CUBE_MAP, texture.__webglTexture ); | |
} | |
// Render targets | |
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 ); | |
} | |
} | |
this.setRenderTarget = function ( renderTarget ) { | |
var isCube = ( renderTarget instanceof THREE.WebGLRenderTargetCube ); | |
if ( renderTarget && renderTarget.__webglFramebuffer === undefined ) { | |
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 = THREE.Math.isPowerOfTwo( renderTarget.width ) && THREE.Math.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 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 ); | |
} | |
} | |
// 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; | |
} | |
// Map three.js constants to WebGL constants | |
function paramThreeToGL ( p ) { | |
var extension; | |
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; | |
extension = extensions.get( 'WEBGL_compressed_texture_s3tc' ); | |
if ( extension !== null ) { | |
if ( p === THREE.RGB_S3TC_DXT1_Format ) return extension.COMPRESSED_RGB_S3TC_DXT1_EXT; | |
if ( p === THREE.RGBA_S3TC_DXT1_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT1_EXT; | |
if ( p === THREE.RGBA_S3TC_DXT3_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT3_EXT; | |
if ( p === THREE.RGBA_S3TC_DXT5_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT5_EXT; | |
} | |
extension = extensions.get( 'WEBGL_compressed_texture_pvrtc' ); | |
if ( extension !== null ) { | |
if ( p === THREE.RGB_PVRTC_4BPPV1_Format ) return extension.COMPRESSED_RGB_PVRTC_4BPPV1_IMG; | |
if ( p === THREE.RGB_PVRTC_2BPPV1_Format ) return extension.COMPRESSED_RGB_PVRTC_2BPPV1_IMG; | |
if ( p === THREE.RGBA_PVRTC_4BPPV1_Format ) return extension.COMPRESSED_RGBA_PVRTC_4BPPV1_IMG; | |
if ( p === THREE.RGBA_PVRTC_2BPPV1_Format ) return extension.COMPRESSED_RGBA_PVRTC_2BPPV1_IMG; | |
} | |
extension = extensions.get( 'EXT_blend_minmax' ); | |
if ( extension !== null ) { | |
if ( p === THREE.MinEquation ) return extension.MIN_EXT; | |
if ( p === THREE.MaxEquation ) return extension.MAX_EXT; | |
} | |
return 0; | |
} | |
// Allocations | |
function allocateBones ( object ) { | |
if ( _supportsBoneTextures && object && object.skeleton && object.skeleton.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 = _gl.getParameter( _gl.MAX_VERTEX_UNIFORM_VECTORS ); | |
var nVertexMatrices = Math.floor( ( nVertexUniforms - 20 ) / 4 ); | |
var maxBones = nVertexMatrices; | |
if ( object !== undefined && object instanceof THREE.SkinnedMesh ) { | |
maxBones = Math.min( object.skeleton.bones.length, maxBones ); | |
if ( maxBones < object.skeleton.bones.length ) { | |
console.warn( 'WebGLRenderer: too many bones - ' + object.skeleton.bones.length + ', this GPU supports just ' + maxBones + ' (try OpenGL instead of ANGLE)' ); | |
} | |
} | |
return maxBones; | |
} | |
} | |
function allocateLights( lights ) { | |
var dirLights = 0; | |
var pointLights = 0; | |
var spotLights = 0; | |
var hemiLights = 0; | |
for ( var l = 0, ll = lights.length; l < ll; l ++ ) { | |
var light = lights[ l ]; | |
if ( light.onlyShadow || light.visible === false ) 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 maxShadows = 0; | |
for ( var l = 0, ll = lights.length; l < ll; l ++ ) { | |
var light = lights[ l ]; | |
if ( ! light.castShadow ) continue; | |
if ( light instanceof THREE.SpotLight ) maxShadows ++; | |
if ( light instanceof THREE.DirectionalLight && ! light.shadowCascade ) maxShadows ++; | |
} | |
return maxShadows; | |
} | |
// DEPRECATED | |
this.initMaterial = function () { | |
console.warn( 'THREE.WebGLRenderer: .initMaterial() has been removed.' ); | |
}; | |
this.addPrePlugin = function () { | |
console.warn( 'THREE.WebGLRenderer: .addPrePlugin() has been removed.' ); | |
}; | |
this.addPostPlugin = function () { | |
console.warn( 'THREE.WebGLRenderer: .addPostPlugin() has been removed.' ); | |
}; | |
this.updateShadowMap = function () { | |
console.warn( 'THREE.WebGLRenderer: .updateShadowMap() has been removed.' ); | |
}; | |
}; | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment