initial commit

This commit is contained in:
Mahdi Dibaiee
2018-12-25 17:29:22 +03:30
commit e983346ffc
388 changed files with 174266 additions and 0 deletions

View File

@ -0,0 +1,56 @@
/**
* @author mrdoob / http://mrdoob.com/
*/
function WebGLAnimation() {
var context = null;
var isAnimating = false;
var animationLoop = null;
function onAnimationFrame( time, frame ) {
if ( isAnimating === false ) return;
animationLoop( time, frame );
context.requestAnimationFrame( onAnimationFrame );
}
return {
start: function () {
if ( isAnimating === true ) return;
if ( animationLoop === null ) return;
context.requestAnimationFrame( onAnimationFrame );
isAnimating = true;
},
stop: function () {
isAnimating = false;
},
setAnimationLoop: function ( callback ) {
animationLoop = callback;
},
setContext: function ( value ) {
context = value;
}
};
}
export { WebGLAnimation };

View File

@ -0,0 +1,155 @@
/**
* @author mrdoob / http://mrdoob.com/
*/
function WebGLAttributes( gl ) {
var buffers = new WeakMap();
function createBuffer( attribute, bufferType ) {
var array = attribute.array;
var usage = attribute.dynamic ? gl.DYNAMIC_DRAW : gl.STATIC_DRAW;
var buffer = gl.createBuffer();
gl.bindBuffer( bufferType, buffer );
gl.bufferData( bufferType, array, usage );
attribute.onUploadCallback();
var type = gl.FLOAT;
if ( array instanceof Float32Array ) {
type = gl.FLOAT;
} else if ( array instanceof Float64Array ) {
console.warn( 'THREE.WebGLAttributes: 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;
}
return {
buffer: buffer,
type: type,
bytesPerElement: array.BYTES_PER_ELEMENT,
version: attribute.version
};
}
function updateBuffer( buffer, attribute, bufferType ) {
var array = attribute.array;
var updateRange = attribute.updateRange;
gl.bindBuffer( bufferType, buffer );
if ( attribute.dynamic === false ) {
gl.bufferData( bufferType, array, gl.STATIC_DRAW );
} else if ( updateRange.count === - 1 ) {
// Not using update ranges
gl.bufferSubData( bufferType, 0, array );
} else if ( updateRange.count === 0 ) {
console.error( 'THREE.WebGLObjects.updateBuffer: dynamic THREE.BufferAttribute marked as needsUpdate but updateRange.count is 0, ensure you are using set methods or updating manually.' );
} else {
gl.bufferSubData( bufferType, updateRange.offset * array.BYTES_PER_ELEMENT,
array.subarray( updateRange.offset, updateRange.offset + updateRange.count ) );
updateRange.count = - 1; // reset range
}
}
//
function get( attribute ) {
if ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data;
return buffers.get( attribute );
}
function remove( attribute ) {
if ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data;
var data = buffers.get( attribute );
if ( data ) {
gl.deleteBuffer( data.buffer );
buffers.delete( attribute );
}
}
function update( attribute, bufferType ) {
if ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data;
var data = buffers.get( attribute );
if ( data === undefined ) {
buffers.set( attribute, createBuffer( attribute, bufferType ) );
} else if ( data.version < attribute.version ) {
updateBuffer( data.buffer, attribute, bufferType );
data.version = attribute.version;
}
}
return {
get: get,
remove: remove,
update: update
};
}
export { WebGLAttributes };

View File

@ -0,0 +1,149 @@
/**
* @author mrdoob / http://mrdoob.com/
*/
import { BackSide, FrontSide } from '../../constants.js';
import { BoxBufferGeometry } from '../../geometries/BoxGeometry.js';
import { PlaneBufferGeometry } from '../../geometries/PlaneGeometry.js';
import { ShaderMaterial } from '../../materials/ShaderMaterial.js';
import { Color } from '../../math/Color.js';
import { Mesh } from '../../objects/Mesh.js';
import { ShaderLib } from '../shaders/ShaderLib.js';
import { UniformsUtils } from '../shaders/UniformsUtils.js';
function WebGLBackground( renderer, state, objects, premultipliedAlpha ) {
var clearColor = new Color( 0x000000 );
var clearAlpha = 0;
var planeMesh;
var boxMesh;
function render( renderList, scene, camera, forceClear ) {
var background = scene.background;
if ( background === null ) {
setClear( clearColor, clearAlpha );
} else if ( background && background.isColor ) {
setClear( background, 1 );
forceClear = true;
}
if ( renderer.autoClear || forceClear ) {
renderer.clear( renderer.autoClearColor, renderer.autoClearDepth, renderer.autoClearStencil );
}
if ( background && ( background.isCubeTexture || background.isWebGLRenderTargetCube ) ) {
if ( boxMesh === undefined ) {
boxMesh = new Mesh(
new BoxBufferGeometry( 1, 1, 1 ),
new ShaderMaterial( {
uniforms: UniformsUtils.clone( ShaderLib.cube.uniforms ),
vertexShader: ShaderLib.cube.vertexShader,
fragmentShader: ShaderLib.cube.fragmentShader,
side: BackSide,
depthTest: true,
depthWrite: false,
fog: false
} )
);
boxMesh.geometry.removeAttribute( 'normal' );
boxMesh.geometry.removeAttribute( 'uv' );
boxMesh.onBeforeRender = function ( renderer, scene, camera ) {
this.matrixWorld.copyPosition( camera.matrixWorld );
};
objects.update( boxMesh );
}
boxMesh.material.uniforms.tCube.value = ( background.isWebGLRenderTargetCube ) ? background.texture : background;
boxMesh.material.uniforms.tFlip.value = ( background.isWebGLRenderTargetCube ) ? 1 : - 1;
// push to the pre-sorted opaque render list
renderList.push( boxMesh, boxMesh.geometry, boxMesh.material, 0, null );
} else if ( background && background.isTexture ) {
if ( planeMesh === undefined ) {
planeMesh = new Mesh(
new PlaneBufferGeometry( 2, 2 ),
new ShaderMaterial( {
uniforms: UniformsUtils.clone( ShaderLib.background.uniforms ),
vertexShader: ShaderLib.background.vertexShader,
fragmentShader: ShaderLib.background.fragmentShader,
side: FrontSide,
depthTest: true,
depthWrite: false,
fog: false
} )
);
planeMesh.geometry.removeAttribute( 'normal' );
objects.update( planeMesh );
}
planeMesh.material.uniforms.t2D.value = background;
// push to the pre-sorted opaque render list
renderList.push( planeMesh, planeMesh.geometry, planeMesh.material, 0, null );
}
}
function setClear( color, alpha ) {
state.buffers.color.setClear( color.r, color.g, color.b, alpha, premultipliedAlpha );
}
return {
getClearColor: function () {
return clearColor;
},
setClearColor: function ( color, alpha ) {
clearColor.set( color );
clearAlpha = alpha !== undefined ? alpha : 1;
setClear( clearColor, clearAlpha );
},
getClearAlpha: function () {
return clearAlpha;
},
setClearAlpha: function ( alpha ) {
clearAlpha = alpha;
setClear( clearColor, clearAlpha );
},
render: render
};
}
export { WebGLBackground };

View File

@ -0,0 +1,59 @@
/**
* @author mrdoob / http://mrdoob.com/
*/
function WebGLBufferRenderer( gl, extensions, info, capabilities ) {
var mode;
function setMode( value ) {
mode = value;
}
function render( start, count ) {
gl.drawArrays( mode, start, count );
info.update( count, mode );
}
function renderInstances( geometry, start, count ) {
var extension;
if ( capabilities.isWebGL2 ) {
extension = gl;
} else {
extension = extensions.get( 'ANGLE_instanced_arrays' );
if ( extension === null ) {
console.error( 'THREE.WebGLBufferRenderer: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays.' );
return;
}
}
extension[ capabilities.isWebGL2 ? 'drawArraysInstanced' : 'drawArraysInstancedANGLE' ]( mode, start, count, geometry.maxInstancedCount );
info.update( count, mode, geometry.maxInstancedCount );
}
//
this.setMode = setMode;
this.render = render;
this.renderInstances = renderInstances;
}
export { WebGLBufferRenderer };

View File

@ -0,0 +1,116 @@
/**
* @author mrdoob / http://mrdoob.com/
*/
function WebGLCapabilities( gl, extensions, parameters ) {
var maxAnisotropy;
function getMaxAnisotropy() {
if ( maxAnisotropy !== undefined ) return maxAnisotropy;
var extension = extensions.get( 'EXT_texture_filter_anisotropic' );
if ( extension !== null ) {
maxAnisotropy = gl.getParameter( extension.MAX_TEXTURE_MAX_ANISOTROPY_EXT );
} else {
maxAnisotropy = 0;
}
return maxAnisotropy;
}
function getMaxPrecision( precision ) {
if ( precision === 'highp' ) {
if ( gl.getShaderPrecisionFormat( gl.VERTEX_SHADER, gl.HIGH_FLOAT ).precision > 0 &&
gl.getShaderPrecisionFormat( gl.FRAGMENT_SHADER, gl.HIGH_FLOAT ).precision > 0 ) {
return 'highp';
}
precision = 'mediump';
}
if ( precision === 'mediump' ) {
if ( gl.getShaderPrecisionFormat( gl.VERTEX_SHADER, gl.MEDIUM_FLOAT ).precision > 0 &&
gl.getShaderPrecisionFormat( gl.FRAGMENT_SHADER, gl.MEDIUM_FLOAT ).precision > 0 ) {
return 'mediump';
}
}
return 'lowp';
}
var isWebGL2 = typeof WebGL2RenderingContext !== 'undefined' && gl instanceof WebGL2RenderingContext;
var precision = parameters.precision !== undefined ? parameters.precision : 'highp';
var maxPrecision = getMaxPrecision( precision );
if ( maxPrecision !== precision ) {
console.warn( 'THREE.WebGLRenderer:', precision, 'not supported, using', maxPrecision, 'instead.' );
precision = maxPrecision;
}
var logarithmicDepthBuffer = parameters.logarithmicDepthBuffer === true;
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 maxAttributes = gl.getParameter( gl.MAX_VERTEX_ATTRIBS );
var maxVertexUniforms = gl.getParameter( gl.MAX_VERTEX_UNIFORM_VECTORS );
var maxVaryings = gl.getParameter( gl.MAX_VARYING_VECTORS );
var maxFragmentUniforms = gl.getParameter( gl.MAX_FRAGMENT_UNIFORM_VECTORS );
var vertexTextures = maxVertexTextures > 0;
var floatFragmentTextures = isWebGL2 || !! extensions.get( 'OES_texture_float' );
var floatVertexTextures = vertexTextures && floatFragmentTextures;
return {
isWebGL2: isWebGL2,
getMaxAnisotropy: getMaxAnisotropy,
getMaxPrecision: getMaxPrecision,
precision: precision,
logarithmicDepthBuffer: logarithmicDepthBuffer,
maxTextures: maxTextures,
maxVertexTextures: maxVertexTextures,
maxTextureSize: maxTextureSize,
maxCubemapSize: maxCubemapSize,
maxAttributes: maxAttributes,
maxVertexUniforms: maxVertexUniforms,
maxVaryings: maxVaryings,
maxFragmentUniforms: maxFragmentUniforms,
vertexTextures: vertexTextures,
floatFragmentTextures: floatFragmentTextures,
floatVertexTextures: floatVertexTextures
};
}
export { WebGLCapabilities };

View File

@ -0,0 +1,164 @@
/**
* @author tschw
*/
import { Matrix3 } from '../../math/Matrix3.js';
import { Plane } from '../../math/Plane.js';
function WebGLClipping() {
var scope = this,
globalState = null,
numGlobalPlanes = 0,
localClippingEnabled = false,
renderingShadows = false,
plane = new Plane(),
viewNormalMatrix = new Matrix3(),
uniform = { value: null, needsUpdate: false };
this.uniform = uniform;
this.numPlanes = 0;
this.numIntersection = 0;
this.init = function ( planes, enableLocalClipping, camera ) {
var enabled =
planes.length !== 0 ||
enableLocalClipping ||
// enable state of previous frame - the clipping code has to
// run another frame in order to reset the state:
numGlobalPlanes !== 0 ||
localClippingEnabled;
localClippingEnabled = enableLocalClipping;
globalState = projectPlanes( planes, camera, 0 );
numGlobalPlanes = planes.length;
return enabled;
};
this.beginShadows = function () {
renderingShadows = true;
projectPlanes( null );
};
this.endShadows = function () {
renderingShadows = false;
resetGlobalState();
};
this.setState = function ( planes, clipIntersection, clipShadows, camera, cache, fromCache ) {
if ( ! localClippingEnabled || planes === null || planes.length === 0 || renderingShadows && ! clipShadows ) {
// there's no local clipping
if ( renderingShadows ) {
// there's no global clipping
projectPlanes( null );
} else {
resetGlobalState();
}
} else {
var nGlobal = renderingShadows ? 0 : numGlobalPlanes,
lGlobal = nGlobal * 4,
dstArray = cache.clippingState || null;
uniform.value = dstArray; // ensure unique state
dstArray = projectPlanes( planes, camera, lGlobal, fromCache );
for ( var i = 0; i !== lGlobal; ++ i ) {
dstArray[ i ] = globalState[ i ];
}
cache.clippingState = dstArray;
this.numIntersection = clipIntersection ? this.numPlanes : 0;
this.numPlanes += nGlobal;
}
};
function resetGlobalState() {
if ( uniform.value !== globalState ) {
uniform.value = globalState;
uniform.needsUpdate = numGlobalPlanes > 0;
}
scope.numPlanes = numGlobalPlanes;
scope.numIntersection = 0;
}
function projectPlanes( planes, camera, dstOffset, skipTransform ) {
var nPlanes = planes !== null ? planes.length : 0,
dstArray = null;
if ( nPlanes !== 0 ) {
dstArray = uniform.value;
if ( skipTransform !== true || dstArray === null ) {
var flatSize = dstOffset + nPlanes * 4,
viewMatrix = camera.matrixWorldInverse;
viewNormalMatrix.getNormalMatrix( viewMatrix );
if ( dstArray === null || dstArray.length < flatSize ) {
dstArray = new Float32Array( flatSize );
}
for ( var i = 0, i4 = dstOffset; i !== nPlanes; ++ i, i4 += 4 ) {
plane.copy( planes[ i ] ).applyMatrix4( viewMatrix, viewNormalMatrix );
plane.normal.toArray( dstArray, i4 );
dstArray[ i4 + 3 ] = plane.constant;
}
}
uniform.value = dstArray;
uniform.needsUpdate = true;
}
scope.numPlanes = nPlanes;
return dstArray;
}
}
export { WebGLClipping };

View File

@ -0,0 +1,61 @@
/**
* @author mrdoob / http://mrdoob.com/
*/
function WebGLExtensions( gl ) {
var extensions = {};
return {
get: function ( name ) {
if ( extensions[ name ] !== undefined ) {
return extensions[ name ];
}
var extension;
switch ( name ) {
case 'WEBGL_depth_texture':
extension = gl.getExtension( 'WEBGL_depth_texture' ) || gl.getExtension( 'MOZ_WEBGL_depth_texture' ) || gl.getExtension( 'WEBKIT_WEBGL_depth_texture' );
break;
case 'EXT_texture_filter_anisotropic':
extension = gl.getExtension( 'EXT_texture_filter_anisotropic' ) || gl.getExtension( 'MOZ_EXT_texture_filter_anisotropic' ) || gl.getExtension( 'WEBKIT_EXT_texture_filter_anisotropic' );
break;
case 'WEBGL_compressed_texture_s3tc':
extension = gl.getExtension( 'WEBGL_compressed_texture_s3tc' ) || gl.getExtension( 'MOZ_WEBGL_compressed_texture_s3tc' ) || gl.getExtension( 'WEBKIT_WEBGL_compressed_texture_s3tc' );
break;
case 'WEBGL_compressed_texture_pvrtc':
extension = gl.getExtension( 'WEBGL_compressed_texture_pvrtc' ) || gl.getExtension( 'WEBKIT_WEBGL_compressed_texture_pvrtc' );
break;
default:
extension = gl.getExtension( name );
}
if ( extension === null ) {
console.warn( 'THREE.WebGLRenderer: ' + name + ' extension not supported.' );
}
extensions[ name ] = extension;
return extension;
}
};
}
export { WebGLExtensions };

View File

@ -0,0 +1,184 @@
/**
* @author mrdoob / http://mrdoob.com/
*/
import { Uint16BufferAttribute, Uint32BufferAttribute } from '../../core/BufferAttribute.js';
import { BufferGeometry } from '../../core/BufferGeometry.js';
import { arrayMax } from '../../utils.js';
function WebGLGeometries( gl, attributes, info ) {
var geometries = {};
var wireframeAttributes = {};
function onGeometryDispose( event ) {
var geometry = event.target;
var buffergeometry = geometries[ geometry.id ];
if ( buffergeometry.index !== null ) {
attributes.remove( buffergeometry.index );
}
for ( var name in buffergeometry.attributes ) {
attributes.remove( buffergeometry.attributes[ name ] );
}
geometry.removeEventListener( 'dispose', onGeometryDispose );
delete geometries[ geometry.id ];
var attribute = wireframeAttributes[ buffergeometry.id ];
if ( attribute ) {
attributes.remove( attribute );
delete wireframeAttributes[ buffergeometry.id ];
}
//
info.memory.geometries --;
}
function get( object, geometry ) {
var buffergeometry = geometries[ geometry.id ];
if ( buffergeometry ) return buffergeometry;
geometry.addEventListener( 'dispose', onGeometryDispose );
if ( geometry.isBufferGeometry ) {
buffergeometry = geometry;
} else if ( geometry.isGeometry ) {
if ( geometry._bufferGeometry === undefined ) {
geometry._bufferGeometry = new BufferGeometry().setFromObject( object );
}
buffergeometry = geometry._bufferGeometry;
}
geometries[ geometry.id ] = buffergeometry;
info.memory.geometries ++;
return buffergeometry;
}
function update( geometry ) {
var index = geometry.index;
var geometryAttributes = geometry.attributes;
if ( index !== null ) {
attributes.update( index, gl.ELEMENT_ARRAY_BUFFER );
}
for ( var name in geometryAttributes ) {
attributes.update( geometryAttributes[ name ], gl.ARRAY_BUFFER );
}
// morph targets
var morphAttributes = geometry.morphAttributes;
for ( var name in morphAttributes ) {
var array = morphAttributes[ name ];
for ( var i = 0, l = array.length; i < l; i ++ ) {
attributes.update( array[ i ], gl.ARRAY_BUFFER );
}
}
}
function getWireframeAttribute( geometry ) {
var attribute = wireframeAttributes[ geometry.id ];
if ( attribute ) return attribute;
var indices = [];
var geometryIndex = geometry.index;
var geometryAttributes = geometry.attributes;
// console.time( 'wireframe' );
if ( geometryIndex !== null ) {
var array = geometryIndex.array;
for ( var i = 0, l = array.length; i < l; i += 3 ) {
var a = array[ i + 0 ];
var b = array[ i + 1 ];
var c = array[ i + 2 ];
indices.push( a, b, b, c, c, a );
}
} else {
var array = geometryAttributes.position.array;
for ( var i = 0, l = ( array.length / 3 ) - 1; i < l; i += 3 ) {
var a = i + 0;
var b = i + 1;
var c = i + 2;
indices.push( a, b, b, c, c, a );
}
}
// console.timeEnd( 'wireframe' );
attribute = new ( arrayMax( indices ) > 65535 ? Uint32BufferAttribute : Uint16BufferAttribute )( indices, 1 );
attributes.update( attribute, gl.ELEMENT_ARRAY_BUFFER );
wireframeAttributes[ geometry.id ] = attribute;
return attribute;
}
return {
get: get,
update: update,
getWireframeAttribute: getWireframeAttribute
};
}
export { WebGLGeometries };

View File

@ -0,0 +1,69 @@
/**
* @author mrdoob / http://mrdoob.com/
*/
function WebGLIndexedBufferRenderer( gl, extensions, info, capabilities ) {
var mode;
function setMode( value ) {
mode = value;
}
var type, bytesPerElement;
function setIndex( value ) {
type = value.type;
bytesPerElement = value.bytesPerElement;
}
function render( start, count ) {
gl.drawElements( mode, count, type, start * bytesPerElement );
info.update( count, mode );
}
function renderInstances( geometry, start, count ) {
var extension;
if ( capabilities.isWebGL2 ) {
extension = gl;
} else {
var extension = extensions.get( 'ANGLE_instanced_arrays' );
if ( extension === null ) {
console.error( 'THREE.WebGLIndexedBufferRenderer: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays.' );
return;
}
}
extension[ capabilities.isWebGL2 ? 'drawElementsInstanced' : 'drawElementsInstancedANGLE' ]( mode, count, type, start * bytesPerElement, geometry.maxInstancedCount );
info.update( count, mode, geometry.maxInstancedCount );
}
//
this.setMode = setMode;
this.setIndex = setIndex;
this.render = render;
this.renderInstances = renderInstances;
}
export { WebGLIndexedBufferRenderer };

View File

@ -0,0 +1,83 @@
/**
* @author Mugen87 / https://github.com/Mugen87
*/
function WebGLInfo( gl ) {
var memory = {
geometries: 0,
textures: 0
};
var render = {
frame: 0,
calls: 0,
triangles: 0,
points: 0,
lines: 0
};
function update( count, mode, instanceCount ) {
instanceCount = instanceCount || 1;
render.calls ++;
switch ( mode ) {
case gl.TRIANGLES:
render.triangles += instanceCount * ( count / 3 );
break;
case gl.TRIANGLE_STRIP:
case gl.TRIANGLE_FAN:
render.triangles += instanceCount * ( count - 2 );
break;
case gl.LINES:
render.lines += instanceCount * ( count / 2 );
break;
case gl.LINE_STRIP:
render.lines += instanceCount * ( count - 1 );
break;
case gl.LINE_LOOP:
render.lines += instanceCount * count;
break;
case gl.POINTS:
render.points += instanceCount * count;
break;
default:
console.error( 'THREE.WebGLInfo: Unknown draw mode:', mode );
break;
}
}
function reset() {
render.frame ++;
render.calls = 0;
render.triangles = 0;
render.points = 0;
render.lines = 0;
}
return {
memory: memory,
render: render,
programs: null,
autoReset: true,
reset: reset,
update: update
};
}
export { WebGLInfo };

View File

@ -0,0 +1,345 @@
/**
* @author mrdoob / http://mrdoob.com/
*/
import { Color } from '../../math/Color.js';
import { Matrix4 } from '../../math/Matrix4.js';
import { Vector2 } from '../../math/Vector2.js';
import { Vector3 } from '../../math/Vector3.js';
function UniformsCache() {
var lights = {};
return {
get: function ( light ) {
if ( lights[ light.id ] !== undefined ) {
return lights[ light.id ];
}
var uniforms;
switch ( light.type ) {
case 'DirectionalLight':
uniforms = {
direction: new Vector3(),
color: new Color(),
shadow: false,
shadowBias: 0,
shadowRadius: 1,
shadowMapSize: new Vector2()
};
break;
case 'SpotLight':
uniforms = {
position: new Vector3(),
direction: new Vector3(),
color: new Color(),
distance: 0,
coneCos: 0,
penumbraCos: 0,
decay: 0,
shadow: false,
shadowBias: 0,
shadowRadius: 1,
shadowMapSize: new Vector2()
};
break;
case 'PointLight':
uniforms = {
position: new Vector3(),
color: new Color(),
distance: 0,
decay: 0,
shadow: false,
shadowBias: 0,
shadowRadius: 1,
shadowMapSize: new Vector2(),
shadowCameraNear: 1,
shadowCameraFar: 1000
};
break;
case 'HemisphereLight':
uniforms = {
direction: new Vector3(),
skyColor: new Color(),
groundColor: new Color()
};
break;
case 'RectAreaLight':
uniforms = {
color: new Color(),
position: new Vector3(),
halfWidth: new Vector3(),
halfHeight: new Vector3()
// TODO (abelnation): set RectAreaLight shadow uniforms
};
break;
}
lights[ light.id ] = uniforms;
return uniforms;
}
};
}
var count = 0;
function WebGLLights() {
var cache = new UniformsCache();
var state = {
id: count ++,
hash: {
stateID: - 1,
directionalLength: - 1,
pointLength: - 1,
spotLength: - 1,
rectAreaLength: - 1,
hemiLength: - 1,
shadowsLength: - 1
},
ambient: [ 0, 0, 0 ],
directional: [],
directionalShadowMap: [],
directionalShadowMatrix: [],
spot: [],
spotShadowMap: [],
spotShadowMatrix: [],
rectArea: [],
point: [],
pointShadowMap: [],
pointShadowMatrix: [],
hemi: []
};
var vector3 = new Vector3();
var matrix4 = new Matrix4();
var matrix42 = new Matrix4();
function setup( lights, shadows, camera ) {
var r = 0, g = 0, b = 0;
var directionalLength = 0;
var pointLength = 0;
var spotLength = 0;
var rectAreaLength = 0;
var hemiLength = 0;
var viewMatrix = camera.matrixWorldInverse;
for ( var i = 0, l = lights.length; i < l; i ++ ) {
var light = lights[ i ];
var color = light.color;
var intensity = light.intensity;
var distance = light.distance;
var shadowMap = ( light.shadow && light.shadow.map ) ? light.shadow.map.texture : null;
if ( light.isAmbientLight ) {
r += color.r * intensity;
g += color.g * intensity;
b += color.b * intensity;
} else if ( light.isDirectionalLight ) {
var uniforms = cache.get( light );
uniforms.color.copy( light.color ).multiplyScalar( light.intensity );
uniforms.direction.setFromMatrixPosition( light.matrixWorld );
vector3.setFromMatrixPosition( light.target.matrixWorld );
uniforms.direction.sub( vector3 );
uniforms.direction.transformDirection( viewMatrix );
uniforms.shadow = light.castShadow;
if ( light.castShadow ) {
var shadow = light.shadow;
uniforms.shadowBias = shadow.bias;
uniforms.shadowRadius = shadow.radius;
uniforms.shadowMapSize = shadow.mapSize;
}
state.directionalShadowMap[ directionalLength ] = shadowMap;
state.directionalShadowMatrix[ directionalLength ] = light.shadow.matrix;
state.directional[ directionalLength ] = uniforms;
directionalLength ++;
} else if ( light.isSpotLight ) {
var uniforms = cache.get( light );
uniforms.position.setFromMatrixPosition( light.matrixWorld );
uniforms.position.applyMatrix4( viewMatrix );
uniforms.color.copy( color ).multiplyScalar( intensity );
uniforms.distance = distance;
uniforms.direction.setFromMatrixPosition( light.matrixWorld );
vector3.setFromMatrixPosition( light.target.matrixWorld );
uniforms.direction.sub( vector3 );
uniforms.direction.transformDirection( viewMatrix );
uniforms.coneCos = Math.cos( light.angle );
uniforms.penumbraCos = Math.cos( light.angle * ( 1 - light.penumbra ) );
uniforms.decay = light.decay;
uniforms.shadow = light.castShadow;
if ( light.castShadow ) {
var shadow = light.shadow;
uniforms.shadowBias = shadow.bias;
uniforms.shadowRadius = shadow.radius;
uniforms.shadowMapSize = shadow.mapSize;
}
state.spotShadowMap[ spotLength ] = shadowMap;
state.spotShadowMatrix[ spotLength ] = light.shadow.matrix;
state.spot[ spotLength ] = uniforms;
spotLength ++;
} else if ( light.isRectAreaLight ) {
var uniforms = cache.get( light );
// (a) intensity is the total visible light emitted
//uniforms.color.copy( color ).multiplyScalar( intensity / ( light.width * light.height * Math.PI ) );
// (b) intensity is the brightness of the light
uniforms.color.copy( color ).multiplyScalar( intensity );
uniforms.position.setFromMatrixPosition( light.matrixWorld );
uniforms.position.applyMatrix4( viewMatrix );
// extract local rotation of light to derive width/height half vectors
matrix42.identity();
matrix4.copy( light.matrixWorld );
matrix4.premultiply( viewMatrix );
matrix42.extractRotation( matrix4 );
uniforms.halfWidth.set( light.width * 0.5, 0.0, 0.0 );
uniforms.halfHeight.set( 0.0, light.height * 0.5, 0.0 );
uniforms.halfWidth.applyMatrix4( matrix42 );
uniforms.halfHeight.applyMatrix4( matrix42 );
// TODO (abelnation): RectAreaLight distance?
// uniforms.distance = distance;
state.rectArea[ rectAreaLength ] = uniforms;
rectAreaLength ++;
} else if ( light.isPointLight ) {
var uniforms = cache.get( light );
uniforms.position.setFromMatrixPosition( light.matrixWorld );
uniforms.position.applyMatrix4( viewMatrix );
uniforms.color.copy( light.color ).multiplyScalar( light.intensity );
uniforms.distance = light.distance;
uniforms.decay = light.decay;
uniforms.shadow = light.castShadow;
if ( light.castShadow ) {
var shadow = light.shadow;
uniforms.shadowBias = shadow.bias;
uniforms.shadowRadius = shadow.radius;
uniforms.shadowMapSize = shadow.mapSize;
uniforms.shadowCameraNear = shadow.camera.near;
uniforms.shadowCameraFar = shadow.camera.far;
}
state.pointShadowMap[ pointLength ] = shadowMap;
state.pointShadowMatrix[ pointLength ] = light.shadow.matrix;
state.point[ pointLength ] = uniforms;
pointLength ++;
} else if ( light.isHemisphereLight ) {
var uniforms = cache.get( light );
uniforms.direction.setFromMatrixPosition( light.matrixWorld );
uniforms.direction.transformDirection( viewMatrix );
uniforms.direction.normalize();
uniforms.skyColor.copy( light.color ).multiplyScalar( intensity );
uniforms.groundColor.copy( light.groundColor ).multiplyScalar( intensity );
state.hemi[ hemiLength ] = uniforms;
hemiLength ++;
}
}
state.ambient[ 0 ] = r;
state.ambient[ 1 ] = g;
state.ambient[ 2 ] = b;
state.directional.length = directionalLength;
state.spot.length = spotLength;
state.rectArea.length = rectAreaLength;
state.point.length = pointLength;
state.hemi.length = hemiLength;
state.hash.stateID = state.id;
state.hash.directionalLength = directionalLength;
state.hash.pointLength = pointLength;
state.hash.spotLength = spotLength;
state.hash.rectAreaLength = rectAreaLength;
state.hash.hemiLength = hemiLength;
state.hash.shadowsLength = shadows.length;
}
return {
setup: setup,
state: state
};
}
export { WebGLLights };

View File

@ -0,0 +1,111 @@
/**
* @author mrdoob / http://mrdoob.com/
*/
function absNumericalSort( a, b ) {
return Math.abs( b[ 1 ] ) - Math.abs( a[ 1 ] );
}
function WebGLMorphtargets( gl ) {
var influencesList = {};
var morphInfluences = new Float32Array( 8 );
function update( object, geometry, material, program ) {
var objectInfluences = object.morphTargetInfluences;
var length = objectInfluences.length;
var influences = influencesList[ geometry.id ];
if ( influences === undefined ) {
// initialise list
influences = [];
for ( var i = 0; i < length; i ++ ) {
influences[ i ] = [ i, 0 ];
}
influencesList[ geometry.id ] = influences;
}
var morphTargets = material.morphTargets && geometry.morphAttributes.position;
var morphNormals = material.morphNormals && geometry.morphAttributes.normal;
// Remove current morphAttributes
for ( var i = 0; i < length; i ++ ) {
var influence = influences[ i ];
if ( influence[ 1 ] !== 0 ) {
if ( morphTargets ) geometry.removeAttribute( 'morphTarget' + i );
if ( morphNormals ) geometry.removeAttribute( 'morphNormal' + i );
}
}
// Collect influences
for ( var i = 0; i < length; i ++ ) {
var influence = influences[ i ];
influence[ 0 ] = i;
influence[ 1 ] = objectInfluences[ i ];
}
influences.sort( absNumericalSort );
// Add morphAttributes
for ( var i = 0; i < 8; i ++ ) {
var influence = influences[ i ];
if ( influence ) {
var index = influence[ 0 ];
var value = influence[ 1 ];
if ( value ) {
if ( morphTargets ) geometry.addAttribute( 'morphTarget' + i, morphTargets[ index ] );
if ( morphNormals ) geometry.addAttribute( 'morphNormal' + i, morphNormals[ index ] );
morphInfluences[ i ] = value;
continue;
}
}
morphInfluences[ i ] = 0;
}
program.getUniforms().setValue( gl, 'morphTargetInfluences', morphInfluences );
}
return {
update: update
};
}
export { WebGLMorphtargets };

View File

@ -0,0 +1,52 @@
/**
* @author mrdoob / http://mrdoob.com/
*/
function WebGLObjects( geometries, info ) {
var updateList = {};
function update( object ) {
var frame = info.render.frame;
var geometry = object.geometry;
var buffergeometry = geometries.get( object, geometry );
// Update once per frame
if ( updateList[ buffergeometry.id ] !== frame ) {
if ( geometry.isGeometry ) {
buffergeometry.updateFromObject( object );
}
geometries.update( buffergeometry );
updateList[ buffergeometry.id ] = frame;
}
return buffergeometry;
}
function dispose() {
updateList = {};
}
return {
update: update,
dispose: dispose
};
}
export { WebGLObjects };

View File

@ -0,0 +1,730 @@
/**
* @author mrdoob / http://mrdoob.com/
*/
import { WebGLUniforms } from './WebGLUniforms.js';
import { WebGLShader } from './WebGLShader.js';
import { ShaderChunk } from '../shaders/ShaderChunk.js';
import { NoToneMapping, AddOperation, MixOperation, MultiplyOperation, EquirectangularRefractionMapping, CubeRefractionMapping, SphericalReflectionMapping, EquirectangularReflectionMapping, CubeUVRefractionMapping, CubeUVReflectionMapping, CubeReflectionMapping, PCFSoftShadowMap, PCFShadowMap, CineonToneMapping, Uncharted2ToneMapping, ReinhardToneMapping, LinearToneMapping, GammaEncoding, RGBDEncoding, RGBM16Encoding, RGBM7Encoding, RGBEEncoding, sRGBEncoding, LinearEncoding } from '../../constants.js';
var programIdCount = 0;
function getEncodingComponents( encoding ) {
switch ( encoding ) {
case LinearEncoding:
return [ 'Linear', '( value )' ];
case sRGBEncoding:
return [ 'sRGB', '( value )' ];
case RGBEEncoding:
return [ 'RGBE', '( value )' ];
case RGBM7Encoding:
return [ 'RGBM', '( value, 7.0 )' ];
case RGBM16Encoding:
return [ 'RGBM', '( value, 16.0 )' ];
case RGBDEncoding:
return [ 'RGBD', '( value, 256.0 )' ];
case GammaEncoding:
return [ 'Gamma', '( value, float( GAMMA_FACTOR ) )' ];
default:
throw new Error( 'unsupported encoding: ' + encoding );
}
}
function getTexelDecodingFunction( functionName, encoding ) {
var components = getEncodingComponents( encoding );
return 'vec4 ' + functionName + '( vec4 value ) { return ' + components[ 0 ] + 'ToLinear' + components[ 1 ] + '; }';
}
function getTexelEncodingFunction( functionName, encoding ) {
var components = getEncodingComponents( encoding );
return 'vec4 ' + functionName + '( vec4 value ) { return LinearTo' + components[ 0 ] + components[ 1 ] + '; }';
}
function getToneMappingFunction( functionName, toneMapping ) {
var toneMappingName;
switch ( toneMapping ) {
case LinearToneMapping:
toneMappingName = 'Linear';
break;
case ReinhardToneMapping:
toneMappingName = 'Reinhard';
break;
case Uncharted2ToneMapping:
toneMappingName = 'Uncharted2';
break;
case CineonToneMapping:
toneMappingName = 'OptimizedCineon';
break;
default:
throw new Error( 'unsupported toneMapping: ' + toneMapping );
}
return 'vec3 ' + functionName + '( vec3 color ) { return ' + toneMappingName + 'ToneMapping( color ); }';
}
function generateExtensions( extensions, parameters, rendererExtensions ) {
extensions = extensions || {};
var chunks = [
( extensions.derivatives || parameters.envMapCubeUV || parameters.bumpMap || ( parameters.normalMap && ! parameters.objectSpaceNormalMap ) || parameters.flatShading ) ? '#extension GL_OES_standard_derivatives : enable' : '',
( extensions.fragDepth || parameters.logarithmicDepthBuffer ) && rendererExtensions.get( 'EXT_frag_depth' ) ? '#extension GL_EXT_frag_depth : enable' : '',
( extensions.drawBuffers ) && rendererExtensions.get( 'WEBGL_draw_buffers' ) ? '#extension GL_EXT_draw_buffers : require' : '',
( extensions.shaderTextureLOD || parameters.envMap ) && rendererExtensions.get( 'EXT_shader_texture_lod' ) ? '#extension GL_EXT_shader_texture_lod : enable' : ''
];
return chunks.filter( filterEmptyLine ).join( '\n' );
}
function generateDefines( defines ) {
var chunks = [];
for ( var name in defines ) {
var value = defines[ name ];
if ( value === false ) continue;
chunks.push( '#define ' + name + ' ' + value );
}
return chunks.join( '\n' );
}
function fetchAttributeLocations( gl, program ) {
var attributes = {};
var n = gl.getProgramParameter( program, gl.ACTIVE_ATTRIBUTES );
for ( var i = 0; i < n; i ++ ) {
var info = gl.getActiveAttrib( program, i );
var name = info.name;
// console.log( 'THREE.WebGLProgram: ACTIVE VERTEX ATTRIBUTE:', name, i );
attributes[ name ] = gl.getAttribLocation( program, name );
}
return attributes;
}
function filterEmptyLine( string ) {
return string !== '';
}
function replaceLightNums( string, parameters ) {
return string
.replace( /NUM_DIR_LIGHTS/g, parameters.numDirLights )
.replace( /NUM_SPOT_LIGHTS/g, parameters.numSpotLights )
.replace( /NUM_RECT_AREA_LIGHTS/g, parameters.numRectAreaLights )
.replace( /NUM_POINT_LIGHTS/g, parameters.numPointLights )
.replace( /NUM_HEMI_LIGHTS/g, parameters.numHemiLights );
}
function replaceClippingPlaneNums( string, parameters ) {
return string
.replace( /NUM_CLIPPING_PLANES/g, parameters.numClippingPlanes )
.replace( /UNION_CLIPPING_PLANES/g, ( parameters.numClippingPlanes - parameters.numClipIntersection ) );
}
function parseIncludes( string ) {
var pattern = /^[ \t]*#include +<([\w\d./]+)>/gm;
function replace( match, include ) {
var replace = ShaderChunk[ include ];
if ( replace === undefined ) {
throw new Error( 'Can not resolve #include <' + include + '>' );
}
return parseIncludes( replace );
}
return string.replace( pattern, replace );
}
function unrollLoops( string ) {
var pattern = /#pragma unroll_loop[\s]+?for \( int i \= (\d+)\; i < (\d+)\; i \+\+ \) \{([\s\S]+?)(?=\})\}/g;
function replace( match, start, end, snippet ) {
var unroll = '';
for ( var i = parseInt( start ); i < parseInt( end ); i ++ ) {
unroll += snippet.replace( /\[ i \]/g, '[ ' + i + ' ]' );
}
return unroll;
}
return string.replace( pattern, replace );
}
function WebGLProgram( renderer, extensions, code, material, shader, parameters, capabilities ) {
var gl = renderer.context;
var defines = material.defines;
var vertexShader = shader.vertexShader;
var fragmentShader = shader.fragmentShader;
var shadowMapTypeDefine = 'SHADOWMAP_TYPE_BASIC';
if ( parameters.shadowMapType === PCFShadowMap ) {
shadowMapTypeDefine = 'SHADOWMAP_TYPE_PCF';
} else if ( parameters.shadowMapType === PCFSoftShadowMap ) {
shadowMapTypeDefine = 'SHADOWMAP_TYPE_PCF_SOFT';
}
var envMapTypeDefine = 'ENVMAP_TYPE_CUBE';
var envMapModeDefine = 'ENVMAP_MODE_REFLECTION';
var envMapBlendingDefine = 'ENVMAP_BLENDING_MULTIPLY';
if ( parameters.envMap ) {
switch ( material.envMap.mapping ) {
case CubeReflectionMapping:
case CubeRefractionMapping:
envMapTypeDefine = 'ENVMAP_TYPE_CUBE';
break;
case CubeUVReflectionMapping:
case CubeUVRefractionMapping:
envMapTypeDefine = 'ENVMAP_TYPE_CUBE_UV';
break;
case EquirectangularReflectionMapping:
case EquirectangularRefractionMapping:
envMapTypeDefine = 'ENVMAP_TYPE_EQUIREC';
break;
case SphericalReflectionMapping:
envMapTypeDefine = 'ENVMAP_TYPE_SPHERE';
break;
}
switch ( material.envMap.mapping ) {
case CubeRefractionMapping:
case EquirectangularRefractionMapping:
envMapModeDefine = 'ENVMAP_MODE_REFRACTION';
break;
}
switch ( material.combine ) {
case MultiplyOperation:
envMapBlendingDefine = 'ENVMAP_BLENDING_MULTIPLY';
break;
case MixOperation:
envMapBlendingDefine = 'ENVMAP_BLENDING_MIX';
break;
case AddOperation:
envMapBlendingDefine = 'ENVMAP_BLENDING_ADD';
break;
}
}
var gammaFactorDefine = ( renderer.gammaFactor > 0 ) ? renderer.gammaFactor : 1.0;
// console.log( 'building new program ' );
//
var customExtensions = capabilities.isWebGL2 ? '' : generateExtensions( material.extensions, parameters, extensions );
var customDefines = generateDefines( defines );
//
var program = gl.createProgram();
var prefixVertex, prefixFragment;
if ( material.isRawShaderMaterial ) {
prefixVertex = [
customDefines
].filter( filterEmptyLine ).join( '\n' );
if ( prefixVertex.length > 0 ) {
prefixVertex += '\n';
}
prefixFragment = [
customExtensions,
customDefines
].filter( filterEmptyLine ).join( '\n' );
if ( prefixFragment.length > 0 ) {
prefixFragment += '\n';
}
} else {
prefixVertex = [
'precision ' + parameters.precision + ' float;',
'precision ' + parameters.precision + ' int;',
'#define SHADER_NAME ' + shader.name,
customDefines,
parameters.supportsVertexTextures ? '#define VERTEX_TEXTURES' : '',
'#define GAMMA_FACTOR ' + gammaFactorDefine,
'#define MAX_BONES ' + parameters.maxBones,
( parameters.useFog && parameters.fog ) ? '#define USE_FOG' : '',
( parameters.useFog && parameters.fogExp ) ? '#define FOG_EXP2' : '',
parameters.map ? '#define USE_MAP' : '',
parameters.envMap ? '#define USE_ENVMAP' : '',
parameters.envMap ? '#define ' + envMapModeDefine : '',
parameters.lightMap ? '#define USE_LIGHTMAP' : '',
parameters.aoMap ? '#define USE_AOMAP' : '',
parameters.emissiveMap ? '#define USE_EMISSIVEMAP' : '',
parameters.bumpMap ? '#define USE_BUMPMAP' : '',
parameters.normalMap ? '#define USE_NORMALMAP' : '',
( parameters.normalMap && parameters.objectSpaceNormalMap ) ? '#define OBJECTSPACE_NORMALMAP' : '',
parameters.displacementMap && parameters.supportsVertexTextures ? '#define USE_DISPLACEMENTMAP' : '',
parameters.specularMap ? '#define USE_SPECULARMAP' : '',
parameters.roughnessMap ? '#define USE_ROUGHNESSMAP' : '',
parameters.metalnessMap ? '#define USE_METALNESSMAP' : '',
parameters.alphaMap ? '#define USE_ALPHAMAP' : '',
parameters.vertexColors ? '#define USE_COLOR' : '',
parameters.flatShading ? '#define FLAT_SHADED' : '',
parameters.skinning ? '#define USE_SKINNING' : '',
parameters.useVertexTexture ? '#define BONE_TEXTURE' : '',
parameters.morphTargets ? '#define USE_MORPHTARGETS' : '',
parameters.morphNormals && parameters.flatShading === false ? '#define USE_MORPHNORMALS' : '',
parameters.doubleSided ? '#define DOUBLE_SIDED' : '',
parameters.flipSided ? '#define FLIP_SIDED' : '',
parameters.shadowMapEnabled ? '#define USE_SHADOWMAP' : '',
parameters.shadowMapEnabled ? '#define ' + shadowMapTypeDefine : '',
parameters.sizeAttenuation ? '#define USE_SIZEATTENUATION' : '',
parameters.logarithmicDepthBuffer ? '#define USE_LOGDEPTHBUF' : '',
parameters.logarithmicDepthBuffer && ( capabilities.isWebGL2 || extensions.get( 'EXT_frag_depth' ) ) ? '#define USE_LOGDEPTHBUF_EXT' : '',
'uniform mat4 modelMatrix;',
'uniform mat4 modelViewMatrix;',
'uniform mat4 projectionMatrix;',
'uniform mat4 viewMatrix;',
'uniform mat3 normalMatrix;',
'uniform vec3 cameraPosition;',
'attribute vec3 position;',
'attribute vec3 normal;',
'attribute vec2 uv;',
'#ifdef USE_COLOR',
' attribute vec3 color;',
'#endif',
'#ifdef USE_MORPHTARGETS',
' attribute vec3 morphTarget0;',
' attribute vec3 morphTarget1;',
' attribute vec3 morphTarget2;',
' attribute vec3 morphTarget3;',
' #ifdef USE_MORPHNORMALS',
' attribute vec3 morphNormal0;',
' attribute vec3 morphNormal1;',
' attribute vec3 morphNormal2;',
' attribute vec3 morphNormal3;',
' #else',
' attribute vec3 morphTarget4;',
' attribute vec3 morphTarget5;',
' attribute vec3 morphTarget6;',
' attribute vec3 morphTarget7;',
' #endif',
'#endif',
'#ifdef USE_SKINNING',
' attribute vec4 skinIndex;',
' attribute vec4 skinWeight;',
'#endif',
'\n'
].filter( filterEmptyLine ).join( '\n' );
prefixFragment = [
customExtensions,
'precision ' + parameters.precision + ' float;',
'precision ' + parameters.precision + ' int;',
'#define SHADER_NAME ' + shader.name,
customDefines,
parameters.alphaTest ? '#define ALPHATEST ' + parameters.alphaTest + ( parameters.alphaTest % 1 ? '' : '.0' ) : '', // add '.0' if integer
'#define GAMMA_FACTOR ' + gammaFactorDefine,
( parameters.useFog && parameters.fog ) ? '#define USE_FOG' : '',
( parameters.useFog && parameters.fogExp ) ? '#define FOG_EXP2' : '',
parameters.map ? '#define USE_MAP' : '',
parameters.envMap ? '#define USE_ENVMAP' : '',
parameters.envMap ? '#define ' + envMapTypeDefine : '',
parameters.envMap ? '#define ' + envMapModeDefine : '',
parameters.envMap ? '#define ' + envMapBlendingDefine : '',
parameters.lightMap ? '#define USE_LIGHTMAP' : '',
parameters.aoMap ? '#define USE_AOMAP' : '',
parameters.emissiveMap ? '#define USE_EMISSIVEMAP' : '',
parameters.bumpMap ? '#define USE_BUMPMAP' : '',
parameters.normalMap ? '#define USE_NORMALMAP' : '',
( parameters.normalMap && parameters.objectSpaceNormalMap ) ? '#define OBJECTSPACE_NORMALMAP' : '',
parameters.specularMap ? '#define USE_SPECULARMAP' : '',
parameters.roughnessMap ? '#define USE_ROUGHNESSMAP' : '',
parameters.metalnessMap ? '#define USE_METALNESSMAP' : '',
parameters.alphaMap ? '#define USE_ALPHAMAP' : '',
parameters.vertexColors ? '#define USE_COLOR' : '',
parameters.gradientMap ? '#define USE_GRADIENTMAP' : '',
parameters.flatShading ? '#define FLAT_SHADED' : '',
parameters.doubleSided ? '#define DOUBLE_SIDED' : '',
parameters.flipSided ? '#define FLIP_SIDED' : '',
parameters.shadowMapEnabled ? '#define USE_SHADOWMAP' : '',
parameters.shadowMapEnabled ? '#define ' + shadowMapTypeDefine : '',
parameters.premultipliedAlpha ? '#define PREMULTIPLIED_ALPHA' : '',
parameters.physicallyCorrectLights ? '#define PHYSICALLY_CORRECT_LIGHTS' : '',
parameters.logarithmicDepthBuffer ? '#define USE_LOGDEPTHBUF' : '',
parameters.logarithmicDepthBuffer && ( capabilities.isWebGL2 || extensions.get( 'EXT_frag_depth' ) ) ? '#define USE_LOGDEPTHBUF_EXT' : '',
parameters.envMap && ( capabilities.isWebGL2 || extensions.get( 'EXT_shader_texture_lod' ) ) ? '#define TEXTURE_LOD_EXT' : '',
'uniform mat4 viewMatrix;',
'uniform vec3 cameraPosition;',
( parameters.toneMapping !== NoToneMapping ) ? '#define TONE_MAPPING' : '',
( parameters.toneMapping !== NoToneMapping ) ? ShaderChunk[ 'tonemapping_pars_fragment' ] : '', // this code is required here because it is used by the toneMapping() function defined below
( parameters.toneMapping !== NoToneMapping ) ? getToneMappingFunction( 'toneMapping', parameters.toneMapping ) : '',
parameters.dithering ? '#define DITHERING' : '',
( parameters.outputEncoding || parameters.mapEncoding || parameters.matcapEncoding || parameters.envMapEncoding || parameters.emissiveMapEncoding ) ?
ShaderChunk[ 'encodings_pars_fragment' ] : '', // this code is required here because it is used by the various encoding/decoding function defined below
parameters.mapEncoding ? getTexelDecodingFunction( 'mapTexelToLinear', parameters.mapEncoding ) : '',
parameters.matcapEncoding ? getTexelDecodingFunction( 'matcapTexelToLinear', parameters.matcapEncoding ) : '',
parameters.envMapEncoding ? getTexelDecodingFunction( 'envMapTexelToLinear', parameters.envMapEncoding ) : '',
parameters.emissiveMapEncoding ? getTexelDecodingFunction( 'emissiveMapTexelToLinear', parameters.emissiveMapEncoding ) : '',
parameters.outputEncoding ? getTexelEncodingFunction( 'linearToOutputTexel', parameters.outputEncoding ) : '',
parameters.depthPacking ? '#define DEPTH_PACKING ' + material.depthPacking : '',
'\n'
].filter( filterEmptyLine ).join( '\n' );
}
vertexShader = parseIncludes( vertexShader );
vertexShader = replaceLightNums( vertexShader, parameters );
vertexShader = replaceClippingPlaneNums( vertexShader, parameters );
fragmentShader = parseIncludes( fragmentShader );
fragmentShader = replaceLightNums( fragmentShader, parameters );
fragmentShader = replaceClippingPlaneNums( fragmentShader, parameters );
vertexShader = unrollLoops( vertexShader );
fragmentShader = unrollLoops( fragmentShader );
if ( capabilities.isWebGL2 && ! material.isRawShaderMaterial ) {
var isGLSL3ShaderMaterial = false;
var versionRegex = /^\s*#version\s+300\s+es\s*\n/;
if ( material.isShaderMaterial &&
vertexShader.match( versionRegex ) !== null &&
fragmentShader.match( versionRegex ) !== null ) {
isGLSL3ShaderMaterial = true;
vertexShader = vertexShader.replace( versionRegex, '' );
fragmentShader = fragmentShader.replace( versionRegex, '' );
}
// GLSL 3.0 conversion
prefixVertex = [
'#version 300 es\n',
'#define attribute in',
'#define varying out',
'#define texture2D texture'
].join( '\n' ) + '\n' + prefixVertex;
prefixFragment = [
'#version 300 es\n',
'#define varying in',
isGLSL3ShaderMaterial ? '' : 'out highp vec4 pc_fragColor;',
isGLSL3ShaderMaterial ? '' : '#define gl_FragColor pc_fragColor',
'#define gl_FragDepthEXT gl_FragDepth',
'#define texture2D texture',
'#define textureCube texture',
'#define texture2DProj textureProj',
'#define texture2DLodEXT textureLod',
'#define texture2DProjLodEXT textureProjLod',
'#define textureCubeLodEXT textureLod',
'#define texture2DGradEXT textureGrad',
'#define texture2DProjGradEXT textureProjGrad',
'#define textureCubeGradEXT textureGrad'
].join( '\n' ) + '\n' + prefixFragment;
}
var vertexGlsl = prefixVertex + vertexShader;
var fragmentGlsl = prefixFragment + fragmentShader;
// console.log( '*VERTEX*', vertexGlsl );
// console.log( '*FRAGMENT*', fragmentGlsl );
var glVertexShader = WebGLShader( gl, gl.VERTEX_SHADER, vertexGlsl );
var glFragmentShader = WebGLShader( gl, gl.FRAGMENT_SHADER, fragmentGlsl );
gl.attachShader( program, glVertexShader );
gl.attachShader( program, glFragmentShader );
// Force a particular attribute to index 0.
if ( material.index0AttributeName !== undefined ) {
gl.bindAttribLocation( program, 0, material.index0AttributeName );
} else if ( parameters.morphTargets === true ) {
// programs with morphTargets displace position out of attribute 0
gl.bindAttribLocation( program, 0, 'position' );
}
gl.linkProgram( program );
var programLog = gl.getProgramInfoLog( program ).trim();
var vertexLog = gl.getShaderInfoLog( glVertexShader ).trim();
var fragmentLog = gl.getShaderInfoLog( glFragmentShader ).trim();
var runnable = true;
var haveDiagnostics = true;
// console.log( '**VERTEX**', gl.getExtension( 'WEBGL_debug_shaders' ).getTranslatedShaderSource( glVertexShader ) );
// console.log( '**FRAGMENT**', gl.getExtension( 'WEBGL_debug_shaders' ).getTranslatedShaderSource( glFragmentShader ) );
if ( gl.getProgramParameter( program, gl.LINK_STATUS ) === false ) {
runnable = false;
console.error( 'THREE.WebGLProgram: shader error: ', gl.getError(), 'gl.VALIDATE_STATUS', gl.getProgramParameter( program, gl.VALIDATE_STATUS ), 'gl.getProgramInfoLog', programLog, vertexLog, fragmentLog );
} else if ( programLog !== '' ) {
console.warn( 'THREE.WebGLProgram: gl.getProgramInfoLog()', programLog );
} else if ( vertexLog === '' || fragmentLog === '' ) {
haveDiagnostics = false;
}
if ( haveDiagnostics ) {
this.diagnostics = {
runnable: runnable,
material: material,
programLog: programLog,
vertexShader: {
log: vertexLog,
prefix: prefixVertex
},
fragmentShader: {
log: fragmentLog,
prefix: prefixFragment
}
};
}
// clean up
gl.deleteShader( glVertexShader );
gl.deleteShader( glFragmentShader );
// set up caching for uniform locations
var cachedUniforms;
this.getUniforms = function () {
if ( cachedUniforms === undefined ) {
cachedUniforms = new WebGLUniforms( gl, program, renderer );
}
return cachedUniforms;
};
// set up caching for attribute locations
var cachedAttributes;
this.getAttributes = function () {
if ( cachedAttributes === undefined ) {
cachedAttributes = fetchAttributeLocations( gl, program );
}
return cachedAttributes;
};
// free resource
this.destroy = function () {
gl.deleteProgram( program );
this.program = undefined;
};
// DEPRECATED
Object.defineProperties( this, {
uniforms: {
get: function () {
console.warn( 'THREE.WebGLProgram: .uniforms is now .getUniforms().' );
return this.getUniforms();
}
},
attributes: {
get: function () {
console.warn( 'THREE.WebGLProgram: .attributes is now .getAttributes().' );
return this.getAttributes();
}
}
} );
//
this.name = shader.name;
this.id = programIdCount ++;
this.code = code;
this.usedTimes = 1;
this.program = program;
this.vertexShader = glVertexShader;
this.fragmentShader = glFragmentShader;
return this;
}
export { WebGLProgram };

View File

@ -0,0 +1,312 @@
/**
* @author mrdoob / http://mrdoob.com/
*/
import { BackSide, DoubleSide, CubeUVRefractionMapping, CubeUVReflectionMapping, GammaEncoding, LinearEncoding, ObjectSpaceNormalMap } from '../../constants.js';
import { WebGLProgram } from './WebGLProgram.js';
function WebGLPrograms( renderer, extensions, capabilities ) {
var programs = [];
var shaderIDs = {
MeshDepthMaterial: 'depth',
MeshDistanceMaterial: 'distanceRGBA',
MeshNormalMaterial: 'normal',
MeshBasicMaterial: 'basic',
MeshLambertMaterial: 'lambert',
MeshPhongMaterial: 'phong',
MeshToonMaterial: 'phong',
MeshStandardMaterial: 'physical',
MeshPhysicalMaterial: 'physical',
MeshMatcapMaterial: 'matcap',
LineBasicMaterial: 'basic',
LineDashedMaterial: 'dashed',
PointsMaterial: 'points',
ShadowMaterial: 'shadow',
SpriteMaterial: 'sprite'
};
var parameterNames = [
"precision", "supportsVertexTextures", "map", "mapEncoding", "matcapEncoding", "envMap", "envMapMode", "envMapEncoding",
"lightMap", "aoMap", "emissiveMap", "emissiveMapEncoding", "bumpMap", "normalMap", "objectSpaceNormalMap", "displacementMap", "specularMap",
"roughnessMap", "metalnessMap", "gradientMap",
"alphaMap", "combine", "vertexColors", "fog", "useFog", "fogExp",
"flatShading", "sizeAttenuation", "logarithmicDepthBuffer", "skinning",
"maxBones", "useVertexTexture", "morphTargets", "morphNormals",
"maxMorphTargets", "maxMorphNormals", "premultipliedAlpha",
"numDirLights", "numPointLights", "numSpotLights", "numHemiLights", "numRectAreaLights",
"shadowMapEnabled", "shadowMapType", "toneMapping", 'physicallyCorrectLights',
"alphaTest", "doubleSided", "flipSided", "numClippingPlanes", "numClipIntersection", "depthPacking", "dithering"
];
function allocateBones( object ) {
var skeleton = object.skeleton;
var bones = skeleton.bones;
if ( capabilities.floatVertexTextures ) {
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 = capabilities.maxVertexUniforms;
var nVertexMatrices = Math.floor( ( nVertexUniforms - 20 ) / 4 );
var maxBones = Math.min( nVertexMatrices, bones.length );
if ( maxBones < bones.length ) {
console.warn( 'THREE.WebGLRenderer: Skeleton has ' + bones.length + ' bones. This GPU supports ' + maxBones + '.' );
return 0;
}
return maxBones;
}
}
function getTextureEncodingFromMap( map, gammaOverrideLinear ) {
var encoding;
if ( ! map ) {
encoding = LinearEncoding;
} else if ( map.isTexture ) {
encoding = map.encoding;
} else if ( map.isWebGLRenderTarget ) {
console.warn( "THREE.WebGLPrograms.getTextureEncodingFromMap: don't use render targets as textures. Use their .texture property instead." );
encoding = map.texture.encoding;
}
// add backwards compatibility for WebGLRenderer.gammaInput/gammaOutput parameter, should probably be removed at some point.
if ( encoding === LinearEncoding && gammaOverrideLinear ) {
encoding = GammaEncoding;
}
return encoding;
}
this.getParameters = function ( material, lights, shadows, fog, nClipPlanes, nClipIntersection, object ) {
var shaderID = shaderIDs[ material.type ];
// heuristics to create shader parameters according to lights in the scene
// (not to blow over maxLights budget)
var maxBones = object.isSkinnedMesh ? allocateBones( object ) : 0;
var precision = capabilities.precision;
if ( material.precision !== null ) {
precision = capabilities.getMaxPrecision( material.precision );
if ( precision !== material.precision ) {
console.warn( 'THREE.WebGLProgram.getParameters:', material.precision, 'not supported, using', precision, 'instead.' );
}
}
var currentRenderTarget = renderer.getRenderTarget();
var parameters = {
shaderID: shaderID,
precision: precision,
supportsVertexTextures: capabilities.vertexTextures,
outputEncoding: getTextureEncodingFromMap( ( ! currentRenderTarget ) ? null : currentRenderTarget.texture, renderer.gammaOutput ),
map: !! material.map,
mapEncoding: getTextureEncodingFromMap( material.map, renderer.gammaInput ),
matcap: !! material.matcap,
matcapEncoding: getTextureEncodingFromMap( material.matcap, renderer.gammaInput ),
envMap: !! material.envMap,
envMapMode: material.envMap && material.envMap.mapping,
envMapEncoding: getTextureEncodingFromMap( material.envMap, renderer.gammaInput ),
envMapCubeUV: ( !! material.envMap ) && ( ( material.envMap.mapping === CubeUVReflectionMapping ) || ( material.envMap.mapping === CubeUVRefractionMapping ) ),
lightMap: !! material.lightMap,
aoMap: !! material.aoMap,
emissiveMap: !! material.emissiveMap,
emissiveMapEncoding: getTextureEncodingFromMap( material.emissiveMap, renderer.gammaInput ),
bumpMap: !! material.bumpMap,
normalMap: !! material.normalMap,
objectSpaceNormalMap: material.normalMapType === ObjectSpaceNormalMap,
displacementMap: !! material.displacementMap,
roughnessMap: !! material.roughnessMap,
metalnessMap: !! material.metalnessMap,
specularMap: !! material.specularMap,
alphaMap: !! material.alphaMap,
gradientMap: !! material.gradientMap,
combine: material.combine,
vertexColors: material.vertexColors,
fog: !! fog,
useFog: material.fog,
fogExp: ( fog && fog.isFogExp2 ),
flatShading: material.flatShading,
sizeAttenuation: material.sizeAttenuation,
logarithmicDepthBuffer: capabilities.logarithmicDepthBuffer,
skinning: material.skinning && maxBones > 0,
maxBones: maxBones,
useVertexTexture: capabilities.floatVertexTextures,
morphTargets: material.morphTargets,
morphNormals: material.morphNormals,
maxMorphTargets: renderer.maxMorphTargets,
maxMorphNormals: renderer.maxMorphNormals,
numDirLights: lights.directional.length,
numPointLights: lights.point.length,
numSpotLights: lights.spot.length,
numRectAreaLights: lights.rectArea.length,
numHemiLights: lights.hemi.length,
numClippingPlanes: nClipPlanes,
numClipIntersection: nClipIntersection,
dithering: material.dithering,
shadowMapEnabled: renderer.shadowMap.enabled && object.receiveShadow && shadows.length > 0,
shadowMapType: renderer.shadowMap.type,
toneMapping: renderer.toneMapping,
physicallyCorrectLights: renderer.physicallyCorrectLights,
premultipliedAlpha: material.premultipliedAlpha,
alphaTest: material.alphaTest,
doubleSided: material.side === DoubleSide,
flipSided: material.side === BackSide,
depthPacking: ( material.depthPacking !== undefined ) ? material.depthPacking : false
};
return parameters;
};
this.getProgramCode = function ( material, parameters ) {
var array = [];
if ( parameters.shaderID ) {
array.push( parameters.shaderID );
} else {
array.push( material.fragmentShader );
array.push( material.vertexShader );
}
if ( material.defines !== undefined ) {
for ( var name in material.defines ) {
array.push( name );
array.push( material.defines[ name ] );
}
}
for ( var i = 0; i < parameterNames.length; i ++ ) {
array.push( parameters[ parameterNames[ i ] ] );
}
array.push( material.onBeforeCompile.toString() );
array.push( renderer.gammaOutput );
array.push( renderer.gammaFactor );
return array.join();
};
this.acquireProgram = function ( material, shader, parameters, code ) {
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 WebGLProgram( renderer, extensions, code, material, shader, parameters, capabilities );
programs.push( program );
}
return program;
};
this.releaseProgram = function ( program ) {
if ( -- program.usedTimes === 0 ) {
// Remove from unordered set
var i = programs.indexOf( program );
programs[ i ] = programs[ programs.length - 1 ];
programs.pop();
// Free WebGL resources
program.destroy();
}
};
// Exposed for resource monitoring & error feedback via renderer.info:
this.programs = programs;
}
export { WebGLPrograms };

