three.fbo-helper
Version:
FrameBuffer Object inspector for three.js
2,178 lines (1,269 loc) • 67.6 kB
JavaScript
import { REVISION, MaxEquation, MinEquation, RGB_ETC1_Format, RGBA_PVRTC_2BPPV1_Format, RGBA_PVRTC_4BPPV1_Format, RGB_PVRTC_2BPPV1_Format, RGB_PVRTC_4BPPV1_Format, RGBA_S3TC_DXT5_Format, RGBA_S3TC_DXT3_Format, RGBA_S3TC_DXT1_Format, RGB_S3TC_DXT1_Format, SrcAlphaSaturateFactor, OneMinusDstColorFactor, DstColorFactor, OneMinusDstAlphaFactor, DstAlphaFactor, OneMinusSrcAlphaFactor, SrcAlphaFactor, OneMinusSrcColorFactor, SrcColorFactor, OneFactor, ZeroFactor, ReverseSubtractEquation, SubtractEquation, AddEquation, DepthFormat, DepthStencilFormat, LuminanceAlphaFormat, LuminanceFormat, RGBAFormat, RGBFormat, AlphaFormat, HalfFloatType, FloatType, UnsignedIntType, IntType, UnsignedShortType, ShortType, ByteType, UnsignedInt248Type, UnsignedShort565Type, UnsignedShort5551Type, UnsignedShort4444Type, UnsignedByteType, LinearMipMapLinearFilter, LinearMipMapNearestFilter, LinearFilter, NearestMipMapLinearFilter, NearestMipMapNearestFilter, NearestFilter, MirroredRepeatWrapping, ClampToEdgeWrapping, RepeatWrapping, FrontFaceDirectionCW, NoBlending, BackSide, DoubleSide, TriangleFanDrawMode, TriangleStripDrawMode, TrianglesDrawMode, NoColors, FlatShading, LinearToneMapping } from '../constants';
import { Matrix4 } from '../math/Matrix4';
import { WebGLUniforms } from './webgl/WebGLUniforms';
import { UniformsUtils } from './shaders/UniformsUtils';
import { ShaderLib } from './shaders/ShaderLib';
import { LensFlarePlugin } from './webgl/plugins/LensFlarePlugin';
import { SpritePlugin } from './webgl/plugins/SpritePlugin';
import { WebGLShadowMap } from './webgl/WebGLShadowMap';
import { ShaderMaterial } from '../materials/ShaderMaterial';
import { Mesh } from '../objects/Mesh';
import { BoxBufferGeometry } from '../geometries/BoxBufferGeometry';
import { PlaneBufferGeometry } from '../geometries/PlaneBufferGeometry';
import { MeshBasicMaterial } from '../materials/MeshBasicMaterial';
import { PerspectiveCamera } from '../cameras/PerspectiveCamera';
import { OrthographicCamera } from '../cameras/OrthographicCamera';
import { WebGLIndexedBufferRenderer } from './webgl/WebGLIndexedBufferRenderer';
import { WebGLBufferRenderer } from './webgl/WebGLBufferRenderer';
import { WebGLLights } from './webgl/WebGLLights';
import { WebGLPrograms } from './webgl/WebGLPrograms';
import { WebGLObjects } from './webgl/WebGLObjects';
import { WebGLTextures } from './webgl/WebGLTextures';
import { WebGLProperties } from './webgl/WebGLProperties';
import { WebGLState } from './webgl/WebGLState';
import { WebGLCapabilities } from './webgl/WebGLCapabilities';
import { BufferGeometry } from '../core/BufferGeometry';
import { WebGLExtensions } from './webgl/WebGLExtensions';
import { Vector3 } from '../math/Vector3';
import { Sphere } from '../math/Sphere';
import { WebGLClipping } from './webgl/WebGLClipping';
import { Frustum } from '../math/Frustum';
import { Vector4 } from '../math/Vector4';
import { Color } from '../math/Color';
/**
* @author supereggbert / http://www.paulbrunt.co.uk/
* @author mrdoob / http://mrdoob.com/
* @author alteredq / http://alteredqualia.com/
* @author szimek / https://github.com/szimek/
* @author tschw
*/
function WebGLRenderer( parameters ) {
console.log( 'THREE.WebGLRenderer', REVISION );
parameters = parameters || {};
var _canvas = parameters.canvas !== undefined ? parameters.canvas : document.createElementNS( 'http://www.w3.org/1999/xhtml', 'canvas' ),
_context = parameters.context !== undefined ? parameters.context : null,
_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;
var lights = [];
var opaqueObjects = [];
var opaqueObjectsLastIndex = - 1;
var transparentObjects = [];
var transparentObjectsLastIndex = - 1;
var morphInfluences = new Float32Array( 8 );
var sprites = [];
var lensFlares = [];
// public properties
this.domElement = _canvas;
this.context = null;
// clearing
this.autoClear = true;
this.autoClearColor = true;
this.autoClearDepth = true;
this.autoClearStencil = true;
// scene graph
this.sortObjects = true;
// user-defined clipping
this.clippingPlanes = [];
this.localClippingEnabled = false;
// physically based shading
this.gammaFactor = 2.0; // for backwards compatibility
this.gammaInput = false;
this.gammaOutput = false;
// physical lights
this.physicallyCorrectLights = false;
// tone mapping
this.toneMapping = LinearToneMapping;
this.toneMappingExposure = 1.0;
this.toneMappingWhitePoint = 1.0;
// morphs
this.maxMorphTargets = 8;
this.maxMorphNormals = 4;
// internal properties
var _this = this,
// internal state cache
_currentProgram = null,
_currentRenderTarget = null,
_currentFramebuffer = null,
_currentMaterialId = - 1,
_currentGeometryProgram = '',
_currentCamera = null,
_currentScissor = new Vector4(),
_currentScissorTest = null,
_currentViewport = new Vector4(),
//
_usedTextureUnits = 0,
//
_clearColor = new Color( 0x000000 ),
_clearAlpha = 0,
_width = _canvas.width,
_height = _canvas.height,
_pixelRatio = 1,
_scissor = new Vector4( 0, 0, _width, _height ),
_scissorTest = false,
_viewport = new Vector4( 0, 0, _width, _height ),
// frustum
_frustum = new Frustum(),
// clipping
_clipping = new WebGLClipping(),
_clippingEnabled = false,
_localClippingEnabled = false,
_sphere = new Sphere(),
// camera matrices cache
_projScreenMatrix = new Matrix4(),
_vector3 = new Vector3(),
// light arrays cache
_lights = {
hash: '',
ambient: [ 0, 0, 0 ],
directional: [],
directionalShadowMap: [],
directionalShadowMatrix: [],
spot: [],
spotShadowMap: [],
spotShadowMatrix: [],
point: [],
pointShadowMap: [],
pointShadowMatrix: [],
hemi: [],
shadows: []
},
// info
_infoRender = {
calls: 0,
vertices: 0,
faces: 0,
points: 0
};
this.info = {
render: _infoRender,
memory: {
geometries: 0,
textures: 0
},
programs: null
};
// 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.';
}
}
// Some experimental-webgl implementations do not have getShaderPrecisionFormat
if ( _gl.getShaderPrecisionFormat === undefined ) {
_gl.getShaderPrecisionFormat = function () {
return { 'rangeMin': 1, 'rangeMax': 1, 'precision': 1 };
};
}
_canvas.addEventListener( 'webglcontextlost', onContextLost, false );
} catch ( error ) {
console.error( 'THREE.WebGLRenderer: ' + error );
}
var extensions = new WebGLExtensions( _gl );
extensions.get( 'WEBGL_depth_texture' );
extensions.get( 'OES_texture_float' );
extensions.get( 'OES_texture_float_linear' );
extensions.get( 'OES_texture_half_float' );
extensions.get( 'OES_texture_half_float_linear' );
extensions.get( 'OES_standard_derivatives' );
extensions.get( 'ANGLE_instanced_arrays' );
if ( extensions.get( 'OES_element_index_uint' ) ) {
BufferGeometry.MaxIndex = 4294967296;
}
var capabilities = new WebGLCapabilities( _gl, extensions, parameters );
var state = new WebGLState( _gl, extensions, paramThreeToGL );
var properties = new WebGLProperties();
var textures = new WebGLTextures( _gl, extensions, state, properties, capabilities, paramThreeToGL, this.info );
var objects = new WebGLObjects( _gl, properties, this.info );
var programCache = new WebGLPrograms( this, capabilities );
var lightCache = new WebGLLights();
this.info.programs = programCache.programs;
var bufferRenderer = new WebGLBufferRenderer( _gl, extensions, _infoRender );
var indexedBufferRenderer = new WebGLIndexedBufferRenderer( _gl, extensions, _infoRender );
//
var backgroundCamera = new OrthographicCamera( - 1, 1, 1, - 1, 0, 1 );
var backgroundCamera2 = new PerspectiveCamera();
var backgroundPlaneMesh = new Mesh(
new PlaneBufferGeometry( 2, 2 ),
new MeshBasicMaterial( { depthTest: false, depthWrite: false, fog: false } )
);
var backgroundBoxShader = ShaderLib[ 'cube' ];
var backgroundBoxMesh = new Mesh(
new BoxBufferGeometry( 5, 5, 5 ),
new ShaderMaterial( {
uniforms: backgroundBoxShader.uniforms,
vertexShader: backgroundBoxShader.vertexShader,
fragmentShader: backgroundBoxShader.fragmentShader,
side: BackSide,
depthTest: false,
depthWrite: false,
fog: false
} )
);
//
function getTargetPixelRatio() {
return _currentRenderTarget === null ? _pixelRatio : 1;
}
function glClearColor( r, g, b, a ) {
if ( _premultipliedAlpha === true ) {
r *= a; g *= a; b *= a;
}
state.clearColor( r, g, b, a );
}
function setDefaultGLState() {
state.init();
state.scissor( _currentScissor.copy( _scissor ).multiplyScalar( _pixelRatio ) );
state.viewport( _currentViewport.copy( _viewport ).multiplyScalar( _pixelRatio ) );
glClearColor( _clearColor.r, _clearColor.g, _clearColor.b, _clearAlpha );
}
function resetGLState() {
_currentProgram = null;
_currentCamera = null;
_currentGeometryProgram = '';
_currentMaterialId = - 1;
state.reset();
}
setDefaultGLState();
this.context = _gl;
this.capabilities = capabilities;
this.extensions = extensions;
this.properties = properties;
this.state = state;
// shadow map
var shadowMap = new WebGLShadowMap( this, _lights, objects, capabilities );
this.shadowMap = shadowMap;
// Plugins
var spritePlugin = new SpritePlugin( this, sprites );
var lensFlarePlugin = new LensFlarePlugin( this, lensFlares );
// API
this.getContext = function () {
return _gl;
};
this.getContextAttributes = function () {
return _gl.getContextAttributes();
};
this.forceContextLoss = function () {
extensions.get( 'WEBGL_lose_context' ).loseContext();
};
this.getMaxAnisotropy = function () {
return capabilities.getMaxAnisotropy();
};
this.getPrecision = function () {
return capabilities.precision;
};
this.getPixelRatio = function () {
return _pixelRatio;
};
this.setPixelRatio = function ( value ) {
if ( value === undefined ) return;
_pixelRatio = value;
this.setSize( _viewport.z, _viewport.w, false );
};
this.getSize = function () {
return {
width: _width,
height: _height
};
};
this.setSize = function ( width, height, updateStyle ) {
_width = width;
_height = height;
_canvas.width = width * _pixelRatio;
_canvas.height = height * _pixelRatio;
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 ) {
state.viewport( _viewport.set( x, y, width, height ) );
};
this.setScissor = function ( x, y, width, height ) {
state.scissor( _scissor.set( x, y, width, height ) );
};
this.setScissorTest = function ( boolean ) {
state.setScissorTest( _scissorTest = boolean );
};
// Clearing
this.getClearColor = function () {
return _clearColor;
};
this.setClearColor = function ( color, alpha ) {
_clearColor.set( color );
_clearAlpha = alpha !== undefined ? alpha : 1;
glClearColor( _clearColor.r, _clearColor.g, _clearColor.b, _clearAlpha );
};
this.getClearAlpha = function () {
return _clearAlpha;
};
this.setClearAlpha = function ( alpha ) {
_clearAlpha = alpha;
glClearColor( _clearColor.r, _clearColor.g, _clearColor.b, _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 () {
this.clear( true, false, false );
};
this.clearDepth = function () {
this.clear( false, true, false );
};
this.clearStencil = function () {
this.clear( false, false, true );
};
this.clearTarget = function ( renderTarget, color, depth, stencil ) {
this.setRenderTarget( renderTarget );
this.clear( color, depth, stencil );
};
// Reset
this.resetGLState = resetGLState;
this.dispose = function() {
transparentObjects = [];
transparentObjectsLastIndex = -1;
opaqueObjects = [];
opaqueObjectsLastIndex = -1;
_canvas.removeEventListener( 'webglcontextlost', onContextLost, false );
};
// Events
function onContextLost( event ) {
event.preventDefault();
resetGLState();
setDefaultGLState();
properties.clear();
}
function onMaterialDispose( event ) {
var material = event.target;
material.removeEventListener( 'dispose', onMaterialDispose );
deallocateMaterial( material );
}
// Buffer deallocation
function deallocateMaterial( material ) {
releaseMaterialProgramReference( material );
properties.delete( material );
}
function releaseMaterialProgramReference( material ) {
var programInfo = properties.get( material ).program;
material.program = undefined;
if ( programInfo !== undefined ) {
programCache.releaseProgram( programInfo );
}
}
// Buffer rendering
this.renderBufferImmediate = function ( object, program, material ) {
state.initAttributes();
var buffers = properties.get( object );
if ( object.hasPositions && ! buffers.position ) buffers.position = _gl.createBuffer();
if ( object.hasNormals && ! buffers.normal ) buffers.normal = _gl.createBuffer();
if ( object.hasUvs && ! buffers.uv ) buffers.uv = _gl.createBuffer();
if ( object.hasColors && ! buffers.color ) buffers.color = _gl.createBuffer();
var attributes = program.getAttributes();
if ( object.hasPositions ) {
_gl.bindBuffer( _gl.ARRAY_BUFFER, buffers.position );
_gl.bufferData( _gl.ARRAY_BUFFER, object.positionArray, _gl.DYNAMIC_DRAW );
state.enableAttribute( attributes.position );
_gl.vertexAttribPointer( attributes.position, 3, _gl.FLOAT, false, 0, 0 );
}
if ( object.hasNormals ) {
_gl.bindBuffer( _gl.ARRAY_BUFFER, buffers.normal );
if ( ! material.isMeshPhongMaterial &&
! material.isMeshStandardMaterial &&
material.shading === FlatShading ) {
for ( var i = 0, l = object.count * 3; i < l; i += 9 ) {
var array = object.normalArray;
var nx = ( array[ i + 0 ] + array[ i + 3 ] + array[ i + 6 ] ) / 3;
var ny = ( array[ i + 1 ] + array[ i + 4 ] + array[ i + 7 ] ) / 3;
var nz = ( array[ i + 2 ] + array[ i + 5 ] + array[ i + 8 ] ) / 3;
array[ i + 0 ] = nx;
array[ i + 1 ] = ny;
array[ i + 2 ] = nz;
array[ i + 3 ] = nx;
array[ i + 4 ] = ny;
array[ i + 5 ] = nz;
array[ i + 6 ] = nx;
array[ i + 7 ] = ny;
array[ i + 8 ] = nz;
}
}
_gl.bufferData( _gl.ARRAY_BUFFER, object.normalArray, _gl.DYNAMIC_DRAW );
state.enableAttribute( attributes.normal );
_gl.vertexAttribPointer( attributes.normal, 3, _gl.FLOAT, false, 0, 0 );
}
if ( object.hasUvs && material.map ) {
_gl.bindBuffer( _gl.ARRAY_BUFFER, buffers.uv );
_gl.bufferData( _gl.ARRAY_BUFFER, object.uvArray, _gl.DYNAMIC_DRAW );
state.enableAttribute( attributes.uv );
_gl.vertexAttribPointer( attributes.uv, 2, _gl.FLOAT, false, 0, 0 );
}
if ( object.hasColors && material.vertexColors !== NoColors ) {
_gl.bindBuffer( _gl.ARRAY_BUFFER, buffers.color );
_gl.bufferData( _gl.ARRAY_BUFFER, object.colorArray, _gl.DYNAMIC_DRAW );
state.enableAttribute( attributes.color );
_gl.vertexAttribPointer( attributes.color, 3, _gl.FLOAT, false, 0, 0 );
}
state.disableUnusedAttributes();
_gl.drawArrays( _gl.TRIANGLES, 0, object.count );
object.count = 0;
};
this.renderBufferDirect = function ( camera, fog, geometry, material, object, group ) {
setMaterial( material );
var program = setProgram( camera, fog, material, object );
var updateBuffers = false;
var geometryProgram = geometry.id + '_' + program.id + '_' + material.wireframe;
if ( geometryProgram !== _currentGeometryProgram ) {
_currentGeometryProgram = geometryProgram;
updateBuffers = true;
}
// morph targets
var morphTargetInfluences = object.morphTargetInfluences;
if ( morphTargetInfluences !== undefined ) {
var activeInfluences = [];
for ( var i = 0, l = morphTargetInfluences.length; i < l; i ++ ) {
var influence = morphTargetInfluences[ i ];
activeInfluences.push( [ influence, i ] );
}
activeInfluences.sort( absNumericalSort );
if ( activeInfluences.length > 8 ) {
activeInfluences.length = 8;
}
var morphAttributes = geometry.morphAttributes;
for ( var i = 0, l = activeInfluences.length; i < l; i ++ ) {
var influence = activeInfluences[ i ];
morphInfluences[ i ] = influence[ 0 ];
if ( influence[ 0 ] !== 0 ) {
var index = influence[ 1 ];
if ( material.morphTargets === true && morphAttributes.position ) geometry.addAttribute( 'morphTarget' + i, morphAttributes.position[ index ] );
if ( material.morphNormals === true && morphAttributes.normal ) geometry.addAttribute( 'morphNormal' + i, morphAttributes.normal[ index ] );
} else {
if ( material.morphTargets === true ) geometry.removeAttribute( 'morphTarget' + i );
if ( material.morphNormals === true ) geometry.removeAttribute( 'morphNormal' + i );
}
}
for ( var i = activeInfluences.length, il = morphInfluences.length; i < il; i ++ ) {
morphInfluences[ i ] = 0.0;
}
program.getUniforms().setValue(
_gl, 'morphTargetInfluences', morphInfluences );
updateBuffers = true;
}
//
var index = geometry.index;
var position = geometry.attributes.position;
var rangeFactor = 1;
if ( material.wireframe === true ) {
index = objects.getWireframeAttribute( geometry );
rangeFactor = 2;
}
var renderer;
if ( index !== null ) {
renderer = indexedBufferRenderer;
renderer.setIndex( index );
} else {
renderer = bufferRenderer;
}
if ( updateBuffers ) {
setupVertexAttributes( material, program, geometry );
if ( index !== null ) {
_gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, objects.getAttributeBuffer( index ) );
}
}
//
var dataCount = 0;
if ( index !== null ) {
dataCount = index.count;
} else if ( position !== undefined ) {
dataCount = position.count;
}
var rangeStart = geometry.drawRange.start * rangeFactor;
var rangeCount = geometry.drawRange.count * rangeFactor;
var groupStart = group !== null ? group.start * rangeFactor : 0;
var groupCount = group !== null ? group.count * rangeFactor : Infinity;
var drawStart = Math.max( rangeStart, groupStart );
var drawEnd = Math.min( dataCount, rangeStart + rangeCount, groupStart + groupCount ) - 1;
var drawCount = Math.max( 0, drawEnd - drawStart + 1 );
if ( drawCount === 0 ) return;
//
if ( object.isMesh ) {
if ( material.wireframe === true ) {
state.setLineWidth( material.wireframeLinewidth * getTargetPixelRatio() );
renderer.setMode( _gl.LINES );
} else {
switch ( object.drawMode ) {
case TrianglesDrawMode:
renderer.setMode( _gl.TRIANGLES );
break;
case TriangleStripDrawMode:
renderer.setMode( _gl.TRIANGLE_STRIP );
break;
case TriangleFanDrawMode:
renderer.setMode( _gl.TRIANGLE_FAN );
break;
}
}
} else if ( object.isLine ) {
var lineWidth = material.linewidth;
if ( lineWidth === undefined ) lineWidth = 1; // Not using Line*Material
state.setLineWidth( lineWidth * getTargetPixelRatio() );
if ( object.isLineSegments ) {
renderer.setMode( _gl.LINES );
} else {
renderer.setMode( _gl.LINE_STRIP );
}
} else if ( object.isPoints ) {
renderer.setMode( _gl.POINTS );
}
if ( geometry && geometry.isInstancedBufferGeometry ) {
if ( geometry.maxInstancedCount > 0 ) {
renderer.renderInstances( geometry, drawStart, drawCount );
}
} else {
renderer.render( drawStart, drawCount );
}
};
function setupVertexAttributes( material, program, geometry, startIndex ) {
var extension;
if ( geometry && geometry.isInstancedBufferGeometry ) {
extension = extensions.get( 'ANGLE_instanced_arrays' );
if ( extension === null ) {
console.error( 'THREE.WebGLRenderer.setupVertexAttributes: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays.' );
return;
}
}
if ( startIndex === undefined ) startIndex = 0;
state.initAttributes();
var geometryAttributes = geometry.attributes;
var programAttributes = program.getAttributes();
var materialDefaultAttributeValues = material.defaultAttributeValues;
for ( var name in programAttributes ) {
var programAttribute = programAttributes[ name ];
if ( programAttribute >= 0 ) {
var geometryAttribute = geometryAttributes[ name ];
if ( geometryAttribute !== undefined ) {
var type = _gl.FLOAT;
var array = geometryAttribute.array;
var normalized = geometryAttribute.normalized;
if ( array instanceof Float32Array ) {
type = _gl.FLOAT;
} else if ( array instanceof Float64Array ) {
console.warn( "Unsupported data buffer format: Float64Array" );
} else if ( array instanceof Uint16Array ) {
type = _gl.UNSIGNED_SHORT;
} else if ( array instanceof Int16Array ) {
type = _gl.SHORT;
} else if ( array instanceof Uint32Array ) {
type = _gl.UNSIGNED_INT;
} else if ( array instanceof Int32Array ) {
type = _gl.INT;
} else if ( array instanceof Int8Array ) {
type = _gl.BYTE;
} else if ( array instanceof Uint8Array ) {
type = _gl.UNSIGNED_BYTE;
}
var size = geometryAttribute.itemSize;
var buffer = objects.getAttributeBuffer( geometryAttribute );
if ( geometryAttribute && geometryAttribute.isInterleavedBufferAttribute ) {
var data = geometryAttribute.data;
var stride = data.stride;
var offset = geometryAttribute.offset;
if ( data && data.isInstancedInterleavedBuffer ) {
state.enableAttributeAndDivisor( programAttribute, data.meshPerAttribute, extension );
if ( geometry.maxInstancedCount === undefined ) {
geometry.maxInstancedCount = data.meshPerAttribute * data.count;
}
} else {
state.enableAttribute( programAttribute );
}
_gl.bindBuffer( _gl.ARRAY_BUFFER, buffer );
_gl.vertexAttribPointer( programAttribute, size, type, normalized, stride * data.array.BYTES_PER_ELEMENT, ( startIndex * stride + offset ) * data.array.BYTES_PER_ELEMENT );
} else {
if ( geometryAttribute && geometryAttribute.isInstancedBufferAttribute ) {
state.enableAttributeAndDivisor( programAttribute, geometryAttribute.meshPerAttribute, extension );
if ( geometry.maxInstancedCount === undefined ) {
geometry.maxInstancedCount = geometryAttribute.meshPerAttribute * geometryAttribute.count;
}
} else {
state.enableAttribute( programAttribute );
}
_gl.bindBuffer( _gl.ARRAY_BUFFER, buffer );
_gl.vertexAttribPointer( programAttribute, size, type, normalized, 0, startIndex * size * geometryAttribute.array.BYTES_PER_ELEMENT );
}
} else if ( materialDefaultAttributeValues !== undefined ) {
var value = materialDefaultAttributeValues[ name ];
if ( value !== undefined ) {
switch ( value.length ) {
case 2:
_gl.vertexAttrib2fv( programAttribute, value );
break;
case 3:
_gl.vertexAttrib3fv( programAttribute, value );
break;
case 4:
_gl.vertexAttrib4fv( programAttribute, value );
break;
default:
_gl.vertexAttrib1fv( programAttribute, value );
}
}
}
}
}
state.disableUnusedAttributes();
}
// Sorting
function absNumericalSort( a, b ) {
return Math.abs( b[ 0 ] ) - Math.abs( a[ 0 ] );
}
function painterSortStable( a, b ) {
if ( a.object.renderOrder !== b.object.renderOrder ) {
return a.object.renderOrder - b.object.renderOrder;
} else if ( a.material.program && b.material.program && a.material.program !== b.material.program ) {
return a.material.program.id - b.material.program.id;
} else if ( a.material.id !== b.material.id ) {
return a.material.id - b.material.id;
} else if ( a.z !== b.z ) {
return a.z - b.z;
} else {
return a.id - b.id;
}
}
function reversePainterSortStable( a, b ) {
if ( a.object.renderOrder !== b.object.renderOrder ) {
return a.object.renderOrder - b.object.renderOrder;
} if ( a.z !== b.z ) {
return b.z - a.z;
} else {
return a.id - b.id;
}
}
// Rendering
this.render = function ( scene, camera, renderTarget, forceClear ) {
if ( camera !== undefined && camera.isCamera !== true ) {
console.error( 'THREE.WebGLRenderer.render: camera is not an instance of THREE.Camera.' );
return;
}
var fog = scene.fog;
// reset caching for this frame
_currentGeometryProgram = '';
_currentMaterialId = - 1;
_currentCamera = null;
// update scene graph
if ( scene.autoUpdate === true ) scene.updateMatrixWorld();
// update camera matrices and frustum
if ( camera.parent === null ) camera.updateMatrixWorld();
camera.matrixWorldInverse.getInverse( camera.matrixWorld );
_projScreenMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse );
_frustum.setFromMatrix( _projScreenMatrix );
lights.length = 0;
opaqueObjectsLastIndex = - 1;
transparentObjectsLastIndex = - 1;
sprites.length = 0;
lensFlares.length = 0;
_localClippingEnabled = this.localClippingEnabled;
_clippingEnabled = _clipping.init( this.clippingPlanes, _localClippingEnabled, camera );
projectObject( scene, camera );
opaqueObjects.length = opaqueObjectsLastIndex + 1;
transparentObjects.length = transparentObjectsLastIndex + 1;
if ( _this.sortObjects === true ) {
opaqueObjects.sort( painterSortStable );
transparentObjects.sort( reversePainterSortStable );
}
//
if ( _clippingEnabled ) _clipping.beginShadows();
setupShadows( lights );
shadowMap.render( scene, camera );
setupLights( lights, camera );
if ( _clippingEnabled ) _clipping.endShadows();
//
_infoRender.calls = 0;
_infoRender.vertices = 0;
_infoRender.faces = 0;
_infoRender.points = 0;
if ( renderTarget === undefined ) {
renderTarget = null;
}
this.setRenderTarget( renderTarget );
//
var background = scene.background;
if ( background === null ) {
glClearColor( _clearColor.r, _clearColor.g, _clearColor.b, _clearAlpha );
} else if ( background && background.isColor ) {
glClearColor( background.r, background.g, background.b, 1 );
forceClear = true;
}
if ( this.autoClear || forceClear ) {
this.clear( this.autoClearColor, this.autoClearDepth, this.autoClearStencil );
}
if ( background && background.isCubeTexture ) {
backgroundCamera2.projectionMatrix.copy( camera.projectionMatrix );
backgroundCamera2.matrixWorld.extractRotation( camera.matrixWorld );
backgroundCamera2.matrixWorldInverse.getInverse( backgroundCamera2.matrixWorld );
backgroundBoxMesh.material.uniforms[ "tCube" ].value = background;
backgroundBoxMesh.modelViewMatrix.multiplyMatrices( backgroundCamera2.matrixWorldInverse, backgroundBoxMesh.matrixWorld );
objects.update( backgroundBoxMesh );
_this.renderBufferDirect( backgroundCamera2, null, backgroundBoxMesh.geometry, backgroundBoxMesh.material, backgroundBoxMesh, null );
} else if ( background && background.isTexture ) {
backgroundPlaneMesh.material.map = background;
objects.update( backgroundPlaneMesh );
_this.renderBufferDirect( backgroundCamera, null, backgroundPlaneMesh.geometry, backgroundPlaneMesh.material, backgroundPlaneMesh, null );
}
//
if ( scene.overrideMaterial ) {
var overrideMaterial = scene.overrideMaterial;
renderObjects( opaqueObjects, camera, fog, overrideMaterial );
renderObjects( transparentObjects, camera, fog, overrideMaterial );
} else {
// opaque pass (front-to-back order)
state.setBlending( NoBlending );
renderObjects( opaqueObjects, camera, fog );
// transparent pass (back-to-front order)
renderObjects( transparentObjects, camera, fog );
}
// custom render plugins (post pass)
spritePlugin.render( scene, camera );
lensFlarePlugin.render( scene, camera, _currentViewport );
// Generate mipmap if we're using any kind of mipmap filtering
if ( renderTarget ) {
textures.updateRenderTargetMipmap( renderTarget );
}
// Ensure depth buffer writing is enabled so it can be cleared on next render
state.setDepthTest( true );
state.setDepthWrite( true );
state.setColorWrite( true );
// _gl.finish();
};
function pushRenderItem( object, geometry, material, z, group ) {
var array, index;
// allocate the next position in the appropriate array
if ( material.transparent ) {
array = transparentObjects;
index = ++ transparentObjectsLastIndex;
} else {
array = opaqueObjects;
index = ++ opaqueObjectsLastIndex;
}
// recycle existing render item or grow the array
var renderItem = array[ index ];
if ( renderItem !== undefined ) {
renderItem.id = object.id;
renderItem.object = object;
renderItem.geometry = geometry;
renderItem.material = material;
renderItem.z = _vector3.z;
renderItem.group = group;
} else {
renderItem = {
id: object.id,
object: object,
geometry: geometry,
material: material,
z: _vector3.z,
group: group
};
// assert( index === array.length );
array.push( renderItem );
}
}
// TODO Duplicated code (Frustum)
function isObjectViewable( object ) {
var geometry = object.geometry;
if ( geometry.boundingSphere === null )
geometry.computeBoundingSphere();
_sphere.copy( geometry.boundingSphere ).
applyMatrix4( object.matrixWorld );
return isSphereViewable( _sphere );
}
function isSpriteViewable( sprite ) {
_sphere.center.set( 0, 0, 0 );
_sphere.radius = 0.7071067811865476;
_sphere.applyMatrix4( sprite.matrixWorld );
return isSphereViewable( _sphere );
}
function isSphereViewable( sphere ) {
if ( ! _frustum.intersectsSphere( sphere ) ) return false;
var numPlanes = _clipping.numPlanes;
if ( numPlanes === 0 ) return true;
var planes = _this.clippingPlanes,
center = sphere.center,
negRad = - sphere.radius,
i = 0;
do {
// out when deeper than radius in the negative halfspace
if ( planes[ i ].distanceToPoint( center ) < negRad ) return false;
} while ( ++ i !== numPlanes );
return true;
}
function projectObject( object, camera ) {
if ( object.visible === false ) return;
var visible = ( object.layers.mask & camera.layers.mask ) !== 0;
if ( visible ) {
if ( object.isLight ) {
lights.push( object );
} else if ( object.isSprite ) {
if ( object.frustumCulled === false || isSpriteViewable( object ) === true ) {
sprites.push( object );
}
} else if ( object.isLensFlare ) {
lensFlares.push( object );
} else if ( object.isImmediateRenderObject ) {
if ( _this.sortObjects === true ) {
_vector3.setFromMatrixPosition( object.matrixWorld );
_vector3.applyProjection( _projScreenMatrix );
}
pushRenderItem( object, null, object.material, _vector3.z, null );
} else if ( object.isMesh || object.isLine || object.isPoints ) {
if ( object.isSkinnedMesh ) {
object.skeleton.update();
}
if ( object.frustumCulled === false || isObjectViewable( object ) === true ) {
var material = object.material;
if ( material.visible === true ) {
if ( _this.sortObjects === true ) {
_vector3.setFromMatrixPosition( object.matrixWorld );
_vector3.applyProjection( _projScreenMatrix );
}
var geometry = objects.update( object );
if ( material.isMultiMaterial ) {
var groups = geometry.groups;
var materials = material.materials;
for ( var i = 0, l = groups.length; i < l; i ++ ) {
var group = groups[ i ];
var groupMaterial = materials[ group.materialIndex ];
if ( groupMaterial.visible === true ) {
pushRenderItem( object, geometry, groupMaterial, _vector3.z, group );
}
}
} else {
pushRenderItem( object, geometry, material, _vector3.z, null );
}
}
}
}
}
var children = object.children;
for ( var i = 0, l = children.length; i < l; i ++ ) {
projectObject( children[ i ], camera );
}
}
function renderObjects( renderList, camera, fog, overrideMaterial ) {
for ( var i = 0, l = renderList.length; i < l; i ++ ) {
var renderItem = renderList[ i ];
var object = renderItem.object;
var geometry = renderItem.geometry;
var material = overrideMaterial === undefined ? renderItem.material : overrideMaterial;
var group = renderItem.group;
object.modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, object.matrixWorld );
object.normalMatrix.getNormalMatrix( object.modelViewMatrix );
if ( object.isImmediateRenderObject ) {
setMaterial( material );
var program = setProgram( camera, fog, material, object );
_currentGeometryProgram = '';
object.render( function ( object ) {
_this.renderBufferImmediate( object, program, material );
} );
} else {
if ( object.onBeforeRender !== null ) object.onBeforeRender();
_this.renderBufferDirect( camera, fog, geometry, material, object, group );
}
}
}
function initMaterial( material, fog, object ) {
var materialProperties = properties.get( material );
var parameters = programCache.getParameters(
material, _lights, fog, _clipping.numPlanes, object );
var code = programCache.getProgramCode( material, parameters );
var program = materialProperties.program;
var programChange = true;
if ( program === undefined ) {
// new material
material.addEventListener( 'dispose', onMaterialDispose );
} else if ( program.code !== code ) {
// changed glsl or parameters
releaseMaterialProgramReference( material );
} else if ( parameters.shaderID !== undefined ) {
// same glsl and uniform list
return;
} else {
// only rebuild uniform list
programChange = false;
}
if ( programChange ) {
if ( parameters.shaderID ) {
var shader = ShaderLib[ parameters.shaderID ];
materialProperties.__webglShader = {
name: material.type,
uniforms: UniformsUtils.clone( shader.uniforms ),
vertexShader: shader.vertexShader,
fragmentShader: shader.fragmentShader
};
} else {
materialProperties.__webglShader = {
name: material.type,
uniforms: material.uniforms,
vertexShader: material.vertexShader,
fragmentShader: material.fragmentShader
};
}
material.__webglShader = materialProperties.__webglShader;
program = programCache.acquireProgram( material, parameters, code );
materialProperties.program = program;
material.program = program;
}
var attributes = program.getAttributes();
if ( material.morphTargets ) {
material.numSupportedMorphTargets = 0;
for ( var i = 0; i < _this.maxMorphTargets; i ++ ) {
if ( attributes[ 'morphTarget' + i ] >= 0 ) {
material.numSupportedMorphTargets ++;
}
}
}
if ( material.morphNormals ) {
material.numSupportedMorphNormals = 0;
for ( var i = 0; i < _this.maxMorphNormals; i ++ ) {
if ( attributes[ 'morphNormal' + i ] >= 0 ) {
material.numSupportedMorphNormals ++;
}
}
}
var uniforms = materialProperties.__webglShader.uniforms;
if ( ! material.isShaderMaterial &&
! material.isRawShaderMaterial ||
material.clipping === true ) {
materialProperties.numClippingPlanes = _clipping.numPlanes;
uniforms.clippingPlanes = _clipping.uniform;
}
materialProperties.fog = fog;
// store the light setup it was created for
materialProperties.lightsHash = _lights.hash;
if ( material.lights ) {
// wire up the material to this renderer's lighting state
uniforms.ambientLightColor.value = _lights.ambient;
uniforms.directionalLights.value = _lights.directional;
uniforms.spotLights.value = _lights.spot;
uniforms.pointLights.value = _lights.point;
uniforms.hemisphereLights.value = _lights.hemi;
uniforms.directionalShadowMap.value = _lights.directionalShadowMap;
uniforms.directionalShadowMatrix.value = _lights.directionalShadowMatrix;
uniforms.spotShadowMap.value = _lights.spotShadowMap;
uniforms.spotShadowMatrix.value = _lights.spotShadowMatrix;
uniforms.pointShadowMap.value = _lights.pointShadowMap;
uniforms.pointShadowMatrix.value = _lights.pointShadowMatrix;
}
var progUniforms = materialProperties.program.getUniforms(),
uniformsList =
WebGLUniforms.seqWithValue( progUniforms.seq, uniforms );
materialProperties.uniformsList = uniformsList;
materialProperties.dynamicUniforms =
WebGLUniforms.splitDynamic( uniformsList, uniforms );
}
function setMaterial( material ) {
material.side === DoubleSide
? state.disable( _gl.CULL_FACE )
: state.enable( _gl.CULL_FACE );
state.setFlipSided( material.side === BackSide );
material.transparent === true
? state.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst, material.blendEquationAlpha, material.blendSrcAlpha, material.blendDstAlpha, material.premultipliedAlpha )
: state.setBlending( NoBlending );
state.setDepthFunc( material.depthFunc );
state.setDepthTest( material.depthTest );
state.setDepthWrite( material.depthWrite );
state.setColorWrite( material.colorWrite );
state.setPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits );
}
function setProgram( camera, fog, material, object ) {
_usedTextureUnits = 0;
var materialProperties = properties.get( material );
if ( _clippingEnabled ) {
if ( _localClippingEnabled || camera !== _currentCamera ) {
var useCache =
camera === _currentCamera &&
material.id === _currentMaterialId;
// we might want to call this function with some ClippingGroup
// object instead of the material, once it becomes feasible
// (#8465, #8379)
_clipping.setState(
material.clippingPlanes, material.clipShadows,
camera, materialProperties, useCache );
}
}
if ( material.needsUpdate === false ) {
if ( materialProperties.program === undefined ) {
material.needsUpdate = true;
} else if ( material.fog && materialProperties.fog !== fog ) {
material.needsUpdate = true;
} else if ( material.lights && materialProperties.lightsHash !== _lights.hash ) {
material.needsUpdate = true;
} else if ( materialProperties.numClippingPlanes !== undefined &&
materialProperties.numClippingPlanes !== _clipping.numPlanes ) {
material.needsUpdate = true;
}
}
if ( material.needsUpdate ) {
initMaterial( material, fog, object );
material.needsUpdate = false;
}
var refreshProgram = false;
var refreshMaterial = false;
var refreshLights = false;
var program = materialProperties.program,
p_uniforms = program.getUniforms(),
m_uniforms = materialProperties.__webglShader.uniforms;
if ( program.id !== _currentProgram ) {
_gl.useProgram( program.program );
_currentProgram = program.id;
refreshProgram = true;
refreshMaterial = true;
refreshLights = true;
}
if ( material.id !== _currentMaterialId ) {
_currentMaterialId = material.id;
refreshMaterial = true;
}
if ( refreshProgram || camera !== _currentCamera ) {
p_uniforms.set( _gl, camera, 'projectionMatrix' );
if ( capabilities.logarithmicDepthBuffer ) {
p_uniforms.setValue( _gl, 'logDepthBufFC',
2.0 / ( Math.log( camera.far + 1.0 ) / Math.LN2 ) );
}
if ( camera !== _currentCamera ) {
_currentCamera = camera;
// lighting uniforms depend on the camera so enforce an update
// now, in case this material supports lights - or later, when
// the next material that does gets activated:
refreshMaterial = true; // set to true on material change
refreshLights = true; // remains set until update done
}
// load material specific uniforms
// (shader material also gets them for the sake of genericity)
if ( material.isShaderMaterial ||
material.isMeshPhongMaterial ||
material.isMeshStandardMaterial ||
material.envMap ) {
var uCamPos = p_uniforms.map.cameraPosition;
if ( uCamPos !== undefined ) {
uCamPos.setValue( _gl,
_vector3.setFromMatrixPosition( camera.matrixWorld ) );
}
}
if ( material.isMeshPhongMaterial ||
material.isMeshLambertMaterial ||
material.isMeshBasicMaterial ||
material.isMeshStandardMaterial ||
material.isShaderMaterial ||
material.skinning ) {
p_uniforms.setValue( _gl, 'viewMatrix', camera.matrixWorldInverse );
}
p_uniforms.set( _gl, _this, 'toneMappingExposure' );
p_uniforms.set( _gl, _this, 'toneMappingWhitePoint' );
}
// 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 ) {
p_uniforms.setOptional( _gl, object, 'bindMatrix' );
p_uniforms.setOptional( _gl, object, 'bindMatrixInverse' );
var skeleton = object.skeleton;
if ( skeleton ) {
if ( capabilities.floatVertexTextures && skeleton.useVertexTexture ) {
p_uniforms.set( _gl, skeleton, 'boneTexture' );
p_uniforms.set( _gl, skeleton, 'boneTextureWidth' );
p_uniforms.set( _gl, skeleton, 'boneTextureHeight' );
} else {
p_uniforms.setOptional( _gl, skeleton, 'boneMatrices' );
}
}
}
if ( refreshMaterial ) {
if ( material.lights ) {
// the current material requires lighting info
// note: all lighting uniforms are always set correctly
// they simply reference the renderer's state for their
// values
//
// use the current material's .needsUpdate flags to set
// the GL state when required
markUniformsLightsNeedsUpdate( m_uniforms, refreshLights );
}
// refresh uniforms common to several materials
if ( fog && material.fog ) {
refreshUniformsFog( m_uniforms, fog );
}
if ( material.isMeshBasicMaterial ||
material.isMeshLambertMaterial ||
material.isMeshPhongMaterial ||
material.isMeshStandardMaterial ||
material.isMeshDepthMaterial ) {
refreshUniformsCommon( m_uniforms, material );
}
// refresh single material specific uniforms
if ( material.isLineBasicMaterial ) {
refreshUniformsLine( m_uniforms, material );
} else if ( material.isLineDashedMaterial ) {
refreshUniformsLine( m_uniforms, material );
refreshUniformsDash( m_uniforms, material );
} else if ( material.isPointsMaterial ) {
refreshUniformsPoints( m_uniforms, material );
} else if ( material.isMeshLambertMaterial ) {
refreshUniformsLambert( m_uniforms, material );
} else if ( material.isMeshPhongMaterial ) {
refreshUniformsPhong( m_uniforms, material );
} else if ( material.isMeshPhysicalMaterial ) {
refreshUniformsPhysical( m_uniforms, material );
} else if ( material.isMeshStandardMaterial ) {
refreshUniformsStandard( m_uniforms, material );
} else if ( material.isMeshDepthMaterial ) {
if ( material.displacementMap ) {
m_uniforms.displacementMap.value = material.displacementMap;
m_uniforms.displacementScale.value = material.displacementScale;
m_uniforms.displacementBias.value = material.displacementBias;
}
} else if ( material.isMeshNormalMaterial ) {
m_uniforms.opacity.value = material.opacity;
}
WebGLUniforms.upload(
_gl, materialProperties.uniformsList, m_uniforms, _this );
}
// common matrices
p_uniforms.set( _gl, object, 'modelViewMatrix' );
p_uniforms.set( _gl, object, 'normalMatrix' );
p_uniforms.setValue( _gl, 'modelMatrix', object.matrixWorld );
// dynamic uniforms
var dynUniforms = materialProperties.dynamicUniforms;
if ( dynUniforms !== null ) {
WebGLUniforms.evalDynamic( dynUniforms, m_uniforms, object, material, camera );
WebGLUniforms.upload( _gl, dynUniforms, m_uniforms, _this );
}
return program;
}
// Uniforms (refresh uniforms objects)
function refreshUniformsCommon( uniforms, material ) {
uniforms.opacity.value = material.opacity;
uniforms.diffuse.value = material.color;
if ( material.emissive ) {
uniforms.emissive.value.copy( material.emissive ).multiplyScalar( material.emissiveIntensity );
}
uniforms.map.value = material.map;
uniforms.specularMap.value = material.specularMap;
uniforms.alphaMap.value = material.alphaMap;
if ( material.aoMap ) {
uniforms.aoMap.value = material.aoMap;
uniforms.aoMapIntensity.value = material.aoMapIntensity;
}
// uv repeat and offset setting priorities
// 1. color map
// 2. specular map
// 3. normal map
// 4. bump map
// 5. alpha map
// 6. emissive map
var uvScaleMap;
if ( material.map ) {
uvScaleMap = material.map;
} else if ( material.specularMap ) {
uvScaleMap = material.specularMap;
} else if ( material.displacementMap ) {
uvScaleMap = material.displacementMap;
} else if ( material.normalMap ) {
uvScaleMap = material.normalMap;
} else if ( material.bumpMap ) {
uvScaleMap = material.bumpMap;
} else if ( material.roughnessMap ) {
uvScaleMap = material.roughnessMap;
} else if ( material.metalnessMap ) {
uvScaleMap = material.metalnessMap;
} else if ( material.alphaMap ) {
uvScaleMap = material.alphaMap;
} else if ( material.emissiveMap ) {
uvScaleMap = material.emissiveMap;
}
if ( uvScaleMap !== undefined ) {
// backwards compatibility
if ( uvScaleMap.isWebGLRenderTarget ) {
uvScaleMap = uvScaleMap.texture;
}
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;
// don't flip CubeTexture envMaps, flip everything else:
// WebGLRenderTargetCube will be flipped for backwards compatibility
// WebGLRenderTargetCube.texture will be flipped because it's a Texture and NOT a CubeTexture
// this check must be handled differently, or removed entirely, if WebGLRenderTargetCube uses a CubeTexture in the future
uniforms.flipEnvMap.value = ( ! ( material.envMap && material.envMap.isCubeTexture ) ) ? 1 : - 1;
uniforms.reflectivity.value = material.reflectivity;
uniforms.refractionRatio.value = material.refractionRatio;
}
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 refreshUniformsPoints( uniforms, material ) {
uniforms.diffuse.value = material.color;
uniforms.opacity.value = material.opacity;
uniforms.size.value = material.size * _pixelRatio;
uniforms.scale.value = _canvas.clientHeight * 0.5;
uniforms.map.value = material.map;
if ( material.map !== null ) {
var offset = material.map.offset;
var repeat = material.map.repeat;
uniforms.offsetRepeat.value.set( offset.x, offset.y, repeat.x, repeat.y );
}
}
function refreshUniformsFog( uniforms, fog ) {
uniforms.fogColor.value = fog.color;
if ( fog.isFog ) {
uniforms.fogNear.value = fog.near;
uniforms.fogFar.value = fog.far;
} else if ( fog.isFogExp2 ) {
uniforms.fogDensity.value = fog.density;
}
}
function refreshUniformsLambert( uniforms, material ) {
if ( material.lightMap ) {
uniforms.lightMap.value = material.lightMap;
uniforms.lightMapIntensity.value = material.lightMapIntensity;
}
if ( material.emissiveMap ) {
uniforms.emissiveMap.value = material.emissiveMap;
}
}
function refreshUniformsPhong( uniforms, material ) {
uniforms.specular.value = material.specular;
uniforms.shininess.value = Math.max( material.shininess, 1e-4 ); // to prevent pow( 0.0, 0.0 )
if ( material.lightMap ) {
uniforms.lightMap.value = material.lightMap;
uniforms.lightMapIntensity.value = material.lightMapIntensity;
}
if ( material.emissiveMap ) {
uniforms.emissiveMap.value = material.emissiveMap;
}
if ( material.bumpMap ) {
uniforms.bumpMap.value = material.bumpMap;
uniforms.bumpScale.value = material.bumpSca