|
@@ -20339,7 +20339,6 @@ THREE.WebGLRenderer = function ( parameters ) {
|
|
|
var _this = this,
|
|
|
|
|
|
_programs = [],
|
|
|
- _programs_counter = 0,
|
|
|
|
|
|
// internal state cache
|
|
|
|
|
@@ -24317,6 +24316,9 @@ THREE.WebGLRenderer = function ( parameters ) {
|
|
|
|
|
|
parameters = {
|
|
|
|
|
|
+ precision: _precision,
|
|
|
+ supportsVertexTextures: _supportsVertexTextures,
|
|
|
+
|
|
|
map: !!material.map,
|
|
|
envMap: !!material.envMap,
|
|
|
lightMap: !!material.lightMap,
|
|
@@ -24360,7 +24362,66 @@ THREE.WebGLRenderer = function ( parameters ) {
|
|
|
|
|
|
};
|
|
|
|
|
|
- material.program = buildProgram( shaderID, material.fragmentShader, material.vertexShader, material.uniforms, material.attributes, material.defines, parameters, material.index0AttributeName );
|
|
|
+ // Generate code
|
|
|
+
|
|
|
+ var chunks = [];
|
|
|
+
|
|
|
+ if ( shaderID ) {
|
|
|
+
|
|
|
+ chunks.push( shaderID );
|
|
|
+
|
|
|
+ } else {
|
|
|
+
|
|
|
+ chunks.push( material.fragmentShader );
|
|
|
+ chunks.push( material.vertexShader );
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ for ( var d in material.defines ) {
|
|
|
+
|
|
|
+ chunks.push( d );
|
|
|
+ chunks.push( material.defines[ d ] );
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ for ( var p in parameters ) {
|
|
|
+
|
|
|
+ chunks.push( p );
|
|
|
+ chunks.push( parameters[ p ] );
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ var code = chunks.join();
|
|
|
+
|
|
|
+ var program;
|
|
|
+
|
|
|
+ // Check if code has been already compiled
|
|
|
+
|
|
|
+ for ( var p = 0, pl = _programs.length; p < pl; p ++ ) {
|
|
|
+
|
|
|
+ var programInfo = _programs[ p ];
|
|
|
+
|
|
|
+ if ( programInfo.code === code ) {
|
|
|
+
|
|
|
+ program = programInfo;
|
|
|
+ program.usedTimes ++;
|
|
|
+
|
|
|
+ break;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ if ( program === undefined ) {
|
|
|
+
|
|
|
+ program = new THREE.WebGLProgram( this, code, material, parameters );
|
|
|
+ _programs.push( program );
|
|
|
+
|
|
|
+ _this.info.memory.programs = _programs.length;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ material.program = program;
|
|
|
|
|
|
var attributes = material.program.attributes;
|
|
|
|
|
@@ -24451,10 +24512,10 @@ THREE.WebGLRenderer = function ( parameters ) {
|
|
|
p_uniforms = program.uniforms,
|
|
|
m_uniforms = material.uniforms;
|
|
|
|
|
|
- if ( program !== _currentProgram ) {
|
|
|
+ if ( program.id !== _currentProgram ) {
|
|
|
|
|
|
- _gl.useProgram( program );
|
|
|
- _currentProgram = program;
|
|
|
+ _gl.useProgram( program.program );
|
|
|
+ _currentProgram = program.id;
|
|
|
|
|
|
refreshMaterial = true;
|
|
|
|
|
@@ -25590,1238 +25651,1191 @@ THREE.WebGLRenderer = function ( parameters ) {
|
|
|
|
|
|
};
|
|
|
|
|
|
- // Defines
|
|
|
+ // Textures
|
|
|
|
|
|
- function generateDefines ( defines ) {
|
|
|
+ function setTextureParameters ( textureType, texture, isImagePowerOfTwo ) {
|
|
|
|
|
|
- var value, chunk, chunks = [];
|
|
|
+ if ( isImagePowerOfTwo ) {
|
|
|
|
|
|
- for ( var d in defines ) {
|
|
|
+ _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_S, paramThreeToGL( texture.wrapS ) );
|
|
|
+ _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_T, paramThreeToGL( texture.wrapT ) );
|
|
|
|
|
|
- value = defines[ d ];
|
|
|
- if ( value === false ) continue;
|
|
|
+ _gl.texParameteri( textureType, _gl.TEXTURE_MAG_FILTER, paramThreeToGL( texture.magFilter ) );
|
|
|
+ _gl.texParameteri( textureType, _gl.TEXTURE_MIN_FILTER, paramThreeToGL( texture.minFilter ) );
|
|
|
|
|
|
- chunk = "#define " + d + " " + value;
|
|
|
- chunks.push( chunk );
|
|
|
+ } else {
|
|
|
|
|
|
- }
|
|
|
+ _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_S, _gl.CLAMP_TO_EDGE );
|
|
|
+ _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_T, _gl.CLAMP_TO_EDGE );
|
|
|
|
|
|
- return chunks.join( "\n" );
|
|
|
+ _gl.texParameteri( textureType, _gl.TEXTURE_MAG_FILTER, filterFallback( texture.magFilter ) );
|
|
|
+ _gl.texParameteri( textureType, _gl.TEXTURE_MIN_FILTER, filterFallback( texture.minFilter ) );
|
|
|
|
|
|
- };
|
|
|
+ }
|
|
|
|
|
|
- // Shaders
|
|
|
+ if ( _glExtensionTextureFilterAnisotropic && texture.type !== THREE.FloatType ) {
|
|
|
|
|
|
- function buildProgram( shaderID, fragmentShader, vertexShader, uniforms, attributes, defines, parameters, index0AttributeName ) {
|
|
|
+ if ( texture.anisotropy > 1 || texture.__oldAnisotropy ) {
|
|
|
|
|
|
- var p, pl, d, program, code;
|
|
|
- var chunks = [];
|
|
|
+ _gl.texParameterf( textureType, _glExtensionTextureFilterAnisotropic.TEXTURE_MAX_ANISOTROPY_EXT, Math.min( texture.anisotropy, _maxAnisotropy ) );
|
|
|
+ texture.__oldAnisotropy = texture.anisotropy;
|
|
|
|
|
|
- // Generate code
|
|
|
+ }
|
|
|
|
|
|
- if ( shaderID ) {
|
|
|
+ }
|
|
|
|
|
|
- chunks.push( shaderID );
|
|
|
+ };
|
|
|
|
|
|
- } else {
|
|
|
+ this.setTexture = function ( texture, slot ) {
|
|
|
|
|
|
- chunks.push( fragmentShader );
|
|
|
- chunks.push( vertexShader );
|
|
|
+ if ( texture.needsUpdate ) {
|
|
|
|
|
|
- }
|
|
|
+ if ( ! texture.__webglInit ) {
|
|
|
|
|
|
- for ( d in defines ) {
|
|
|
+ texture.__webglInit = true;
|
|
|
|
|
|
- chunks.push( d );
|
|
|
- chunks.push( defines[ d ] );
|
|
|
+ texture.addEventListener( 'dispose', onTextureDispose );
|
|
|
|
|
|
- }
|
|
|
+ texture.__webglTexture = _gl.createTexture();
|
|
|
|
|
|
- for ( p in parameters ) {
|
|
|
+ _this.info.memory.textures ++;
|
|
|
|
|
|
- chunks.push( p );
|
|
|
- chunks.push( parameters[ p ] );
|
|
|
+ }
|
|
|
|
|
|
- }
|
|
|
+ _gl.activeTexture( _gl.TEXTURE0 + slot );
|
|
|
+ _gl.bindTexture( _gl.TEXTURE_2D, texture.__webglTexture );
|
|
|
|
|
|
- code = chunks.join();
|
|
|
+ _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 );
|
|
|
|
|
|
- // Check if code has been already compiled
|
|
|
+ var image = texture.image,
|
|
|
+ isImagePowerOfTwo = THREE.Math.isPowerOfTwo( image.width ) && THREE.Math.isPowerOfTwo( image.height ),
|
|
|
+ glFormat = paramThreeToGL( texture.format ),
|
|
|
+ glType = paramThreeToGL( texture.type );
|
|
|
|
|
|
- for ( p = 0, pl = _programs.length; p < pl; p ++ ) {
|
|
|
+ setTextureParameters( _gl.TEXTURE_2D, texture, isImagePowerOfTwo );
|
|
|
|
|
|
- var programInfo = _programs[ p ];
|
|
|
+ var mipmap, mipmaps = texture.mipmaps;
|
|
|
|
|
|
- if ( programInfo.code === code ) {
|
|
|
+ if ( texture instanceof THREE.DataTexture ) {
|
|
|
|
|
|
- // console.log( "Code already compiled." /*: \n\n" + code*/ );
|
|
|
+ // 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
|
|
|
|
|
|
- programInfo.usedTimes ++;
|
|
|
+ if ( mipmaps.length > 0 && isImagePowerOfTwo ) {
|
|
|
|
|
|
- return programInfo.program;
|
|
|
+ for ( var i = 0, il = mipmaps.length; i < il; i ++ ) {
|
|
|
|
|
|
- }
|
|
|
+ mipmap = mipmaps[ i ];
|
|
|
+ _gl.texImage2D( _gl.TEXTURE_2D, i, glFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data );
|
|
|
|
|
|
- }
|
|
|
+ }
|
|
|
|
|
|
- var shadowMapTypeDefine = "SHADOWMAP_TYPE_BASIC";
|
|
|
+ texture.generateMipmaps = false;
|
|
|
|
|
|
- if ( parameters.shadowMapType === THREE.PCFShadowMap ) {
|
|
|
+ } else {
|
|
|
|
|
|
- shadowMapTypeDefine = "SHADOWMAP_TYPE_PCF";
|
|
|
+ _gl.texImage2D( _gl.TEXTURE_2D, 0, glFormat, image.width, image.height, 0, glFormat, glType, image.data );
|
|
|
|
|
|
- } else if ( parameters.shadowMapType === THREE.PCFSoftShadowMap ) {
|
|
|
+ }
|
|
|
|
|
|
- shadowMapTypeDefine = "SHADOWMAP_TYPE_PCF_SOFT";
|
|
|
+ } else if ( texture instanceof THREE.CompressedTexture ) {
|
|
|
|
|
|
- }
|
|
|
+ for( var i = 0, il = mipmaps.length; i < il; i ++ ) {
|
|
|
|
|
|
- // console.log( "building new program " );
|
|
|
+ mipmap = mipmaps[ i ];
|
|
|
+ if ( texture.format!==THREE.RGBAFormat ) {
|
|
|
+ _gl.compressedTexImage2D( _gl.TEXTURE_2D, i, glFormat, mipmap.width, mipmap.height, 0, mipmap.data );
|
|
|
+ } else {
|
|
|
+ _gl.texImage2D( _gl.TEXTURE_2D, i, glFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data );
|
|
|
+ }
|
|
|
|
|
|
- //
|
|
|
+ }
|
|
|
|
|
|
- var customDefines = generateDefines( defines );
|
|
|
+ } 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
|
|
|
|
|
|
- program = _gl.createProgram();
|
|
|
+ if ( mipmaps.length > 0 && isImagePowerOfTwo ) {
|
|
|
|
|
|
- var prefix_vertex = [
|
|
|
+ for ( var i = 0, il = mipmaps.length; i < il; i ++ ) {
|
|
|
|
|
|
- "precision " + _precision + " float;",
|
|
|
- "precision " + _precision + " int;",
|
|
|
+ mipmap = mipmaps[ i ];
|
|
|
+ _gl.texImage2D( _gl.TEXTURE_2D, i, glFormat, glFormat, glType, mipmap );
|
|
|
|
|
|
- customDefines,
|
|
|
+ }
|
|
|
|
|
|
- _supportsVertexTextures ? "#define VERTEX_TEXTURES" : "",
|
|
|
+ texture.generateMipmaps = false;
|
|
|
|
|
|
- _this.gammaInput ? "#define GAMMA_INPUT" : "",
|
|
|
- _this.gammaOutput ? "#define GAMMA_OUTPUT" : "",
|
|
|
+ } else {
|
|
|
|
|
|
- "#define MAX_DIR_LIGHTS " + parameters.maxDirLights,
|
|
|
- "#define MAX_POINT_LIGHTS " + parameters.maxPointLights,
|
|
|
- "#define MAX_SPOT_LIGHTS " + parameters.maxSpotLights,
|
|
|
- "#define MAX_HEMI_LIGHTS " + parameters.maxHemiLights,
|
|
|
+ _gl.texImage2D( _gl.TEXTURE_2D, 0, glFormat, glFormat, glType, texture.image );
|
|
|
|
|
|
- "#define MAX_SHADOWS " + parameters.maxShadows,
|
|
|
+ }
|
|
|
|
|
|
- "#define MAX_BONES " + parameters.maxBones,
|
|
|
+ }
|
|
|
|
|
|
- parameters.map ? "#define USE_MAP" : "",
|
|
|
- parameters.envMap ? "#define USE_ENVMAP" : "",
|
|
|
- parameters.lightMap ? "#define USE_LIGHTMAP" : "",
|
|
|
- parameters.bumpMap ? "#define USE_BUMPMAP" : "",
|
|
|
- parameters.normalMap ? "#define USE_NORMALMAP" : "",
|
|
|
- parameters.specularMap ? "#define USE_SPECULARMAP" : "",
|
|
|
- parameters.vertexColors ? "#define USE_COLOR" : "",
|
|
|
+ if ( texture.generateMipmaps && isImagePowerOfTwo ) _gl.generateMipmap( _gl.TEXTURE_2D );
|
|
|
|
|
|
- parameters.skinning ? "#define USE_SKINNING" : "",
|
|
|
- parameters.useVertexTexture ? "#define BONE_TEXTURE" : "",
|
|
|
+ texture.needsUpdate = false;
|
|
|
|
|
|
- parameters.morphTargets ? "#define USE_MORPHTARGETS" : "",
|
|
|
- parameters.morphNormals ? "#define USE_MORPHNORMALS" : "",
|
|
|
- parameters.wrapAround ? "#define WRAP_AROUND" : "",
|
|
|
- parameters.doubleSided ? "#define DOUBLE_SIDED" : "",
|
|
|
- parameters.flipSided ? "#define FLIP_SIDED" : "",
|
|
|
+ if ( texture.onUpdate ) texture.onUpdate();
|
|
|
|
|
|
- parameters.shadowMapEnabled ? "#define USE_SHADOWMAP" : "",
|
|
|
- parameters.shadowMapEnabled ? "#define " + shadowMapTypeDefine : "",
|
|
|
- parameters.shadowMapDebug ? "#define SHADOWMAP_DEBUG" : "",
|
|
|
- parameters.shadowMapCascade ? "#define SHADOWMAP_CASCADE" : "",
|
|
|
+ } else {
|
|
|
|
|
|
- parameters.sizeAttenuation ? "#define USE_SIZEATTENUATION" : "",
|
|
|
+ _gl.activeTexture( _gl.TEXTURE0 + slot );
|
|
|
+ _gl.bindTexture( _gl.TEXTURE_2D, texture.__webglTexture );
|
|
|
|
|
|
- "uniform mat4 modelMatrix;",
|
|
|
- "uniform mat4 modelViewMatrix;",
|
|
|
- "uniform mat4 projectionMatrix;",
|
|
|
- "uniform mat4 viewMatrix;",
|
|
|
- "uniform mat3 normalMatrix;",
|
|
|
- "uniform vec3 cameraPosition;",
|
|
|
+ }
|
|
|
|
|
|
- "attribute vec3 position;",
|
|
|
- "attribute vec3 normal;",
|
|
|
- "attribute vec2 uv;",
|
|
|
- "attribute vec2 uv2;",
|
|
|
+ };
|
|
|
|
|
|
- "#ifdef USE_COLOR",
|
|
|
+ function clampToMaxSize ( image, maxSize ) {
|
|
|
|
|
|
- " attribute vec3 color;",
|
|
|
+ if ( image.width <= maxSize && image.height <= maxSize ) {
|
|
|
|
|
|
- "#endif",
|
|
|
+ return image;
|
|
|
|
|
|
- "#ifdef USE_MORPHTARGETS",
|
|
|
+ }
|
|
|
|
|
|
- " attribute vec3 morphTarget0;",
|
|
|
- " attribute vec3 morphTarget1;",
|
|
|
- " attribute vec3 morphTarget2;",
|
|
|
- " attribute vec3 morphTarget3;",
|
|
|
+ // Warning: Scaling through the canvas will only work with images that use
|
|
|
+ // premultiplied alpha.
|
|
|
|
|
|
- " #ifdef USE_MORPHNORMALS",
|
|
|
+ var maxDimension = Math.max( image.width, image.height );
|
|
|
+ var newWidth = Math.floor( image.width * maxSize / maxDimension );
|
|
|
+ var newHeight = Math.floor( image.height * maxSize / maxDimension );
|
|
|
|
|
|
- " attribute vec3 morphNormal0;",
|
|
|
- " attribute vec3 morphNormal1;",
|
|
|
- " attribute vec3 morphNormal2;",
|
|
|
- " attribute vec3 morphNormal3;",
|
|
|
+ var canvas = document.createElement( 'canvas' );
|
|
|
+ canvas.width = newWidth;
|
|
|
+ canvas.height = newHeight;
|
|
|
|
|
|
- " #else",
|
|
|
+ var ctx = canvas.getContext( "2d" );
|
|
|
+ ctx.drawImage( image, 0, 0, image.width, image.height, 0, 0, newWidth, newHeight );
|
|
|
|
|
|
- " attribute vec3 morphTarget4;",
|
|
|
- " attribute vec3 morphTarget5;",
|
|
|
- " attribute vec3 morphTarget6;",
|
|
|
- " attribute vec3 morphTarget7;",
|
|
|
+ return canvas;
|
|
|
|
|
|
- " #endif",
|
|
|
+ }
|
|
|
|
|
|
- "#endif",
|
|
|
+ function setCubeTexture ( texture, slot ) {
|
|
|
|
|
|
- "#ifdef USE_SKINNING",
|
|
|
+ if ( texture.image.length === 6 ) {
|
|
|
|
|
|
- " attribute vec4 skinIndex;",
|
|
|
- " attribute vec4 skinWeight;",
|
|
|
+ if ( texture.needsUpdate ) {
|
|
|
|
|
|
- "#endif",
|
|
|
+ if ( ! texture.image.__webglTextureCube ) {
|
|
|
|
|
|
- ""
|
|
|
+ texture.addEventListener( 'dispose', onTextureDispose );
|
|
|
|
|
|
- ].join("\n");
|
|
|
+ texture.image.__webglTextureCube = _gl.createTexture();
|
|
|
|
|
|
- var prefix_fragment = [
|
|
|
+ _this.info.memory.textures ++;
|
|
|
|
|
|
- "precision " + _precision + " float;",
|
|
|
- "precision " + _precision + " int;",
|
|
|
+ }
|
|
|
|
|
|
- ( parameters.bumpMap || parameters.normalMap ) ? "#extension GL_OES_standard_derivatives : enable" : "",
|
|
|
+ _gl.activeTexture( _gl.TEXTURE0 + slot );
|
|
|
+ _gl.bindTexture( _gl.TEXTURE_CUBE_MAP, texture.image.__webglTextureCube );
|
|
|
|
|
|
- customDefines,
|
|
|
-
|
|
|
- "#define MAX_DIR_LIGHTS " + parameters.maxDirLights,
|
|
|
- "#define MAX_POINT_LIGHTS " + parameters.maxPointLights,
|
|
|
- "#define MAX_SPOT_LIGHTS " + parameters.maxSpotLights,
|
|
|
- "#define MAX_HEMI_LIGHTS " + parameters.maxHemiLights,
|
|
|
+ _gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, texture.flipY );
|
|
|
|
|
|
- "#define MAX_SHADOWS " + parameters.maxShadows,
|
|
|
+ var isCompressed = texture instanceof THREE.CompressedTexture;
|
|
|
|
|
|
- parameters.alphaTest ? "#define ALPHATEST " + parameters.alphaTest: "",
|
|
|
+ var cubeImage = [];
|
|
|
|
|
|
- _this.gammaInput ? "#define GAMMA_INPUT" : "",
|
|
|
- _this.gammaOutput ? "#define GAMMA_OUTPUT" : "",
|
|
|
+ for ( var i = 0; i < 6; i ++ ) {
|
|
|
|
|
|
- ( parameters.useFog && parameters.fog ) ? "#define USE_FOG" : "",
|
|
|
- ( parameters.useFog && parameters.fogExp ) ? "#define FOG_EXP2" : "",
|
|
|
+ if ( _this.autoScaleCubemaps && ! isCompressed ) {
|
|
|
|
|
|
- parameters.map ? "#define USE_MAP" : "",
|
|
|
- parameters.envMap ? "#define USE_ENVMAP" : "",
|
|
|
- parameters.lightMap ? "#define USE_LIGHTMAP" : "",
|
|
|
- parameters.bumpMap ? "#define USE_BUMPMAP" : "",
|
|
|
- parameters.normalMap ? "#define USE_NORMALMAP" : "",
|
|
|
- parameters.specularMap ? "#define USE_SPECULARMAP" : "",
|
|
|
- parameters.vertexColors ? "#define USE_COLOR" : "",
|
|
|
+ cubeImage[ i ] = clampToMaxSize( texture.image[ i ], _maxCubemapSize );
|
|
|
|
|
|
- parameters.metal ? "#define METAL" : "",
|
|
|
- parameters.wrapAround ? "#define WRAP_AROUND" : "",
|
|
|
- parameters.doubleSided ? "#define DOUBLE_SIDED" : "",
|
|
|
- parameters.flipSided ? "#define FLIP_SIDED" : "",
|
|
|
+ } else {
|
|
|
|
|
|
- parameters.shadowMapEnabled ? "#define USE_SHADOWMAP" : "",
|
|
|
- parameters.shadowMapEnabled ? "#define " + shadowMapTypeDefine : "",
|
|
|
- parameters.shadowMapDebug ? "#define SHADOWMAP_DEBUG" : "",
|
|
|
- parameters.shadowMapCascade ? "#define SHADOWMAP_CASCADE" : "",
|
|
|
+ cubeImage[ i ] = texture.image[ i ];
|
|
|
|
|
|
- "uniform mat4 viewMatrix;",
|
|
|
- "uniform vec3 cameraPosition;",
|
|
|
- ""
|
|
|
+ }
|
|
|
|
|
|
- ].join( '\n' );
|
|
|
+ }
|
|
|
|
|
|
- var glVertexShader = new THREE.WebGLShader( _gl, _gl.VERTEX_SHADER, prefix_vertex + vertexShader );
|
|
|
- var glFragmentShader = new THREE.WebGLShader( _gl, _gl.FRAGMENT_SHADER, prefix_fragment + fragmentShader );
|
|
|
+ var image = cubeImage[ 0 ],
|
|
|
+ isImagePowerOfTwo = THREE.Math.isPowerOfTwo( image.width ) && THREE.Math.isPowerOfTwo( image.height ),
|
|
|
+ glFormat = paramThreeToGL( texture.format ),
|
|
|
+ glType = paramThreeToGL( texture.type );
|
|
|
|
|
|
- _gl.attachShader( program, glVertexShader );
|
|
|
- _gl.attachShader( program, glFragmentShader );
|
|
|
+ setTextureParameters( _gl.TEXTURE_CUBE_MAP, texture, isImagePowerOfTwo );
|
|
|
|
|
|
- // Force a particular attribute to index 0.
|
|
|
- // because potentially expensive emulation is done by browser if attribute 0 is disabled.
|
|
|
- // And, color, for example is often automatically bound to index 0 so disabling it
|
|
|
- if ( index0AttributeName !== undefined ) {
|
|
|
+ for ( var i = 0; i < 6; i ++ ) {
|
|
|
|
|
|
- _gl.bindAttribLocation( program, 0, index0AttributeName );
|
|
|
+ if( !isCompressed ) {
|
|
|
|
|
|
- }
|
|
|
+ _gl.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glFormat, glFormat, glType, cubeImage[ i ] );
|
|
|
|
|
|
- _gl.linkProgram( program );
|
|
|
+ } else {
|
|
|
+
|
|
|
+ var mipmap, mipmaps = cubeImage[ i ].mipmaps;
|
|
|
|
|
|
- if ( _gl.getProgramParameter( program, _gl.LINK_STATUS ) === false ) {
|
|
|
+ for( var j = 0, jl = mipmaps.length; j < jl; j ++ ) {
|
|
|
|
|
|
- console.error( 'Could not initialise shader' );
|
|
|
- console.error( 'gl.VALIDATE_STATUS', _gl.getProgramParameter( program, _gl.VALIDATE_STATUS ) );
|
|
|
- console.error( 'gl.getError()', _gl.getError() );
|
|
|
+ mipmap = mipmaps[ j ];
|
|
|
+ if ( texture.format!==THREE.RGBAFormat ) {
|
|
|
|
|
|
- }
|
|
|
+ _gl.compressedTexImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glFormat, mipmap.width, mipmap.height, 0, mipmap.data );
|
|
|
|
|
|
- if ( _gl.getProgramInfoLog( program ) !== '' ) {
|
|
|
+ } else {
|
|
|
+ _gl.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data );
|
|
|
+ }
|
|
|
|
|
|
- console.error( 'gl.getProgramInfoLog()', _gl.getProgramInfoLog( program ) );
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- }
|
|
|
+ if ( texture.generateMipmaps && isImagePowerOfTwo ) {
|
|
|
|
|
|
- program.vertexShader = _gl.getShaderSource( glVertexShader );
|
|
|
- program.fragmentShader = _gl.getShaderSource( glFragmentShader );
|
|
|
+ _gl.generateMipmap( _gl.TEXTURE_CUBE_MAP );
|
|
|
|
|
|
- // clean up
|
|
|
+ }
|
|
|
|
|
|
- _gl.deleteShader( glVertexShader );
|
|
|
- _gl.deleteShader( glFragmentShader );
|
|
|
+ texture.needsUpdate = false;
|
|
|
|
|
|
- // console.log( prefix_fragment + fragmentShader );
|
|
|
- // console.log( prefix_vertex + vertexShader );
|
|
|
+ if ( texture.onUpdate ) texture.onUpdate();
|
|
|
|
|
|
- program.uniforms = {};
|
|
|
- program.attributes = {};
|
|
|
+ } else {
|
|
|
|
|
|
- var identifiers, u, a, i;
|
|
|
+ _gl.activeTexture( _gl.TEXTURE0 + slot );
|
|
|
+ _gl.bindTexture( _gl.TEXTURE_CUBE_MAP, texture.image.__webglTextureCube );
|
|
|
|
|
|
- // cache uniform locations
|
|
|
+ }
|
|
|
|
|
|
- identifiers = [
|
|
|
+ }
|
|
|
|
|
|
- 'viewMatrix', 'modelViewMatrix', 'projectionMatrix', 'normalMatrix', 'modelMatrix', 'cameraPosition',
|
|
|
- 'morphTargetInfluences'
|
|
|
+ };
|
|
|
|
|
|
- ];
|
|
|
+ function setCubeTextureDynamic ( texture, slot ) {
|
|
|
|
|
|
- if ( parameters.useVertexTexture ) {
|
|
|
+ _gl.activeTexture( _gl.TEXTURE0 + slot );
|
|
|
+ _gl.bindTexture( _gl.TEXTURE_CUBE_MAP, texture.__webglTexture );
|
|
|
|
|
|
- identifiers.push( 'boneTexture' );
|
|
|
- identifiers.push( 'boneTextureWidth' );
|
|
|
- identifiers.push( 'boneTextureHeight' );
|
|
|
+ };
|
|
|
|
|
|
- } else {
|
|
|
+ // Render targets
|
|
|
|
|
|
- identifiers.push( 'boneGlobalMatrices' );
|
|
|
+ function setupFrameBuffer ( framebuffer, renderTarget, textureTarget ) {
|
|
|
|
|
|
- }
|
|
|
+ _gl.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );
|
|
|
+ _gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, textureTarget, renderTarget.__webglTexture, 0 );
|
|
|
|
|
|
- for ( u in uniforms ) {
|
|
|
+ };
|
|
|
|
|
|
- identifiers.push( u );
|
|
|
+ function setupRenderBuffer ( renderbuffer, renderTarget ) {
|
|
|
|
|
|
- }
|
|
|
+ _gl.bindRenderbuffer( _gl.RENDERBUFFER, renderbuffer );
|
|
|
|
|
|
- cacheUniformLocations( program, identifiers );
|
|
|
+ if ( renderTarget.depthBuffer && ! renderTarget.stencilBuffer ) {
|
|
|
|
|
|
- // cache attributes locations
|
|
|
+ _gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.DEPTH_COMPONENT16, renderTarget.width, renderTarget.height );
|
|
|
+ _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer );
|
|
|
|
|
|
- identifiers = [
|
|
|
+ /* For some reason this is not working. Defaulting to RGBA4.
|
|
|
+ } else if( ! renderTarget.depthBuffer && renderTarget.stencilBuffer ) {
|
|
|
|
|
|
- "position", "normal", "uv", "uv2", "tangent", "color",
|
|
|
- "skinIndex", "skinWeight", "lineDistance"
|
|
|
+ _gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.STENCIL_INDEX8, renderTarget.width, renderTarget.height );
|
|
|
+ _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.STENCIL_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer );
|
|
|
+ */
|
|
|
+ } else if ( renderTarget.depthBuffer && renderTarget.stencilBuffer ) {
|
|
|
|
|
|
- ];
|
|
|
+ _gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.DEPTH_STENCIL, renderTarget.width, renderTarget.height );
|
|
|
+ _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer );
|
|
|
|
|
|
- for ( i = 0; i < parameters.maxMorphTargets; i ++ ) {
|
|
|
+ } else {
|
|
|
|
|
|
- identifiers.push( "morphTarget" + i );
|
|
|
+ _gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.RGBA4, renderTarget.width, renderTarget.height );
|
|
|
|
|
|
}
|
|
|
|
|
|
- for ( i = 0; i < parameters.maxMorphNormals; i ++ ) {
|
|
|
+ };
|
|
|
|
|
|
- identifiers.push( "morphNormal" + i );
|
|
|
+ this.setRenderTarget = function ( renderTarget ) {
|
|
|
|
|
|
- }
|
|
|
+ var isCube = ( renderTarget instanceof THREE.WebGLRenderTargetCube );
|
|
|
|
|
|
- for ( a in attributes ) {
|
|
|
+ if ( renderTarget && ! renderTarget.__webglFramebuffer ) {
|
|
|
|
|
|
- identifiers.push( a );
|
|
|
+ if ( renderTarget.depthBuffer === undefined ) renderTarget.depthBuffer = true;
|
|
|
+ if ( renderTarget.stencilBuffer === undefined ) renderTarget.stencilBuffer = true;
|
|
|
|
|
|
- }
|
|
|
+ renderTarget.addEventListener( 'dispose', onRenderTargetDispose );
|
|
|
|
|
|
- cacheAttributeLocations( program, identifiers );
|
|
|
+ renderTarget.__webglTexture = _gl.createTexture();
|
|
|
|
|
|
- program.id = _programs_counter ++;
|
|
|
+ _this.info.memory.textures ++;
|
|
|
|
|
|
- _programs.push( { program: program, code: code, usedTimes: 1 } );
|
|
|
+ // Setup texture, create render and frame buffers
|
|
|
|
|
|
- _this.info.memory.programs = _programs.length;
|
|
|
+ var isTargetPowerOfTwo = THREE.Math.isPowerOfTwo( renderTarget.width ) && THREE.Math.isPowerOfTwo( renderTarget.height ),
|
|
|
+ glFormat = paramThreeToGL( renderTarget.format ),
|
|
|
+ glType = paramThreeToGL( renderTarget.type );
|
|
|
|
|
|
- return program;
|
|
|
+ if ( isCube ) {
|
|
|
|
|
|
- };
|
|
|
+ renderTarget.__webglFramebuffer = [];
|
|
|
+ renderTarget.__webglRenderbuffer = [];
|
|
|
|
|
|
- // Shader parameters cache
|
|
|
+ _gl.bindTexture( _gl.TEXTURE_CUBE_MAP, renderTarget.__webglTexture );
|
|
|
+ setTextureParameters( _gl.TEXTURE_CUBE_MAP, renderTarget, isTargetPowerOfTwo );
|
|
|
|
|
|
- function cacheUniformLocations ( program, identifiers ) {
|
|
|
+ for ( var i = 0; i < 6; i ++ ) {
|
|
|
|
|
|
- var i, l, id;
|
|
|
+ renderTarget.__webglFramebuffer[ i ] = _gl.createFramebuffer();
|
|
|
+ renderTarget.__webglRenderbuffer[ i ] = _gl.createRenderbuffer();
|
|
|
|
|
|
- for( i = 0, l = identifiers.length; i < l; i ++ ) {
|
|
|
+ _gl.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glFormat, renderTarget.width, renderTarget.height, 0, glFormat, glType, null );
|
|
|
|
|
|
- id = identifiers[ i ];
|
|
|
- program.uniforms[ id ] = _gl.getUniformLocation( program, id );
|
|
|
+ setupFrameBuffer( renderTarget.__webglFramebuffer[ i ], renderTarget, _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i );
|
|
|
+ setupRenderBuffer( renderTarget.__webglRenderbuffer[ i ], renderTarget );
|
|
|
|
|
|
- }
|
|
|
+ }
|
|
|
|
|
|
- };
|
|
|
+ if ( isTargetPowerOfTwo ) _gl.generateMipmap( _gl.TEXTURE_CUBE_MAP );
|
|
|
|
|
|
- function cacheAttributeLocations ( program, identifiers ) {
|
|
|
+ } else {
|
|
|
|
|
|
- var i, l, id;
|
|
|
+ renderTarget.__webglFramebuffer = _gl.createFramebuffer();
|
|
|
|
|
|
- for( i = 0, l = identifiers.length; i < l; i ++ ) {
|
|
|
+ if ( renderTarget.shareDepthFrom ) {
|
|
|
|
|
|
- id = identifiers[ i ];
|
|
|
- program.attributes[ id ] = _gl.getAttribLocation( program, id );
|
|
|
+ renderTarget.__webglRenderbuffer = renderTarget.shareDepthFrom.__webglRenderbuffer;
|
|
|
|
|
|
- }
|
|
|
+ } else {
|
|
|
|
|
|
- };
|
|
|
+ renderTarget.__webglRenderbuffer = _gl.createRenderbuffer();
|
|
|
|
|
|
+ }
|
|
|
|
|
|
+ _gl.bindTexture( _gl.TEXTURE_2D, renderTarget.__webglTexture );
|
|
|
+ setTextureParameters( _gl.TEXTURE_2D, renderTarget, isTargetPowerOfTwo );
|
|
|
|
|
|
- // Textures
|
|
|
+ _gl.texImage2D( _gl.TEXTURE_2D, 0, glFormat, renderTarget.width, renderTarget.height, 0, glFormat, glType, null );
|
|
|
|
|
|
- function setTextureParameters ( textureType, texture, isImagePowerOfTwo ) {
|
|
|
+ setupFrameBuffer( renderTarget.__webglFramebuffer, renderTarget, _gl.TEXTURE_2D );
|
|
|
|
|
|
- if ( isImagePowerOfTwo ) {
|
|
|
+ if ( renderTarget.shareDepthFrom ) {
|
|
|
|
|
|
- _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_S, paramThreeToGL( texture.wrapS ) );
|
|
|
- _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_T, paramThreeToGL( texture.wrapT ) );
|
|
|
+ if ( renderTarget.depthBuffer && ! renderTarget.stencilBuffer ) {
|
|
|
|
|
|
- _gl.texParameteri( textureType, _gl.TEXTURE_MAG_FILTER, paramThreeToGL( texture.magFilter ) );
|
|
|
- _gl.texParameteri( textureType, _gl.TEXTURE_MIN_FILTER, paramThreeToGL( texture.minFilter ) );
|
|
|
+ _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.RENDERBUFFER, renderTarget.__webglRenderbuffer );
|
|
|
|
|
|
- } else {
|
|
|
+ } else if ( renderTarget.depthBuffer && renderTarget.stencilBuffer ) {
|
|
|
|
|
|
- _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_S, _gl.CLAMP_TO_EDGE );
|
|
|
- _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_T, _gl.CLAMP_TO_EDGE );
|
|
|
+ _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.RENDERBUFFER, renderTarget.__webglRenderbuffer );
|
|
|
|
|
|
- _gl.texParameteri( textureType, _gl.TEXTURE_MAG_FILTER, filterFallback( texture.magFilter ) );
|
|
|
- _gl.texParameteri( textureType, _gl.TEXTURE_MIN_FILTER, filterFallback( texture.minFilter ) );
|
|
|
+ }
|
|
|
|
|
|
- }
|
|
|
+ } else {
|
|
|
|
|
|
- if ( _glExtensionTextureFilterAnisotropic && texture.type !== THREE.FloatType ) {
|
|
|
+ setupRenderBuffer( renderTarget.__webglRenderbuffer, renderTarget );
|
|
|
|
|
|
- if ( texture.anisotropy > 1 || texture.__oldAnisotropy ) {
|
|
|
+ }
|
|
|
|
|
|
- _gl.texParameterf( textureType, _glExtensionTextureFilterAnisotropic.TEXTURE_MAX_ANISOTROPY_EXT, Math.min( texture.anisotropy, _maxAnisotropy ) );
|
|
|
- texture.__oldAnisotropy = texture.anisotropy;
|
|
|
+ if ( isTargetPowerOfTwo ) _gl.generateMipmap( _gl.TEXTURE_2D );
|
|
|
|
|
|
}
|
|
|
|
|
|
- }
|
|
|
+ // Release everything
|
|
|
|
|
|
- };
|
|
|
+ if ( isCube ) {
|
|
|
|
|
|
- this.setTexture = function ( texture, slot ) {
|
|
|
+ _gl.bindTexture( _gl.TEXTURE_CUBE_MAP, null );
|
|
|
|
|
|
- if ( texture.needsUpdate ) {
|
|
|
+ } else {
|
|
|
|
|
|
- if ( ! texture.__webglInit ) {
|
|
|
+ _gl.bindTexture( _gl.TEXTURE_2D, null );
|
|
|
|
|
|
- texture.__webglInit = true;
|
|
|
+ }
|
|
|
|
|
|
- texture.addEventListener( 'dispose', onTextureDispose );
|
|
|
+ _gl.bindRenderbuffer( _gl.RENDERBUFFER, null );
|
|
|
+ _gl.bindFramebuffer( _gl.FRAMEBUFFER, null );
|
|
|
|
|
|
- texture.__webglTexture = _gl.createTexture();
|
|
|
+ }
|
|
|
|
|
|
- _this.info.memory.textures ++;
|
|
|
+ var framebuffer, width, height, vx, vy;
|
|
|
|
|
|
- }
|
|
|
+ if ( renderTarget ) {
|
|
|
|
|
|
- _gl.activeTexture( _gl.TEXTURE0 + slot );
|
|
|
- _gl.bindTexture( _gl.TEXTURE_2D, texture.__webglTexture );
|
|
|
+ if ( isCube ) {
|
|
|
|
|
|
- _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 );
|
|
|
+ framebuffer = renderTarget.__webglFramebuffer[ renderTarget.activeCubeFace ];
|
|
|
|
|
|
- var image = texture.image,
|
|
|
- isImagePowerOfTwo = THREE.Math.isPowerOfTwo( image.width ) && THREE.Math.isPowerOfTwo( image.height ),
|
|
|
- glFormat = paramThreeToGL( texture.format ),
|
|
|
- glType = paramThreeToGL( texture.type );
|
|
|
+ } else {
|
|
|
|
|
|
- setTextureParameters( _gl.TEXTURE_2D, texture, isImagePowerOfTwo );
|
|
|
+ framebuffer = renderTarget.__webglFramebuffer;
|
|
|
|
|
|
- var mipmap, mipmaps = texture.mipmaps;
|
|
|
+ }
|
|
|
|
|
|
- if ( texture instanceof THREE.DataTexture ) {
|
|
|
+ width = renderTarget.width;
|
|
|
+ height = renderTarget.height;
|
|
|
|
|
|
- // use manually created mipmaps if available
|
|
|
- // if there are no manual mipmaps
|
|
|
- // set 0 level mipmap and then use GL to generate other mipmap levels
|
|
|
-
|
|
|
- if ( mipmaps.length > 0 && isImagePowerOfTwo ) {
|
|
|
-
|
|
|
- for ( var i = 0, il = mipmaps.length; i < il; i ++ ) {
|
|
|
-
|
|
|
- mipmap = mipmaps[ i ];
|
|
|
- _gl.texImage2D( _gl.TEXTURE_2D, i, glFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data );
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- texture.generateMipmaps = false;
|
|
|
-
|
|
|
- } else {
|
|
|
+ vx = 0;
|
|
|
+ vy = 0;
|
|
|
|
|
|
- _gl.texImage2D( _gl.TEXTURE_2D, 0, glFormat, image.width, image.height, 0, glFormat, glType, image.data );
|
|
|
+ } else {
|
|
|
|
|
|
- }
|
|
|
+ framebuffer = null;
|
|
|
|
|
|
- } else if ( texture instanceof THREE.CompressedTexture ) {
|
|
|
+ width = _viewportWidth;
|
|
|
+ height = _viewportHeight;
|
|
|
|
|
|
- for( var i = 0, il = mipmaps.length; i < il; i ++ ) {
|
|
|
+ vx = _viewportX;
|
|
|
+ vy = _viewportY;
|
|
|
|
|
|
- mipmap = mipmaps[ i ];
|
|
|
- if ( texture.format!==THREE.RGBAFormat ) {
|
|
|
- _gl.compressedTexImage2D( _gl.TEXTURE_2D, i, glFormat, mipmap.width, mipmap.height, 0, mipmap.data );
|
|
|
- } else {
|
|
|
- _gl.texImage2D( _gl.TEXTURE_2D, i, glFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data );
|
|
|
- }
|
|
|
+ }
|
|
|
|
|
|
- }
|
|
|
+ if ( framebuffer !== _currentFramebuffer ) {
|
|
|
|
|
|
- } else { // regular Texture (image, video, canvas)
|
|
|
+ _gl.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );
|
|
|
+ _gl.viewport( vx, vy, width, height );
|
|
|
|
|
|
- // 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
|
|
|
+ _currentFramebuffer = framebuffer;
|
|
|
|
|
|
- if ( mipmaps.length > 0 && isImagePowerOfTwo ) {
|
|
|
+ }
|
|
|
|
|
|
- for ( var i = 0, il = mipmaps.length; i < il; i ++ ) {
|
|
|
+ _currentWidth = width;
|
|
|
+ _currentHeight = height;
|
|
|
|
|
|
- mipmap = mipmaps[ i ];
|
|
|
- _gl.texImage2D( _gl.TEXTURE_2D, i, glFormat, glFormat, glType, mipmap );
|
|
|
+ };
|
|
|
|
|
|
- }
|
|
|
+ function updateRenderTargetMipmap ( renderTarget ) {
|
|
|
|
|
|
- texture.generateMipmaps = false;
|
|
|
+ if ( renderTarget instanceof THREE.WebGLRenderTargetCube ) {
|
|
|
|
|
|
- } else {
|
|
|
+ _gl.bindTexture( _gl.TEXTURE_CUBE_MAP, renderTarget.__webglTexture );
|
|
|
+ _gl.generateMipmap( _gl.TEXTURE_CUBE_MAP );
|
|
|
+ _gl.bindTexture( _gl.TEXTURE_CUBE_MAP, null );
|
|
|
|
|
|
- _gl.texImage2D( _gl.TEXTURE_2D, 0, glFormat, glFormat, glType, texture.image );
|
|
|
+ } else {
|
|
|
|
|
|
- }
|
|
|
+ _gl.bindTexture( _gl.TEXTURE_2D, renderTarget.__webglTexture );
|
|
|
+ _gl.generateMipmap( _gl.TEXTURE_2D );
|
|
|
+ _gl.bindTexture( _gl.TEXTURE_2D, null );
|
|
|
|
|
|
- }
|
|
|
+ }
|
|
|
|
|
|
- if ( texture.generateMipmaps && isImagePowerOfTwo ) _gl.generateMipmap( _gl.TEXTURE_2D );
|
|
|
+ };
|
|
|
|
|
|
- texture.needsUpdate = false;
|
|
|
+ // Fallback filters for non-power-of-2 textures
|
|
|
|
|
|
- if ( texture.onUpdate ) texture.onUpdate();
|
|
|
+ function filterFallback ( f ) {
|
|
|
|
|
|
- } else {
|
|
|
+ if ( f === THREE.NearestFilter || f === THREE.NearestMipMapNearestFilter || f === THREE.NearestMipMapLinearFilter ) {
|
|
|
|
|
|
- _gl.activeTexture( _gl.TEXTURE0 + slot );
|
|
|
- _gl.bindTexture( _gl.TEXTURE_2D, texture.__webglTexture );
|
|
|
+ return _gl.NEAREST;
|
|
|
|
|
|
}
|
|
|
|
|
|
+ return _gl.LINEAR;
|
|
|
+
|
|
|
};
|
|
|
|
|
|
- function clampToMaxSize ( image, maxSize ) {
|
|
|
+ // Map three.js constants to WebGL constants
|
|
|
|
|
|
- if ( image.width <= maxSize && image.height <= maxSize ) {
|
|
|
+ function paramThreeToGL ( p ) {
|
|
|
|
|
|
- return image;
|
|
|
+ if ( p === THREE.RepeatWrapping ) return _gl.REPEAT;
|
|
|
+ if ( p === THREE.ClampToEdgeWrapping ) return _gl.CLAMP_TO_EDGE;
|
|
|
+ if ( p === THREE.MirroredRepeatWrapping ) return _gl.MIRRORED_REPEAT;
|
|
|
|
|
|
- }
|
|
|
+ if ( p === THREE.NearestFilter ) return _gl.NEAREST;
|
|
|
+ if ( p === THREE.NearestMipMapNearestFilter ) return _gl.NEAREST_MIPMAP_NEAREST;
|
|
|
+ if ( p === THREE.NearestMipMapLinearFilter ) return _gl.NEAREST_MIPMAP_LINEAR;
|
|
|
|
|
|
- // Warning: Scaling through the canvas will only work with images that use
|
|
|
- // premultiplied alpha.
|
|
|
+ if ( p === THREE.LinearFilter ) return _gl.LINEAR;
|
|
|
+ if ( p === THREE.LinearMipMapNearestFilter ) return _gl.LINEAR_MIPMAP_NEAREST;
|
|
|
+ if ( p === THREE.LinearMipMapLinearFilter ) return _gl.LINEAR_MIPMAP_LINEAR;
|
|
|
|
|
|
- var maxDimension = Math.max( image.width, image.height );
|
|
|
- var newWidth = Math.floor( image.width * maxSize / maxDimension );
|
|
|
- var newHeight = Math.floor( image.height * maxSize / maxDimension );
|
|
|
+ if ( p === THREE.UnsignedByteType ) return _gl.UNSIGNED_BYTE;
|
|
|
+ if ( p === THREE.UnsignedShort4444Type ) return _gl.UNSIGNED_SHORT_4_4_4_4;
|
|
|
+ if ( p === THREE.UnsignedShort5551Type ) return _gl.UNSIGNED_SHORT_5_5_5_1;
|
|
|
+ if ( p === THREE.UnsignedShort565Type ) return _gl.UNSIGNED_SHORT_5_6_5;
|
|
|
|
|
|
- var canvas = document.createElement( 'canvas' );
|
|
|
- canvas.width = newWidth;
|
|
|
- canvas.height = newHeight;
|
|
|
+ if ( p === THREE.ByteType ) return _gl.BYTE;
|
|
|
+ if ( p === THREE.ShortType ) return _gl.SHORT;
|
|
|
+ if ( p === THREE.UnsignedShortType ) return _gl.UNSIGNED_SHORT;
|
|
|
+ if ( p === THREE.IntType ) return _gl.INT;
|
|
|
+ if ( p === THREE.UnsignedIntType ) return _gl.UNSIGNED_INT;
|
|
|
+ if ( p === THREE.FloatType ) return _gl.FLOAT;
|
|
|
|
|
|
- var ctx = canvas.getContext( "2d" );
|
|
|
- ctx.drawImage( image, 0, 0, image.width, image.height, 0, 0, newWidth, newHeight );
|
|
|
+ if ( p === THREE.AlphaFormat ) return _gl.ALPHA;
|
|
|
+ if ( p === THREE.RGBFormat ) return _gl.RGB;
|
|
|
+ if ( p === THREE.RGBAFormat ) return _gl.RGBA;
|
|
|
+ if ( p === THREE.LuminanceFormat ) return _gl.LUMINANCE;
|
|
|
+ if ( p === THREE.LuminanceAlphaFormat ) return _gl.LUMINANCE_ALPHA;
|
|
|
|
|
|
- return canvas;
|
|
|
+ if ( p === THREE.AddEquation ) return _gl.FUNC_ADD;
|
|
|
+ if ( p === THREE.SubtractEquation ) return _gl.FUNC_SUBTRACT;
|
|
|
+ if ( p === THREE.ReverseSubtractEquation ) return _gl.FUNC_REVERSE_SUBTRACT;
|
|
|
|
|
|
- }
|
|
|
+ if ( p === THREE.ZeroFactor ) return _gl.ZERO;
|
|
|
+ if ( p === THREE.OneFactor ) return _gl.ONE;
|
|
|
+ if ( p === THREE.SrcColorFactor ) return _gl.SRC_COLOR;
|
|
|
+ if ( p === THREE.OneMinusSrcColorFactor ) return _gl.ONE_MINUS_SRC_COLOR;
|
|
|
+ if ( p === THREE.SrcAlphaFactor ) return _gl.SRC_ALPHA;
|
|
|
+ if ( p === THREE.OneMinusSrcAlphaFactor ) return _gl.ONE_MINUS_SRC_ALPHA;
|
|
|
+ if ( p === THREE.DstAlphaFactor ) return _gl.DST_ALPHA;
|
|
|
+ if ( p === THREE.OneMinusDstAlphaFactor ) return _gl.ONE_MINUS_DST_ALPHA;
|
|
|
|
|
|
- function setCubeTexture ( texture, slot ) {
|
|
|
+ if ( p === THREE.DstColorFactor ) return _gl.DST_COLOR;
|
|
|
+ if ( p === THREE.OneMinusDstColorFactor ) return _gl.ONE_MINUS_DST_COLOR;
|
|
|
+ if ( p === THREE.SrcAlphaSaturateFactor ) return _gl.SRC_ALPHA_SATURATE;
|
|
|
|
|
|
- if ( texture.image.length === 6 ) {
|
|
|
+ if ( _glExtensionCompressedTextureS3TC !== undefined ) {
|
|
|
|
|
|
- if ( texture.needsUpdate ) {
|
|
|
+ if ( p === THREE.RGB_S3TC_DXT1_Format ) return _glExtensionCompressedTextureS3TC.COMPRESSED_RGB_S3TC_DXT1_EXT;
|
|
|
+ if ( p === THREE.RGBA_S3TC_DXT1_Format ) return _glExtensionCompressedTextureS3TC.COMPRESSED_RGBA_S3TC_DXT1_EXT;
|
|
|
+ if ( p === THREE.RGBA_S3TC_DXT3_Format ) return _glExtensionCompressedTextureS3TC.COMPRESSED_RGBA_S3TC_DXT3_EXT;
|
|
|
+ if ( p === THREE.RGBA_S3TC_DXT5_Format ) return _glExtensionCompressedTextureS3TC.COMPRESSED_RGBA_S3TC_DXT5_EXT;
|
|
|
|
|
|
- if ( ! texture.image.__webglTextureCube ) {
|
|
|
+ }
|
|
|
|
|
|
- texture.addEventListener( 'dispose', onTextureDispose );
|
|
|
+ return 0;
|
|
|
|
|
|
- texture.image.__webglTextureCube = _gl.createTexture();
|
|
|
+ };
|
|
|
|
|
|
- _this.info.memory.textures ++;
|
|
|
+ // Allocations
|
|
|
|
|
|
- }
|
|
|
+ function allocateBones ( object ) {
|
|
|
|
|
|
- _gl.activeTexture( _gl.TEXTURE0 + slot );
|
|
|
- _gl.bindTexture( _gl.TEXTURE_CUBE_MAP, texture.image.__webglTextureCube );
|
|
|
+ if ( _supportsBoneTextures && object && object.useVertexTexture ) {
|
|
|
|
|
|
- _gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, texture.flipY );
|
|
|
+ return 1024;
|
|
|
|
|
|
- var isCompressed = texture instanceof THREE.CompressedTexture;
|
|
|
+ } else {
|
|
|
|
|
|
- var cubeImage = [];
|
|
|
+ // 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)
|
|
|
|
|
|
- for ( var i = 0; i < 6; i ++ ) {
|
|
|
+ var nVertexUniforms = _gl.getParameter( _gl.MAX_VERTEX_UNIFORM_VECTORS );
|
|
|
+ var nVertexMatrices = Math.floor( ( nVertexUniforms - 20 ) / 4 );
|
|
|
|
|
|
- if ( _this.autoScaleCubemaps && ! isCompressed ) {
|
|
|
+ var maxBones = nVertexMatrices;
|
|
|
|
|
|
- cubeImage[ i ] = clampToMaxSize( texture.image[ i ], _maxCubemapSize );
|
|
|
+ if ( object !== undefined && object instanceof THREE.SkinnedMesh ) {
|
|
|
|
|
|
- } else {
|
|
|
+ maxBones = Math.min( object.bones.length, maxBones );
|
|
|
|
|
|
- cubeImage[ i ] = texture.image[ i ];
|
|
|
+ if ( maxBones < object.bones.length ) {
|
|
|
|
|
|
- }
|
|
|
+ console.warn( "WebGLRenderer: too many bones - " + object.bones.length + ", this GPU supports just " + maxBones + " (try OpenGL instead of ANGLE)" );
|
|
|
|
|
|
}
|
|
|
|
|
|
- var image = cubeImage[ 0 ],
|
|
|
- isImagePowerOfTwo = THREE.Math.isPowerOfTwo( image.width ) && THREE.Math.isPowerOfTwo( image.height ),
|
|
|
- glFormat = paramThreeToGL( texture.format ),
|
|
|
- glType = paramThreeToGL( texture.type );
|
|
|
+ }
|
|
|
|
|
|
- setTextureParameters( _gl.TEXTURE_CUBE_MAP, texture, isImagePowerOfTwo );
|
|
|
+ return maxBones;
|
|
|
|
|
|
- for ( var i = 0; i < 6; i ++ ) {
|
|
|
+ }
|
|
|
|
|
|
- if( !isCompressed ) {
|
|
|
+ };
|
|
|
|
|
|
- _gl.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glFormat, glFormat, glType, cubeImage[ i ] );
|
|
|
+ function allocateLights( lights ) {
|
|
|
|
|
|
- } else {
|
|
|
-
|
|
|
- var mipmap, mipmaps = cubeImage[ i ].mipmaps;
|
|
|
+ var dirLights = 0;
|
|
|
+ var pointLights = 0;
|
|
|
+ var spotLights = 0;
|
|
|
+ var hemiLights = 0;
|
|
|
|
|
|
- for( var j = 0, jl = mipmaps.length; j < jl; j ++ ) {
|
|
|
+ for ( var l = 0, ll = lights.length; l < ll; l ++ ) {
|
|
|
|
|
|
- mipmap = mipmaps[ j ];
|
|
|
- if ( texture.format!==THREE.RGBAFormat ) {
|
|
|
+ var light = lights[ l ];
|
|
|
|
|
|
- _gl.compressedTexImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glFormat, mipmap.width, mipmap.height, 0, mipmap.data );
|
|
|
+ if ( light.onlyShadow || light.visible === false ) continue;
|
|
|
|
|
|
- } else {
|
|
|
- _gl.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data );
|
|
|
- }
|
|
|
+ if ( light instanceof THREE.DirectionalLight ) dirLights ++;
|
|
|
+ if ( light instanceof THREE.PointLight ) pointLights ++;
|
|
|
+ if ( light instanceof THREE.SpotLight ) spotLights ++;
|
|
|
+ if ( light instanceof THREE.HemisphereLight ) hemiLights ++;
|
|
|
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
+ }
|
|
|
|
|
|
- if ( texture.generateMipmaps && isImagePowerOfTwo ) {
|
|
|
+ return { 'directional' : dirLights, 'point' : pointLights, 'spot': spotLights, 'hemi': hemiLights };
|
|
|
|
|
|
- _gl.generateMipmap( _gl.TEXTURE_CUBE_MAP );
|
|
|
+ };
|
|
|
|
|
|
- }
|
|
|
+ function allocateShadows( lights ) {
|
|
|
|
|
|
- texture.needsUpdate = false;
|
|
|
+ var maxShadows = 0;
|
|
|
|
|
|
- if ( texture.onUpdate ) texture.onUpdate();
|
|
|
+ for ( var l = 0, ll = lights.length; l < ll; l++ ) {
|
|
|
|
|
|
- } else {
|
|
|
+ var light = lights[ l ];
|
|
|
|
|
|
- _gl.activeTexture( _gl.TEXTURE0 + slot );
|
|
|
- _gl.bindTexture( _gl.TEXTURE_CUBE_MAP, texture.image.__webglTextureCube );
|
|
|
+ if ( ! light.castShadow ) continue;
|
|
|
|
|
|
- }
|
|
|
+ if ( light instanceof THREE.SpotLight ) maxShadows ++;
|
|
|
+ if ( light instanceof THREE.DirectionalLight && ! light.shadowCascade ) maxShadows ++;
|
|
|
|
|
|
}
|
|
|
|
|
|
+ return maxShadows;
|
|
|
+
|
|
|
};
|
|
|
|
|
|
- function setCubeTextureDynamic ( texture, slot ) {
|
|
|
+ // Initialization
|
|
|
|
|
|
- _gl.activeTexture( _gl.TEXTURE0 + slot );
|
|
|
- _gl.bindTexture( _gl.TEXTURE_CUBE_MAP, texture.__webglTexture );
|
|
|
+ function initGL() {
|
|
|
|
|
|
- };
|
|
|
+ try {
|
|
|
|
|
|
- // Render targets
|
|
|
+ var attributes = {
|
|
|
+ alpha: _alpha,
|
|
|
+ depth: _depth,
|
|
|
+ stencil: _stencil,
|
|
|
+ antialias: _antialias,
|
|
|
+ premultipliedAlpha: _premultipliedAlpha,
|
|
|
+ preserveDrawingBuffer: _preserveDrawingBuffer
|
|
|
+ };
|
|
|
|
|
|
- function setupFrameBuffer ( framebuffer, renderTarget, textureTarget ) {
|
|
|
+ _gl = _context || _canvas.getContext( 'webgl', attributes ) || _canvas.getContext( 'experimental-webgl', attributes );
|
|
|
|
|
|
- _gl.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );
|
|
|
- _gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, textureTarget, renderTarget.__webglTexture, 0 );
|
|
|
+ if ( _gl === null ) {
|
|
|
|
|
|
- };
|
|
|
+ throw 'Error creating WebGL context.';
|
|
|
|
|
|
- function setupRenderBuffer ( renderbuffer, renderTarget ) {
|
|
|
+ }
|
|
|
|
|
|
- _gl.bindRenderbuffer( _gl.RENDERBUFFER, renderbuffer );
|
|
|
+ } catch ( error ) {
|
|
|
|
|
|
- if ( renderTarget.depthBuffer && ! renderTarget.stencilBuffer ) {
|
|
|
+ console.error( error );
|
|
|
|
|
|
- _gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.DEPTH_COMPONENT16, renderTarget.width, renderTarget.height );
|
|
|
- _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer );
|
|
|
+ }
|
|
|
|
|
|
- /* For some reason this is not working. Defaulting to RGBA4.
|
|
|
- } else if( ! renderTarget.depthBuffer && renderTarget.stencilBuffer ) {
|
|
|
+ _glExtensionTextureFloat = _gl.getExtension( 'OES_texture_float' );
|
|
|
+ _glExtensionTextureFloatLinear = _gl.getExtension( 'OES_texture_float_linear' );
|
|
|
+ _glExtensionStandardDerivatives = _gl.getExtension( 'OES_standard_derivatives' );
|
|
|
|
|
|
- _gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.STENCIL_INDEX8, renderTarget.width, renderTarget.height );
|
|
|
- _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.STENCIL_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer );
|
|
|
- */
|
|
|
- } else if ( renderTarget.depthBuffer && renderTarget.stencilBuffer ) {
|
|
|
+ _glExtensionTextureFilterAnisotropic = _gl.getExtension( 'EXT_texture_filter_anisotropic' ) || _gl.getExtension( 'MOZ_EXT_texture_filter_anisotropic' ) || _gl.getExtension( 'WEBKIT_EXT_texture_filter_anisotropic' );
|
|
|
|
|
|
- _gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.DEPTH_STENCIL, renderTarget.width, renderTarget.height );
|
|
|
- _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer );
|
|
|
+ _glExtensionCompressedTextureS3TC = _gl.getExtension( 'WEBGL_compressed_texture_s3tc' ) || _gl.getExtension( 'MOZ_WEBGL_compressed_texture_s3tc' ) || _gl.getExtension( 'WEBKIT_WEBGL_compressed_texture_s3tc' );
|
|
|
|
|
|
- } else {
|
|
|
+ _glExtensionElementIndexUint = _gl.getExtension( 'OES_element_index_uint' );
|
|
|
+
|
|
|
+
|
|
|
+ if ( _glExtensionTextureFloat === null ) {
|
|
|
|
|
|
- _gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.RGBA4, renderTarget.width, renderTarget.height );
|
|
|
+ console.log( 'THREE.WebGLRenderer: Float textures not supported.' );
|
|
|
|
|
|
}
|
|
|
|
|
|
- };
|
|
|
+ if ( _glExtensionStandardDerivatives === null ) {
|
|
|
|
|
|
- this.setRenderTarget = function ( renderTarget ) {
|
|
|
+ console.log( 'THREE.WebGLRenderer: Standard derivatives not supported.' );
|
|
|
|
|
|
- var isCube = ( renderTarget instanceof THREE.WebGLRenderTargetCube );
|
|
|
+ }
|
|
|
|
|
|
- if ( renderTarget && ! renderTarget.__webglFramebuffer ) {
|
|
|
+ if ( _glExtensionTextureFilterAnisotropic === null ) {
|
|
|
|
|
|
- if ( renderTarget.depthBuffer === undefined ) renderTarget.depthBuffer = true;
|
|
|
- if ( renderTarget.stencilBuffer === undefined ) renderTarget.stencilBuffer = true;
|
|
|
+ console.log( 'THREE.WebGLRenderer: Anisotropic texture filtering not supported.' );
|
|
|
|
|
|
- renderTarget.addEventListener( 'dispose', onRenderTargetDispose );
|
|
|
+ }
|
|
|
|
|
|
- renderTarget.__webglTexture = _gl.createTexture();
|
|
|
+ if ( _glExtensionCompressedTextureS3TC === null ) {
|
|
|
|
|
|
- _this.info.memory.textures ++;
|
|
|
+ console.log( 'THREE.WebGLRenderer: S3TC compressed textures not supported.' );
|
|
|
|
|
|
- // Setup texture, create render and frame buffers
|
|
|
+ }
|
|
|
|
|
|
- var isTargetPowerOfTwo = THREE.Math.isPowerOfTwo( renderTarget.width ) && THREE.Math.isPowerOfTwo( renderTarget.height ),
|
|
|
- glFormat = paramThreeToGL( renderTarget.format ),
|
|
|
- glType = paramThreeToGL( renderTarget.type );
|
|
|
+ if ( _glExtensionElementIndexUint === null ) {
|
|
|
|
|
|
- if ( isCube ) {
|
|
|
+ console.log( 'THREE.WebGLRenderer: elementindex as unsigned integer not supported.' );
|
|
|
|
|
|
- renderTarget.__webglFramebuffer = [];
|
|
|
- renderTarget.__webglRenderbuffer = [];
|
|
|
+ }
|
|
|
|
|
|
- _gl.bindTexture( _gl.TEXTURE_CUBE_MAP, renderTarget.__webglTexture );
|
|
|
- setTextureParameters( _gl.TEXTURE_CUBE_MAP, renderTarget, isTargetPowerOfTwo );
|
|
|
+ if ( _gl.getShaderPrecisionFormat === undefined ) {
|
|
|
|
|
|
- for ( var i = 0; i < 6; i ++ ) {
|
|
|
+ _gl.getShaderPrecisionFormat = function() {
|
|
|
|
|
|
- renderTarget.__webglFramebuffer[ i ] = _gl.createFramebuffer();
|
|
|
- renderTarget.__webglRenderbuffer[ i ] = _gl.createRenderbuffer();
|
|
|
+ return {
|
|
|
+ "rangeMin" : 1,
|
|
|
+ "rangeMax" : 1,
|
|
|
+ "precision" : 1
|
|
|
+ };
|
|
|
|
|
|
- _gl.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glFormat, renderTarget.width, renderTarget.height, 0, glFormat, glType, null );
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- setupFrameBuffer( renderTarget.__webglFramebuffer[ i ], renderTarget, _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i );
|
|
|
- setupRenderBuffer( renderTarget.__webglRenderbuffer[ i ], renderTarget );
|
|
|
+ };
|
|
|
|
|
|
- }
|
|
|
+ function setDefaultGLState () {
|
|
|
|
|
|
- if ( isTargetPowerOfTwo ) _gl.generateMipmap( _gl.TEXTURE_CUBE_MAP );
|
|
|
+ _gl.clearColor( 0, 0, 0, 1 );
|
|
|
+ _gl.clearDepth( 1 );
|
|
|
+ _gl.clearStencil( 0 );
|
|
|
|
|
|
- } else {
|
|
|
+ _gl.enable( _gl.DEPTH_TEST );
|
|
|
+ _gl.depthFunc( _gl.LEQUAL );
|
|
|
|
|
|
- renderTarget.__webglFramebuffer = _gl.createFramebuffer();
|
|
|
+ _gl.frontFace( _gl.CCW );
|
|
|
+ _gl.cullFace( _gl.BACK );
|
|
|
+ _gl.enable( _gl.CULL_FACE );
|
|
|
|
|
|
- if ( renderTarget.shareDepthFrom ) {
|
|
|
+ _gl.enable( _gl.BLEND );
|
|
|
+ _gl.blendEquation( _gl.FUNC_ADD );
|
|
|
+ _gl.blendFunc( _gl.SRC_ALPHA, _gl.ONE_MINUS_SRC_ALPHA );
|
|
|
|
|
|
- renderTarget.__webglRenderbuffer = renderTarget.shareDepthFrom.__webglRenderbuffer;
|
|
|
+ _gl.viewport( _viewportX, _viewportY, _viewportWidth, _viewportHeight );
|
|
|
+
|
|
|
+ _gl.clearColor( _clearColor.r, _clearColor.g, _clearColor.b, _clearAlpha );
|
|
|
|
|
|
- } else {
|
|
|
+ };
|
|
|
|
|
|
- renderTarget.__webglRenderbuffer = _gl.createRenderbuffer();
|
|
|
+ // default plugins (order is important)
|
|
|
|
|
|
- }
|
|
|
+ this.shadowMapPlugin = new THREE.ShadowMapPlugin();
|
|
|
+ this.addPrePlugin( this.shadowMapPlugin );
|
|
|
|
|
|
- _gl.bindTexture( _gl.TEXTURE_2D, renderTarget.__webglTexture );
|
|
|
- setTextureParameters( _gl.TEXTURE_2D, renderTarget, isTargetPowerOfTwo );
|
|
|
+ this.addPostPlugin( new THREE.SpritePlugin() );
|
|
|
+ this.addPostPlugin( new THREE.LensFlarePlugin() );
|
|
|
|
|
|
- _gl.texImage2D( _gl.TEXTURE_2D, 0, glFormat, renderTarget.width, renderTarget.height, 0, glFormat, glType, null );
|
|
|
+};
|
|
|
|
|
|
- setupFrameBuffer( renderTarget.__webglFramebuffer, renderTarget, _gl.TEXTURE_2D );
|
|
|
+/**
|
|
|
+ * @author szimek / https://github.com/szimek/
|
|
|
+ * @author alteredq / http://alteredqualia.com/
|
|
|
+ */
|
|
|
|
|
|
- if ( renderTarget.shareDepthFrom ) {
|
|
|
+THREE.WebGLRenderTarget = function ( width, height, options ) {
|
|
|
|
|
|
- if ( renderTarget.depthBuffer && ! renderTarget.stencilBuffer ) {
|
|
|
+ this.width = width;
|
|
|
+ this.height = height;
|
|
|
|
|
|
- _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.RENDERBUFFER, renderTarget.__webglRenderbuffer );
|
|
|
+ options = options || {};
|
|
|
|
|
|
- } else if ( renderTarget.depthBuffer && renderTarget.stencilBuffer ) {
|
|
|
+ this.wrapS = options.wrapS !== undefined ? options.wrapS : THREE.ClampToEdgeWrapping;
|
|
|
+ this.wrapT = options.wrapT !== undefined ? options.wrapT : THREE.ClampToEdgeWrapping;
|
|
|
|
|
|
- _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.RENDERBUFFER, renderTarget.__webglRenderbuffer );
|
|
|
+ this.magFilter = options.magFilter !== undefined ? options.magFilter : THREE.LinearFilter;
|
|
|
+ this.minFilter = options.minFilter !== undefined ? options.minFilter : THREE.LinearMipMapLinearFilter;
|
|
|
|
|
|
- }
|
|
|
+ this.anisotropy = options.anisotropy !== undefined ? options.anisotropy : 1;
|
|
|
|
|
|
- } else {
|
|
|
+ this.offset = new THREE.Vector2( 0, 0 );
|
|
|
+ this.repeat = new THREE.Vector2( 1, 1 );
|
|
|
|
|
|
- setupRenderBuffer( renderTarget.__webglRenderbuffer, renderTarget );
|
|
|
+ this.format = options.format !== undefined ? options.format : THREE.RGBAFormat;
|
|
|
+ this.type = options.type !== undefined ? options.type : THREE.UnsignedByteType;
|
|
|
|
|
|
- }
|
|
|
+ this.depthBuffer = options.depthBuffer !== undefined ? options.depthBuffer : true;
|
|
|
+ this.stencilBuffer = options.stencilBuffer !== undefined ? options.stencilBuffer : true;
|
|
|
|
|
|
- if ( isTargetPowerOfTwo ) _gl.generateMipmap( _gl.TEXTURE_2D );
|
|
|
+ this.generateMipmaps = true;
|
|
|
|
|
|
- }
|
|
|
+ this.shareDepthFrom = null;
|
|
|
|
|
|
- // Release everything
|
|
|
+};
|
|
|
|
|
|
- if ( isCube ) {
|
|
|
+THREE.WebGLRenderTarget.prototype = {
|
|
|
|
|
|
- _gl.bindTexture( _gl.TEXTURE_CUBE_MAP, null );
|
|
|
+ constructor: THREE.WebGLRenderTarget,
|
|
|
|
|
|
- } else {
|
|
|
+ clone: function () {
|
|
|
|
|
|
- _gl.bindTexture( _gl.TEXTURE_2D, null );
|
|
|
+ var tmp = new THREE.WebGLRenderTarget( this.width, this.height );
|
|
|
|
|
|
- }
|
|
|
+ tmp.wrapS = this.wrapS;
|
|
|
+ tmp.wrapT = this.wrapT;
|
|
|
|
|
|
- _gl.bindRenderbuffer( _gl.RENDERBUFFER, null );
|
|
|
- _gl.bindFramebuffer( _gl.FRAMEBUFFER, null );
|
|
|
+ tmp.magFilter = this.magFilter;
|
|
|
+ tmp.minFilter = this.minFilter;
|
|
|
|
|
|
- }
|
|
|
+ tmp.anisotropy = this.anisotropy;
|
|
|
|
|
|
- var framebuffer, width, height, vx, vy;
|
|
|
+ tmp.offset.copy( this.offset );
|
|
|
+ tmp.repeat.copy( this.repeat );
|
|
|
|
|
|
- if ( renderTarget ) {
|
|
|
+ tmp.format = this.format;
|
|
|
+ tmp.type = this.type;
|
|
|
|
|
|
- if ( isCube ) {
|
|
|
+ tmp.depthBuffer = this.depthBuffer;
|
|
|
+ tmp.stencilBuffer = this.stencilBuffer;
|
|
|
|
|
|
- framebuffer = renderTarget.__webglFramebuffer[ renderTarget.activeCubeFace ];
|
|
|
+ tmp.generateMipmaps = this.generateMipmaps;
|
|
|
|
|
|
- } else {
|
|
|
+ tmp.shareDepthFrom = this.shareDepthFrom;
|
|
|
|
|
|
- framebuffer = renderTarget.__webglFramebuffer;
|
|
|
+ return tmp;
|
|
|
|
|
|
- }
|
|
|
+ },
|
|
|
|
|
|
- width = renderTarget.width;
|
|
|
- height = renderTarget.height;
|
|
|
+ dispose: function () {
|
|
|
|
|
|
- vx = 0;
|
|
|
- vy = 0;
|
|
|
+ this.dispatchEvent( { type: 'dispose' } );
|
|
|
|
|
|
- } else {
|
|
|
+ }
|
|
|
|
|
|
- framebuffer = null;
|
|
|
+};
|
|
|
|
|
|
- width = _viewportWidth;
|
|
|
- height = _viewportHeight;
|
|
|
+THREE.EventDispatcher.prototype.apply( THREE.WebGLRenderTarget.prototype );
|
|
|
|
|
|
- vx = _viewportX;
|
|
|
- vy = _viewportY;
|
|
|
+/**
|
|
|
+ * @author alteredq / http://alteredqualia.com
|
|
|
+ */
|
|
|
|
|
|
- }
|
|
|
+THREE.WebGLRenderTargetCube = function ( width, height, options ) {
|
|
|
|
|
|
- if ( framebuffer !== _currentFramebuffer ) {
|
|
|
+ THREE.WebGLRenderTarget.call( this, width, height, options );
|
|
|
|
|
|
- _gl.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );
|
|
|
- _gl.viewport( vx, vy, width, height );
|
|
|
+ this.activeCubeFace = 0; // PX 0, NX 1, PY 2, NY 3, PZ 4, NZ 5
|
|
|
|
|
|
- _currentFramebuffer = framebuffer;
|
|
|
+};
|
|
|
|
|
|
- }
|
|
|
+THREE.WebGLRenderTargetCube.prototype = Object.create( THREE.WebGLRenderTarget.prototype );
|
|
|
|
|
|
- _currentWidth = width;
|
|
|
- _currentHeight = height;
|
|
|
+THREE.WebGLProgram = ( function () {
|
|
|
|
|
|
- };
|
|
|
+ var programIdCount = 0;
|
|
|
|
|
|
- function updateRenderTargetMipmap ( renderTarget ) {
|
|
|
+ var generateDefines = function ( defines ) {
|
|
|
|
|
|
- if ( renderTarget instanceof THREE.WebGLRenderTargetCube ) {
|
|
|
+ var value, chunk, chunks = [];
|
|
|
|
|
|
- _gl.bindTexture( _gl.TEXTURE_CUBE_MAP, renderTarget.__webglTexture );
|
|
|
- _gl.generateMipmap( _gl.TEXTURE_CUBE_MAP );
|
|
|
- _gl.bindTexture( _gl.TEXTURE_CUBE_MAP, null );
|
|
|
+ for ( var d in defines ) {
|
|
|
|
|
|
- } else {
|
|
|
+ value = defines[ d ];
|
|
|
+ if ( value === false ) continue;
|
|
|
|
|
|
- _gl.bindTexture( _gl.TEXTURE_2D, renderTarget.__webglTexture );
|
|
|
- _gl.generateMipmap( _gl.TEXTURE_2D );
|
|
|
- _gl.bindTexture( _gl.TEXTURE_2D, null );
|
|
|
+ chunk = "#define " + d + " " + value;
|
|
|
+ chunks.push( chunk );
|
|
|
|
|
|
}
|
|
|
|
|
|
+ return chunks.join( "\n" );
|
|
|
+
|
|
|
};
|
|
|
|
|
|
- // Fallback filters for non-power-of-2 textures
|
|
|
+ var cacheUniformLocations = function ( gl, program, identifiers ) {
|
|
|
|
|
|
- function filterFallback ( f ) {
|
|
|
+ var uniforms = {};
|
|
|
|
|
|
- if ( f === THREE.NearestFilter || f === THREE.NearestMipMapNearestFilter || f === THREE.NearestMipMapLinearFilter ) {
|
|
|
+ for ( var i = 0, l = identifiers.length; i < l; i ++ ) {
|
|
|
|
|
|
- return _gl.NEAREST;
|
|
|
+ var id = identifiers[ i ];
|
|
|
+ uniforms[ id ] = gl.getUniformLocation( program, id );
|
|
|
|
|
|
}
|
|
|
|
|
|
- return _gl.LINEAR;
|
|
|
+ return uniforms;
|
|
|
|
|
|
};
|
|
|
|
|
|
- // Map three.js constants to WebGL constants
|
|
|
+ var cacheAttributeLocations = function ( gl, program, identifiers ) {
|
|
|
|
|
|
- function paramThreeToGL ( p ) {
|
|
|
+ var attributes = {};
|
|
|
|
|
|
- if ( p === THREE.RepeatWrapping ) return _gl.REPEAT;
|
|
|
- if ( p === THREE.ClampToEdgeWrapping ) return _gl.CLAMP_TO_EDGE;
|
|
|
- if ( p === THREE.MirroredRepeatWrapping ) return _gl.MIRRORED_REPEAT;
|
|
|
+ for ( var i = 0, l = identifiers.length; i < l; i ++ ) {
|
|
|
|
|
|
- if ( p === THREE.NearestFilter ) return _gl.NEAREST;
|
|
|
- if ( p === THREE.NearestMipMapNearestFilter ) return _gl.NEAREST_MIPMAP_NEAREST;
|
|
|
- if ( p === THREE.NearestMipMapLinearFilter ) return _gl.NEAREST_MIPMAP_LINEAR;
|
|
|
+ var id = identifiers[ i ];
|
|
|
+ attributes[ id ] = gl.getAttribLocation( program, id );
|
|
|
|
|
|
- if ( p === THREE.LinearFilter ) return _gl.LINEAR;
|
|
|
- if ( p === THREE.LinearMipMapNearestFilter ) return _gl.LINEAR_MIPMAP_NEAREST;
|
|
|
- if ( p === THREE.LinearMipMapLinearFilter ) return _gl.LINEAR_MIPMAP_LINEAR;
|
|
|
+ }
|
|
|
|
|
|
- if ( p === THREE.UnsignedByteType ) return _gl.UNSIGNED_BYTE;
|
|
|
- if ( p === THREE.UnsignedShort4444Type ) return _gl.UNSIGNED_SHORT_4_4_4_4;
|
|
|
- if ( p === THREE.UnsignedShort5551Type ) return _gl.UNSIGNED_SHORT_5_5_5_1;
|
|
|
- if ( p === THREE.UnsignedShort565Type ) return _gl.UNSIGNED_SHORT_5_6_5;
|
|
|
-
|
|
|
- if ( p === THREE.ByteType ) return _gl.BYTE;
|
|
|
- if ( p === THREE.ShortType ) return _gl.SHORT;
|
|
|
- if ( p === THREE.UnsignedShortType ) return _gl.UNSIGNED_SHORT;
|
|
|
- if ( p === THREE.IntType ) return _gl.INT;
|
|
|
- if ( p === THREE.UnsignedIntType ) return _gl.UNSIGNED_INT;
|
|
|
- if ( p === THREE.FloatType ) return _gl.FLOAT;
|
|
|
-
|
|
|
- if ( p === THREE.AlphaFormat ) return _gl.ALPHA;
|
|
|
- if ( p === THREE.RGBFormat ) return _gl.RGB;
|
|
|
- if ( p === THREE.RGBAFormat ) return _gl.RGBA;
|
|
|
- if ( p === THREE.LuminanceFormat ) return _gl.LUMINANCE;
|
|
|
- if ( p === THREE.LuminanceAlphaFormat ) return _gl.LUMINANCE_ALPHA;
|
|
|
-
|
|
|
- if ( p === THREE.AddEquation ) return _gl.FUNC_ADD;
|
|
|
- if ( p === THREE.SubtractEquation ) return _gl.FUNC_SUBTRACT;
|
|
|
- if ( p === THREE.ReverseSubtractEquation ) return _gl.FUNC_REVERSE_SUBTRACT;
|
|
|
-
|
|
|
- if ( p === THREE.ZeroFactor ) return _gl.ZERO;
|
|
|
- if ( p === THREE.OneFactor ) return _gl.ONE;
|
|
|
- if ( p === THREE.SrcColorFactor ) return _gl.SRC_COLOR;
|
|
|
- if ( p === THREE.OneMinusSrcColorFactor ) return _gl.ONE_MINUS_SRC_COLOR;
|
|
|
- if ( p === THREE.SrcAlphaFactor ) return _gl.SRC_ALPHA;
|
|
|
- if ( p === THREE.OneMinusSrcAlphaFactor ) return _gl.ONE_MINUS_SRC_ALPHA;
|
|
|
- if ( p === THREE.DstAlphaFactor ) return _gl.DST_ALPHA;
|
|
|
- if ( p === THREE.OneMinusDstAlphaFactor ) return _gl.ONE_MINUS_DST_ALPHA;
|
|
|
-
|
|
|
- if ( p === THREE.DstColorFactor ) return _gl.DST_COLOR;
|
|
|
- if ( p === THREE.OneMinusDstColorFactor ) return _gl.ONE_MINUS_DST_COLOR;
|
|
|
- if ( p === THREE.SrcAlphaSaturateFactor ) return _gl.SRC_ALPHA_SATURATE;
|
|
|
-
|
|
|
- if ( _glExtensionCompressedTextureS3TC !== undefined ) {
|
|
|
-
|
|
|
- if ( p === THREE.RGB_S3TC_DXT1_Format ) return _glExtensionCompressedTextureS3TC.COMPRESSED_RGB_S3TC_DXT1_EXT;
|
|
|
- if ( p === THREE.RGBA_S3TC_DXT1_Format ) return _glExtensionCompressedTextureS3TC.COMPRESSED_RGBA_S3TC_DXT1_EXT;
|
|
|
- if ( p === THREE.RGBA_S3TC_DXT3_Format ) return _glExtensionCompressedTextureS3TC.COMPRESSED_RGBA_S3TC_DXT3_EXT;
|
|
|
- if ( p === THREE.RGBA_S3TC_DXT5_Format ) return _glExtensionCompressedTextureS3TC.COMPRESSED_RGBA_S3TC_DXT5_EXT;
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- return 0;
|
|
|
+ return attributes;
|
|
|
|
|
|
};
|
|
|
|
|
|
- // Allocations
|
|
|
+ return function ( renderer, code, material, parameters ) {
|
|
|
|
|
|
- function allocateBones ( object ) {
|
|
|
+ var _this = renderer;
|
|
|
+ var _gl = _this.context;
|
|
|
|
|
|
- if ( _supportsBoneTextures && object && object.useVertexTexture ) {
|
|
|
+ var fragmentShader = material.fragmentShader;
|
|
|
+ var vertexShader = material.vertexShader;
|
|
|
+ var uniforms = material.uniforms;
|
|
|
+ var attributes = material.attributes;
|
|
|
+ var defines = material.defines;
|
|
|
+ var index0AttributeName = material.index0AttributeName;
|
|
|
|
|
|
- return 1024;
|
|
|
+ var shadowMapTypeDefine = "SHADOWMAP_TYPE_BASIC";
|
|
|
|
|
|
- } else {
|
|
|
+ if ( parameters.shadowMapType === THREE.PCFShadowMap ) {
|
|
|
|
|
|
- // 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)
|
|
|
+ shadowMapTypeDefine = "SHADOWMAP_TYPE_PCF";
|
|
|
|
|
|
- var nVertexUniforms = _gl.getParameter( _gl.MAX_VERTEX_UNIFORM_VECTORS );
|
|
|
- var nVertexMatrices = Math.floor( ( nVertexUniforms - 20 ) / 4 );
|
|
|
+ } else if ( parameters.shadowMapType === THREE.PCFSoftShadowMap ) {
|
|
|
|
|
|
- var maxBones = nVertexMatrices;
|
|
|
+ shadowMapTypeDefine = "SHADOWMAP_TYPE_PCF_SOFT";
|
|
|
|
|
|
- if ( object !== undefined && object instanceof THREE.SkinnedMesh ) {
|
|
|
+ }
|
|
|
|
|
|
- maxBones = Math.min( object.bones.length, maxBones );
|
|
|
+ // console.log( "building new program " );
|
|
|
|
|
|
- if ( maxBones < object.bones.length ) {
|
|
|
+ //
|
|
|
|
|
|
- console.warn( "WebGLRenderer: too many bones - " + object.bones.length + ", this GPU supports just " + maxBones + " (try OpenGL instead of ANGLE)" );
|
|
|
+ var customDefines = generateDefines( defines );
|
|
|
|
|
|
- }
|
|
|
+ //
|
|
|
|
|
|
- }
|
|
|
+ var program = _gl.createProgram();
|
|
|
|
|
|
- return maxBones;
|
|
|
+ var prefix_vertex = [
|
|
|
|
|
|
- }
|
|
|
+ "precision " + parameters.precision + " float;",
|
|
|
+ "precision " + parameters.precision + " int;",
|
|
|
|
|
|
- };
|
|
|
+ customDefines,
|
|
|
|
|
|
- function allocateLights( lights ) {
|
|
|
+ parameters.supportsVertexTextures ? "#define VERTEX_TEXTURES" : "",
|
|
|
|
|
|
- var dirLights = 0;
|
|
|
- var pointLights = 0;
|
|
|
- var spotLights = 0;
|
|
|
- var hemiLights = 0;
|
|
|
+ _this.gammaInput ? "#define GAMMA_INPUT" : "",
|
|
|
+ _this.gammaOutput ? "#define GAMMA_OUTPUT" : "",
|
|
|
|
|
|
- for ( var l = 0, ll = lights.length; l < ll; l ++ ) {
|
|
|
+ "#define MAX_DIR_LIGHTS " + parameters.maxDirLights,
|
|
|
+ "#define MAX_POINT_LIGHTS " + parameters.maxPointLights,
|
|
|
+ "#define MAX_SPOT_LIGHTS " + parameters.maxSpotLights,
|
|
|
+ "#define MAX_HEMI_LIGHTS " + parameters.maxHemiLights,
|
|
|
|
|
|
- var light = lights[ l ];
|
|
|
+ "#define MAX_SHADOWS " + parameters.maxShadows,
|
|
|
|
|
|
- if ( light.onlyShadow || light.visible === false ) continue;
|
|
|
+ "#define MAX_BONES " + parameters.maxBones,
|
|
|
|
|
|
- if ( light instanceof THREE.DirectionalLight ) dirLights ++;
|
|
|
- if ( light instanceof THREE.PointLight ) pointLights ++;
|
|
|
- if ( light instanceof THREE.SpotLight ) spotLights ++;
|
|
|
- if ( light instanceof THREE.HemisphereLight ) hemiLights ++;
|
|
|
+ parameters.map ? "#define USE_MAP" : "",
|
|
|
+ parameters.envMap ? "#define USE_ENVMAP" : "",
|
|
|
+ parameters.lightMap ? "#define USE_LIGHTMAP" : "",
|
|
|
+ parameters.bumpMap ? "#define USE_BUMPMAP" : "",
|
|
|
+ parameters.normalMap ? "#define USE_NORMALMAP" : "",
|
|
|
+ parameters.specularMap ? "#define USE_SPECULARMAP" : "",
|
|
|
+ parameters.vertexColors ? "#define USE_COLOR" : "",
|
|
|
|
|
|
- }
|
|
|
+ parameters.skinning ? "#define USE_SKINNING" : "",
|
|
|
+ parameters.useVertexTexture ? "#define BONE_TEXTURE" : "",
|
|
|
|
|
|
- return { 'directional' : dirLights, 'point' : pointLights, 'spot': spotLights, 'hemi': hemiLights };
|
|
|
+ parameters.morphTargets ? "#define USE_MORPHTARGETS" : "",
|
|
|
+ parameters.morphNormals ? "#define USE_MORPHNORMALS" : "",
|
|
|
+ parameters.wrapAround ? "#define WRAP_AROUND" : "",
|
|
|
+ parameters.doubleSided ? "#define DOUBLE_SIDED" : "",
|
|
|
+ parameters.flipSided ? "#define FLIP_SIDED" : "",
|
|
|
|
|
|
- };
|
|
|
+ parameters.shadowMapEnabled ? "#define USE_SHADOWMAP" : "",
|
|
|
+ parameters.shadowMapEnabled ? "#define " + shadowMapTypeDefine : "",
|
|
|
+ parameters.shadowMapDebug ? "#define SHADOWMAP_DEBUG" : "",
|
|
|
+ parameters.shadowMapCascade ? "#define SHADOWMAP_CASCADE" : "",
|
|
|
|
|
|
- function allocateShadows( lights ) {
|
|
|
+ parameters.sizeAttenuation ? "#define USE_SIZEATTENUATION" : "",
|
|
|
|
|
|
- var maxShadows = 0;
|
|
|
+ "uniform mat4 modelMatrix;",
|
|
|
+ "uniform mat4 modelViewMatrix;",
|
|
|
+ "uniform mat4 projectionMatrix;",
|
|
|
+ "uniform mat4 viewMatrix;",
|
|
|
+ "uniform mat3 normalMatrix;",
|
|
|
+ "uniform vec3 cameraPosition;",
|
|
|
|
|
|
- for ( var l = 0, ll = lights.length; l < ll; l++ ) {
|
|
|
+ "attribute vec3 position;",
|
|
|
+ "attribute vec3 normal;",
|
|
|
+ "attribute vec2 uv;",
|
|
|
+ "attribute vec2 uv2;",
|
|
|
|
|
|
- var light = lights[ l ];
|
|
|
+ "#ifdef USE_COLOR",
|
|
|
|
|
|
- if ( ! light.castShadow ) continue;
|
|
|
+ " attribute vec3 color;",
|
|
|
|
|
|
- if ( light instanceof THREE.SpotLight ) maxShadows ++;
|
|
|
- if ( light instanceof THREE.DirectionalLight && ! light.shadowCascade ) maxShadows ++;
|
|
|
+ "#endif",
|
|
|
|
|
|
- }
|
|
|
+ "#ifdef USE_MORPHTARGETS",
|
|
|
|
|
|
- return maxShadows;
|
|
|
+ " attribute vec3 morphTarget0;",
|
|
|
+ " attribute vec3 morphTarget1;",
|
|
|
+ " attribute vec3 morphTarget2;",
|
|
|
+ " attribute vec3 morphTarget3;",
|
|
|
|
|
|
- };
|
|
|
+ " #ifdef USE_MORPHNORMALS",
|
|
|
|
|
|
- // Initialization
|
|
|
+ " attribute vec3 morphNormal0;",
|
|
|
+ " attribute vec3 morphNormal1;",
|
|
|
+ " attribute vec3 morphNormal2;",
|
|
|
+ " attribute vec3 morphNormal3;",
|
|
|
|
|
|
- function initGL() {
|
|
|
+ " #else",
|
|
|
|
|
|
- try {
|
|
|
+ " attribute vec3 morphTarget4;",
|
|
|
+ " attribute vec3 morphTarget5;",
|
|
|
+ " attribute vec3 morphTarget6;",
|
|
|
+ " attribute vec3 morphTarget7;",
|
|
|
|
|
|
- var attributes = {
|
|
|
- alpha: _alpha,
|
|
|
- depth: _depth,
|
|
|
- stencil: _stencil,
|
|
|
- antialias: _antialias,
|
|
|
- premultipliedAlpha: _premultipliedAlpha,
|
|
|
- preserveDrawingBuffer: _preserveDrawingBuffer
|
|
|
- };
|
|
|
+ " #endif",
|
|
|
|
|
|
- _gl = _context || _canvas.getContext( 'webgl', attributes ) || _canvas.getContext( 'experimental-webgl', attributes );
|
|
|
+ "#endif",
|
|
|
|
|
|
- if ( _gl === null ) {
|
|
|
+ "#ifdef USE_SKINNING",
|
|
|
|
|
|
- throw 'Error creating WebGL context.';
|
|
|
+ " attribute vec4 skinIndex;",
|
|
|
+ " attribute vec4 skinWeight;",
|
|
|
|
|
|
- }
|
|
|
+ "#endif",
|
|
|
|
|
|
- } catch ( error ) {
|
|
|
+ ""
|
|
|
|
|
|
- console.error( error );
|
|
|
+ ].join( '\n' );
|
|
|
|
|
|
- }
|
|
|
+ var prefix_fragment = [
|
|
|
|
|
|
- _glExtensionTextureFloat = _gl.getExtension( 'OES_texture_float' );
|
|
|
- _glExtensionTextureFloatLinear = _gl.getExtension( 'OES_texture_float_linear' );
|
|
|
- _glExtensionStandardDerivatives = _gl.getExtension( 'OES_standard_derivatives' );
|
|
|
+ "precision " + parameters.precision + " float;",
|
|
|
+ "precision " + parameters.precision + " int;",
|
|
|
|
|
|
- _glExtensionTextureFilterAnisotropic = _gl.getExtension( 'EXT_texture_filter_anisotropic' ) || _gl.getExtension( 'MOZ_EXT_texture_filter_anisotropic' ) || _gl.getExtension( 'WEBKIT_EXT_texture_filter_anisotropic' );
|
|
|
+ ( parameters.bumpMap || parameters.normalMap ) ? "#extension GL_OES_standard_derivatives : enable" : "",
|
|
|
|
|
|
- _glExtensionCompressedTextureS3TC = _gl.getExtension( 'WEBGL_compressed_texture_s3tc' ) || _gl.getExtension( 'MOZ_WEBGL_compressed_texture_s3tc' ) || _gl.getExtension( 'WEBKIT_WEBGL_compressed_texture_s3tc' );
|
|
|
+ customDefines,
|
|
|
|
|
|
- _glExtensionElementIndexUint = _gl.getExtension( 'OES_element_index_uint' );
|
|
|
-
|
|
|
-
|
|
|
- if ( _glExtensionTextureFloat === null ) {
|
|
|
+ "#define MAX_DIR_LIGHTS " + parameters.maxDirLights,
|
|
|
+ "#define MAX_POINT_LIGHTS " + parameters.maxPointLights,
|
|
|
+ "#define MAX_SPOT_LIGHTS " + parameters.maxSpotLights,
|
|
|
+ "#define MAX_HEMI_LIGHTS " + parameters.maxHemiLights,
|
|
|
|
|
|
- console.log( 'THREE.WebGLRenderer: Float textures not supported.' );
|
|
|
+ "#define MAX_SHADOWS " + parameters.maxShadows,
|
|
|
|
|
|
- }
|
|
|
+ parameters.alphaTest ? "#define ALPHATEST " + parameters.alphaTest: "",
|
|
|
|
|
|
- if ( _glExtensionStandardDerivatives === null ) {
|
|
|
+ _this.gammaInput ? "#define GAMMA_INPUT" : "",
|
|
|
+ _this.gammaOutput ? "#define GAMMA_OUTPUT" : "",
|
|
|
|
|
|
- console.log( 'THREE.WebGLRenderer: Standard derivatives not supported.' );
|
|
|
+ ( parameters.useFog && parameters.fog ) ? "#define USE_FOG" : "",
|
|
|
+ ( parameters.useFog && parameters.fogExp ) ? "#define FOG_EXP2" : "",
|
|
|
|
|
|
- }
|
|
|
+ parameters.map ? "#define USE_MAP" : "",
|
|
|
+ parameters.envMap ? "#define USE_ENVMAP" : "",
|
|
|
+ parameters.lightMap ? "#define USE_LIGHTMAP" : "",
|
|
|
+ parameters.bumpMap ? "#define USE_BUMPMAP" : "",
|
|
|
+ parameters.normalMap ? "#define USE_NORMALMAP" : "",
|
|
|
+ parameters.specularMap ? "#define USE_SPECULARMAP" : "",
|
|
|
+ parameters.vertexColors ? "#define USE_COLOR" : "",
|
|
|
|
|
|
- if ( _glExtensionTextureFilterAnisotropic === null ) {
|
|
|
+ parameters.metal ? "#define METAL" : "",
|
|
|
+ parameters.wrapAround ? "#define WRAP_AROUND" : "",
|
|
|
+ parameters.doubleSided ? "#define DOUBLE_SIDED" : "",
|
|
|
+ parameters.flipSided ? "#define FLIP_SIDED" : "",
|
|
|
|
|
|
- console.log( 'THREE.WebGLRenderer: Anisotropic texture filtering not supported.' );
|
|
|
+ parameters.shadowMapEnabled ? "#define USE_SHADOWMAP" : "",
|
|
|
+ parameters.shadowMapEnabled ? "#define " + shadowMapTypeDefine : "",
|
|
|
+ parameters.shadowMapDebug ? "#define SHADOWMAP_DEBUG" : "",
|
|
|
+ parameters.shadowMapCascade ? "#define SHADOWMAP_CASCADE" : "",
|
|
|
|
|
|
- }
|
|
|
+ "uniform mat4 viewMatrix;",
|
|
|
+ "uniform vec3 cameraPosition;",
|
|
|
+ ""
|
|
|
|
|
|
- if ( _glExtensionCompressedTextureS3TC === null ) {
|
|
|
+ ].join( '\n' );
|
|
|
|
|
|
- console.log( 'THREE.WebGLRenderer: S3TC compressed textures not supported.' );
|
|
|
+ var glVertexShader = new THREE.WebGLShader( _gl, _gl.VERTEX_SHADER, prefix_vertex + vertexShader );
|
|
|
+ var glFragmentShader = new THREE.WebGLShader( _gl, _gl.FRAGMENT_SHADER, prefix_fragment + fragmentShader );
|
|
|
|
|
|
- }
|
|
|
+ _gl.attachShader( program, glVertexShader );
|
|
|
+ _gl.attachShader( program, glFragmentShader );
|
|
|
|
|
|
- if ( _glExtensionElementIndexUint === null ) {
|
|
|
+ // Force a particular attribute to index 0.
|
|
|
+ // because potentially expensive emulation is done by browser if attribute 0 is disabled.
|
|
|
+ // And, color, for example is often automatically bound to index 0 so disabling it
|
|
|
+ if ( index0AttributeName !== undefined ) {
|
|
|
|
|
|
- console.log( 'THREE.WebGLRenderer: elementindex as unsigned integer not supported.' );
|
|
|
+ _gl.bindAttribLocation( program, 0, index0AttributeName );
|
|
|
|
|
|
}
|
|
|
|
|
|
- if ( _gl.getShaderPrecisionFormat === undefined ) {
|
|
|
+ _gl.linkProgram( program );
|
|
|
|
|
|
- _gl.getShaderPrecisionFormat = function() {
|
|
|
+ if ( _gl.getProgramParameter( program, _gl.LINK_STATUS ) === false ) {
|
|
|
|
|
|
- return {
|
|
|
- "rangeMin" : 1,
|
|
|
- "rangeMax" : 1,
|
|
|
- "precision" : 1
|
|
|
- };
|
|
|
+ console.error( 'Could not initialise shader' );
|
|
|
+ console.error( 'gl.VALIDATE_STATUS', _gl.getProgramParameter( program, _gl.VALIDATE_STATUS ) );
|
|
|
+ console.error( 'gl.getError()', _gl.getError() );
|
|
|
|
|
|
- }
|
|
|
}
|
|
|
|
|
|
- };
|
|
|
-
|
|
|
- function setDefaultGLState () {
|
|
|
-
|
|
|
- _gl.clearColor( 0, 0, 0, 1 );
|
|
|
- _gl.clearDepth( 1 );
|
|
|
- _gl.clearStencil( 0 );
|
|
|
-
|
|
|
- _gl.enable( _gl.DEPTH_TEST );
|
|
|
- _gl.depthFunc( _gl.LEQUAL );
|
|
|
-
|
|
|
- _gl.frontFace( _gl.CCW );
|
|
|
- _gl.cullFace( _gl.BACK );
|
|
|
- _gl.enable( _gl.CULL_FACE );
|
|
|
-
|
|
|
- _gl.enable( _gl.BLEND );
|
|
|
- _gl.blendEquation( _gl.FUNC_ADD );
|
|
|
- _gl.blendFunc( _gl.SRC_ALPHA, _gl.ONE_MINUS_SRC_ALPHA );
|
|
|
-
|
|
|
- _gl.viewport( _viewportX, _viewportY, _viewportWidth, _viewportHeight );
|
|
|
-
|
|
|
- _gl.clearColor( _clearColor.r, _clearColor.g, _clearColor.b, _clearAlpha );
|
|
|
-
|
|
|
- };
|
|
|
-
|
|
|
- // default plugins (order is important)
|
|
|
-
|
|
|
- this.shadowMapPlugin = new THREE.ShadowMapPlugin();
|
|
|
- this.addPrePlugin( this.shadowMapPlugin );
|
|
|
-
|
|
|
- this.addPostPlugin( new THREE.SpritePlugin() );
|
|
|
- this.addPostPlugin( new THREE.LensFlarePlugin() );
|
|
|
-
|
|
|
-};
|
|
|
-
|
|
|
-/**
|
|
|
- * @author szimek / https://github.com/szimek/
|
|
|
- * @author alteredq / http://alteredqualia.com/
|
|
|
- */
|
|
|
-
|
|
|
-THREE.WebGLRenderTarget = function ( width, height, options ) {
|
|
|
-
|
|
|
- this.width = width;
|
|
|
- this.height = height;
|
|
|
+ if ( _gl.getProgramInfoLog( program ) !== '' ) {
|
|
|
|
|
|
- options = options || {};
|
|
|
+ console.error( 'gl.getProgramInfoLog()', _gl.getProgramInfoLog( program ) );
|
|
|
|
|
|
- this.wrapS = options.wrapS !== undefined ? options.wrapS : THREE.ClampToEdgeWrapping;
|
|
|
- this.wrapT = options.wrapT !== undefined ? options.wrapT : THREE.ClampToEdgeWrapping;
|
|
|
+ }
|
|
|
|
|
|
- this.magFilter = options.magFilter !== undefined ? options.magFilter : THREE.LinearFilter;
|
|
|
- this.minFilter = options.minFilter !== undefined ? options.minFilter : THREE.LinearMipMapLinearFilter;
|
|
|
+ // cache uniform locations
|
|
|
|
|
|
- this.anisotropy = options.anisotropy !== undefined ? options.anisotropy : 1;
|
|
|
+ var identifiers = [
|
|
|
|
|
|
- this.offset = new THREE.Vector2( 0, 0 );
|
|
|
- this.repeat = new THREE.Vector2( 1, 1 );
|
|
|
+ 'viewMatrix', 'modelViewMatrix', 'projectionMatrix', 'normalMatrix', 'modelMatrix', 'cameraPosition',
|
|
|
+ 'morphTargetInfluences'
|
|
|
|
|
|
- this.format = options.format !== undefined ? options.format : THREE.RGBAFormat;
|
|
|
- this.type = options.type !== undefined ? options.type : THREE.UnsignedByteType;
|
|
|
+ ];
|
|
|
|
|
|
- this.depthBuffer = options.depthBuffer !== undefined ? options.depthBuffer : true;
|
|
|
- this.stencilBuffer = options.stencilBuffer !== undefined ? options.stencilBuffer : true;
|
|
|
+ if ( parameters.useVertexTexture ) {
|
|
|
|
|
|
- this.generateMipmaps = true;
|
|
|
+ identifiers.push( 'boneTexture' );
|
|
|
+ identifiers.push( 'boneTextureWidth' );
|
|
|
+ identifiers.push( 'boneTextureHeight' );
|
|
|
|
|
|
- this.shareDepthFrom = null;
|
|
|
+ } else {
|
|
|
|
|
|
-};
|
|
|
+ identifiers.push( 'boneGlobalMatrices' );
|
|
|
|
|
|
-THREE.WebGLRenderTarget.prototype = {
|
|
|
+ }
|
|
|
|
|
|
- constructor: THREE.WebGLRenderTarget,
|
|
|
+ for ( var u in uniforms ) {
|
|
|
|
|
|
- clone: function () {
|
|
|
+ identifiers.push( u );
|
|
|
|
|
|
- var tmp = new THREE.WebGLRenderTarget( this.width, this.height );
|
|
|
+ }
|
|
|
|
|
|
- tmp.wrapS = this.wrapS;
|
|
|
- tmp.wrapT = this.wrapT;
|
|
|
+ this.uniforms = cacheUniformLocations( _gl, program, identifiers );
|
|
|
|
|
|
- tmp.magFilter = this.magFilter;
|
|
|
- tmp.minFilter = this.minFilter;
|
|
|
+ // cache attributes locations
|
|
|
|
|
|
- tmp.anisotropy = this.anisotropy;
|
|
|
+ identifiers = [
|
|
|
|
|
|
- tmp.offset.copy( this.offset );
|
|
|
- tmp.repeat.copy( this.repeat );
|
|
|
+ "position", "normal", "uv", "uv2", "tangent", "color",
|
|
|
+ "skinIndex", "skinWeight", "lineDistance"
|
|
|
|
|
|
- tmp.format = this.format;
|
|
|
- tmp.type = this.type;
|
|
|
+ ];
|
|
|
|
|
|
- tmp.depthBuffer = this.depthBuffer;
|
|
|
- tmp.stencilBuffer = this.stencilBuffer;
|
|
|
+ for ( var i = 0; i < parameters.maxMorphTargets; i ++ ) {
|
|
|
|
|
|
- tmp.generateMipmaps = this.generateMipmaps;
|
|
|
+ identifiers.push( "morphTarget" + i );
|
|
|
|
|
|
- tmp.shareDepthFrom = this.shareDepthFrom;
|
|
|
+ }
|
|
|
|
|
|
- return tmp;
|
|
|
+ for ( var i = 0; i < parameters.maxMorphNormals; i ++ ) {
|
|
|
|
|
|
- },
|
|
|
+ identifiers.push( "morphNormal" + i );
|
|
|
|
|
|
- dispose: function () {
|
|
|
+ }
|
|
|
|
|
|
- this.dispatchEvent( { type: 'dispose' } );
|
|
|
+ for ( var a in attributes ) {
|
|
|
|
|
|
- }
|
|
|
+ identifiers.push( a );
|
|
|
|
|
|
-};
|
|
|
+ }
|
|
|
|
|
|
-THREE.EventDispatcher.prototype.apply( THREE.WebGLRenderTarget.prototype );
|
|
|
+ this.attributes = cacheAttributeLocations( _gl, program, identifiers );
|
|
|
|
|
|
-/**
|
|
|
- * @author alteredq / http://alteredqualia.com
|
|
|
- */
|
|
|
+ //
|
|
|
|
|
|
-THREE.WebGLRenderTargetCube = function ( width, height, options ) {
|
|
|
+ this.id = programIdCount ++;
|
|
|
+ this.code = code;
|
|
|
+ this.usedTimes = 1;
|
|
|
+ this.program = program;
|
|
|
+ this.vertexShader = glVertexShader; // _gl.getShaderSource( glVertexShader );
|
|
|
+ this.fragmentShader = _gl.getShaderSource( glFragmentShader );
|
|
|
|
|
|
- THREE.WebGLRenderTarget.call( this, width, height, options );
|
|
|
+ // clean up
|
|
|
|
|
|
- this.activeCubeFace = 0; // PX 0, NX 1, PY 2, NY 3, PZ 4, NZ 5
|
|
|
+ _gl.deleteShader( glVertexShader );
|
|
|
+ _gl.deleteShader( glFragmentShader );
|
|
|
|
|
|
-};
|
|
|
+ return this;
|
|
|
|
|
|
-THREE.WebGLRenderTargetCube.prototype = Object.create( THREE.WebGLRenderTarget.prototype );
|
|
|
+ };
|
|
|
|
|
|
+} )();
|
|
|
THREE.WebGLShader = ( function () {
|
|
|
|
|
|
var addLineNumbers = function ( string ) {
|