View File

@ -0,0 +1,52 @@
/**
* @author fordacious / fordacious.github.io
*/
function WebGLProperties() {
var properties = new WeakMap();
function get( object ) {
var map = properties.get( object );
if ( map === undefined ) {
map = {};
properties.set( object, map );
}
return map;
}
function remove( object ) {
properties.delete( object );
}
function update( object, key, value ) {
properties.get( object )[ key ] = value;
}
function dispose() {
properties = new WeakMap();
}
return {
get: get,
remove: remove,
update: update,
dispose: dispose
};
}
export { WebGLProperties };

View File

@ -0,0 +1,161 @@
/**
* @author mrdoob / http://mrdoob.com/
*/
function painterSortStable( a, b ) {
if ( a.renderOrder !== b.renderOrder ) {
return a.renderOrder - b.renderOrder;
} else if ( a.program && b.program && a.program !== b.program ) {
return a.program.id - b.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.renderOrder !== b.renderOrder ) {
return a.renderOrder - b.renderOrder;
} if ( a.z !== b.z ) {
return b.z - a.z;
} else {
return a.id - b.id;
}
}
function WebGLRenderList() {
var renderItems = [];
var renderItemsIndex = 0;
var opaque = [];
var transparent = [];
function init() {
renderItemsIndex = 0;
opaque.length = 0;
transparent.length = 0;
}
function push( object, geometry, material, z, group ) {
var renderItem = renderItems[ renderItemsIndex ];
if ( renderItem === undefined ) {
renderItem = {
id: object.id,
object: object,
geometry: geometry,
material: material,
program: material.program,
renderOrder: object.renderOrder,
z: z,
group: group
};
renderItems[ renderItemsIndex ] = renderItem;
} else {
renderItem.id = object.id;
renderItem.object = object;
renderItem.geometry = geometry;
renderItem.material = material;
renderItem.program = material.program;
renderItem.renderOrder = object.renderOrder;
renderItem.z = z;
renderItem.group = group;
}
( material.transparent === true ? transparent : opaque ).push( renderItem );
renderItemsIndex ++;
}
function sort() {
if ( opaque.length > 1 ) opaque.sort( painterSortStable );
if ( transparent.length > 1 ) transparent.sort( reversePainterSortStable );
}
return {
opaque: opaque,
transparent: transparent,
init: init,
push: push,
sort: sort
};
}
function WebGLRenderLists() {
var lists = {};
function get( scene, camera ) {
var hash = scene.id + ',' + camera.id;
var list = lists[ hash ];
if ( list === undefined ) {
// console.log( 'THREE.WebGLRenderLists:', hash );
list = new WebGLRenderList();
lists[ hash ] = list;
}
return list;
}
function dispose() {
lists = {};
}
return {
get: get,
dispose: dispose
};
}
export { WebGLRenderLists };

View File

@ -0,0 +1,104 @@
/**
* @author Mugen87 / https://github.com/Mugen87
*/
import { WebGLLights } from './WebGLLights.js';
function WebGLRenderState() {
var lights = new WebGLLights();
var lightsArray = [];
var shadowsArray = [];
function init() {
lightsArray.length = 0;
shadowsArray.length = 0;
}
function pushLight( light ) {
lightsArray.push( light );
}
function pushShadow( shadowLight ) {
shadowsArray.push( shadowLight );
}
function setupLights( camera ) {
lights.setup( lightsArray, shadowsArray, camera );
}
var state = {
lightsArray: lightsArray,
shadowsArray: shadowsArray,
lights: lights
};
return {
init: init,
state: state,
setupLights: setupLights,
pushLight: pushLight,
pushShadow: pushShadow
};
}
function WebGLRenderStates() {
var renderStates = {};
function get( scene, camera ) {
var renderState;
if ( renderStates[ scene.id ] === undefined ) {
renderState = new WebGLRenderState();
renderStates[ scene.id ] = {};
renderStates[ scene.id ][ camera.id ] = renderState;
} else {
if ( renderStates[ scene.id ][ camera.id ] === undefined ) {
renderState = new WebGLRenderState();
renderStates[ scene.id ][ camera.id ] = renderState;
} else {
renderState = renderStates[ scene.id ][ camera.id ];
}
}
return renderState;
}
function dispose() {
renderStates = {};
}
return {
get: get,
dispose: dispose
};
}
export { WebGLRenderStates };

View File

@ -0,0 +1,46 @@
/**
* @author mrdoob / http://mrdoob.com/
*/
function addLineNumbers( string ) {
var lines = string.split( '\n' );
for ( var i = 0; i < lines.length; i ++ ) {
lines[ i ] = ( i + 1 ) + ': ' + lines[ i ];
}
return lines.join( '\n' );
}
function WebGLShader( gl, type, string ) {
var shader = gl.createShader( type );
gl.shaderSource( shader, string );
gl.compileShader( shader );
if ( gl.getShaderParameter( shader, gl.COMPILE_STATUS ) === false ) {
console.error( 'THREE.WebGLShader: Shader couldn\'t compile.' );
}
if ( gl.getShaderInfoLog( shader ) !== '' ) {
console.warn( 'THREE.WebGLShader: gl.getShaderInfoLog()', type === gl.VERTEX_SHADER ? 'vertex' : 'fragment', gl.getShaderInfoLog( shader ), addLineNumbers( string ) );
}
// --enable-privileged-webgl-extension
// console.log( type, gl.getExtension( 'WEBGL_debug_shaders' ).getTranslatedShaderSource( shader ) );
return shader;
}
export { WebGLShader };

View File

@ -0,0 +1,430 @@
/**
* @author alteredq / http://alteredqualia.com/
* @author mrdoob / http://mrdoob.com/
*/
import { FrontSide, BackSide, DoubleSide, RGBAFormat, NearestFilter, PCFShadowMap, RGBADepthPacking } from '../../constants.js';
import { WebGLRenderTarget } from '../WebGLRenderTarget.js';
import { MeshDepthMaterial } from '../../materials/MeshDepthMaterial.js';
import { MeshDistanceMaterial } from '../../materials/MeshDistanceMaterial.js';
import { Vector4 } from '../../math/Vector4.js';
import { Vector3 } from '../../math/Vector3.js';
import { Vector2 } from '../../math/Vector2.js';
import { Matrix4 } from '../../math/Matrix4.js';
import { Frustum } from '../../math/Frustum.js';
function WebGLShadowMap( _renderer, _objects, maxTextureSize ) {
var _frustum = new Frustum(),
_projScreenMatrix = new Matrix4(),
_shadowMapSize = new Vector2(),
_maxShadowMapSize = new Vector2( maxTextureSize, maxTextureSize ),
_lookTarget = new Vector3(),
_lightPositionWorld = new Vector3(),
_MorphingFlag = 1,
_SkinningFlag = 2,
_NumberOfMaterialVariants = ( _MorphingFlag | _SkinningFlag ) + 1,
_depthMaterials = new Array( _NumberOfMaterialVariants ),
_distanceMaterials = new Array( _NumberOfMaterialVariants ),
_materialCache = {};
var shadowSide = { 0: BackSide, 1: FrontSide, 2: DoubleSide };
var cubeDirections = [
new Vector3( 1, 0, 0 ), new Vector3( - 1, 0, 0 ), new Vector3( 0, 0, 1 ),
new Vector3( 0, 0, - 1 ), new Vector3( 0, 1, 0 ), new Vector3( 0, - 1, 0 )
];
var cubeUps = [
new Vector3( 0, 1, 0 ), new Vector3( 0, 1, 0 ), new Vector3( 0, 1, 0 ),
new Vector3( 0, 1, 0 ), new Vector3( 0, 0, 1 ), new Vector3( 0, 0, - 1 )
];
var cube2DViewPorts = [
new Vector4(), new Vector4(), new Vector4(),
new Vector4(), new Vector4(), new Vector4()
];
// init
for ( var i = 0; i !== _NumberOfMaterialVariants; ++ i ) {
var useMorphing = ( i & _MorphingFlag ) !== 0;
var useSkinning = ( i & _SkinningFlag ) !== 0;
var depthMaterial = new MeshDepthMaterial( {
depthPacking: RGBADepthPacking,
morphTargets: useMorphing,
skinning: useSkinning
} );
_depthMaterials[ i ] = depthMaterial;
//
var distanceMaterial = new MeshDistanceMaterial( {
morphTargets: useMorphing,
skinning: useSkinning
} );
_distanceMaterials[ i ] = distanceMaterial;
}
//
var scope = this;
this.enabled = false;
this.autoUpdate = true;
this.needsUpdate = false;
this.type = PCFShadowMap;
this.render = function ( lights, scene, camera ) {
if ( scope.enabled === false ) return;
if ( scope.autoUpdate === false && scope.needsUpdate === false ) return;
if ( lights.length === 0 ) return;
// TODO Clean up (needed in case of contextlost)
var _gl = _renderer.context;
var _state = _renderer.state;
// Set GL state for depth map.
_state.disable( _gl.BLEND );
_state.buffers.color.setClear( 1, 1, 1, 1 );
_state.buffers.depth.setTest( true );
_state.setScissorTest( false );
// render depth map
var faceCount;
for ( var i = 0, il = lights.length; i < il; i ++ ) {
var light = lights[ i ];
var shadow = light.shadow;
var isPointLight = light && light.isPointLight;
if ( shadow === undefined ) {
console.warn( 'THREE.WebGLShadowMap:', light, 'has no shadow.' );
continue;
}
var shadowCamera = shadow.camera;
_shadowMapSize.copy( shadow.mapSize );
_shadowMapSize.min( _maxShadowMapSize );
if ( isPointLight ) {
var vpWidth = _shadowMapSize.x;
var vpHeight = _shadowMapSize.y;
// These viewports map a cube-map onto a 2D texture with the
// following orientation:
//
// xzXZ
// y Y
//
// X - Positive x direction
// x - Negative x direction
// Y - Positive y direction
// y - Negative y direction
// Z - Positive z direction
// z - Negative z direction
// positive X
cube2DViewPorts[ 0 ].set( vpWidth * 2, vpHeight, vpWidth, vpHeight );
// negative X
cube2DViewPorts[ 1 ].set( 0, vpHeight, vpWidth, vpHeight );
// positive Z
cube2DViewPorts[ 2 ].set( vpWidth * 3, vpHeight, vpWidth, vpHeight );
// negative Z
cube2DViewPorts[ 3 ].set( vpWidth, vpHeight, vpWidth, vpHeight );
// positive Y
cube2DViewPorts[ 4 ].set( vpWidth * 3, 0, vpWidth, vpHeight );
// negative Y
cube2DViewPorts[ 5 ].set( vpWidth, 0, vpWidth, vpHeight );
_shadowMapSize.x *= 4.0;
_shadowMapSize.y *= 2.0;
}
if ( shadow.map === null ) {
var pars = { minFilter: NearestFilter, magFilter: NearestFilter, format: RGBAFormat };
shadow.map = new WebGLRenderTarget( _shadowMapSize.x, _shadowMapSize.y, pars );
shadow.map.texture.name = light.name + ".shadowMap";
shadowCamera.updateProjectionMatrix();
}
if ( shadow.isSpotLightShadow ) {
shadow.update( light );
}
var shadowMap = shadow.map;
var shadowMatrix = shadow.matrix;
_lightPositionWorld.setFromMatrixPosition( light.matrixWorld );
shadowCamera.position.copy( _lightPositionWorld );
if ( isPointLight ) {
faceCount = 6;
// for point lights we set the shadow matrix to be a translation-only matrix
// equal to inverse of the light's position
shadowMatrix.makeTranslation( - _lightPositionWorld.x, - _lightPositionWorld.y, - _lightPositionWorld.z );
} else {
faceCount = 1;
_lookTarget.setFromMatrixPosition( light.target.matrixWorld );
shadowCamera.lookAt( _lookTarget );
shadowCamera.updateMatrixWorld();
// compute shadow matrix
shadowMatrix.set(
0.5, 0.0, 0.0, 0.5,
0.0, 0.5, 0.0, 0.5,
0.0, 0.0, 0.5, 0.5,
0.0, 0.0, 0.0, 1.0
);
shadowMatrix.multiply( shadowCamera.projectionMatrix );
shadowMatrix.multiply( shadowCamera.matrixWorldInverse );
}
_renderer.setRenderTarget( shadowMap );
_renderer.clear();
// render shadow map for each cube face (if omni-directional) or
// run a single pass if not
for ( var face = 0; face < faceCount; face ++ ) {
if ( isPointLight ) {
_lookTarget.copy( shadowCamera.position );
_lookTarget.add( cubeDirections[ face ] );
shadowCamera.up.copy( cubeUps[ face ] );
shadowCamera.lookAt( _lookTarget );
shadowCamera.updateMatrixWorld();
var vpDimensions = cube2DViewPorts[ face ];
_state.viewport( vpDimensions );
}
// update camera matrices and frustum
_projScreenMatrix.multiplyMatrices( shadowCamera.projectionMatrix, shadowCamera.matrixWorldInverse );
_frustum.setFromMatrix( _projScreenMatrix );
// set object matrices & frustum culling
renderObject( scene, camera, shadowCamera, isPointLight );
}
}
scope.needsUpdate = false;
};
function getDepthMaterial( object, material, isPointLight, lightPositionWorld, shadowCameraNear, shadowCameraFar ) {
var geometry = object.geometry;
var result = null;
var materialVariants = _depthMaterials;
var customMaterial = object.customDepthMaterial;
if ( isPointLight ) {
materialVariants = _distanceMaterials;
customMaterial = object.customDistanceMaterial;
}
if ( ! customMaterial ) {
var useMorphing = false;
if ( material.morphTargets ) {
if ( geometry && geometry.isBufferGeometry ) {
useMorphing = geometry.morphAttributes && geometry.morphAttributes.position && geometry.morphAttributes.position.length > 0;
} else if ( geometry && geometry.isGeometry ) {
useMorphing = geometry.morphTargets && geometry.morphTargets.length > 0;
}
}
if ( object.isSkinnedMesh && material.skinning === false ) {
console.warn( 'THREE.WebGLShadowMap: THREE.SkinnedMesh with material.skinning set to false:', object );
}
var useSkinning = object.isSkinnedMesh && material.skinning;
var variantIndex = 0;
if ( useMorphing ) variantIndex |= _MorphingFlag;
if ( useSkinning ) variantIndex |= _SkinningFlag;
result = materialVariants[ variantIndex ];
} else {
result = customMaterial;
}
if ( _renderer.localClippingEnabled &&
material.clipShadows === true &&
material.clippingPlanes.length !== 0 ) {
// in this case we need a unique material instance reflecting the
// appropriate state
var keyA = result.uuid, keyB = material.uuid;
var materialsForVariant = _materialCache[ keyA ];
if ( materialsForVariant === undefined ) {
materialsForVariant = {};
_materialCache[ keyA ] = materialsForVariant;
}
var cachedMaterial = materialsForVariant[ keyB ];
if ( cachedMaterial === undefined ) {
cachedMaterial = result.clone();
materialsForVariant[ keyB ] = cachedMaterial;
}
result = cachedMaterial;
}
result.visible = material.visible;
result.wireframe = material.wireframe;
result.side = ( material.shadowSide != null ) ? material.shadowSide : shadowSide[ material.side ];
result.clipShadows = material.clipShadows;
result.clippingPlanes = material.clippingPlanes;
result.clipIntersection = material.clipIntersection;
result.wireframeLinewidth = material.wireframeLinewidth;
result.linewidth = material.linewidth;
if ( isPointLight && result.isMeshDistanceMaterial ) {
result.referencePosition.copy( lightPositionWorld );
result.nearDistance = shadowCameraNear;
result.farDistance = shadowCameraFar;
}
return result;
}
function renderObject( object, camera, shadowCamera, isPointLight ) {
if ( object.visible === false ) return;
var visible = object.layers.test( camera.layers );
if ( visible && ( object.isMesh || object.isLine || object.isPoints ) ) {
if ( object.castShadow && ( ! object.frustumCulled || _frustum.intersectsObject( object ) ) ) {
object.modelViewMatrix.multiplyMatrices( shadowCamera.matrixWorldInverse, object.matrixWorld );
var geometry = _objects.update( object );
var material = object.material;
if ( Array.isArray( material ) ) {
var groups = geometry.groups;
for ( var k = 0, kl = groups.length; k < kl; k ++ ) {
var group = groups[ k ];
var groupMaterial = material[ group.materialIndex ];
if ( groupMaterial && groupMaterial.visible ) {
var depthMaterial = getDepthMaterial( object, groupMaterial, isPointLight, _lightPositionWorld, shadowCamera.near, shadowCamera.far );
_renderer.renderBufferDirect( shadowCamera, null, geometry, depthMaterial, object, group );
}
}
} else if ( material.visible ) {
var depthMaterial = getDepthMaterial( object, material, isPointLight, _lightPositionWorld, shadowCamera.near, shadowCamera.far );
_renderer.renderBufferDirect( shadowCamera, null, geometry, depthMaterial, object, null );
}
}
}
var children = object.children;
for ( var i = 0, l = children.length; i < l; i ++ ) {
renderObject( children[ i ], camera, shadowCamera, isPointLight );
}
}
}
export { WebGLShadowMap };

View File

@ -0,0 +1,978 @@
/**
* @author mrdoob / http://mrdoob.com/
*/
import { NotEqualDepth, GreaterDepth, GreaterEqualDepth, EqualDepth, LessEqualDepth, LessDepth, AlwaysDepth, NeverDepth, CullFaceFront, CullFaceBack, CullFaceNone, CustomBlending, MultiplyBlending, SubtractiveBlending, AdditiveBlending, NoBlending, NormalBlending, AddEquation, DoubleSide, BackSide } from '../../constants.js';
import { Vector4 } from '../../math/Vector4.js';
function WebGLState( gl, extensions, utils, capabilities ) {
function ColorBuffer() {
var locked = false;
var color = new Vector4();
var currentColorMask = null;
var currentColorClear = new Vector4( 0, 0, 0, 0 );
return {
setMask: function ( colorMask ) {
if ( currentColorMask !== colorMask && ! locked ) {
gl.colorMask( colorMask, colorMask, colorMask, colorMask );
currentColorMask = colorMask;
}
},
setLocked: function ( lock ) {
locked = lock;
},
setClear: function ( r, g, b, a, premultipliedAlpha ) {
if ( premultipliedAlpha === true ) {
r *= a; g *= a; b *= a;
}
color.set( r, g, b, a );
if ( currentColorClear.equals( color ) === false ) {
gl.clearColor( r, g, b, a );
currentColorClear.copy( color );
}
},
reset: function () {
locked = false;
currentColorMask = null;
currentColorClear.set( - 1, 0, 0, 0 ); // set to invalid state
}
};
}
function DepthBuffer() {
var locked = false;
var currentDepthMask = null;
var currentDepthFunc = null;
var currentDepthClear = null;
return {
setTest: function ( depthTest ) {
if ( depthTest ) {
enable( gl.DEPTH_TEST );
} else {
disable( gl.DEPTH_TEST );
}
},
setMask: function ( depthMask ) {
if ( currentDepthMask !== depthMask && ! locked ) {
gl.depthMask( depthMask );
currentDepthMask = depthMask;
}
},
setFunc: function ( depthFunc ) {
if ( currentDepthFunc !== depthFunc ) {
if ( depthFunc ) {
switch ( depthFunc ) {
case NeverDepth:
gl.depthFunc( gl.NEVER );
break;
case AlwaysDepth:
gl.depthFunc( gl.ALWAYS );
break;
case LessDepth:
gl.depthFunc( gl.LESS );
break;
case LessEqualDepth:
gl.depthFunc( gl.LEQUAL );
break;
case EqualDepth:
gl.depthFunc( gl.EQUAL );
break;
case GreaterEqualDepth:
gl.depthFunc( gl.GEQUAL );
break;
case GreaterDepth:
gl.depthFunc( gl.GREATER );
break;
case NotEqualDepth:
gl.depthFunc( gl.NOTEQUAL );
break;
default:
gl.depthFunc( gl.LEQUAL );
}
} else {
gl.depthFunc( gl.LEQUAL );
}
currentDepthFunc = depthFunc;
}
},
setLocked: function ( lock ) {
locked = lock;
},
setClear: function ( depth ) {
if ( currentDepthClear !== depth ) {
gl.clearDepth( depth );
currentDepthClear = depth;
}
},
reset: function () {
locked = false;
currentDepthMask = null;
currentDepthFunc = null;
currentDepthClear = null;
}
};
}
function StencilBuffer() {
var locked = false;
var currentStencilMask = null;
var currentStencilFunc = null;
var currentStencilRef = null;
var currentStencilFuncMask = null;
var currentStencilFail = null;
var currentStencilZFail = null;
var currentStencilZPass = null;
var currentStencilClear = null;
return {
setTest: function ( stencilTest ) {
if ( stencilTest ) {
enable( gl.STENCIL_TEST );
} else {
disable( gl.STENCIL_TEST );
}
},
setMask: function ( stencilMask ) {
if ( currentStencilMask !== stencilMask && ! locked ) {
gl.stencilMask( stencilMask );
currentStencilMask = stencilMask;
}
},
setFunc: function ( stencilFunc, stencilRef, stencilMask ) {
if ( currentStencilFunc !== stencilFunc ||
currentStencilRef !== stencilRef ||
currentStencilFuncMask !== stencilMask ) {
gl.stencilFunc( stencilFunc, stencilRef, stencilMask );
currentStencilFunc = stencilFunc;
currentStencilRef = stencilRef;
currentStencilFuncMask = stencilMask;
}
},
setOp: function ( stencilFail, stencilZFail, stencilZPass ) {
if ( currentStencilFail !== stencilFail ||
currentStencilZFail !== stencilZFail ||
currentStencilZPass !== stencilZPass ) {
gl.stencilOp( stencilFail, stencilZFail, stencilZPass );
currentStencilFail = stencilFail;
currentStencilZFail = stencilZFail;
currentStencilZPass = stencilZPass;
}
},
setLocked: function ( lock ) {
locked = lock;
},
setClear: function ( stencil ) {
if ( currentStencilClear !== stencil ) {
gl.clearStencil( stencil );
currentStencilClear = stencil;
}
},
reset: function () {
locked = false;
currentStencilMask = null;
currentStencilFunc = null;
currentStencilRef = null;
currentStencilFuncMask = null;
currentStencilFail = null;
currentStencilZFail = null;
currentStencilZPass = null;
currentStencilClear = null;
}
};
}
//
var colorBuffer = new ColorBuffer();
var depthBuffer = new DepthBuffer();
var stencilBuffer = new StencilBuffer();
var maxVertexAttributes = gl.getParameter( gl.MAX_VERTEX_ATTRIBS );
var newAttributes = new Uint8Array( maxVertexAttributes );
var enabledAttributes = new Uint8Array( maxVertexAttributes );
var attributeDivisors = new Uint8Array( maxVertexAttributes );
var enabledCapabilities = {};
var compressedTextureFormats = null;
var currentProgram = null;
var currentBlendingEnabled = null;
var currentBlending = null;
var currentBlendEquation = null;
var currentBlendSrc = null;
var currentBlendDst = null;
var currentBlendEquationAlpha = null;
var currentBlendSrcAlpha = null;
var currentBlendDstAlpha = null;
var currentPremultipledAlpha = false;
var currentFlipSided = null;
var currentCullFace = null;
var currentLineWidth = null;
var currentPolygonOffsetFactor = null;
var currentPolygonOffsetUnits = null;
var maxTextures = gl.getParameter( gl.MAX_COMBINED_TEXTURE_IMAGE_UNITS );
var lineWidthAvailable = false;
var version = 0;
var glVersion = gl.getParameter( gl.VERSION );
if ( glVersion.indexOf( 'WebGL' ) !== - 1 ) {
version = parseFloat( /^WebGL\ ([0-9])/.exec( glVersion )[ 1 ] );
lineWidthAvailable = ( version >= 1.0 );
} else if ( glVersion.indexOf( 'OpenGL ES' ) !== - 1 ) {
version = parseFloat( /^OpenGL\ ES\ ([0-9])/.exec( glVersion )[ 1 ] );
lineWidthAvailable = ( version >= 2.0 );
}
var currentTextureSlot = null;
var currentBoundTextures = {};
var currentScissor = new Vector4();
var currentViewport = new Vector4();
function createTexture( type, target, count ) {
var data = new Uint8Array( 4 ); // 4 is required to match default unpack alignment of 4.
var texture = gl.createTexture();
gl.bindTexture( type, texture );
gl.texParameteri( type, gl.TEXTURE_MIN_FILTER, gl.NEAREST );
gl.texParameteri( type, gl.TEXTURE_MAG_FILTER, gl.NEAREST );
for ( var i = 0; i < count; i ++ ) {
gl.texImage2D( target + i, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, data );
}
return texture;
}
var emptyTextures = {};
emptyTextures[ gl.TEXTURE_2D ] = createTexture( gl.TEXTURE_2D, gl.TEXTURE_2D, 1 );
emptyTextures[ gl.TEXTURE_CUBE_MAP ] = createTexture( gl.TEXTURE_CUBE_MAP, gl.TEXTURE_CUBE_MAP_POSITIVE_X, 6 );
// init
colorBuffer.setClear( 0, 0, 0, 1 );
depthBuffer.setClear( 1 );
stencilBuffer.setClear( 0 );
enable( gl.DEPTH_TEST );
depthBuffer.setFunc( LessEqualDepth );
setFlipSided( false );
setCullFace( CullFaceBack );
enable( gl.CULL_FACE );
setBlending( NoBlending );
//
function initAttributes() {
for ( var i = 0, l = newAttributes.length; i < l; i ++ ) {
newAttributes[ i ] = 0;
}
}
function enableAttribute( attribute ) {
enableAttributeAndDivisor( attribute, 0 );
}
function enableAttributeAndDivisor( attribute, meshPerAttribute ) {
newAttributes[ attribute ] = 1;
if ( enabledAttributes[ attribute ] === 0 ) {
gl.enableVertexAttribArray( attribute );
enabledAttributes[ attribute ] = 1;
}
if ( attributeDivisors[ attribute ] !== meshPerAttribute ) {
var extension = capabilities.isWebGL2 ? gl : extensions.get( 'ANGLE_instanced_arrays' );
extension[ capabilities.isWebGL2 ? 'vertexAttribDivisor' : 'vertexAttribDivisorANGLE' ]( attribute, meshPerAttribute );
attributeDivisors[ attribute ] = meshPerAttribute;
}
}
function disableUnusedAttributes() {
for ( var i = 0, l = enabledAttributes.length; i !== l; ++ i ) {
if ( enabledAttributes[ i ] !== newAttributes[ i ] ) {
gl.disableVertexAttribArray( i );
enabledAttributes[ i ] = 0;
}
}
}
function enable( id ) {
if ( enabledCapabilities[ id ] !== true ) {
gl.enable( id );
enabledCapabilities[ id ] = true;
}
}
function disable( id ) {
if ( enabledCapabilities[ id ] !== false ) {
gl.disable( id );
enabledCapabilities[ id ] = false;
}
}
function getCompressedTextureFormats() {
if ( compressedTextureFormats === null ) {
compressedTextureFormats = [];
if ( extensions.get( 'WEBGL_compressed_texture_pvrtc' ) ||
extensions.get( 'WEBGL_compressed_texture_s3tc' ) ||
extensions.get( 'WEBGL_compressed_texture_etc1' ) ||
extensions.get( 'WEBGL_compressed_texture_astc' ) ) {
var formats = gl.getParameter( gl.COMPRESSED_TEXTURE_FORMATS );
for ( var i = 0; i < formats.length; i ++ ) {
compressedTextureFormats.push( formats[ i ] );
}
}
}
return compressedTextureFormats;
}
function useProgram( program ) {
if ( currentProgram !== program ) {
gl.useProgram( program );
currentProgram = program;
return true;
}
return false;
}
function setBlending( blending, blendEquation, blendSrc, blendDst, blendEquationAlpha, blendSrcAlpha, blendDstAlpha, premultipliedAlpha ) {
if ( blending === NoBlending ) {
if ( currentBlendingEnabled ) {
disable( gl.BLEND );
currentBlendingEnabled = false;
}
return;
}
if ( ! currentBlendingEnabled ) {
enable( gl.BLEND );
currentBlendingEnabled = true;
}
if ( blending !== CustomBlending ) {
if ( blending !== currentBlending || premultipliedAlpha !== currentPremultipledAlpha ) {
if ( currentBlendEquation !== AddEquation || currentBlendEquationAlpha !== AddEquation ) {
gl.blendEquation( gl.FUNC_ADD );
currentBlendEquation = AddEquation;
currentBlendEquationAlpha = AddEquation;
}
if ( premultipliedAlpha ) {
switch ( blending ) {
case NormalBlending:
gl.blendFuncSeparate( gl.ONE, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA );
break;
case AdditiveBlending:
gl.blendFunc( gl.ONE, gl.ONE );
break;
case SubtractiveBlending:
gl.blendFuncSeparate( gl.ZERO, gl.ZERO, gl.ONE_MINUS_SRC_COLOR, gl.ONE_MINUS_SRC_ALPHA );
break;
case MultiplyBlending:
gl.blendFuncSeparate( gl.ZERO, gl.SRC_COLOR, gl.ZERO, gl.SRC_ALPHA );
break;
default:
console.error( 'THREE.WebGLState: Invalid blending: ', blending );
break;
}
} else {
switch ( blending ) {
case NormalBlending:
gl.blendFuncSeparate( gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA );
break;
case AdditiveBlending:
gl.blendFunc( gl.SRC_ALPHA, gl.ONE );
break;
case SubtractiveBlending:
gl.blendFunc( gl.ZERO, gl.ONE_MINUS_SRC_COLOR );
break;
case MultiplyBlending:
gl.blendFunc( gl.ZERO, gl.SRC_COLOR );
break;
default:
console.error( 'THREE.WebGLState: Invalid blending: ', blending );
break;
}
}
currentBlendSrc = null;
currentBlendDst = null;
currentBlendSrcAlpha = null;
currentBlendDstAlpha = null;
currentBlending = blending;
currentPremultipledAlpha = premultipliedAlpha;
}
return;
}
// custom blending
blendEquationAlpha = blendEquationAlpha || blendEquation;
blendSrcAlpha = blendSrcAlpha || blendSrc;
blendDstAlpha = blendDstAlpha || blendDst;
if ( blendEquation !== currentBlendEquation || blendEquationAlpha !== currentBlendEquationAlpha ) {
gl.blendEquationSeparate( utils.convert( blendEquation ), utils.convert( blendEquationAlpha ) );
currentBlendEquation = blendEquation;
currentBlendEquationAlpha = blendEquationAlpha;
}
if ( blendSrc !== currentBlendSrc || blendDst !== currentBlendDst || blendSrcAlpha !== currentBlendSrcAlpha || blendDstAlpha !== currentBlendDstAlpha ) {
gl.blendFuncSeparate( utils.convert( blendSrc ), utils.convert( blendDst ), utils.convert( blendSrcAlpha ), utils.convert( blendDstAlpha ) );
currentBlendSrc = blendSrc;
currentBlendDst = blendDst;
currentBlendSrcAlpha = blendSrcAlpha;
currentBlendDstAlpha = blendDstAlpha;
}
currentBlending = blending;
currentPremultipledAlpha = null;
}
function setMaterial( material, frontFaceCW ) {
material.side === DoubleSide
? disable( gl.CULL_FACE )
: enable( gl.CULL_FACE );
var flipSided = ( material.side === BackSide );
if ( frontFaceCW ) flipSided = ! flipSided;
setFlipSided( flipSided );
( material.blending === NormalBlending && material.transparent === false )
? setBlending( NoBlending )
: setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst, material.blendEquationAlpha, material.blendSrcAlpha, material.blendDstAlpha, material.premultipliedAlpha );
depthBuffer.setFunc( material.depthFunc );
depthBuffer.setTest( material.depthTest );
depthBuffer.setMask( material.depthWrite );
colorBuffer.setMask( material.colorWrite );
setPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits );
}
//
function setFlipSided( flipSided ) {
if ( currentFlipSided !== flipSided ) {
if ( flipSided ) {
gl.frontFace( gl.CW );
} else {
gl.frontFace( gl.CCW );
}
currentFlipSided = flipSided;
}
}
function setCullFace( cullFace ) {
if ( cullFace !== CullFaceNone ) {
enable( gl.CULL_FACE );
if ( cullFace !== currentCullFace ) {
if ( cullFace === CullFaceBack ) {
gl.cullFace( gl.BACK );
} else if ( cullFace === CullFaceFront ) {
gl.cullFace( gl.FRONT );
} else {
gl.cullFace( gl.FRONT_AND_BACK );
}
}
} else {
disable( gl.CULL_FACE );
}
currentCullFace = cullFace;
}
function setLineWidth( width ) {
if ( width !== currentLineWidth ) {
if ( lineWidthAvailable ) gl.lineWidth( width );
currentLineWidth = width;
}
}
function setPolygonOffset( polygonOffset, factor, units ) {
if ( polygonOffset ) {
enable( gl.POLYGON_OFFSET_FILL );
if ( currentPolygonOffsetFactor !== factor || currentPolygonOffsetUnits !== units ) {
gl.polygonOffset( factor, units );
currentPolygonOffsetFactor = factor;
currentPolygonOffsetUnits = units;
}
} else {
disable( gl.POLYGON_OFFSET_FILL );
}
}
function setScissorTest( scissorTest ) {
if ( scissorTest ) {
enable( gl.SCISSOR_TEST );
} else {
disable( gl.SCISSOR_TEST );
}
}
// texture
function activeTexture( webglSlot ) {
if ( webglSlot === undefined ) webglSlot = gl.TEXTURE0 + maxTextures - 1;
if ( currentTextureSlot !== webglSlot ) {
gl.activeTexture( webglSlot );
currentTextureSlot = webglSlot;
}
}
function bindTexture( webglType, webglTexture ) {
if ( currentTextureSlot === null ) {
activeTexture();
}
var boundTexture = currentBoundTextures[ currentTextureSlot ];
if ( boundTexture === undefined ) {
boundTexture = { type: undefined, texture: undefined };
currentBoundTextures[ currentTextureSlot ] = boundTexture;
}
if ( boundTexture.type !== webglType || boundTexture.texture !== webglTexture ) {
gl.bindTexture( webglType, webglTexture || emptyTextures[ webglType ] );
boundTexture.type = webglType;
boundTexture.texture = webglTexture;
}
}
function compressedTexImage2D() {
try {
gl.compressedTexImage2D.apply( gl, arguments );
} catch ( error ) {
console.error( 'THREE.WebGLState:', error );
}
}
function texImage2D() {
try {
gl.texImage2D.apply( gl, arguments );
} catch ( error ) {
console.error( 'THREE.WebGLState:', error );
}
}
function texImage3D() {
try {
gl.texImage3D.apply( gl, arguments );
} catch ( error ) {
console.error( 'THREE.WebGLState:', error );
}
}
//
function scissor( scissor ) {
if ( currentScissor.equals( scissor ) === false ) {
gl.scissor( scissor.x, scissor.y, scissor.z, scissor.w );
currentScissor.copy( scissor );
}
}
function viewport( viewport ) {
if ( currentViewport.equals( viewport ) === false ) {
gl.viewport( viewport.x, viewport.y, viewport.z, viewport.w );
currentViewport.copy( viewport );
}
}
//
function reset() {
for ( var i = 0; i < enabledAttributes.length; i ++ ) {
if ( enabledAttributes[ i ] === 1 ) {
gl.disableVertexAttribArray( i );
enabledAttributes[ i ] = 0;
}
}
enabledCapabilities = {};
compressedTextureFormats = null;
currentTextureSlot = null;
currentBoundTextures = {};
currentProgram = null;
currentBlending = null;
currentFlipSided = null;
currentCullFace = null;
colorBuffer.reset();
depthBuffer.reset();
stencilBuffer.reset();
}
return {
buffers: {
color: colorBuffer,
depth: depthBuffer,
stencil: stencilBuffer
},
initAttributes: initAttributes,
enableAttribute: enableAttribute,
enableAttributeAndDivisor: enableAttributeAndDivisor,
disableUnusedAttributes: disableUnusedAttributes,
enable: enable,
disable: disable,
getCompressedTextureFormats: getCompressedTextureFormats,
useProgram: useProgram,
setBlending: setBlending,
setMaterial: setMaterial,
setFlipSided: setFlipSided,
setCullFace: setCullFace,
setLineWidth: setLineWidth,
setPolygonOffset: setPolygonOffset,
setScissorTest: setScissorTest,
activeTexture: activeTexture,
bindTexture: bindTexture,
compressedTexImage2D: compressedTexImage2D,
texImage2D: texImage2D,
texImage3D: texImage3D,
scissor: scissor,
viewport: viewport,
reset: reset
};
}
export { WebGLState };

View File

@ -0,0 +1,948 @@
/**
* @author mrdoob / http://mrdoob.com/
*/
import { LinearFilter, NearestFilter, RGBFormat, RGBAFormat, DepthFormat, DepthStencilFormat, UnsignedShortType, UnsignedIntType, UnsignedInt248Type, FloatType, HalfFloatType, ClampToEdgeWrapping, NearestMipMapLinearFilter, NearestMipMapNearestFilter } from '../../constants.js';
import { _Math } from '../../math/Math.js';
function WebGLTextures( _gl, extensions, state, properties, capabilities, utils, info ) {
var _videoTextures = {};
var _canvas;
//
function clampToMaxSize( image, maxSize ) {
if ( image.width > maxSize || image.height > maxSize ) {
if ( 'data' in image ) {
console.warn( 'THREE.WebGLRenderer: image in DataTexture is too big (' + image.width + 'x' + image.height + ').' );
return;
}
// 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.createElementNS( 'http://www.w3.org/1999/xhtml', '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.warn( 'THREE.WebGLRenderer: image is too big (' + image.width + 'x' + image.height + '). Resized to ' + canvas.width + 'x' + canvas.height );
return canvas;
}
return image;
}
function isPowerOfTwo( image ) {
return _Math.isPowerOfTwo( image.width ) && _Math.isPowerOfTwo( image.height );
}
function makePowerOfTwo( image ) {
if ( image instanceof HTMLImageElement || image instanceof HTMLCanvasElement || image instanceof ImageBitmap ) {
if ( _canvas === undefined ) _canvas = document.createElementNS( 'http://www.w3.org/1999/xhtml', 'canvas' );
_canvas.width = _Math.floorPowerOfTwo( image.width );
_canvas.height = _Math.floorPowerOfTwo( image.height );
var context = _canvas.getContext( '2d' );
context.drawImage( image, 0, 0, _canvas.width, _canvas.height );
console.warn( 'THREE.WebGLRenderer: image is not power of two (' + image.width + 'x' + image.height + '). Resized to ' + _canvas.width + 'x' + _canvas.height );
return _canvas;
}
return image;
}
function textureNeedsPowerOfTwo( texture ) {
if ( capabilities.isWebGL2 ) return false;
return ( texture.wrapS !== ClampToEdgeWrapping || texture.wrapT !== ClampToEdgeWrapping ) ||
( texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter );
}
function textureNeedsGenerateMipmaps( texture, isPowerOfTwo ) {
return texture.generateMipmaps && isPowerOfTwo &&
texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter;
}
function generateMipmap( target, texture, width, height ) {
_gl.generateMipmap( target );
var textureProperties = properties.get( texture );
// Note: Math.log( x ) * Math.LOG2E used instead of Math.log2( x ) which is not supported by IE11
textureProperties.__maxMipLevel = Math.log( Math.max( width, height ) ) * Math.LOG2E;
}
function getInternalFormat( glFormat, glType ) {
if ( ! capabilities.isWebGL2 ) return glFormat;
if ( glFormat === _gl.RED ) {
if ( glType === _gl.FLOAT ) return _gl.R32F;
if ( glType === _gl.HALF_FLOAT ) return _gl.R16F;
if ( glType === _gl.UNSIGNED_BYTE ) return _gl.R8;
}
if ( glFormat === _gl.RGB ) {
if ( glType === _gl.FLOAT ) return _gl.RGB32F;
if ( glType === _gl.HALF_FLOAT ) return _gl.RGB16F;
if ( glType === _gl.UNSIGNED_BYTE ) return _gl.RGB8;
}
if ( glFormat === _gl.RGBA ) {
if ( glType === _gl.FLOAT ) return _gl.RGBA32F;
if ( glType === _gl.HALF_FLOAT ) return _gl.RGBA16F;
if ( glType === _gl.UNSIGNED_BYTE ) return _gl.RGBA8;
}
return glFormat;
}
// Fallback filters for non-power-of-2 textures
function filterFallback( f ) {
if ( f === NearestFilter || f === NearestMipMapNearestFilter || f === NearestMipMapLinearFilter ) {
return _gl.NEAREST;
}
return _gl.LINEAR;
}
//
function onTextureDispose( event ) {
var texture = event.target;
texture.removeEventListener( 'dispose', onTextureDispose );
deallocateTexture( texture );
if ( texture.isVideoTexture ) {
delete _videoTextures[ texture.id ];
}
info.memory.textures --;
}
function onRenderTargetDispose( event ) {
var renderTarget = event.target;
renderTarget.removeEventListener( 'dispose', onRenderTargetDispose );
deallocateRenderTarget( renderTarget );
info.memory.textures --;
}
//
function deallocateTexture( texture ) {
var textureProperties = properties.get( texture );
if ( texture.image && textureProperties.__image__webglTextureCube ) {
// cube texture
_gl.deleteTexture( textureProperties.__image__webglTextureCube );
} else {
// 2D texture
if ( textureProperties.__webglInit === undefined ) return;
_gl.deleteTexture( textureProperties.__webglTexture );
}
// remove all webgl properties
properties.remove( texture );
}
function deallocateRenderTarget( renderTarget ) {
var renderTargetProperties = properties.get( renderTarget );
var textureProperties = properties.get( renderTarget.texture );
if ( ! renderTarget ) return;
if ( textureProperties.__webglTexture !== undefined ) {
_gl.deleteTexture( textureProperties.__webglTexture );
}
if ( renderTarget.depthTexture ) {
renderTarget.depthTexture.dispose();
}
if ( renderTarget.isWebGLRenderTargetCube ) {
for ( var i = 0; i < 6; i ++ ) {
_gl.deleteFramebuffer( renderTargetProperties.__webglFramebuffer[ i ] );
if ( renderTargetProperties.__webglDepthbuffer ) _gl.deleteRenderbuffer( renderTargetProperties.__webglDepthbuffer[ i ] );
}
} else {
_gl.deleteFramebuffer( renderTargetProperties.__webglFramebuffer );
if ( renderTargetProperties.__webglDepthbuffer ) _gl.deleteRenderbuffer( renderTargetProperties.__webglDepthbuffer );
}
properties.remove( renderTarget.texture );
properties.remove( renderTarget );
}
//
function setTexture2D( texture, slot ) {
var textureProperties = properties.get( texture );
if ( texture.isVideoTexture ) updateVideoTexture( texture );
if ( texture.version > 0 && textureProperties.__version !== texture.version ) {
var image = texture.image;
if ( image === undefined ) {
console.warn( 'THREE.WebGLRenderer: Texture marked for update but image is undefined' );
} else if ( image.complete === false ) {
console.warn( 'THREE.WebGLRenderer: Texture marked for update but image is incomplete' );
} else {
uploadTexture( textureProperties, texture, slot );
return;
}
}
state.activeTexture( _gl.TEXTURE0 + slot );
state.bindTexture( _gl.TEXTURE_2D, textureProperties.__webglTexture );
}
function setTexture3D( texture, slot ) {
var textureProperties = properties.get( texture );
if ( texture.version > 0 && textureProperties.__version !== texture.version ) {
uploadTexture( textureProperties, texture, slot );
return;
}
state.activeTexture( _gl.TEXTURE0 + slot );
state.bindTexture( _gl.TEXTURE_3D, textureProperties.__webglTexture );
}
function setTextureCube( texture, slot ) {
var textureProperties = properties.get( texture );
if ( texture.image.length === 6 ) {
if ( texture.version > 0 && textureProperties.__version !== texture.version ) {
if ( ! textureProperties.__image__webglTextureCube ) {
texture.addEventListener( 'dispose', onTextureDispose );
textureProperties.__image__webglTextureCube = _gl.createTexture();
info.memory.textures ++;
}
state.activeTexture( _gl.TEXTURE0 + slot );
state.bindTexture( _gl.TEXTURE_CUBE_MAP, textureProperties.__image__webglTextureCube );
_gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, texture.flipY );
var isCompressed = ( texture && texture.isCompressedTexture );
var isDataTexture = ( texture.image[ 0 ] && texture.image[ 0 ].isDataTexture );
var cubeImage = [];
for ( var i = 0; i < 6; i ++ ) {
if ( ! isCompressed && ! isDataTexture ) {
cubeImage[ i ] = clampToMaxSize( texture.image[ i ], capabilities.maxCubemapSize );
} else {
cubeImage[ i ] = isDataTexture ? texture.image[ i ].image : texture.image[ i ];
}
}
var image = cubeImage[ 0 ],
isPowerOfTwoImage = isPowerOfTwo( image ),
glFormat = utils.convert( texture.format ),
glType = utils.convert( texture.type ),
glInternalFormat = getInternalFormat( glFormat, glType );
setTextureParameters( _gl.TEXTURE_CUBE_MAP, texture, isPowerOfTwoImage );
for ( var i = 0; i < 6; i ++ ) {
if ( ! isCompressed ) {
if ( isDataTexture ) {
state.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glInternalFormat, cubeImage[ i ].width, cubeImage[ i ].height, 0, glFormat, glType, cubeImage[ i ].data );
} else {
state.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glInternalFormat, 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 !== RGBAFormat && texture.format !== RGBFormat ) {
if ( state.getCompressedTextureFormats().indexOf( glFormat ) > - 1 ) {
state.compressedTexImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glInternalFormat, mipmap.width, mipmap.height, 0, mipmap.data );
} else {
console.warn( 'THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .setTextureCube()' );
}
} else {
state.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glInternalFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data );
}
}
}
}
if ( ! isCompressed ) {
textureProperties.__maxMipLevel = 0;
} else {
textureProperties.__maxMipLevel = mipmaps.length - 1;
}
if ( textureNeedsGenerateMipmaps( texture, isPowerOfTwoImage ) ) {
// We assume images for cube map have the same size.
generateMipmap( _gl.TEXTURE_CUBE_MAP, texture, image.width, image.height );
}
textureProperties.__version = texture.version;
if ( texture.onUpdate ) texture.onUpdate( texture );
} else {
state.activeTexture( _gl.TEXTURE0 + slot );
state.bindTexture( _gl.TEXTURE_CUBE_MAP, textureProperties.__image__webglTextureCube );
}
}
}
function setTextureCubeDynamic( texture, slot ) {
state.activeTexture( _gl.TEXTURE0 + slot );
state.bindTexture( _gl.TEXTURE_CUBE_MAP, properties.get( texture ).__webglTexture );
}
function setTextureParameters( textureType, texture, isPowerOfTwoImage ) {
var extension;
if ( isPowerOfTwoImage ) {
_gl.texParameteri( textureType, _gl.TEXTURE_WRAP_S, utils.convert( texture.wrapS ) );
_gl.texParameteri( textureType, _gl.TEXTURE_WRAP_T, utils.convert( texture.wrapT ) );
_gl.texParameteri( textureType, _gl.TEXTURE_MAG_FILTER, utils.convert( texture.magFilter ) );
_gl.texParameteri( textureType, _gl.TEXTURE_MIN_FILTER, utils.convert( 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 );
if ( texture.wrapS !== ClampToEdgeWrapping || texture.wrapT !== ClampToEdgeWrapping ) {
console.warn( 'THREE.WebGLRenderer: Texture is not power of two. Texture.wrapS and Texture.wrapT should be set to THREE.ClampToEdgeWrapping.' );
}
_gl.texParameteri( textureType, _gl.TEXTURE_MAG_FILTER, filterFallback( texture.magFilter ) );
_gl.texParameteri( textureType, _gl.TEXTURE_MIN_FILTER, filterFallback( texture.minFilter ) );
if ( texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter ) {
console.warn( 'THREE.WebGLRenderer: Texture is not power of two. Texture.minFilter should be set to THREE.NearestFilter or THREE.LinearFilter.' );
}
}
extension = extensions.get( 'EXT_texture_filter_anisotropic' );
if ( extension ) {
if ( texture.type === FloatType && extensions.get( 'OES_texture_float_linear' ) === null ) return;
if ( texture.type === HalfFloatType && ( capabilities.isWebGL2 || extensions.get( 'OES_texture_half_float_linear' ) ) === null ) return;
if ( texture.anisotropy > 1 || properties.get( texture ).__currentAnisotropy ) {
_gl.texParameterf( textureType, extension.TEXTURE_MAX_ANISOTROPY_EXT, Math.min( texture.anisotropy, capabilities.getMaxAnisotropy() ) );
properties.get( texture ).__currentAnisotropy = texture.anisotropy;
}
}
}
function uploadTexture( textureProperties, texture, slot ) {
var textureType;
if ( texture.isDataTexture3D ) {
textureType = _gl.TEXTURE_3D;
} else {
textureType = _gl.TEXTURE_2D;
}
if ( textureProperties.__webglInit === undefined ) {
textureProperties.__webglInit = true;
texture.addEventListener( 'dispose', onTextureDispose );
textureProperties.__webglTexture = _gl.createTexture();
info.memory.textures ++;
}
state.activeTexture( _gl.TEXTURE0 + slot );
state.bindTexture( textureType, textureProperties.__webglTexture );
_gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, texture.flipY );
_gl.pixelStorei( _gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultiplyAlpha );
_gl.pixelStorei( _gl.UNPACK_ALIGNMENT, texture.unpackAlignment );
var image = clampToMaxSize( texture.image, capabilities.maxTextureSize );
if ( textureNeedsPowerOfTwo( texture ) && isPowerOfTwo( image ) === false ) {
image = makePowerOfTwo( image );
}
var isPowerOfTwoImage = isPowerOfTwo( image ),
glFormat = utils.convert( texture.format ),
glType = utils.convert( texture.type ),
glInternalFormat = getInternalFormat( glFormat, glType );
setTextureParameters( textureType, texture, isPowerOfTwoImage );
var mipmap, mipmaps = texture.mipmaps;
if ( texture.isDepthTexture ) {
// populate depth texture with dummy data
glInternalFormat = _gl.DEPTH_COMPONENT;
if ( texture.type === FloatType ) {
if ( ! capabilities.isWebGL2 ) throw new Error( 'Float Depth Texture only supported in WebGL2.0' );
glInternalFormat = _gl.DEPTH_COMPONENT32F;
} else if ( capabilities.isWebGL2 ) {
// WebGL 2.0 requires signed internalformat for glTexImage2D
glInternalFormat = _gl.DEPTH_COMPONENT16;
}
if ( texture.format === DepthFormat && glInternalFormat === _gl.DEPTH_COMPONENT ) {
// The error INVALID_OPERATION is generated by texImage2D if format and internalformat are
// DEPTH_COMPONENT and type is not UNSIGNED_SHORT or UNSIGNED_INT
// (https://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/)
if ( texture.type !== UnsignedShortType && texture.type !== UnsignedIntType ) {
console.warn( 'THREE.WebGLRenderer: Use UnsignedShortType or UnsignedIntType for DepthFormat DepthTexture.' );
texture.type = UnsignedShortType;
glType = utils.convert( texture.type );
}
}
// Depth stencil textures need the DEPTH_STENCIL internal format
// (https://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/)
if ( texture.format === DepthStencilFormat ) {
glInternalFormat = _gl.DEPTH_STENCIL;
// The error INVALID_OPERATION is generated by texImage2D if format and internalformat are
// DEPTH_STENCIL and type is not UNSIGNED_INT_24_8_WEBGL.
// (https://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/)
if ( texture.type !== UnsignedInt248Type ) {
console.warn( 'THREE.WebGLRenderer: Use UnsignedInt248Type for DepthStencilFormat DepthTexture.' );
texture.type = UnsignedInt248Type;
glType = utils.convert( texture.type );
}
}
state.texImage2D( _gl.TEXTURE_2D, 0, glInternalFormat, image.width, image.height, 0, glFormat, glType, null );
} else if ( texture.isDataTexture ) {
// 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 && isPowerOfTwoImage ) {
for ( var i = 0, il = mipmaps.length; i < il; i ++ ) {
mipmap = mipmaps[ i ];
state.texImage2D( _gl.TEXTURE_2D, i, glInternalFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data );
}
texture.generateMipmaps = false;
textureProperties.__maxMipLevel = mipmaps.length - 1;
} else {
state.texImage2D( _gl.TEXTURE_2D, 0, glInternalFormat, image.width, image.height, 0, glFormat, glType, image.data );
textureProperties.__maxMipLevel = 0;
}
} else if ( texture.isCompressedTexture ) {
for ( var i = 0, il = mipmaps.length; i < il; i ++ ) {
mipmap = mipmaps[ i ];
if ( texture.format !== RGBAFormat && texture.format !== RGBFormat ) {
if ( state.getCompressedTextureFormats().indexOf( glFormat ) > - 1 ) {
state.compressedTexImage2D( _gl.TEXTURE_2D, i, glInternalFormat, mipmap.width, mipmap.height, 0, mipmap.data );
} else {
console.warn( 'THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .uploadTexture()' );
}
} else {
state.texImage2D( _gl.TEXTURE_2D, i, glInternalFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data );
}
}
textureProperties.__maxMipLevel = mipmaps.length - 1;
} else if ( texture.isDataTexture3D ) {
state.texImage3D( _gl.TEXTURE_3D, 0, glInternalFormat, image.width, image.height, image.depth, 0, glFormat, glType, image.data );
textureProperties.__maxMipLevel = 0;
} 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 && isPowerOfTwoImage ) {
for ( var i = 0, il = mipmaps.length; i < il; i ++ ) {
mipmap = mipmaps[ i ];
state.texImage2D( _gl.TEXTURE_2D, i, glInternalFormat, glFormat, glType, mipmap );
}
texture.generateMipmaps = false;
textureProperties.__maxMipLevel = mipmaps.length - 1;
} else {
state.texImage2D( _gl.TEXTURE_2D, 0, glInternalFormat, glFormat, glType, image );
textureProperties.__maxMipLevel = 0;
}
}
if ( textureNeedsGenerateMipmaps( texture, isPowerOfTwoImage ) ) {
generateMipmap( _gl.TEXTURE_2D, texture, image.width, image.height );
}
textureProperties.__version = texture.version;
if ( texture.onUpdate ) texture.onUpdate( texture );
}
// Render targets
// Setup storage for target texture and bind it to correct framebuffer
function setupFrameBufferTexture( framebuffer, renderTarget, attachment, textureTarget ) {
var glFormat = utils.convert( renderTarget.texture.format );
var glType = utils.convert( renderTarget.texture.type );
var glInternalFormat = getInternalFormat( glFormat, glType );
state.texImage2D( textureTarget, 0, glInternalFormat, renderTarget.width, renderTarget.height, 0, glFormat, glType, null );
_gl.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );
_gl.framebufferTexture2D( _gl.FRAMEBUFFER, attachment, textureTarget, properties.get( renderTarget.texture ).__webglTexture, 0 );
_gl.bindFramebuffer( _gl.FRAMEBUFFER, null );
}
// Setup storage for internal depth/stencil buffers and bind to correct framebuffer
function setupRenderBufferStorage( 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 );
} 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 {
// FIXME: We don't support !depth !stencil
_gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.RGBA4, renderTarget.width, renderTarget.height );
}
_gl.bindRenderbuffer( _gl.RENDERBUFFER, null );
}
// Setup resources for a Depth Texture for a FBO (needs an extension)
function setupDepthTexture( framebuffer, renderTarget ) {
var isCube = ( renderTarget && renderTarget.isWebGLRenderTargetCube );
if ( isCube ) throw new Error( 'Depth Texture with cube render targets is not supported' );
_gl.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );
if ( ! ( renderTarget.depthTexture && renderTarget.depthTexture.isDepthTexture ) ) {
throw new Error( 'renderTarget.depthTexture must be an instance of THREE.DepthTexture' );
}
// upload an empty depth texture with framebuffer size
if ( ! properties.get( renderTarget.depthTexture ).__webglTexture ||
renderTarget.depthTexture.image.width !== renderTarget.width ||
renderTarget.depthTexture.image.height !== renderTarget.height ) {
renderTarget.depthTexture.image.width = renderTarget.width;
renderTarget.depthTexture.image.height = renderTarget.height;
renderTarget.depthTexture.needsUpdate = true;
}
setTexture2D( renderTarget.depthTexture, 0 );
var webglDepthTexture = properties.get( renderTarget.depthTexture ).__webglTexture;
if ( renderTarget.depthTexture.format === DepthFormat ) {
_gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.TEXTURE_2D, webglDepthTexture, 0 );
} else if ( renderTarget.depthTexture.format === DepthStencilFormat ) {
_gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.TEXTURE_2D, webglDepthTexture, 0 );
} else {
throw new Error( 'Unknown depthTexture format' );
}
}
// Setup GL resources for a non-texture depth buffer
function setupDepthRenderbuffer( renderTarget ) {
var renderTargetProperties = properties.get( renderTarget );
var isCube = ( renderTarget.isWebGLRenderTargetCube === true );
if ( renderTarget.depthTexture ) {
if ( isCube ) throw new Error( 'target.depthTexture not supported in Cube render targets' );
setupDepthTexture( renderTargetProperties.__webglFramebuffer, renderTarget );
} else {
if ( isCube ) {
renderTargetProperties.__webglDepthbuffer = [];
for ( var i = 0; i < 6; i ++ ) {
_gl.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglFramebuffer[ i ] );
renderTargetProperties.__webglDepthbuffer[ i ] = _gl.createRenderbuffer();
setupRenderBufferStorage( renderTargetProperties.__webglDepthbuffer[ i ], renderTarget );
}
} else {
_gl.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglFramebuffer );
renderTargetProperties.__webglDepthbuffer = _gl.createRenderbuffer();
setupRenderBufferStorage( renderTargetProperties.__webglDepthbuffer, renderTarget );
}
}
_gl.bindFramebuffer( _gl.FRAMEBUFFER, null );
}
// Set up GL resources for the render target
function setupRenderTarget( renderTarget ) {
var renderTargetProperties = properties.get( renderTarget );
var textureProperties = properties.get( renderTarget.texture );
renderTarget.addEventListener( 'dispose', onRenderTargetDispose );
textureProperties.__webglTexture = _gl.createTexture();
info.memory.textures ++;
var isCube = ( renderTarget.isWebGLRenderTargetCube === true );
var isTargetPowerOfTwo = isPowerOfTwo( renderTarget );
// Setup framebuffer
if ( isCube ) {
renderTargetProperties.__webglFramebuffer = [];
for ( var i = 0; i < 6; i ++ ) {
renderTargetProperties.__webglFramebuffer[ i ] = _gl.createFramebuffer();
}
} else {
renderTargetProperties.__webglFramebuffer = _gl.createFramebuffer();
}
// Setup color buffer
if ( isCube ) {
state.bindTexture( _gl.TEXTURE_CUBE_MAP, textureProperties.__webglTexture );
setTextureParameters( _gl.TEXTURE_CUBE_MAP, renderTarget.texture, isTargetPowerOfTwo );
for ( var i = 0; i < 6; i ++ ) {
setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer[ i ], renderTarget, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i );
}
if ( textureNeedsGenerateMipmaps( renderTarget.texture, isTargetPowerOfTwo ) ) {
generateMipmap( _gl.TEXTURE_CUBE_MAP, renderTarget.texture, renderTarget.width, renderTarget.height );
}
state.bindTexture( _gl.TEXTURE_CUBE_MAP, null );
} else {
state.bindTexture( _gl.TEXTURE_2D, textureProperties.__webglTexture );
setTextureParameters( _gl.TEXTURE_2D, renderTarget.texture, isTargetPowerOfTwo );
setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer, renderTarget, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_2D );
if ( textureNeedsGenerateMipmaps( renderTarget.texture, isTargetPowerOfTwo ) ) {
generateMipmap( _gl.TEXTURE_2D, renderTarget.texture, renderTarget.width, renderTarget.height );
}
state.bindTexture( _gl.TEXTURE_2D, null );
}
// Setup depth and stencil buffers
if ( renderTarget.depthBuffer ) {
setupDepthRenderbuffer( renderTarget );
}
}
function updateRenderTargetMipmap( renderTarget ) {
var texture = renderTarget.texture;
var isTargetPowerOfTwo = isPowerOfTwo( renderTarget );
if ( textureNeedsGenerateMipmaps( texture, isTargetPowerOfTwo ) ) {
var target = renderTarget.isWebGLRenderTargetCube ? _gl.TEXTURE_CUBE_MAP : _gl.TEXTURE_2D;
var webglTexture = properties.get( texture ).__webglTexture;
state.bindTexture( target, webglTexture );
generateMipmap( target, texture, renderTarget.width, renderTarget.height );
state.bindTexture( target, null );
}
}
function updateVideoTexture( texture ) {
var id = texture.id;
var frame = info.render.frame;
// Check the last frame we updated the VideoTexture
if ( _videoTextures[ id ] !== frame ) {
_videoTextures[ id ] = frame;
texture.update();
}
}
this.setTexture2D = setTexture2D;
this.setTexture3D = setTexture3D;
this.setTextureCube = setTextureCube;
this.setTextureCubeDynamic = setTextureCubeDynamic;
this.setupRenderTarget = setupRenderTarget;
this.updateRenderTargetMipmap = updateRenderTargetMipmap;
}
export { WebGLTextures };

View File

@ -0,0 +1,876 @@
/**
* @author tschw
* @author Mugen87 / https://github.com/Mugen87
* @author mrdoob / http://mrdoob.com/
*
* Uniforms of a program.
* Those form a tree structure with a special top-level container for the root,
* which you get by calling 'new WebGLUniforms( gl, program, renderer )'.
*
*
* Properties of inner nodes including the top-level container:
*
* .seq - array of nested uniforms
* .map - nested uniforms by name
*
*
* Methods of all nodes except the top-level container:
*
* .setValue( gl, value, [renderer] )
*
* uploads a uniform value(s)
* the 'renderer' parameter is needed for sampler uniforms
*
*
* Static methods of the top-level container (renderer factorizations):
*
* .upload( gl, seq, values, renderer )
*
* sets uniforms in 'seq' to 'values[id].value'
*
* .seqWithValue( seq, values ) : filteredSeq
*
* filters 'seq' entries with corresponding entry in values
*
*
* Methods of the top-level container (renderer factorizations):
*
* .setValue( gl, name, value )
*
* sets uniform with name 'name' to 'value'
*
* .set( gl, obj, prop )
*
* sets uniform from object and property with same name than uniform
*
* .setOptional( gl, obj, prop )
*
* like .set for an optional property of the object
*
*/
import { CubeTexture } from '../../textures/CubeTexture.js';
import { Texture } from '../../textures/Texture.js';
import { DataTexture3D } from '../../textures/DataTexture3D.js';
var emptyTexture = new Texture();
var emptyTexture3d = new DataTexture3D();
var emptyCubeTexture = new CubeTexture();
// --- Base for inner nodes (including the root) ---
function UniformContainer() {
this.seq = [];
this.map = {};
}
// --- Utilities ---
// Array Caches (provide typed arrays for temporary by size)
var arrayCacheF32 = [];
var arrayCacheI32 = [];
// Float32Array caches used for uploading Matrix uniforms
var mat4array = new Float32Array( 16 );
var mat3array = new Float32Array( 9 );
var mat2array = new Float32Array( 4 );
// Flattening for arrays of vectors and matrices
function flatten( array, nBlocks, blockSize ) {
var firstElem = array[ 0 ];
if ( firstElem <= 0 || firstElem > 0 ) return array;
// unoptimized: ! isNaN( firstElem )
// see http://jacksondunstan.com/articles/983
var n = nBlocks * blockSize,
r = arrayCacheF32[ n ];
if ( r === undefined ) {
r = new Float32Array( n );
arrayCacheF32[ n ] = r;
}
if ( nBlocks !== 0 ) {
firstElem.toArray( r, 0 );
for ( var i = 1, offset = 0; i !== nBlocks; ++ i ) {
offset += blockSize;
array[ i ].toArray( r, offset );
}
}
return r;
}
function arraysEqual( a, b ) {
if ( a.length !== b.length ) return false;
for ( var i = 0, l = a.length; i < l; i ++ ) {
if ( a[ i ] !== b[ i ] ) return false;
}
return true;
}
function copyArray( a, b ) {
for ( var i = 0, l = b.length; i < l; i ++ ) {
a[ i ] = b[ i ];
}
}
// Texture unit allocation
function allocTexUnits( renderer, n ) {
var r = arrayCacheI32[ n ];
if ( r === undefined ) {
r = new Int32Array( n );
arrayCacheI32[ n ] = r;
}
for ( var i = 0; i !== n; ++ i )
r[ i ] = renderer.allocTextureUnit();
return r;
}
// --- Setters ---
// Note: Defining these methods externally, because they come in a bunch
// and this way their names minify.
// Single scalar
function setValue1f( gl, v ) {
var cache = this.cache;
if ( cache[ 0 ] === v ) return;
gl.uniform1f( this.addr, v );
cache[ 0 ] = v;
}
function setValue1i( gl, v ) {
var cache = this.cache;
if ( cache[ 0 ] === v ) return;
gl.uniform1i( this.addr, v );
cache[ 0 ] = v;
}
// Single float vector (from flat array or THREE.VectorN)
function setValue2fv( gl, v ) {
var cache = this.cache;
if ( v.x !== undefined ) {
if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y ) {
gl.uniform2f( this.addr, v.x, v.y );
cache[ 0 ] = v.x;
cache[ 1 ] = v.y;
}
} else {
if ( arraysEqual( cache, v ) ) return;
gl.uniform2fv( this.addr, v );
copyArray( cache, v );
}
}
function setValue3fv( gl, v ) {
var cache = this.cache;
if ( v.x !== undefined ) {
if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y || cache[ 2 ] !== v.z ) {
gl.uniform3f( this.addr, v.x, v.y, v.z );
cache[ 0 ] = v.x;
cache[ 1 ] = v.y;
cache[ 2 ] = v.z;
}
} else if ( v.r !== undefined ) {
if ( cache[ 0 ] !== v.r || cache[ 1 ] !== v.g || cache[ 2 ] !== v.b ) {
gl.uniform3f( this.addr, v.r, v.g, v.b );
cache[ 0 ] = v.r;
cache[ 1 ] = v.g;
cache[ 2 ] = v.b;
}
} else {
if ( arraysEqual( cache, v ) ) return;
gl.uniform3fv( this.addr, v );
copyArray( cache, v );
}
}
function setValue4fv( gl, v ) {
var cache = this.cache;
if ( v.x !== undefined ) {
if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y || cache[ 2 ] !== v.z || cache[ 3 ] !== v.w ) {
gl.uniform4f( this.addr, v.x, v.y, v.z, v.w );
cache[ 0 ] = v.x;
cache[ 1 ] = v.y;
cache[ 2 ] = v.z;
cache[ 3 ] = v.w;
}
} else {
if ( arraysEqual( cache, v ) ) return;
gl.uniform4fv( this.addr, v );
copyArray( cache, v );
}
}
// Single matrix (from flat array or MatrixN)
function setValue2fm( gl, v ) {
var cache = this.cache;
var elements = v.elements;
if ( elements === undefined ) {
if ( arraysEqual( cache, v ) ) return;
gl.uniformMatrix2fv( this.addr, false, v );
copyArray( cache, v );
} else {
if ( arraysEqual( cache, elements ) ) return;
mat2array.set( elements );
gl.uniformMatrix2fv( this.addr, false, mat2array );
copyArray( cache, elements );
}
}
function setValue3fm( gl, v ) {
var cache = this.cache;
var elements = v.elements;
if ( elements === undefined ) {
if ( arraysEqual( cache, v ) ) return;
gl.uniformMatrix3fv( this.addr, false, v );
copyArray( cache, v );
} else {
if ( arraysEqual( cache, elements ) ) return;
mat3array.set( elements );
gl.uniformMatrix3fv( this.addr, false, mat3array );
copyArray( cache, elements );
}
}
function setValue4fm( gl, v ) {
var cache = this.cache;
var elements = v.elements;
if ( elements === undefined ) {
if ( arraysEqual( cache, v ) ) return;
gl.uniformMatrix4fv( this.addr, false, v );
copyArray( cache, v );
} else {
if ( arraysEqual( cache, elements ) ) return;
mat4array.set( elements );
gl.uniformMatrix4fv( this.addr, false, mat4array );
copyArray( cache, elements );
}
}
// Single texture (2D / Cube)
function setValueT1( gl, v, renderer ) {
var cache = this.cache;
var unit = renderer.allocTextureUnit();
if ( cache[ 0 ] !== unit ) {
gl.uniform1i( this.addr, unit );
cache[ 0 ] = unit;
}
renderer.setTexture2D( v || emptyTexture, unit );
}
function setValueT3D1( gl, v, renderer ) {
var cache = this.cache;
var unit = renderer.allocTextureUnit();
if ( cache[ 0 ] !== unit ) {
gl.uniform1i( this.addr, unit );
cache[ 0 ] = unit;
}
renderer.setTexture3D( v || emptyTexture3d, unit );
}
function setValueT6( gl, v, renderer ) {
var cache = this.cache;
var unit = renderer.allocTextureUnit();
if ( cache[ 0 ] !== unit ) {
gl.uniform1i( this.addr, unit );
cache[ 0 ] = unit;
}
renderer.setTextureCube( v || emptyCubeTexture, unit );
}
// Integer / Boolean vectors or arrays thereof (always flat arrays)
function setValue2iv( gl, v ) {
var cache = this.cache;
if ( arraysEqual( cache, v ) ) return;
gl.uniform2iv( this.addr, v );
copyArray( cache, v );
}
function setValue3iv( gl, v ) {
var cache = this.cache;
if ( arraysEqual( cache, v ) ) return;
gl.uniform3iv( this.addr, v );
copyArray( cache, v );
}
function setValue4iv( gl, v ) {
var cache = this.cache;
if ( arraysEqual( cache, v ) ) return;
gl.uniform4iv( this.addr, v );
copyArray( cache, v );
}
// Helper to pick the right setter for the singular case
function getSingularSetter( type ) {
switch ( type ) {
case 0x1406: return setValue1f; // FLOAT
case 0x8b50: return setValue2fv; // _VEC2
case 0x8b51: return setValue3fv; // _VEC3
case 0x8b52: return setValue4fv; // _VEC4
case 0x8b5a: return setValue2fm; // _MAT2
case 0x8b5b: return setValue3fm; // _MAT3
case 0x8b5c: return setValue4fm; // _MAT4
case 0x8b5e: case 0x8d66: return setValueT1; // SAMPLER_2D, SAMPLER_EXTERNAL_OES
case 0x8B5F: return setValueT3D1; // SAMPLER_3D
case 0x8b60: return setValueT6; // SAMPLER_CUBE
case 0x1404: case 0x8b56: return setValue1i; // INT, BOOL
case 0x8b53: case 0x8b57: return setValue2iv; // _VEC2
case 0x8b54: case 0x8b58: return setValue3iv; // _VEC3
case 0x8b55: case 0x8b59: return setValue4iv; // _VEC4
}
}
// Array of scalars
function setValue1fv( gl, v ) {
var cache = this.cache;
if ( arraysEqual( cache, v ) ) return;
gl.uniform1fv( this.addr, v );
copyArray( cache, v );
}
function setValue1iv( gl, v ) {
var cache = this.cache;
if ( arraysEqual( cache, v ) ) return;
gl.uniform1iv( this.addr, v );
copyArray( cache, v );
}
// Array of vectors (flat or from THREE classes)
function setValueV2a( gl, v ) {
var cache = this.cache;
var data = flatten( v, this.size, 2 );
if ( arraysEqual( cache, data ) ) return;
gl.uniform2fv( this.addr, data );
this.updateCache( data );
}
function setValueV3a( gl, v ) {
var cache = this.cache;
var data = flatten( v, this.size, 3 );
if ( arraysEqual( cache, data ) ) return;
gl.uniform3fv( this.addr, data );
this.updateCache( data );
}
function setValueV4a( gl, v ) {
var cache = this.cache;
var data = flatten( v, this.size, 4 );
if ( arraysEqual( cache, data ) ) return;
gl.uniform4fv( this.addr, data );
this.updateCache( data );
}
// Array of matrices (flat or from THREE clases)
function setValueM2a( gl, v ) {
var cache = this.cache;
var data = flatten( v, this.size, 4 );
if ( arraysEqual( cache, data ) ) return;
gl.uniformMatrix2fv( this.addr, false, data );
this.updateCache( data );
}
function setValueM3a( gl, v ) {
var cache = this.cache;
var data = flatten( v, this.size, 9 );
if ( arraysEqual( cache, data ) ) return;
gl.uniformMatrix3fv( this.addr, false, data );
this.updateCache( data );
}
function setValueM4a( gl, v ) {
var cache = this.cache;
var data = flatten( v, this.size, 16 );
if ( arraysEqual( cache, data ) ) return;
gl.uniformMatrix4fv( this.addr, false, data );
this.updateCache( data );
}
// Array of textures (2D / Cube)
function setValueT1a( gl, v, renderer ) {
var cache = this.cache;
var n = v.length;
var units = allocTexUnits( renderer, n );
if ( arraysEqual( cache, units ) === false ) {
gl.uniform1iv( this.addr, units );
copyArray( cache, units );
}
for ( var i = 0; i !== n; ++ i ) {
renderer.setTexture2D( v[ i ] || emptyTexture, units[ i ] );
}
}
function setValueT6a( gl, v, renderer ) {
var cache = this.cache;
var n = v.length;
var units = allocTexUnits( renderer, n );
if ( arraysEqual( cache, units ) === false ) {
gl.uniform1iv( this.addr, units );
copyArray( cache, units );
}
for ( var i = 0; i !== n; ++ i ) {
renderer.setTextureCube( v[ i ] || emptyCubeTexture, units[ i ] );
}
}
// Helper to pick the right setter for a pure (bottom-level) array
function getPureArraySetter( type ) {
switch ( type ) {
case 0x1406: return setValue1fv; // FLOAT
case 0x8b50: return setValueV2a; // _VEC2
case 0x8b51: return setValueV3a; // _VEC3
case 0x8b52: return setValueV4a; // _VEC4
case 0x8b5a: return setValueM2a; // _MAT2
case 0x8b5b: return setValueM3a; // _MAT3
case 0x8b5c: return setValueM4a; // _MAT4
case 0x8b5e: return setValueT1a; // SAMPLER_2D
case 0x8b60: return setValueT6a; // SAMPLER_CUBE
case 0x1404: case 0x8b56: return setValue1iv; // INT, BOOL
case 0x8b53: case 0x8b57: return setValue2iv; // _VEC2
case 0x8b54: case 0x8b58: return setValue3iv; // _VEC3
case 0x8b55: case 0x8b59: return setValue4iv; // _VEC4
}
}
// --- Uniform Classes ---
function SingleUniform( id, activeInfo, addr ) {
this.id = id;
this.addr = addr;
this.cache = [];
this.setValue = getSingularSetter( activeInfo.type );
// this.path = activeInfo.name; // DEBUG
}
function PureArrayUniform( id, activeInfo, addr ) {
this.id = id;
this.addr = addr;
this.cache = [];
this.size = activeInfo.size;
this.setValue = getPureArraySetter( activeInfo.type );
// this.path = activeInfo.name; // DEBUG
}
PureArrayUniform.prototype.updateCache = function ( data ) {
var cache = this.cache;
if ( data instanceof Float32Array && cache.length !== data.length ) {
this.cache = new Float32Array( data.length );
}
copyArray( cache, data );
};
function StructuredUniform( id ) {
this.id = id;
UniformContainer.call( this ); // mix-in
}
StructuredUniform.prototype.setValue = function ( gl, value, renderer ) {
var seq = this.seq;
for ( var i = 0, n = seq.length; i !== n; ++ i ) {
var u = seq[ i ];
u.setValue( gl, value[ u.id ], renderer );
}
};
// --- Top-level ---
// Parser - builds up the property tree from the path strings
var RePathPart = /([\w\d_]+)(\])?(\[|\.)?/g;
// extracts
// - the identifier (member name or array index)
// - followed by an optional right bracket (found when array index)
// - followed by an optional left bracket or dot (type of subscript)
//
// Note: These portions can be read in a non-overlapping fashion and
// allow straightforward parsing of the hierarchy that WebGL encodes
// in the uniform names.
function addUniform( container, uniformObject ) {
container.seq.push( uniformObject );
container.map[ uniformObject.id ] = uniformObject;
}
function parseUniform( activeInfo, addr, container ) {
var path = activeInfo.name,
pathLength = path.length;
// reset RegExp object, because of the early exit of a previous run
RePathPart.lastIndex = 0;
while ( true ) {
var match = RePathPart.exec( path ),
matchEnd = RePathPart.lastIndex,
id = match[ 1 ],
idIsIndex = match[ 2 ] === ']',
subscript = match[ 3 ];
if ( idIsIndex ) id = id | 0; // convert to integer
if ( subscript === undefined || subscript === '[' && matchEnd + 2 === pathLength ) {
// bare name or "pure" bottom-level array "[0]" suffix
addUniform( container, subscript === undefined ?
new SingleUniform( id, activeInfo, addr ) :
new PureArrayUniform( id, activeInfo, addr ) );
break;
} else {
// step into inner node / create it in case it doesn't exist
var map = container.map, next = map[ id ];
if ( next === undefined ) {
next = new StructuredUniform( id );
addUniform( container, next );
}
container = next;
}
}
}
// Root Container
function WebGLUniforms( gl, program, renderer ) {
UniformContainer.call( this );
this.renderer = renderer;
var n = gl.getProgramParameter( program, gl.ACTIVE_UNIFORMS );
for ( var i = 0; i < n; ++ i ) {
var info = gl.getActiveUniform( program, i ),
addr = gl.getUniformLocation( program, info.name );
parseUniform( info, addr, this );
}
}
WebGLUniforms.prototype.setValue = function ( gl, name, value ) {
var u = this.map[ name ];
if ( u !== undefined ) u.setValue( gl, value, this.renderer );
};
WebGLUniforms.prototype.setOptional = function ( gl, object, name ) {
var v = object[ name ];
if ( v !== undefined ) this.setValue( gl, name, v );
};
// Static interface
WebGLUniforms.upload = function ( gl, seq, values, renderer ) {
for ( var i = 0, n = seq.length; i !== n; ++ i ) {
var u = seq[ i ],
v = values[ u.id ];
if ( v.needsUpdate !== false ) {
// note: always updating when .needsUpdate is undefined
u.setValue( gl, v.value, renderer );
}
}
};
WebGLUniforms.seqWithValue = function ( seq, values ) {
var r = [];
for ( var i = 0, n = seq.length; i !== n; ++ i ) {
var u = seq[ i ];
if ( u.id in values ) r.push( u );
}
return r;
};
export { WebGLUniforms };

View File

@ -0,0 +1,168 @@
/**
* @author thespite / http://www.twitter.com/thespite
*/
import { MaxEquation, MinEquation, RGBA_ASTC_4x4_Format, RGBA_ASTC_5x4_Format, RGBA_ASTC_5x5_Format, RGBA_ASTC_6x5_Format, RGBA_ASTC_6x6_Format, RGBA_ASTC_8x5_Format, RGBA_ASTC_8x6_Format, RGBA_ASTC_8x8_Format, RGBA_ASTC_10x5_Format, RGBA_ASTC_10x6_Format, RGBA_ASTC_10x8_Format, RGBA_ASTC_10x10_Format, RGBA_ASTC_12x10_Format, RGBA_ASTC_12x12_Format, 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, RedFormat, RGBAFormat, RGBFormat, AlphaFormat, HalfFloatType, FloatType, UnsignedIntType, IntType, UnsignedShortType, ShortType, ByteType, UnsignedInt248Type, UnsignedShort565Type, UnsignedShort5551Type, UnsignedShort4444Type, UnsignedByteType, LinearMipMapLinearFilter, LinearMipMapNearestFilter, LinearFilter, NearestMipMapLinearFilter, NearestMipMapNearestFilter, NearestFilter, MirroredRepeatWrapping, ClampToEdgeWrapping, RepeatWrapping } from '../../constants.js';
function WebGLUtils( gl, extensions, capabilities ) {
function convert( p ) {
var extension;
if ( p === RepeatWrapping ) return gl.REPEAT;
if ( p === ClampToEdgeWrapping ) return gl.CLAMP_TO_EDGE;
if ( p === MirroredRepeatWrapping ) return gl.MIRRORED_REPEAT;
if ( p === NearestFilter ) return gl.NEAREST;
if ( p === NearestMipMapNearestFilter ) return gl.NEAREST_MIPMAP_NEAREST;
if ( p === NearestMipMapLinearFilter ) return gl.NEAREST_MIPMAP_LINEAR;
if ( p === LinearFilter ) return gl.LINEAR;
if ( p === LinearMipMapNearestFilter ) return gl.LINEAR_MIPMAP_NEAREST;
if ( p === LinearMipMapLinearFilter ) return gl.LINEAR_MIPMAP_LINEAR;
if ( p === UnsignedByteType ) return gl.UNSIGNED_BYTE;
if ( p === UnsignedShort4444Type ) return gl.UNSIGNED_SHORT_4_4_4_4;
if ( p === UnsignedShort5551Type ) return gl.UNSIGNED_SHORT_5_5_5_1;
if ( p === UnsignedShort565Type ) return gl.UNSIGNED_SHORT_5_6_5;
if ( p === ByteType ) return gl.BYTE;
if ( p === ShortType ) return gl.SHORT;
if ( p === UnsignedShortType ) return gl.UNSIGNED_SHORT;
if ( p === IntType ) return gl.INT;
if ( p === UnsignedIntType ) return gl.UNSIGNED_INT;
if ( p === FloatType ) return gl.FLOAT;
if ( p === HalfFloatType ) {
if ( capabilities.isWebGL2 ) return gl.HALF_FLOAT;
extension = extensions.get( 'OES_texture_half_float' );
if ( extension !== null ) return extension.HALF_FLOAT_OES;
}
if ( p === AlphaFormat ) return gl.ALPHA;
if ( p === RGBFormat ) return gl.RGB;
if ( p === RGBAFormat ) return gl.RGBA;
if ( p === LuminanceFormat ) return gl.LUMINANCE;
if ( p === LuminanceAlphaFormat ) return gl.LUMINANCE_ALPHA;
if ( p === DepthFormat ) return gl.DEPTH_COMPONENT;
if ( p === DepthStencilFormat ) return gl.DEPTH_STENCIL;
if ( p === RedFormat ) return gl.RED;
if ( p === AddEquation ) return gl.FUNC_ADD;
if ( p === SubtractEquation ) return gl.FUNC_SUBTRACT;
if ( p === ReverseSubtractEquation ) return gl.FUNC_REVERSE_SUBTRACT;
if ( p === ZeroFactor ) return gl.ZERO;
if ( p === OneFactor ) return gl.ONE;
if ( p === SrcColorFactor ) return gl.SRC_COLOR;
if ( p === OneMinusSrcColorFactor ) return gl.ONE_MINUS_SRC_COLOR;
if ( p === SrcAlphaFactor ) return gl.SRC_ALPHA;
if ( p === OneMinusSrcAlphaFactor ) return gl.ONE_MINUS_SRC_ALPHA;
if ( p === DstAlphaFactor ) return gl.DST_ALPHA;
if ( p === OneMinusDstAlphaFactor ) return gl.ONE_MINUS_DST_ALPHA;
if ( p === DstColorFactor ) return gl.DST_COLOR;
if ( p === OneMinusDstColorFactor ) return gl.ONE_MINUS_DST_COLOR;
if ( p === SrcAlphaSaturateFactor ) return gl.SRC_ALPHA_SATURATE;
if ( p === RGB_S3TC_DXT1_Format || p === RGBA_S3TC_DXT1_Format ||
p === RGBA_S3TC_DXT3_Format || p === RGBA_S3TC_DXT5_Format ) {
extension = extensions.get( 'WEBGL_compressed_texture_s3tc' );
if ( extension !== null ) {
if ( p === RGB_S3TC_DXT1_Format ) return extension.COMPRESSED_RGB_S3TC_DXT1_EXT;
if ( p === RGBA_S3TC_DXT1_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT1_EXT;
if ( p === RGBA_S3TC_DXT3_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT3_EXT;
if ( p === RGBA_S3TC_DXT5_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT5_EXT;
}
}
if ( p === RGB_PVRTC_4BPPV1_Format || p === RGB_PVRTC_2BPPV1_Format ||
p === RGBA_PVRTC_4BPPV1_Format || p === RGBA_PVRTC_2BPPV1_Format ) {
extension = extensions.get( 'WEBGL_compressed_texture_pvrtc' );
if ( extension !== null ) {
if ( p === RGB_PVRTC_4BPPV1_Format ) return extension.COMPRESSED_RGB_PVRTC_4BPPV1_IMG;
if ( p === RGB_PVRTC_2BPPV1_Format ) return extension.COMPRESSED_RGB_PVRTC_2BPPV1_IMG;
if ( p === RGBA_PVRTC_4BPPV1_Format ) return extension.COMPRESSED_RGBA_PVRTC_4BPPV1_IMG;
if ( p === RGBA_PVRTC_2BPPV1_Format ) return extension.COMPRESSED_RGBA_PVRTC_2BPPV1_IMG;
}
}
if ( p === RGB_ETC1_Format ) {
extension = extensions.get( 'WEBGL_compressed_texture_etc1' );
if ( extension !== null ) return extension.COMPRESSED_RGB_ETC1_WEBGL;
}
if ( p === RGBA_ASTC_4x4_Format || p === RGBA_ASTC_5x4_Format || p === RGBA_ASTC_5x5_Format ||
p === RGBA_ASTC_6x5_Format || p === RGBA_ASTC_6x6_Format || p === RGBA_ASTC_8x5_Format ||
p === RGBA_ASTC_8x6_Format || p === RGBA_ASTC_8x8_Format || p === RGBA_ASTC_10x5_Format ||
p === RGBA_ASTC_10x6_Format || p === RGBA_ASTC_10x8_Format || p === RGBA_ASTC_10x10_Format ||
p === RGBA_ASTC_12x10_Format || p === RGBA_ASTC_12x12_Format ) {
extension = extensions.get( 'WEBGL_compressed_texture_astc' );
if ( extension !== null ) {
return p;
}
}
if ( p === MinEquation || p === MaxEquation ) {
if ( capabilities.isWebGL2 ) {
if ( p === MinEquation ) return gl.MIN;
if ( p === MaxEquation ) return gl.MAX;
}
extension = extensions.get( 'EXT_blend_minmax' );
if ( extension !== null ) {
if ( p === MinEquation ) return extension.MIN_EXT;
if ( p === MaxEquation ) return extension.MAX_EXT;
}
}
if ( p === UnsignedInt248Type ) {
if ( capabilities.isWebGL2 ) return gl.UNSIGNED_INT_24_8;
extension = extensions.get( 'WEBGL_depth_texture' );
if ( extension !== null ) return extension.UNSIGNED_INT_24_8_WEBGL;
}
return 0;
}
return { convert: convert };
}
export { WebGLUtils };