Files
three.js/src/renderers/WebGLRenderer.js
T

5665 lines
141 KiB
JavaScript

/**
* @author supereggbert / http://www.paulbrunt.co.uk/
* @author mrdoob / http://mrdoob.com/
* @author alteredq / http://alteredqualia.com/
* @author szimek / https://github.com/szimek/
*/
THREE.WebGLRenderer = function ( parameters ) {
// Currently you can use just up to 4 directional / point lights total.
// Chrome barfs on shader linking when there are more than 4 lights :(
// The problem comes from shader using too many varying vectors.
// This is not GPU limitation as the same shader works ok in Firefox
// and Chrome with "--use-gl=desktop" flag.
// Difference comes from Chrome on Windows using by default ANGLE,
// thus going DirectX9 route (while FF uses OpenGL).
// See http://code.google.com/p/chromium/issues/detail?id=63491
var _this = this,
_gl, _programs = [],
_currentProgram = null,
_currentFramebuffer = null,
_currentDepthMask = true,
// gl state cache
_oldDoubleSided = null,
_oldFlipSided = null,
_oldBlending = null,
_oldDepth = null,
_oldPolygonOffset = null,
_oldPolygonOffsetFactor = null,
_oldPolygonOffsetUnits = null,
_cullEnabled = true,
_viewportX = 0,
_viewportY = 0,
_viewportWidth = 0,
_viewportHeight = 0,
// camera matrices caches
_frustum = [
new THREE.Vector4(),
new THREE.Vector4(),
new THREE.Vector4(),
new THREE.Vector4(),
new THREE.Vector4(),
new THREE.Vector4()
],
_projScreenMatrix = new THREE.Matrix4(),
_projectionMatrixArray = new Float32Array( 16 ),
_viewMatrixArray = new Float32Array( 16 ),
_vector3 = new THREE.Vector4(),
// light arrays cache
_lights = {
ambient: [ 0, 0, 0 ],
directional: { length: 0, colors: new Array(), positions: new Array() },
point: { length: 0, colors: new Array(), positions: new Array(), distances: new Array() }
},
// parameters
parameters = parameters || {},
_canvas = parameters.canvas !== undefined ? parameters.canvas : document.createElement( 'canvas' ),
_stencil = parameters.stencil !== undefined ? parameters.stencil : true,
_antialias = parameters.antialias !== undefined ? parameters.antialias : false,
_clearColor = parameters.clearColor !== undefined ? new THREE.Color( parameters.clearColor ) : new THREE.Color( 0x000000 ),
_clearAlpha = parameters.clearAlpha !== undefined ? parameters.clearAlpha : 0;
this.data = {
vertices: 0,
faces: 0,
drawCalls: 0
};
this.maxMorphTargets = 8;
this.domElement = _canvas;
this.autoClear = true;
this.sortObjects = true;
// Init GL
try {
if ( ! ( _gl = _canvas.getContext( 'experimental-webgl', { antialias: _antialias, stencil: _stencil } ) ) ) {
throw 'Error creating WebGL context.';
}
console.log(
navigator.userAgent + " | " +
_gl.getParameter( _gl.VERSION ) + " | " +
_gl.getParameter( _gl.VENDOR ) + " | " +
_gl.getParameter( _gl.RENDERER ) + " | " +
_gl.getParameter( _gl.SHADING_LANGUAGE_VERSION )
);
} catch ( error ) {
console.error( error );
}
_gl.clearColor( 0, 0, 0, 1 );
_gl.clearDepth( 1 );
_gl.enable( _gl.DEPTH_TEST );
_gl.depthFunc( _gl.LEQUAL );
_gl.frontFace( _gl.CCW );
_gl.cullFace( _gl.BACK );
_gl.enable( _gl.CULL_FACE );
_gl.enable( _gl.BLEND );
_gl.blendEquation( _gl.FUNC_ADD );
_gl.blendFunc( _gl.SRC_ALPHA, _gl.ONE_MINUS_SRC_ALPHA );
_gl.clearColor( _clearColor.r, _clearColor.g, _clearColor.b, _clearAlpha );
_cullEnabled = true;
//
this.context = _gl;
var _supportsVertexTextures = ( maxVertexTextures() > 0 );
// prepare stencil shadow polygon
if ( _stencil ) {
var _stencilShadow = {};
_stencilShadow.vertices = new Float32Array( 12 );
_stencilShadow.faces = new Uint16Array( 6 );
_stencilShadow.darkness = 0.5;
_stencilShadow.vertices[ 0 * 3 + 0 ] = -20; _stencilShadow.vertices[ 0 * 3 + 1 ] = -20; _stencilShadow.vertices[ 0 * 3 + 2 ] = -1;
_stencilShadow.vertices[ 1 * 3 + 0 ] = 20; _stencilShadow.vertices[ 1 * 3 + 1 ] = -20; _stencilShadow.vertices[ 1 * 3 + 2 ] = -1;
_stencilShadow.vertices[ 2 * 3 + 0 ] = 20; _stencilShadow.vertices[ 2 * 3 + 1 ] = 20; _stencilShadow.vertices[ 2 * 3 + 2 ] = -1;
_stencilShadow.vertices[ 3 * 3 + 0 ] = -20; _stencilShadow.vertices[ 3 * 3 + 1 ] = 20; _stencilShadow.vertices[ 3 * 3 + 2 ] = -1;
_stencilShadow.faces[ 0 ] = 0; _stencilShadow.faces[ 1 ] = 1; _stencilShadow.faces[ 2 ] = 2;
_stencilShadow.faces[ 3 ] = 0; _stencilShadow.faces[ 4 ] = 2; _stencilShadow.faces[ 5 ] = 3;
_stencilShadow.vertexBuffer = _gl.createBuffer();
_stencilShadow.elementBuffer = _gl.createBuffer();
_gl.bindBuffer( _gl.ARRAY_BUFFER, _stencilShadow.vertexBuffer );
_gl.bufferData( _gl.ARRAY_BUFFER, _stencilShadow.vertices, _gl.STATIC_DRAW );
_gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, _stencilShadow.elementBuffer );
_gl.bufferData( _gl.ELEMENT_ARRAY_BUFFER, _stencilShadow.faces, _gl.STATIC_DRAW );
_stencilShadow.program = _gl.createProgram();
_gl.attachShader( _stencilShadow.program, getShader( "fragment", THREE.ShaderLib.shadowPost.fragmentShader ));
_gl.attachShader( _stencilShadow.program, getShader( "vertex", THREE.ShaderLib.shadowPost.vertexShader ));
_gl.linkProgram( _stencilShadow.program );
_stencilShadow.vertexLocation = _gl.getAttribLocation ( _stencilShadow.program, "position" );
_stencilShadow.projectionLocation = _gl.getUniformLocation( _stencilShadow.program, "projectionMatrix" );
_stencilShadow.darknessLocation = _gl.getUniformLocation( _stencilShadow.program, "darkness" );
}
// prepare lens flare
var _lensFlare = {};
var i;
_lensFlare.vertices = new Float32Array( 8 + 8 );
_lensFlare.faces = new Uint16Array( 6 );
i = 0;
_lensFlare.vertices[ i++ ] = -1; _lensFlare.vertices[ i++ ] = -1; // vertex
_lensFlare.vertices[ i++ ] = 0; _lensFlare.vertices[ i++ ] = 0; // uv... etc.
_lensFlare.vertices[ i++ ] = 1; _lensFlare.vertices[ i++ ] = -1;
_lensFlare.vertices[ i++ ] = 1; _lensFlare.vertices[ i++ ] = 0;
_lensFlare.vertices[ i++ ] = 1; _lensFlare.vertices[ i++ ] = 1;
_lensFlare.vertices[ i++ ] = 1; _lensFlare.vertices[ i++ ] = 1;
_lensFlare.vertices[ i++ ] = -1; _lensFlare.vertices[ i++ ] = 1;
_lensFlare.vertices[ i++ ] = 0; _lensFlare.vertices[ i++ ] = 1;
i = 0;
_lensFlare.faces[ i++ ] = 0; _lensFlare.faces[ i++ ] = 1; _lensFlare.faces[ i++ ] = 2;
_lensFlare.faces[ i++ ] = 0; _lensFlare.faces[ i++ ] = 2; _lensFlare.faces[ i++ ] = 3;
_lensFlare.vertexBuffer = _gl.createBuffer();
_lensFlare.elementBuffer = _gl.createBuffer();
_lensFlare.tempTexture = _gl.createTexture();
_lensFlare.occlusionTexture = _gl.createTexture();
_gl.bindBuffer( _gl.ARRAY_BUFFER, _lensFlare.vertexBuffer );
_gl.bufferData( _gl.ARRAY_BUFFER, _lensFlare.vertices, _gl.STATIC_DRAW );
_gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, _lensFlare.elementBuffer );
_gl.bufferData( _gl.ELEMENT_ARRAY_BUFFER, _lensFlare.faces, _gl.STATIC_DRAW );
_gl.bindTexture( _gl.TEXTURE_2D, _lensFlare.tempTexture );
_gl.texImage2D( _gl.TEXTURE_2D, 0, _gl.RGB, 16, 16, 0, _gl.RGB, _gl.UNSIGNED_BYTE, null );
_gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_WRAP_S, _gl.CLAMP_TO_EDGE );
_gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_WRAP_T, _gl.CLAMP_TO_EDGE );
_gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_MAG_FILTER, _gl.NEAREST );
_gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_MIN_FILTER, _gl.NEAREST );
_gl.bindTexture( _gl.TEXTURE_2D, _lensFlare.occlusionTexture );
_gl.texImage2D( _gl.TEXTURE_2D, 0, _gl.RGBA, 16, 16, 0, _gl.RGBA, _gl.UNSIGNED_BYTE, null );
_gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_WRAP_S, _gl.CLAMP_TO_EDGE );
_gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_WRAP_T, _gl.CLAMP_TO_EDGE );
_gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_MAG_FILTER, _gl.NEAREST );
_gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_MIN_FILTER, _gl.NEAREST );
if( _gl.getParameter( _gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS ) <= 0 ) {
_lensFlare.hasVertexTexture = false;
_lensFlare.program = _gl.createProgram();
_gl.attachShader( _lensFlare.program, getShader( "fragment", THREE.ShaderLib.lensFlare.fragmentShader ));
_gl.attachShader( _lensFlare.program, getShader( "vertex", THREE.ShaderLib.lensFlare.vertexShader ));
_gl.linkProgram( _lensFlare.program );
} else {
_lensFlare.hasVertexTexture = true;
_lensFlare.program = _gl.createProgram();
_gl.attachShader( _lensFlare.program, getShader( "fragment", THREE.ShaderLib.lensFlareVertexTexture.fragmentShader ));
_gl.attachShader( _lensFlare.program, getShader( "vertex", THREE.ShaderLib.lensFlareVertexTexture.vertexShader ));
_gl.linkProgram( _lensFlare.program );
}
_lensFlare.attributes = {};
_lensFlare.uniforms = {};
_lensFlare.attributes.vertex = _gl.getAttribLocation ( _lensFlare.program, "position" );
_lensFlare.attributes.uv = _gl.getAttribLocation ( _lensFlare.program, "UV" );
_lensFlare.uniforms.renderType = _gl.getUniformLocation( _lensFlare.program, "renderType" );
_lensFlare.uniforms.map = _gl.getUniformLocation( _lensFlare.program, "map" );
_lensFlare.uniforms.occlusionMap = _gl.getUniformLocation( _lensFlare.program, "occlusionMap" );
_lensFlare.uniforms.opacity = _gl.getUniformLocation( _lensFlare.program, "opacity" );
_lensFlare.uniforms.scale = _gl.getUniformLocation( _lensFlare.program, "scale" );
_lensFlare.uniforms.rotation = _gl.getUniformLocation( _lensFlare.program, "rotation" );
_lensFlare.uniforms.screenPosition = _gl.getUniformLocation( _lensFlare.program, "screenPosition" );
//_gl.enableVertexAttribArray( _lensFlare.attributes.vertex );
//_gl.enableVertexAttribArray( _lensFlare.attributes.uv );
var _lensFlareAttributesEnabled = false;
// prepare sprites
var _sprite = {};
_sprite.vertices = new Float32Array( 8 + 8 );
_sprite.faces = new Uint16Array( 6 );
i = 0;
_sprite.vertices[ i++ ] = -1; _sprite.vertices[ i++ ] = -1; // vertex 0
_sprite.vertices[ i++ ] = 0; _sprite.vertices[ i++ ] = 1; // uv 0
_sprite.vertices[ i++ ] = 1; _sprite.vertices[ i++ ] = -1; // vertex 1
_sprite.vertices[ i++ ] = 1; _sprite.vertices[ i++ ] = 1; // uv 1
_sprite.vertices[ i++ ] = 1; _sprite.vertices[ i++ ] = 1; // vertex 2
_sprite.vertices[ i++ ] = 1; _sprite.vertices[ i++ ] = 0; // uv 2
_sprite.vertices[ i++ ] = -1; _sprite.vertices[ i++ ] = 1; // vertex 3
_sprite.vertices[ i++ ] = 0; _sprite.vertices[ i++ ] = 0; // uv 3
i = 0;
_sprite.faces[ i++ ] = 0; _sprite.faces[ i++ ] = 1; _sprite.faces[ i++ ] = 2;
_sprite.faces[ i++ ] = 0; _sprite.faces[ i++ ] = 2; _sprite.faces[ i++ ] = 3;
_sprite.vertexBuffer = _gl.createBuffer();
_sprite.elementBuffer = _gl.createBuffer();
_gl.bindBuffer( _gl.ARRAY_BUFFER, _sprite.vertexBuffer );
_gl.bufferData( _gl.ARRAY_BUFFER, _sprite.vertices, _gl.STATIC_DRAW );
_gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, _sprite.elementBuffer );
_gl.bufferData( _gl.ELEMENT_ARRAY_BUFFER, _sprite.faces, _gl.STATIC_DRAW );
_sprite.program = _gl.createProgram();
_gl.attachShader( _sprite.program, getShader( "fragment", THREE.ShaderLib.sprite.fragmentShader ));
_gl.attachShader( _sprite.program, getShader( "vertex", THREE.ShaderLib.sprite.vertexShader ));
_gl.linkProgram( _sprite.program );
_sprite.attributes = {};
_sprite.uniforms = {};
_sprite.attributes.position = _gl.getAttribLocation ( _sprite.program, "position" );
_sprite.attributes.uv = _gl.getAttribLocation ( _sprite.program, "uv" );
_sprite.uniforms.uvOffset = _gl.getUniformLocation( _sprite.program, "uvOffset" );
_sprite.uniforms.uvScale = _gl.getUniformLocation( _sprite.program, "uvScale" );
_sprite.uniforms.rotation = _gl.getUniformLocation( _sprite.program, "rotation" );
_sprite.uniforms.scale = _gl.getUniformLocation( _sprite.program, "scale" );
_sprite.uniforms.alignment = _gl.getUniformLocation( _sprite.program, "alignment" );
_sprite.uniforms.map = _gl.getUniformLocation( _sprite.program, "map" );
_sprite.uniforms.opacity = _gl.getUniformLocation( _sprite.program, "opacity" );
_sprite.uniforms.useScreenCoordinates = _gl.getUniformLocation( _sprite.program, "useScreenCoordinates" );
_sprite.uniforms.affectedByDistance = _gl.getUniformLocation( _sprite.program, "affectedByDistance" );
_sprite.uniforms.screenPosition = _gl.getUniformLocation( _sprite.program, "screenPosition" );
_sprite.uniforms.modelViewMatrix = _gl.getUniformLocation( _sprite.program, "modelViewMatrix" );
_sprite.uniforms.projectionMatrix = _gl.getUniformLocation( _sprite.program, "projectionMatrix" );
//_gl.enableVertexAttribArray( _sprite.attributes.position );
//_gl.enableVertexAttribArray( _sprite.attributes.uv );
var _spriteAttributesEnabled = false;
this.setSize = function ( width, height ) {
_canvas.width = width;
_canvas.height = height;
this.setViewport( 0, 0, _canvas.width, _canvas.height );
};
this.setViewport = function ( x, y, width, height ) {
_viewportX = x;
_viewportY = y;
_viewportWidth = width;
_viewportHeight = height;
_gl.viewport( _viewportX, _viewportY, _viewportWidth, _viewportHeight );
};
this.setScissor = function ( x, y, width, height ) {
_gl.scissor( x, y, width, height );
};
this.enableScissorTest = function ( enable ) {
if ( enable )
_gl.enable( _gl.SCISSOR_TEST );
else
_gl.disable( _gl.SCISSOR_TEST );
};
this.enableDepthBufferWrite = function ( enable ) {
_currentDepthMask = enable;
_gl.depthMask( enable );
};
this.setClearColorHex = function ( hex, alpha ) {
_clearColor.setHex( hex );
_clearAlpha = alpha;
_gl.clearColor( _clearColor.r, _clearColor.g, _clearColor.b, _clearAlpha );
};
this.setClearColor = function ( color, alpha ) {
_clearColor.copy( color );
_clearAlpha = alpha;
_gl.clearColor( _clearColor.r, _clearColor.g, _clearColor.b, _clearAlpha );
};
this.clear = function () {
_gl.clear( _gl.COLOR_BUFFER_BIT | _gl.DEPTH_BUFFER_BIT | _gl.STENCIL_BUFFER_BIT );
};
this.setStencilShadowDarkness = function( value ) {
_stencilShadow.darkness = value;
};
this.getContext = function() {
return _gl;
}
function setupLights ( program, lights ) {
var l, ll, light, r = 0, g = 0, b = 0,
color, position, intensity, distance,
zlights = _lights,
dcolors = zlights.directional.colors,
dpositions = zlights.directional.positions,
pcolors = zlights.point.colors,
ppositions = zlights.point.positions,
pdistances = zlights.point.distances,
dlength = 0,
plength = 0,
doffset = 0,
poffset = 0;
for ( l = 0, ll = lights.length; l < ll; l++ ) {
light = lights[ l ];
color = light.color;
position = light.position;
intensity = light.intensity;
distance = light.distance;
if ( light instanceof THREE.AmbientLight ) {
r += color.r;
g += color.g;
b += color.b;
} else if ( light instanceof THREE.DirectionalLight ) {
doffset = dlength * 3;
dcolors[ doffset ] = color.r * intensity;
dcolors[ doffset + 1 ] = color.g * intensity;
dcolors[ doffset + 2 ] = color.b * intensity;
dpositions[ doffset ] = position.x;
dpositions[ doffset + 1 ] = position.y;
dpositions[ doffset + 2 ] = position.z;
dlength += 1;
} else if( light instanceof THREE.PointLight ) {
poffset = plength * 3;
pcolors[ poffset ] = color.r * intensity;
pcolors[ poffset + 1 ] = color.g * intensity;
pcolors[ poffset + 2 ] = color.b * intensity;
ppositions[ poffset ] = position.x;
ppositions[ poffset + 1 ] = position.y;
ppositions[ poffset + 2 ] = position.z;
pdistances[ plength ] = distance;
plength += 1;
}
}
// null eventual remains from removed lights
// (this is to avoid if in shader)
for( l = dlength * 3; l < dcolors.length; l++ ) dcolors[ l ] = 0.0;
for( l = plength * 3; l < pcolors.length; l++ ) pcolors[ l ] = 0.0;
zlights.point.length = plength;
zlights.directional.length = dlength;
zlights.ambient[ 0 ] = r;
zlights.ambient[ 1 ] = g;
zlights.ambient[ 2 ] = b;
};
function createParticleBuffers ( geometry ) {
geometry.__webglVertexBuffer = _gl.createBuffer();
geometry.__webglColorBuffer = _gl.createBuffer();
};
function createLineBuffers( geometry ) {
geometry.__webglVertexBuffer = _gl.createBuffer();
geometry.__webglColorBuffer = _gl.createBuffer();
};
function createRibbonBuffers( geometry ) {
geometry.__webglVertexBuffer = _gl.createBuffer();
geometry.__webglColorBuffer = _gl.createBuffer();
};
function createMeshBuffers( geometryGroup ) {
geometryGroup.__webglVertexBuffer = _gl.createBuffer();
geometryGroup.__webglNormalBuffer = _gl.createBuffer();
geometryGroup.__webglTangentBuffer = _gl.createBuffer();
geometryGroup.__webglColorBuffer = _gl.createBuffer();
geometryGroup.__webglUVBuffer = _gl.createBuffer();
geometryGroup.__webglUV2Buffer = _gl.createBuffer();
geometryGroup.__webglSkinVertexABuffer = _gl.createBuffer();
geometryGroup.__webglSkinVertexBBuffer = _gl.createBuffer();
geometryGroup.__webglSkinIndicesBuffer = _gl.createBuffer();
geometryGroup.__webglSkinWeightsBuffer = _gl.createBuffer();
geometryGroup.__webglFaceBuffer = _gl.createBuffer();
geometryGroup.__webglLineBuffer = _gl.createBuffer();
if ( geometryGroup.numMorphTargets ) {
var m, ml;
geometryGroup.__webglMorphTargetsBuffers = [];
for ( m = 0, ml = geometryGroup.numMorphTargets; m < ml; m++ ) {
geometryGroup.__webglMorphTargetsBuffers.push( _gl.createBuffer() );
}
}
};
function initLineBuffers ( geometry ) {
var nvertices = geometry.vertices.length;
geometry.__vertexArray = new Float32Array( nvertices * 3 );
geometry.__colorArray = new Float32Array( nvertices * 3 );
geometry.__webglLineCount = nvertices;
};
function initRibbonBuffers ( geometry ) {
var nvertices = geometry.vertices.length;
geometry.__vertexArray = new Float32Array( nvertices * 3 );
geometry.__colorArray = new Float32Array( nvertices * 3 );
geometry.__webglVertexCount = nvertices;
};
function initParticleBuffers ( geometry, object ) {
var nvertices = geometry.vertices.length;
geometry.__vertexArray = new Float32Array( nvertices * 3 );
geometry.__colorArray = new Float32Array( nvertices * 3 );
geometry.__sortArray = [];
geometry.__webglParticleCount = nvertices;
geometry.__materials = object.materials;
// custom attributes
var m, ml, material;
for ( m = 0, ml = object.materials.length; m < ml; m ++ ) {
material = object.materials[ m ];
if ( material.attributes ) {
if ( geometry.__webglCustomAttributes === undefined ) {
geometry.__webglCustomAttributes = {};
}
for ( a in material.attributes ) {
// Do a shallow copy of the attribute object so different geometryGroup chunks use different
// attribute buffers which are correctly indexed in the setMeshBuffers function
// Not sure how to best translate this into non-indexed arrays
// used for particles, as there are no geometry chunks here
// Probably could be simplified
originalAttribute = material.attributes[ a ];
attribute = {};
for ( property in originalAttribute ) {
attribute[ property ] = originalAttribute[ property ];
}
if( !attribute.__webglInitialized || attribute.createUniqueBuffers ) {
attribute.__webglInitialized = true;
size = 1; // "f" and "i"
if( attribute.type === "v2" ) size = 2;
else if( attribute.type === "v3" ) size = 3;
else if( attribute.type === "v4" ) size = 4;
else if( attribute.type === "c" ) size = 3;
attribute.size = size;
attribute.array = new Float32Array( nvertices * size );
attribute.buffer = _gl.createBuffer();
attribute.buffer.belongsToAttribute = a;
originalAttribute.needsUpdate = true;
attribute.__original = originalAttribute;
}
geometry.__webglCustomAttributes[ a ] = attribute;
}
}
}
};
function initMeshBuffers ( geometryGroup, object ) {
var f, fl, fi, face,
m, ml, size,
nvertices = 0, ntris = 0, nlines = 0,
uvType,
vertexColorType,
normalType,
materials, material,
attribute, property, originalAttribute,
geometry = object.geometry,
obj_faces = geometry.faces,
chunk_faces = geometryGroup.faces;
for ( f = 0, fl = chunk_faces.length; f < fl; f++ ) {
fi = chunk_faces[ f ];
face = obj_faces[ fi ];
if ( face instanceof THREE.Face3 ) {
nvertices += 3;
ntris += 1;
nlines += 3;
} else if ( face instanceof THREE.Face4 ) {
nvertices += 4;
ntris += 2;
nlines += 4;
}
}
materials = unrollGroupMaterials( geometryGroup, object );
// this will not work if materials would change in run-time
// it should be refreshed every frame
// but need to do unrollGroupMaterials
// more properly without push to array
// like unrollBufferMaterials
geometryGroup.__materials = materials;
uvType = bufferGuessUVType( materials, geometryGroup, object );
normalType = bufferGuessNormalType( materials, geometryGroup, object );
vertexColorType = bufferGuessVertexColorType( materials, geometryGroup, object );
//console.log("uvType",uvType, "normalType",normalType, "vertexColorType",vertexColorType, object, geometryGroup, materials );
geometryGroup.__vertexArray = new Float32Array( nvertices * 3 );
if ( normalType ) {
geometryGroup.__normalArray = new Float32Array( nvertices * 3 );
}
if ( geometry.hasTangents ) {
geometryGroup.__tangentArray = new Float32Array( nvertices * 4 );
}
if ( vertexColorType ) {
geometryGroup.__colorArray = new Float32Array( nvertices * 3 );
}
if ( uvType ) {
if ( geometry.faceUvs.length > 0 || geometry.faceVertexUvs.length > 0 ) {
geometryGroup.__uvArray = new Float32Array( nvertices * 2 );
}
if ( geometry.faceUvs.length > 1 || geometry.faceVertexUvs.length > 1 ) {
geometryGroup.__uv2Array = new Float32Array( nvertices * 2 );
}
}
if ( object.geometry.skinWeights.length && object.geometry.skinIndices.length ) {
geometryGroup.__skinVertexAArray = new Float32Array( nvertices * 4 );
geometryGroup.__skinVertexBArray = new Float32Array( nvertices * 4 );
geometryGroup.__skinIndexArray = new Float32Array( nvertices * 4 );
geometryGroup.__skinWeightArray = new Float32Array( nvertices * 4 );
}
geometryGroup.__faceArray = new Uint16Array( ntris * 3 + ( object.geometry.edgeFaces ? object.geometry.edgeFaces.length * 2 * 3 : 0 ));
geometryGroup.__lineArray = new Uint16Array( nlines * 2 );
if ( geometryGroup.numMorphTargets ) {
geometryGroup.__morphTargetsArrays = [];
for ( m = 0, ml = geometryGroup.numMorphTargets; m < ml; m++ ) {
geometryGroup.__morphTargetsArrays.push( new Float32Array( nvertices * 3 ) );
}
}
geometryGroup.__needsSmoothNormals = ( normalType == THREE.SmoothShading );
geometryGroup.__uvType = uvType;
geometryGroup.__vertexColorType = vertexColorType;
geometryGroup.__normalType = normalType;
geometryGroup.__webglFaceCount = ntris * 3 + ( object.geometry.edgeFaces ? object.geometry.edgeFaces.length * 2 * 3 : 0 );
geometryGroup.__webglLineCount = nlines * 2;
// custom attributes
for ( m = 0, ml = materials.length; m < ml; m ++ ) {
material = materials[ m ];
if ( material.attributes ) {
if ( geometryGroup.__webglCustomAttributes === undefined ) {
geometryGroup.__webglCustomAttributes = {};
}
for ( a in material.attributes ) {
// Do a shallow copy of the attribute object so different geometryGroup chunks use different
// attribute buffers which are correctly indexed in the setMeshBuffers function
originalAttribute = material.attributes[ a ];
attribute = {};
for ( property in originalAttribute ) {
attribute[ property ] = originalAttribute[ property ];
}
if( !attribute.__webglInitialized || attribute.createUniqueBuffers ) {
attribute.__webglInitialized = true;
size = 1; // "f" and "i"
if( attribute.type === "v2" ) size = 2;
else if( attribute.type === "v3" ) size = 3;
else if( attribute.type === "v4" ) size = 4;
else if( attribute.type === "c" ) size = 3;
attribute.size = size;
attribute.array = new Float32Array( nvertices * size );
attribute.buffer = _gl.createBuffer();
attribute.buffer.belongsToAttribute = a;
originalAttribute.needsUpdate = true;
attribute.__original = originalAttribute;
}
geometryGroup.__webglCustomAttributes[ a ] = attribute;
}
}
}
geometryGroup.__inittedArrays = true;
};
function setMeshBuffers ( geometryGroup, object, hint ) {
if ( ! geometryGroup.__inittedArrays ) {
// console.log( object );
return;
}
var f, fl, fi, face,
vertexNormals, faceNormal, normal,
vertexColors, faceColor,
vertexTangents,
uvType, vertexColorType, normalType,
uv, uv2, v1, v2, v3, v4, t1, t2, t3, t4,
c1, c2, c3, c4,
sw1, sw2, sw3, sw4,
si1, si2, si3, si4,
sa1, sa2, sa3, sa4,
sb1, sb2, sb3, sb4,
m, ml, i,
vn, uvi, uv2i,
vk, vkl, vka,
a,
vertexIndex = 0,
offset = 0,
offset_uv = 0,
offset_uv2 = 0,
offset_face = 0,
offset_normal = 0,
offset_tangent = 0,
offset_line = 0,
offset_color = 0,
offset_skin = 0,
offset_morphTarget = 0,
offset_custom = 0,
offset_customSrc = 0,
vertexArray = geometryGroup.__vertexArray,
uvArray = geometryGroup.__uvArray,
uv2Array = geometryGroup.__uv2Array,
normalArray = geometryGroup.__normalArray,
tangentArray = geometryGroup.__tangentArray,
colorArray = geometryGroup.__colorArray,
skinVertexAArray = geometryGroup.__skinVertexAArray,
skinVertexBArray = geometryGroup.__skinVertexBArray,
skinIndexArray = geometryGroup.__skinIndexArray,
skinWeightArray = geometryGroup.__skinWeightArray,
morphTargetsArrays = geometryGroup.__morphTargetsArrays,
customAttributes = geometryGroup.__webglCustomAttributes,
customAttribute,
faceArray = geometryGroup.__faceArray,
lineArray = geometryGroup.__lineArray,
needsSmoothNormals = geometryGroup.__needsSmoothNormals,
vertexColorType = geometryGroup.__vertexColorType,
uvType = geometryGroup.__uvType,
normalType = geometryGroup.__normalType,
geometry = object.geometry, // this is shared for all chunks
dirtyVertices = geometry.__dirtyVertices,
dirtyElements = geometry.__dirtyElements,
dirtyUvs = geometry.__dirtyUvs,
dirtyNormals = geometry.__dirtyNormals,
dirtyTangents = geometry.__dirtyTangents,
dirtyColors = geometry.__dirtyColors,
dirtyMorphTargets = geometry.__dirtyMorphTargets,
vertices = geometry.vertices,
chunk_faces = geometryGroup.faces,
obj_faces = geometry.faces,
obj_uvs = geometry.faceVertexUvs[ 0 ],
obj_uvs2 = geometry.faceVertexUvs[ 1 ],
obj_colors = geometry.colors,
obj_skinVerticesA = geometry.skinVerticesA,
obj_skinVerticesB = geometry.skinVerticesB,
obj_skinIndices = geometry.skinIndices,
obj_skinWeights = geometry.skinWeights,
obj_edgeFaces = object instanceof THREE.ShadowVolume ? geometry.edgeFaces : undefined,
morphTargets = geometry.morphTargets;
if ( customAttributes ) {
for ( a in customAttributes ) {
customAttributes[ a ].offset = 0;
customAttributes[ a ].offsetSrc = 0;
}
}
for ( f = 0, fl = chunk_faces.length; f < fl; f ++ ) {
fi = chunk_faces[ f ];
face = obj_faces[ fi ];
if ( obj_uvs ) {
uv = obj_uvs[ fi ];
}
if ( obj_uvs2 ) {
uv2 = obj_uvs2[ fi ];
}
vertexNormals = face.vertexNormals;
faceNormal = face.normal;
vertexColors = face.vertexColors;
faceColor = face.color;
vertexTangents = face.vertexTangents;
if ( face instanceof THREE.Face3 ) {
if ( dirtyVertices ) {
v1 = vertices[ face.a ].position;
v2 = vertices[ face.b ].position;
v3 = vertices[ face.c ].position;
vertexArray[ offset ] = v1.x;
vertexArray[ offset + 1 ] = v1.y;
vertexArray[ offset + 2 ] = v1.z;
vertexArray[ offset + 3 ] = v2.x;
vertexArray[ offset + 4 ] = v2.y;
vertexArray[ offset + 5 ] = v2.z;
vertexArray[ offset + 6 ] = v3.x;
vertexArray[ offset + 7 ] = v3.y;
vertexArray[ offset + 8 ] = v3.z;
offset += 9;
}
if ( customAttributes ) {
for ( a in customAttributes ) {
customAttribute = customAttributes[ a ];
if ( customAttribute.__original.needsUpdate ) {
offset_custom = customAttribute.offset;
offset_customSrc = customAttribute.offsetSrc;
if ( customAttribute.size === 1 ) {
if ( customAttribute.boundTo === undefined || customAttribute.boundTo === "vertices" ) {
customAttribute.array[ offset_custom + 0 ] = customAttribute.value[ face.a ];
customAttribute.array[ offset_custom + 1 ] = customAttribute.value[ face.b ];
customAttribute.array[ offset_custom + 2 ] = customAttribute.value[ face.c ];
} else if ( customAttribute.boundTo === "faces" ) {
customAttribute.array[ offset_custom + 0 ] = customAttribute.value[ offset_customSrc ];
customAttribute.array[ offset_custom + 1 ] = customAttribute.value[ offset_customSrc ];
customAttribute.array[ offset_custom + 2 ] = customAttribute.value[ offset_customSrc ];
customAttribute.offsetSrc ++;
} else if ( customAttribute.boundTo === "faceVertices" ) {
customAttribute.array[ offset_custom + 0 ] = customAttribute.value[ offset_customSrc + 0 ];
customAttribute.array[ offset_custom + 1 ] = customAttribute.value[ offset_customSrc + 1 ];
customAttribute.array[ offset_custom + 2 ] = customAttribute.value[ offset_customSrc + 2 ];
customAttribute.offsetSrc += 3;
}
customAttribute.offset += 3;
} else {
if ( customAttribute.boundTo === undefined || customAttribute.boundTo === "vertices" ) {
v1 = customAttribute.value[ face.a ];
v2 = customAttribute.value[ face.b ];
v3 = customAttribute.value[ face.c ];
} else if ( customAttribute.boundTo === "faces" ) {
v1 = customAttribute.value[ offset_customSrc ];
v2 = customAttribute.value[ offset_customSrc ];
v3 = customAttribute.value[ offset_customSrc ];
customAttribute.offsetSrc ++;
} else if ( customAttribute.boundTo === "faceVertices" ) {
v1 = customAttribute.value[ offset_customSrc + 0 ];
v2 = customAttribute.value[ offset_customSrc + 1 ];
v3 = customAttribute.value[ offset_customSrc + 2 ];
customAttribute.offsetSrc += 3;
}
if ( customAttribute.size === 2 ) {
customAttribute.array[ offset_custom + 0 ] = v1.x;
customAttribute.array[ offset_custom + 1 ] = v1.y;
customAttribute.array[ offset_custom + 2 ] = v2.x;
customAttribute.array[ offset_custom + 3 ] = v2.y;
customAttribute.array[ offset_custom + 4 ] = v3.x;
customAttribute.array[ offset_custom + 5 ] = v3.y;
customAttribute.offset += 6;
} else if ( customAttribute.size === 3 ) {
if ( customAttribute.type === "c" ) {
customAttribute.array[ offset_custom + 0 ] = v1.r;
customAttribute.array[ offset_custom + 1 ] = v1.g;
customAttribute.array[ offset_custom + 2 ] = v1.b;
customAttribute.array[ offset_custom + 3 ] = v2.r;
customAttribute.array[ offset_custom + 4 ] = v2.g;
customAttribute.array[ offset_custom + 5 ] = v2.b;
customAttribute.array[ offset_custom + 6 ] = v3.r;
customAttribute.array[ offset_custom + 7 ] = v3.g;
customAttribute.array[ offset_custom + 8 ] = v3.b;
} else {
customAttribute.array[ offset_custom + 0 ] = v1.x;
customAttribute.array[ offset_custom + 1 ] = v1.y;
customAttribute.array[ offset_custom + 2 ] = v1.z;
customAttribute.array[ offset_custom + 3 ] = v2.x;
customAttribute.array[ offset_custom + 4 ] = v2.y;
customAttribute.array[ offset_custom + 5 ] = v2.z;
customAttribute.array[ offset_custom + 6 ] = v3.x;
customAttribute.array[ offset_custom + 7 ] = v3.y;
customAttribute.array[ offset_custom + 8 ] = v3.z;
}
customAttribute.offset += 9;
} else {
customAttribute.array[ offset_custom + 0 ] = v1.x;
customAttribute.array[ offset_custom + 1 ] = v1.y;
customAttribute.array[ offset_custom + 2 ] = v1.z;
customAttribute.array[ offset_custom + 3 ] = v1.w;
customAttribute.array[ offset_custom + 4 ] = v2.x;
customAttribute.array[ offset_custom + 5 ] = v2.y;
customAttribute.array[ offset_custom + 6 ] = v2.z;
customAttribute.array[ offset_custom + 7 ] = v2.w;
customAttribute.array[ offset_custom + 8 ] = v3.x;
customAttribute.array[ offset_custom + 9 ] = v3.y;
customAttribute.array[ offset_custom + 10 ] = v3.z;
customAttribute.array[ offset_custom + 11 ] = v3.w;
customAttribute.offset += 12;
}
}
}
}
}
if ( dirtyMorphTargets ) {
for ( vk = 0, vkl = morphTargets.length; vk < vkl; vk ++ ) {
v1 = morphTargets[ vk ].vertices[ face.a ].position;
v2 = morphTargets[ vk ].vertices[ face.b ].position;
v3 = morphTargets[ vk ].vertices[ face.c ].position;
vka = morphTargetsArrays[ vk ];
vka[ offset_morphTarget + 0 ] = v1.x;
vka[ offset_morphTarget + 1 ] = v1.y;
vka[ offset_morphTarget + 2 ] = v1.z;
vka[ offset_morphTarget + 3 ] = v2.x;
vka[ offset_morphTarget + 4 ] = v2.y;
vka[ offset_morphTarget + 5 ] = v2.z;
vka[ offset_morphTarget + 6 ] = v3.x;
vka[ offset_morphTarget + 7 ] = v3.y;
vka[ offset_morphTarget + 8 ] = v3.z;
}
offset_morphTarget += 9;
}
if ( obj_skinWeights.length ) {
// weights
sw1 = obj_skinWeights[ face.a ];
sw2 = obj_skinWeights[ face.b ];
sw3 = obj_skinWeights[ face.c ];
skinWeightArray[ offset_skin ] = sw1.x;
skinWeightArray[ offset_skin + 1 ] = sw1.y;
skinWeightArray[ offset_skin + 2 ] = sw1.z;
skinWeightArray[ offset_skin + 3 ] = sw1.w;
skinWeightArray[ offset_skin + 4 ] = sw2.x;
skinWeightArray[ offset_skin + 5 ] = sw2.y;
skinWeightArray[ offset_skin + 6 ] = sw2.z;
skinWeightArray[ offset_skin + 7 ] = sw2.w;
skinWeightArray[ offset_skin + 8 ] = sw3.x;
skinWeightArray[ offset_skin + 9 ] = sw3.y;
skinWeightArray[ offset_skin + 10 ] = sw3.z;
skinWeightArray[ offset_skin + 11 ] = sw3.w;
// indices
si1 = obj_skinIndices[ face.a ];
si2 = obj_skinIndices[ face.b ];
si3 = obj_skinIndices[ face.c ];
skinIndexArray[ offset_skin ] = si1.x;
skinIndexArray[ offset_skin + 1 ] = si1.y;
skinIndexArray[ offset_skin + 2 ] = si1.z;
skinIndexArray[ offset_skin + 3 ] = si1.w;
skinIndexArray[ offset_skin + 4 ] = si2.x;
skinIndexArray[ offset_skin + 5 ] = si2.y;
skinIndexArray[ offset_skin + 6 ] = si2.z;
skinIndexArray[ offset_skin + 7 ] = si2.w;
skinIndexArray[ offset_skin + 8 ] = si3.x;
skinIndexArray[ offset_skin + 9 ] = si3.y;
skinIndexArray[ offset_skin + 10 ] = si3.z;
skinIndexArray[ offset_skin + 11 ] = si3.w;
// vertices A
sa1 = obj_skinVerticesA[ face.a ];
sa2 = obj_skinVerticesA[ face.b ];
sa3 = obj_skinVerticesA[ face.c ];
skinVertexAArray[ offset_skin ] = sa1.x;
skinVertexAArray[ offset_skin + 1 ] = sa1.y;
skinVertexAArray[ offset_skin + 2 ] = sa1.z;
skinVertexAArray[ offset_skin + 3 ] = 1; // pad for faster vertex shader
skinVertexAArray[ offset_skin + 4 ] = sa2.x;
skinVertexAArray[ offset_skin + 5 ] = sa2.y;
skinVertexAArray[ offset_skin + 6 ] = sa2.z;
skinVertexAArray[ offset_skin + 7 ] = 1;
skinVertexAArray[ offset_skin + 8 ] = sa3.x;
skinVertexAArray[ offset_skin + 9 ] = sa3.y;
skinVertexAArray[ offset_skin + 10 ] = sa3.z;
skinVertexAArray[ offset_skin + 11 ] = 1;
// vertices B
sb1 = obj_skinVerticesB[ face.a ];
sb2 = obj_skinVerticesB[ face.b ];
sb3 = obj_skinVerticesB[ face.c ];
skinVertexBArray[ offset_skin ] = sb1.x;
skinVertexBArray[ offset_skin + 1 ] = sb1.y;
skinVertexBArray[ offset_skin + 2 ] = sb1.z;
skinVertexBArray[ offset_skin + 3 ] = 1; // pad for faster vertex shader
skinVertexBArray[ offset_skin + 4 ] = sb2.x;
skinVertexBArray[ offset_skin + 5 ] = sb2.y;
skinVertexBArray[ offset_skin + 6 ] = sb2.z;
skinVertexBArray[ offset_skin + 7 ] = 1;
skinVertexBArray[ offset_skin + 8 ] = sb3.x;
skinVertexBArray[ offset_skin + 9 ] = sb3.y;
skinVertexBArray[ offset_skin + 10 ] = sb3.z;
skinVertexBArray[ offset_skin + 11 ] = 1;
offset_skin += 12;
}
if ( dirtyColors && vertexColorType ) {
if ( vertexColors.length == 3 && vertexColorType == THREE.VertexColors ) {
c1 = vertexColors[ 0 ];
c2 = vertexColors[ 1 ];
c3 = vertexColors[ 2 ];
} else {
c1 = faceColor;
c2 = faceColor;
c3 = faceColor;
}
colorArray[ offset_color ] = c1.r;
colorArray[ offset_color + 1 ] = c1.g;
colorArray[ offset_color + 2 ] = c1.b;
colorArray[ offset_color + 3 ] = c2.r;
colorArray[ offset_color + 4 ] = c2.g;
colorArray[ offset_color + 5 ] = c2.b;
colorArray[ offset_color + 6 ] = c3.r;
colorArray[ offset_color + 7 ] = c3.g;
colorArray[ offset_color + 8 ] = c3.b;
offset_color += 9;
}
if ( dirtyTangents && geometry.hasTangents ) {
t1 = vertexTangents[ 0 ];
t2 = vertexTangents[ 1 ];
t3 = vertexTangents[ 2 ];
tangentArray[ offset_tangent ] = t1.x;
tangentArray[ offset_tangent + 1 ] = t1.y;
tangentArray[ offset_tangent + 2 ] = t1.z;
tangentArray[ offset_tangent + 3 ] = t1.w;
tangentArray[ offset_tangent + 4 ] = t2.x;
tangentArray[ offset_tangent + 5 ] = t2.y;
tangentArray[ offset_tangent + 6 ] = t2.z;
tangentArray[ offset_tangent + 7 ] = t2.w;
tangentArray[ offset_tangent + 8 ] = t3.x;
tangentArray[ offset_tangent + 9 ] = t3.y;
tangentArray[ offset_tangent + 10 ] = t3.z;
tangentArray[ offset_tangent + 11 ] = t3.w;
offset_tangent += 12;
}
if ( dirtyNormals && normalType ) {
if ( vertexNormals.length == 3 && needsSmoothNormals ) {
for ( i = 0; i < 3; i ++ ) {
vn = vertexNormals[ i ];
normalArray[ offset_normal ] = vn.x;
normalArray[ offset_normal + 1 ] = vn.y;
normalArray[ offset_normal + 2 ] = vn.z;
offset_normal += 3;
}
} else {
for ( i = 0; i < 3; i ++ ) {
normalArray[ offset_normal ] = faceNormal.x;
normalArray[ offset_normal + 1 ] = faceNormal.y;
normalArray[ offset_normal + 2 ] = faceNormal.z;
offset_normal += 3;
}
}
}
if ( dirtyUvs && uv !== undefined && uvType ) {
for ( i = 0; i < 3; i ++ ) {
uvi = uv[ i ];
uvArray[ offset_uv ] = uvi.u;
uvArray[ offset_uv + 1 ] = uvi.v;
offset_uv += 2;
}
}
if ( dirtyUvs && uv2 !== undefined && uvType ) {
for ( i = 0; i < 3; i ++ ) {
uv2i = uv2[ i ];
uv2Array[ offset_uv2 ] = uv2i.u;
uv2Array[ offset_uv2 + 1 ] = uv2i.v;
offset_uv2 += 2;
}
}
if ( dirtyElements ) {
faceArray[ offset_face ] = vertexIndex;
faceArray[ offset_face + 1 ] = vertexIndex + 1;
faceArray[ offset_face + 2 ] = vertexIndex + 2;
offset_face += 3;
lineArray[ offset_line ] = vertexIndex;
lineArray[ offset_line + 1 ] = vertexIndex + 1;
lineArray[ offset_line + 2 ] = vertexIndex;
lineArray[ offset_line + 3 ] = vertexIndex + 2;
lineArray[ offset_line + 4 ] = vertexIndex + 1;
lineArray[ offset_line + 5 ] = vertexIndex + 2;
offset_line += 6;
vertexIndex += 3;
}
} else if ( face instanceof THREE.Face4 ) {
if ( dirtyVertices ) {
v1 = vertices[ face.a ].position;
v2 = vertices[ face.b ].position;
v3 = vertices[ face.c ].position;
v4 = vertices[ face.d ].position;
vertexArray[ offset ] = v1.x;
vertexArray[ offset + 1 ] = v1.y;
vertexArray[ offset + 2 ] = v1.z;
vertexArray[ offset + 3 ] = v2.x;
vertexArray[ offset + 4 ] = v2.y;
vertexArray[ offset + 5 ] = v2.z;
vertexArray[ offset + 6 ] = v3.x;
vertexArray[ offset + 7 ] = v3.y;
vertexArray[ offset + 8 ] = v3.z;
vertexArray[ offset + 9 ] = v4.x;
vertexArray[ offset + 10 ] = v4.y;
vertexArray[ offset + 11 ] = v4.z;
offset += 12;
}
if ( customAttributes ) {
for ( a in customAttributes ) {
customAttribute = customAttributes[ a ];
if ( customAttribute.__original.needsUpdate ) {
offset_custom = customAttribute.offset;
offset_customSrc = customAttribute.offsetSrc;
if ( customAttribute.size === 1 ) {
if ( customAttribute.boundTo === undefined || customAttribute.boundTo === "vertices" ) {
customAttribute.array[ offset_custom + 0 ] = customAttribute.value[ face.a ];
customAttribute.array[ offset_custom + 1 ] = customAttribute.value[ face.b ];
customAttribute.array[ offset_custom + 2 ] = customAttribute.value[ face.c ];
customAttribute.array[ offset_custom + 3 ] = customAttribute.value[ face.d ];
} else if ( customAttribute.boundTo === "faces" ) {
customAttribute.array[ offset_custom + 0 ] = customAttribute.value[ offset_customSrc ];
customAttribute.array[ offset_custom + 1 ] = customAttribute.value[ offset_customSrc ];
customAttribute.array[ offset_custom + 2 ] = customAttribute.value[ offset_customSrc ];
customAttribute.array[ offset_custom + 3 ] = customAttribute.value[ offset_customSrc ];
customAttribute.offsetSrc++;
} else if ( customAttribute.boundTo === "faceVertices" ) {
customAttribute.array[ offset_custom + 0 ] = customAttribute.value[ offset_customSrc + 0 ];
customAttribute.array[ offset_custom + 1 ] = customAttribute.value[ offset_customSrc + 1 ];
customAttribute.array[ offset_custom + 2 ] = customAttribute.value[ offset_customSrc + 2 ];
customAttribute.array[ offset_custom + 3 ] = customAttribute.value[ offset_customSrc + 3 ];
customAttribute.offsetSrc += 4;
}
customAttribute.offset += 4;
} else {
if ( customAttribute.boundTo === undefined || customAttribute.boundTo === "vertices" ) {
v1 = customAttribute.value[ face.a ];
v2 = customAttribute.value[ face.b ];
v3 = customAttribute.value[ face.c ];
v4 = customAttribute.value[ face.d ];
} else if ( customAttribute.boundTo === "faces" ) {
v1 = customAttribute.value[ offset_customSrc ];
v2 = customAttribute.value[ offset_customSrc ];
v3 = customAttribute.value[ offset_customSrc ];
v4 = customAttribute.value[ offset_customSrc ];
customAttribute.offsetSrc++;
} else if ( customAttribute.boundTo === "faceVertices" ) {
v1 = customAttribute.value[ offset_customSrc + 0 ];
v2 = customAttribute.value[ offset_customSrc + 1 ];
v3 = customAttribute.value[ offset_customSrc + 2 ];
v4 = customAttribute.value[ offset_customSrc + 3 ];
customAttribute.offsetSrc += 4;
}
if ( customAttribute.size === 2 ) {
customAttribute.array[ offset_custom + 0 ] = v1.x;
customAttribute.array[ offset_custom + 1 ] = v1.y;
customAttribute.array[ offset_custom + 2 ] = v2.x;
customAttribute.array[ offset_custom + 3 ] = v2.y;
customAttribute.array[ offset_custom + 4 ] = v3.x;
customAttribute.array[ offset_custom + 5 ] = v3.y;
customAttribute.array[ offset_custom + 6 ] = v4.x;
customAttribute.array[ offset_custom + 7 ] = v4.y;
customAttribute.offset += 8;
} else if ( customAttribute.size === 3 ) {
if ( customAttribute.type === "c" ) {
customAttribute.array[ offset_custom + 0 ] = v1.r;
customAttribute.array[ offset_custom + 1 ] = v1.g;
customAttribute.array[ offset_custom + 2 ] = v1.b;
customAttribute.array[ offset_custom + 3 ] = v2.r;
customAttribute.array[ offset_custom + 4 ] = v2.g;
customAttribute.array[ offset_custom + 5 ] = v2.b;
customAttribute.array[ offset_custom + 6 ] = v3.r;
customAttribute.array[ offset_custom + 7 ] = v3.g;
customAttribute.array[ offset_custom + 8 ] = v3.b;
customAttribute.array[ offset_custom + 9 ] = v4.r;
customAttribute.array[ offset_custom + 10 ] = v4.g;
customAttribute.array[ offset_custom + 11 ] = v4.b;
} else {
customAttribute.array[ offset_custom + 0 ] = v1.x;
customAttribute.array[ offset_custom + 1 ] = v1.y;
customAttribute.array[ offset_custom + 2 ] = v1.z;
customAttribute.array[ offset_custom + 3 ] = v2.x;
customAttribute.array[ offset_custom + 4 ] = v2.y;
customAttribute.array[ offset_custom + 5 ] = v2.z;
customAttribute.array[ offset_custom + 6 ] = v3.x;
customAttribute.array[ offset_custom + 7 ] = v3.y;
customAttribute.array[ offset_custom + 8 ] = v3.z;
customAttribute.array[ offset_custom + 9 ] = v4.x;
customAttribute.array[ offset_custom + 10 ] = v4.y;
customAttribute.array[ offset_custom + 11 ] = v4.z;
}
customAttribute.offset += 12;
} else {
customAttribute.array[ offset_custom + 0 ] = v1.x;
customAttribute.array[ offset_custom + 1 ] = v1.y;
customAttribute.array[ offset_custom + 2 ] = v1.z;
customAttribute.array[ offset_custom + 3 ] = v1.w;
customAttribute.array[ offset_custom + 4 ] = v2.x;
customAttribute.array[ offset_custom + 5 ] = v2.y;
customAttribute.array[ offset_custom + 6 ] = v2.z;
customAttribute.array[ offset_custom + 7 ] = v2.w;
customAttribute.array[ offset_custom + 8 ] = v3.x;
customAttribute.array[ offset_custom + 9 ] = v3.y;
customAttribute.array[ offset_custom + 10 ] = v3.z;
customAttribute.array[ offset_custom + 11 ] = v3.w;
customAttribute.array[ offset_custom + 12 ] = v4.x;
customAttribute.array[ offset_custom + 13 ] = v4.y;
customAttribute.array[ offset_custom + 14 ] = v4.z;
customAttribute.array[ offset_custom + 15 ] = v4.w;
customAttribute.offset += 16;
}
}
}
}
}
if ( dirtyMorphTargets ) {
for ( vk = 0, vkl = morphTargets.length; vk < vkl; vk++ ) {
v1 = morphTargets[ vk ].vertices[ face.a ].position;
v2 = morphTargets[ vk ].vertices[ face.b ].position;
v3 = morphTargets[ vk ].vertices[ face.c ].position;
v4 = morphTargets[ vk ].vertices[ face.d ].position;
vka = morphTargetsArrays[ vk ];
vka[ offset_morphTarget + 0 ] = v1.x;
vka[ offset_morphTarget + 1 ] = v1.y;
vka[ offset_morphTarget + 2 ] = v1.z;
vka[ offset_morphTarget + 3 ] = v2.x;
vka[ offset_morphTarget + 4 ] = v2.y;
vka[ offset_morphTarget + 5 ] = v2.z;
vka[ offset_morphTarget + 6 ] = v3.x;
vka[ offset_morphTarget + 7 ] = v3.y;
vka[ offset_morphTarget + 8 ] = v3.z;
vka[ offset_morphTarget + 9 ] = v4.x;
vka[ offset_morphTarget + 10 ] = v4.y;
vka[ offset_morphTarget + 11 ] = v4.z;
}
offset_morphTarget += 12;
}
if ( obj_skinWeights.length ) {
// weights
sw1 = obj_skinWeights[ face.a ];
sw2 = obj_skinWeights[ face.b ];
sw3 = obj_skinWeights[ face.c ];
sw4 = obj_skinWeights[ face.d ];
skinWeightArray[ offset_skin ] = sw1.x;
skinWeightArray[ offset_skin + 1 ] = sw1.y;
skinWeightArray[ offset_skin + 2 ] = sw1.z;
skinWeightArray[ offset_skin + 3 ] = sw1.w;
skinWeightArray[ offset_skin + 4 ] = sw2.x;
skinWeightArray[ offset_skin + 5 ] = sw2.y;
skinWeightArray[ offset_skin + 6 ] = sw2.z;
skinWeightArray[ offset_skin + 7 ] = sw2.w;
skinWeightArray[ offset_skin + 8 ] = sw3.x;
skinWeightArray[ offset_skin + 9 ] = sw3.y;
skinWeightArray[ offset_skin + 10 ] = sw3.z;
skinWeightArray[ offset_skin + 11 ] = sw3.w;
skinWeightArray[ offset_skin + 12 ] = sw4.x;
skinWeightArray[ offset_skin + 13 ] = sw4.y;
skinWeightArray[ offset_skin + 14 ] = sw4.z;
skinWeightArray[ offset_skin + 15 ] = sw4.w;
// indices
si1 = obj_skinIndices[ face.a ];
si2 = obj_skinIndices[ face.b ];
si3 = obj_skinIndices[ face.c ];
si4 = obj_skinIndices[ face.d ];
skinIndexArray[ offset_skin ] = si1.x;
skinIndexArray[ offset_skin + 1 ] = si1.y;
skinIndexArray[ offset_skin + 2 ] = si1.z;
skinIndexArray[ offset_skin + 3 ] = si1.w;
skinIndexArray[ offset_skin + 4 ] = si2.x;
skinIndexArray[ offset_skin + 5 ] = si2.y;
skinIndexArray[ offset_skin + 6 ] = si2.z;
skinIndexArray[ offset_skin + 7 ] = si2.w;
skinIndexArray[ offset_skin + 8 ] = si3.x;
skinIndexArray[ offset_skin + 9 ] = si3.y;
skinIndexArray[ offset_skin + 10 ] = si3.z;
skinIndexArray[ offset_skin + 11 ] = si3.w;
skinIndexArray[ offset_skin + 12 ] = si4.x;
skinIndexArray[ offset_skin + 13 ] = si4.y;
skinIndexArray[ offset_skin + 14 ] = si4.z;
skinIndexArray[ offset_skin + 15 ] = si4.w;
// vertices A
sa1 = obj_skinVerticesA[ face.a ];
sa2 = obj_skinVerticesA[ face.b ];
sa3 = obj_skinVerticesA[ face.c ];
sa4 = obj_skinVerticesA[ face.d ];
skinVertexAArray[ offset_skin ] = sa1.x;
skinVertexAArray[ offset_skin + 1 ] = sa1.y;
skinVertexAArray[ offset_skin + 2 ] = sa1.z;
skinVertexAArray[ offset_skin + 3 ] = 1; // pad for faster vertex shader
skinVertexAArray[ offset_skin + 4 ] = sa2.x;
skinVertexAArray[ offset_skin + 5 ] = sa2.y;
skinVertexAArray[ offset_skin + 6 ] = sa2.z;
skinVertexAArray[ offset_skin + 7 ] = 1;
skinVertexAArray[ offset_skin + 8 ] = sa3.x;
skinVertexAArray[ offset_skin + 9 ] = sa3.y;
skinVertexAArray[ offset_skin + 10 ] = sa3.z;
skinVertexAArray[ offset_skin + 11 ] = 1;
skinVertexAArray[ offset_skin + 12 ] = sa4.x;
skinVertexAArray[ offset_skin + 13 ] = sa4.y;
skinVertexAArray[ offset_skin + 14 ] = sa4.z;
skinVertexAArray[ offset_skin + 15 ] = 1;
// vertices B
sb1 = obj_skinVerticesB[ face.a ];
sb2 = obj_skinVerticesB[ face.b ];
sb3 = obj_skinVerticesB[ face.c ];
sb4 = obj_skinVerticesB[ face.d ];
skinVertexBArray[ offset_skin ] = sb1.x;
skinVertexBArray[ offset_skin + 1 ] = sb1.y;
skinVertexBArray[ offset_skin + 2 ] = sb1.z;
skinVertexBArray[ offset_skin + 3 ] = 1; // pad for faster vertex shader
skinVertexBArray[ offset_skin + 4 ] = sb2.x;
skinVertexBArray[ offset_skin + 5 ] = sb2.y;
skinVertexBArray[ offset_skin + 6 ] = sb2.z;
skinVertexBArray[ offset_skin + 7 ] = 1;
skinVertexBArray[ offset_skin + 8 ] = sb3.x;
skinVertexBArray[ offset_skin + 9 ] = sb3.y;
skinVertexBArray[ offset_skin + 10 ] = sb3.z;
skinVertexBArray[ offset_skin + 11 ] = 1;
skinVertexBArray[ offset_skin + 12 ] = sb4.x;
skinVertexBArray[ offset_skin + 13 ] = sb4.y;
skinVertexBArray[ offset_skin + 14 ] = sb4.z;
skinVertexBArray[ offset_skin + 15 ] = 1;
offset_skin += 16;
}
if ( dirtyColors && vertexColorType ) {
if ( vertexColors.length == 4 && vertexColorType == THREE.VertexColors ) {
c1 = vertexColors[ 0 ];
c2 = vertexColors[ 1 ];
c3 = vertexColors[ 2 ];
c4 = vertexColors[ 3 ];
} else {
c1 = faceColor;
c2 = faceColor;
c3 = faceColor;
c4 = faceColor;
}
colorArray[ offset_color ] = c1.r;
colorArray[ offset_color + 1 ] = c1.g;
colorArray[ offset_color + 2 ] = c1.b;
colorArray[ offset_color + 3 ] = c2.r;
colorArray[ offset_color + 4 ] = c2.g;
colorArray[ offset_color + 5 ] = c2.b;
colorArray[ offset_color + 6 ] = c3.r;
colorArray[ offset_color + 7 ] = c3.g;
colorArray[ offset_color + 8 ] = c3.b;
colorArray[ offset_color + 9 ] = c4.r;
colorArray[ offset_color + 10 ] = c4.g;
colorArray[ offset_color + 11 ] = c4.b;
offset_color += 12;
}
if ( dirtyTangents && geometry.hasTangents ) {
t1 = vertexTangents[ 0 ];
t2 = vertexTangents[ 1 ];
t3 = vertexTangents[ 2 ];
t4 = vertexTangents[ 3 ];
tangentArray[ offset_tangent ] = t1.x;
tangentArray[ offset_tangent + 1 ] = t1.y;
tangentArray[ offset_tangent + 2 ] = t1.z;
tangentArray[ offset_tangent + 3 ] = t1.w;
tangentArray[ offset_tangent + 4 ] = t2.x;
tangentArray[ offset_tangent + 5 ] = t2.y;
tangentArray[ offset_tangent + 6 ] = t2.z;
tangentArray[ offset_tangent + 7 ] = t2.w;
tangentArray[ offset_tangent + 8 ] = t3.x;
tangentArray[ offset_tangent + 9 ] = t3.y;
tangentArray[ offset_tangent + 10 ] = t3.z;
tangentArray[ offset_tangent + 11 ] = t3.w;
tangentArray[ offset_tangent + 12 ] = t4.x;
tangentArray[ offset_tangent + 13 ] = t4.y;
tangentArray[ offset_tangent + 14 ] = t4.z;
tangentArray[ offset_tangent + 15 ] = t4.w;
offset_tangent += 16;
}
if ( dirtyNormals && normalType ) {
if ( vertexNormals.length == 4 && needsSmoothNormals ) {
for ( i = 0; i < 4; i ++ ) {
vn = vertexNormals[ i ];
normalArray[ offset_normal ] = vn.x;
normalArray[ offset_normal + 1 ] = vn.y;
normalArray[ offset_normal + 2 ] = vn.z;
offset_normal += 3;
}
} else {
for ( i = 0; i < 4; i ++ ) {
normalArray[ offset_normal ] = faceNormal.x;
normalArray[ offset_normal + 1 ] = faceNormal.y;
normalArray[ offset_normal + 2 ] = faceNormal.z;
offset_normal += 3;
}
}
}
if ( dirtyUvs && uv !== undefined && uvType ) {
for ( i = 0; i < 4; i ++ ) {
uvi = uv[ i ];
uvArray[ offset_uv ] = uvi.u;
uvArray[ offset_uv + 1 ] = uvi.v;
offset_uv += 2;
}
}
if ( dirtyUvs && uv2 !== undefined && uvType ) {
for ( i = 0; i < 4; i ++ ) {
uv2i = uv2[ i ];
uv2Array[ offset_uv2 ] = uv2i.u;
uv2Array[ offset_uv2 + 1 ] = uv2i.v;
offset_uv2 += 2;
}
}
if ( dirtyElements ) {
faceArray[ offset_face ] = vertexIndex;
faceArray[ offset_face + 1 ] = vertexIndex + 1;
faceArray[ offset_face + 2 ] = vertexIndex + 3;
faceArray[ offset_face + 3 ] = vertexIndex + 1;
faceArray[ offset_face + 4 ] = vertexIndex + 2;
faceArray[ offset_face + 5 ] = vertexIndex + 3;
offset_face += 6;
lineArray[ offset_line ] = vertexIndex;
lineArray[ offset_line + 1 ] = vertexIndex + 1;
lineArray[ offset_line + 2 ] = vertexIndex;
lineArray[ offset_line + 3 ] = vertexIndex + 3;
lineArray[ offset_line + 4 ] = vertexIndex + 1;
lineArray[ offset_line + 5 ] = vertexIndex + 2;
lineArray[ offset_line + 6 ] = vertexIndex + 2;
lineArray[ offset_line + 7 ] = vertexIndex + 3;
offset_line += 8;
vertexIndex += 4;
}
}
}
if ( obj_edgeFaces ) {
for ( f = 0, fl = obj_edgeFaces.length; f < fl; f ++ ) {
faceArray[ offset_face ] = obj_edgeFaces[ f ].a;
faceArray[ offset_face + 1 ] = obj_edgeFaces[ f ].b;
faceArray[ offset_face + 2 ] = obj_edgeFaces[ f ].c;
faceArray[ offset_face + 3 ] = obj_edgeFaces[ f ].a;
faceArray[ offset_face + 4 ] = obj_edgeFaces[ f ].c;
faceArray[ offset_face + 5 ] = obj_edgeFaces[ f ].d;
offset_face += 6;
}
}
if ( dirtyVertices ) {
_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglVertexBuffer );
_gl.bufferData( _gl.ARRAY_BUFFER, vertexArray, hint );
}
if ( customAttributes ) {
for ( a in customAttributes ) {
customAttribute = customAttributes[ a ];
if ( customAttribute.__original.needsUpdate ) {
_gl.bindBuffer( _gl.ARRAY_BUFFER, customAttribute.buffer );
_gl.bufferData( _gl.ARRAY_BUFFER, customAttribute.array, hint );
}
}
}
if ( dirtyMorphTargets ) {
for ( vk = 0, vkl = morphTargets.length; vk < vkl; vk ++ ) {
_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphTargetsBuffers[ vk ] );
_gl.bufferData( _gl.ARRAY_BUFFER, morphTargetsArrays[ vk ], hint );
}
}
if ( dirtyColors && offset_color > 0 ) {
_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglColorBuffer );
_gl.bufferData( _gl.ARRAY_BUFFER, colorArray, hint );
}
if ( dirtyNormals ) {
_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglNormalBuffer );
_gl.bufferData( _gl.ARRAY_BUFFER, normalArray, hint );
}
if ( dirtyTangents && geometry.hasTangents ) {
_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglTangentBuffer );
_gl.bufferData( _gl.ARRAY_BUFFER, tangentArray, hint );
}
if ( dirtyUvs && offset_uv > 0 ) {
_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglUVBuffer );
_gl.bufferData( _gl.ARRAY_BUFFER, uvArray, hint );
}
if ( dirtyUvs && offset_uv2 > 0 ) {
_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglUV2Buffer );
_gl.bufferData( _gl.ARRAY_BUFFER, uv2Array, hint );
}
if ( dirtyElements ) {
_gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, geometryGroup.__webglFaceBuffer );
_gl.bufferData( _gl.ELEMENT_ARRAY_BUFFER, faceArray, hint );
_gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, geometryGroup.__webglLineBuffer );
_gl.bufferData( _gl.ELEMENT_ARRAY_BUFFER, lineArray, hint );
}
if ( offset_skin > 0 ) {
_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglSkinVertexABuffer );
_gl.bufferData( _gl.ARRAY_BUFFER, skinVertexAArray, hint );
_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglSkinVertexBBuffer );
_gl.bufferData( _gl.ARRAY_BUFFER, skinVertexBArray, hint );
_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglSkinIndicesBuffer );
_gl.bufferData( _gl.ARRAY_BUFFER, skinIndexArray, hint );
_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglSkinWeightsBuffer );
_gl.bufferData( _gl.ARRAY_BUFFER, skinWeightArray, hint );
}
if ( ! object.dynamic ) {
delete geometryGroup.__inittedArrays;
delete geometryGroup.__colorArray;
delete geometryGroup.__normalArray;
delete geometryGroup.__tangentArray;
delete geometryGroup.__uvArray;
delete geometryGroup.__uv2Array;
delete geometryGroup.__faceArray;
delete geometryGroup.__vertexArray;
delete geometryGroup.__lineArray;
delete geometryGroup.__skinVertexAArray;
delete geometryGroup.__skinVertexBArray;
delete geometryGroup.__skinIndexArray;
delete geometryGroup.__skinWeightArray;
}
};
function setLineBuffers ( geometry, hint ) {
var v, c, vertex, offset,
vertices = geometry.vertices,
colors = geometry.colors,
vl = vertices.length,
cl = colors.length,
vertexArray = geometry.__vertexArray,
colorArray = geometry.__colorArray,
dirtyVertices = geometry.__dirtyVertices,
dirtyColors = geometry.__dirtyColors;
if ( dirtyVertices ) {
for ( v = 0; v < vl; v++ ) {
vertex = vertices[ v ].position;
offset = v * 3;
vertexArray[ offset ] = vertex.x;
vertexArray[ offset + 1 ] = vertex.y;
vertexArray[ offset + 2 ] = vertex.z;
}
_gl.bindBuffer( _gl.ARRAY_BUFFER, geometry.__webglVertexBuffer );
_gl.bufferData( _gl.ARRAY_BUFFER, vertexArray, hint );
}
if ( dirtyColors ) {
for ( c = 0; c < cl; c++ ) {
color = colors[ c ];
offset = c * 3;
colorArray[ offset ] = color.r;
colorArray[ offset + 1 ] = color.g;
colorArray[ offset + 2 ] = color.b;
}
_gl.bindBuffer( _gl.ARRAY_BUFFER, geometry.__webglColorBuffer );
_gl.bufferData( _gl.ARRAY_BUFFER, colorArray, hint );
}
};
function setRibbonBuffers ( geometry, hint ) {
var v, c, vertex, offset,
vertices = geometry.vertices,
colors = geometry.colors,
vl = vertices.length,
cl = colors.length,
vertexArray = geometry.__vertexArray,
colorArray = geometry.__colorArray,
dirtyVertices = geometry.__dirtyVertices,
dirtyColors = geometry.__dirtyColors;
if ( dirtyVertices ) {
for ( v = 0; v < vl; v++ ) {
vertex = vertices[ v ].position;
offset = v * 3;
vertexArray[ offset ] = vertex.x;
vertexArray[ offset + 1 ] = vertex.y;
vertexArray[ offset + 2 ] = vertex.z;
}
_gl.bindBuffer( _gl.ARRAY_BUFFER, geometry.__webglVertexBuffer );
_gl.bufferData( _gl.ARRAY_BUFFER, vertexArray, hint );
}
if ( dirtyColors ) {
for ( c = 0; c < cl; c++ ) {
color = colors[ c ];
offset = c * 3;
colorArray[ offset ] = color.r;
colorArray[ offset + 1 ] = color.g;
colorArray[ offset + 2 ] = color.b;
}
_gl.bindBuffer( _gl.ARRAY_BUFFER, geometry.__webglColorBuffer );
_gl.bufferData( _gl.ARRAY_BUFFER, colorArray, hint );
}
};
function setParticleBuffers ( geometry, hint, object ) {
var v, c, vertex, offset,
vertices = geometry.vertices,
vl = vertices.length,
colors = geometry.colors,
cl = colors.length,
vertexArray = geometry.__vertexArray,
colorArray = geometry.__colorArray,
sortArray = geometry.__sortArray,
dirtyVertices = geometry.__dirtyVertices,
dirtyElements = geometry.__dirtyElements,
dirtyColors = geometry.__dirtyColors,
customAttributes = geometry.__webglCustomAttributes,
a, ca, cal, v1,
offset_custom,
customAttribute;
if ( customAttributes ) {
for ( a in customAttributes ) {
customAttributes[ a ].offset = 0;
}
}
if ( object.sortParticles ) {
_projScreenMatrix.multiplySelf( object.matrixWorld );
for ( v = 0; v < vl; v++ ) {
vertex = vertices[ v ].position;
_vector3.copy( vertex );
_projScreenMatrix.multiplyVector3( _vector3 );
sortArray[ v ] = [ _vector3.z, v ];
}
sortArray.sort( function( a, b ) { return b[ 0 ] - a[ 0 ]; } );
for ( v = 0; v < vl; v++ ) {
vertex = vertices[ sortArray[v][1] ].position;
offset = v * 3;
vertexArray[ offset ] = vertex.x;
vertexArray[ offset + 1 ] = vertex.y;
vertexArray[ offset + 2 ] = vertex.z;
}
for ( c = 0; c < cl; c++ ) {
offset = c * 3;
color = colors[ sortArray[c][1] ];
colorArray[ offset ] = color.r;
colorArray[ offset + 1 ] = color.g;
colorArray[ offset + 2 ] = color.b;
}
if ( customAttributes ) {
for ( a in customAttributes ) {
customAttribute = customAttributes[ a ];
cal = customAttribute.value.length;
for ( ca = 0; ca < cal; ca ++ ) {
index = sortArray[ca][1];
offset_custom = customAttribute.offset;
if ( customAttribute.size === 1 ) {
if ( customAttribute.boundTo === undefined || customAttribute.boundTo === "vertices" ) {
customAttribute.array[ offset_custom ] = customAttribute.value[ index ];
}
} else {
if ( customAttribute.boundTo === undefined || customAttribute.boundTo === "vertices" ) {
v1 = customAttribute.value[ index ];
}
if ( customAttribute.size === 2 ) {
customAttribute.array[ offset_custom ] = v1.x;
customAttribute.array[ offset_custom + 1 ] = v1.y;
} else if ( customAttribute.size === 3 ) {
if ( customAttribute.type === "c" ) {
customAttribute.array[ offset_custom ] = v1.r;
customAttribute.array[ offset_custom + 1 ] = v1.g;
customAttribute.array[ offset_custom + 2 ] = v1.b;
} else {
customAttribute.array[ offset_custom ] = v1.x;
customAttribute.array[ offset_custom + 1 ] = v1.y;
customAttribute.array[ offset_custom + 2 ] = v1.z;
}
} else {
customAttribute.array[ offset_custom ] = v1.x;
customAttribute.array[ offset_custom + 1 ] = v1.y;
customAttribute.array[ offset_custom + 2 ] = v1.z;
customAttribute.array[ offset_custom + 3 ] = v1.w;
}
}
customAttribute.offset += customAttribute.size;
}
}
}
} else {
if ( dirtyVertices ) {
for ( v = 0; v < vl; v++ ) {
vertex = vertices[ v ].position;
offset = v * 3;
vertexArray[ offset ] = vertex.x;
vertexArray[ offset + 1 ] = vertex.y;
vertexArray[ offset + 2 ] = vertex.z;
}
}
if ( dirtyColors ) {
for ( c = 0; c < cl; c++ ) {
color = colors[ c ];
offset = c * 3;
colorArray[ offset ] = color.r;
colorArray[ offset + 1 ] = color.g;
colorArray[ offset + 2 ] = color.b;
}
}
if ( customAttributes ) {
for ( a in customAttributes ) {
customAttribute = customAttributes[ a ];
if ( customAttribute.__original.needsUpdate ) {
cal = customAttribute.value.length;
for ( ca = 0; ca < cal; ca ++ ) {
offset_custom = customAttribute.offset;
if ( customAttribute.size === 1 ) {
if ( customAttribute.boundTo === undefined || customAttribute.boundTo === "vertices" ) {
customAttribute.array[ offset_custom ] = customAttribute.value[ ca ];
}
} else {
if ( customAttribute.boundTo === undefined || customAttribute.boundTo === "vertices" ) {
v1 = customAttribute.value[ ca ];
}
if ( customAttribute.size === 2 ) {
customAttribute.array[ offset_custom ] = v1.x;
customAttribute.array[ offset_custom + 1 ] = v1.y;
} else if ( customAttribute.size === 3 ) {
if ( customAttribute.type === "c" ) {
customAttribute.array[ offset_custom ] = v1.r;
customAttribute.array[ offset_custom + 1 ] = v1.g;
customAttribute.array[ offset_custom + 2 ] = v1.b;
} else {
customAttribute.array[ offset_custom ] = v1.x;
customAttribute.array[ offset_custom + 1 ] = v1.y;
customAttribute.array[ offset_custom + 2 ] = v1.z;
}
} else {
customAttribute.array[ offset_custom ] = v1.x;
customAttribute.array[ offset_custom + 1 ] = v1.y;
customAttribute.array[ offset_custom + 2 ] = v1.z;
customAttribute.array[ offset_custom + 3 ] = v1.w;
}
}
customAttribute.offset += customAttribute.size;
}
}
}
}
}
if ( dirtyVertices || object.sortParticles ) {
_gl.bindBuffer( _gl.ARRAY_BUFFER, geometry.__webglVertexBuffer );
_gl.bufferData( _gl.ARRAY_BUFFER, vertexArray, hint );
}
if ( dirtyColors || object.sortParticles ) {
_gl.bindBuffer( _gl.ARRAY_BUFFER, geometry.__webglColorBuffer );
_gl.bufferData( _gl.ARRAY_BUFFER, colorArray, hint );
}
if ( customAttributes ) {
for ( a in customAttributes ) {
customAttribute = customAttributes[ a ];
if ( customAttribute.__original.needsUpdate || object.sortParticles ) {
_gl.bindBuffer( _gl.ARRAY_BUFFER, customAttribute.buffer );
_gl.bufferData( _gl.ARRAY_BUFFER, customAttribute.array, hint );
}
}
}
};
function setMaterialShaders( material, shaders ) {
material.uniforms = THREE.UniformsUtils.clone( shaders.uniforms );
material.vertexShader = shaders.vertexShader;
material.fragmentShader = shaders.fragmentShader;
};
function refreshUniformsCommon( uniforms, material ) {
uniforms.diffuse.value = material.color;
uniforms.opacity.value = material.opacity;
uniforms.map.texture = material.map;
if ( material.map ) {
uniforms.offsetRepeat.value.set( material.map.offset.x, material.map.offset.y, material.map.repeat.x, material.map.repeat.y );
}
uniforms.lightMap.texture = material.lightMap;
uniforms.envMap.texture = material.envMap;
uniforms.reflectivity.value = material.reflectivity;
uniforms.refractionRatio.value = material.refractionRatio;
uniforms.combine.value = material.combine;
uniforms.useRefract.value = material.envMap && material.envMap.mapping instanceof THREE.CubeRefractionMapping;
};
function refreshUniformsLine( uniforms, material ) {
uniforms.diffuse.value = material.color;
uniforms.opacity.value = material.opacity;
};
function refreshUniformsParticle( uniforms, material ) {
uniforms.psColor.value = material.color;
uniforms.opacity.value = material.opacity;
uniforms.size.value = material.size;
uniforms.scale.value = _canvas.height / 2.0; // TODO: Cache this.
uniforms.map.texture = material.map;
};
function refreshUniformsFog( uniforms, fog ) {
uniforms.fogColor.value = fog.color;
if ( fog instanceof THREE.Fog ) {
uniforms.fogNear.value = fog.near;
uniforms.fogFar.value = fog.far;
} else if ( fog instanceof THREE.FogExp2 ) {
uniforms.fogDensity.value = fog.density;
}
};
function refreshUniformsPhong( uniforms, material ) {
uniforms.ambient.value = material.ambient;
uniforms.specular.value = material.specular;
uniforms.shininess.value = material.shininess;
};
function refreshUniformsLights( uniforms, lights ) {
uniforms.enableLighting.value = lights.directional.length + lights.point.length;
uniforms.ambientLightColor.value = lights.ambient;
uniforms.directionalLightColor.value = lights.directional.colors;
uniforms.directionalLightDirection.value = lights.directional.positions;
uniforms.pointLightColor.value = lights.point.colors;
uniforms.pointLightPosition.value = lights.point.positions;
uniforms.pointLightDistance.value = lights.point.distances;
};
this.initMaterial = function ( material, lights, fog, object ) {
var u, a, identifiers, i, parameters, maxLightCount, maxBones, shaderID;
if ( material instanceof THREE.MeshDepthMaterial ) {
shaderID = 'depth';
} else if ( material instanceof THREE.ShadowVolumeDynamicMaterial ) {
shaderID = 'shadowVolumeDynamic';
} else if ( material instanceof THREE.MeshNormalMaterial ) {
shaderID = 'normal';
} else if ( material instanceof THREE.MeshBasicMaterial ) {
shaderID = 'basic';
} else if ( material instanceof THREE.MeshLambertMaterial ) {
shaderID = 'lambert';
} else if ( material instanceof THREE.MeshPhongMaterial ) {
shaderID = 'phong';
} else if ( material instanceof THREE.LineBasicMaterial ) {
shaderID = 'basic';
} else if ( material instanceof THREE.ParticleBasicMaterial ) {
shaderID = 'particle_basic';
}
if ( shaderID ) {
setMaterialShaders( material, THREE.ShaderLib[ shaderID ] );
}
// heuristics to create shader parameters according to lights in the scene
// (not to blow over maxLights budget)
maxLightCount = allocateLights( lights, 4 );
maxBones = allocateBones( object );
parameters = {
map: !!material.map, envMap: !!material.envMap, lightMap: !!material.lightMap,
vertexColors: material.vertexColors,
fog: fog, sizeAttenuation: material.sizeAttenuation,
skinning: material.skinning,
morphTargets: material.morphTargets,
maxMorphTargets: this.maxMorphTargets,
maxDirLights: maxLightCount.directional, maxPointLights: maxLightCount.point,
maxBones: maxBones
};
material.program = buildProgram( shaderID, material.fragmentShader, material.vertexShader, material.uniforms, material.attributes, parameters );
var attributes = material.program.attributes;
if ( attributes.position >= 0 ) _gl.enableVertexAttribArray( attributes.position );
if ( attributes.color >= 0 ) _gl.enableVertexAttribArray( attributes.color );
if ( attributes.normal >= 0 ) _gl.enableVertexAttribArray( attributes.normal );
if ( attributes.tangent >= 0 ) _gl.enableVertexAttribArray( attributes.tangent );
if ( material.skinning &&
attributes.skinVertexA >=0 && attributes.skinVertexB >= 0 &&
attributes.skinIndex >= 0 && attributes.skinWeight >= 0 ) {
_gl.enableVertexAttribArray( attributes.skinVertexA );
_gl.enableVertexAttribArray( attributes.skinVertexB );
_gl.enableVertexAttribArray( attributes.skinIndex );
_gl.enableVertexAttribArray( attributes.skinWeight );
}
if ( material.attributes ) {
for ( a in material.attributes ) {
if( attributes[ a ] !== undefined && attributes[ a ] >= 0 ) _gl.enableVertexAttribArray( attributes[ a ] );
}
}
if ( material.morphTargets ) {
material.numSupportedMorphTargets = 0;
if ( attributes.morphTarget0 >= 0 ) {
_gl.enableVertexAttribArray( attributes.morphTarget0 );
material.numSupportedMorphTargets ++;
}
if ( attributes.morphTarget1 >= 0 ) {
_gl.enableVertexAttribArray( attributes.morphTarget1 );
material.numSupportedMorphTargets ++;
}
if ( attributes.morphTarget2 >= 0 ) {
_gl.enableVertexAttribArray( attributes.morphTarget2 );
material.numSupportedMorphTargets ++;
}
if ( attributes.morphTarget3 >= 0 ) {
_gl.enableVertexAttribArray( attributes.morphTarget3 );
material.numSupportedMorphTargets ++;
}
if ( attributes.morphTarget4 >= 0 ) {
_gl.enableVertexAttribArray( attributes.morphTarget4 );
material.numSupportedMorphTargets ++;
}
if ( attributes.morphTarget5 >= 0 ) {
_gl.enableVertexAttribArray( attributes.morphTarget5 );
material.numSupportedMorphTargets ++;
}
if ( attributes.morphTarget6 >= 0 ) {
_gl.enableVertexAttribArray( attributes.morphTarget6 );
material.numSupportedMorphTargets ++;
}
if ( attributes.morphTarget7 >= 0 ) {
_gl.enableVertexAttribArray( attributes.morphTarget7 );
material.numSupportedMorphTargets ++;
}
object.__webglMorphTargetInfluences = new Float32Array( this.maxMorphTargets );
for ( var i = 0, il = this.maxMorphTargets; i < il; i ++ ) {
object.__webglMorphTargetInfluences[ i ] = 0;
}
}
};
function setProgram( camera, lights, fog, material, object ) {
if ( ! material.program ) {
_this.initMaterial( material, lights, fog, object );
}
var program = material.program,
p_uniforms = program.uniforms,
m_uniforms = material.uniforms;
if ( program != _currentProgram ) {
_gl.useProgram( program );
_currentProgram = program;
}
_gl.uniformMatrix4fv( p_uniforms.projectionMatrix, false, _projectionMatrixArray );
// refresh uniforms common to several materials
if ( fog && (
material instanceof THREE.MeshBasicMaterial ||
material instanceof THREE.MeshLambertMaterial ||
material instanceof THREE.MeshPhongMaterial ||
material instanceof THREE.LineBasicMaterial ||
material instanceof THREE.ParticleBasicMaterial ||
material.fog )
) {
refreshUniformsFog( m_uniforms, fog );
}
if ( material instanceof THREE.MeshPhongMaterial ||
material instanceof THREE.MeshLambertMaterial ||
material.lights ) {
setupLights( program, lights );
refreshUniformsLights( m_uniforms, _lights );
}
if ( material instanceof THREE.MeshBasicMaterial ||
material instanceof THREE.MeshLambertMaterial ||
material instanceof THREE.MeshPhongMaterial ) {
refreshUniformsCommon( m_uniforms, material );
}
// refresh single material specific uniforms
if ( material instanceof THREE.LineBasicMaterial ) {
refreshUniformsLine( m_uniforms, material );
} else if ( material instanceof THREE.ParticleBasicMaterial ) {
refreshUniformsParticle( m_uniforms, material );
} else if ( material instanceof THREE.MeshPhongMaterial ) {
refreshUniformsPhong( m_uniforms, material );
} else if ( material instanceof THREE.MeshDepthMaterial ) {
m_uniforms.mNear.value = camera.near;
m_uniforms.mFar.value = camera.far;
m_uniforms.opacity.value = material.opacity;
} else if ( material instanceof THREE.MeshNormalMaterial ) {
m_uniforms.opacity.value = material.opacity;
}
// load common uniforms
loadUniformsGeneric( program, m_uniforms );
loadUniformsMatrices( p_uniforms, object );
// load material specific uniforms
// (shader material also gets them for the sake of genericity)
if ( material instanceof THREE.MeshShaderMaterial ||
material instanceof THREE.MeshPhongMaterial ||
material.envMap ) {
if( p_uniforms.cameraPosition !== null ) {
_gl.uniform3f( p_uniforms.cameraPosition, camera.position.x, camera.position.y, camera.position.z );
}
}
if ( material instanceof THREE.MeshShaderMaterial ||
material.envMap ||
material.skinning ) {
if ( p_uniforms.objectMatrix !== null ) {
_gl.uniformMatrix4fv( p_uniforms.objectMatrix, false, object._objectMatrixArray );
}
}
if ( material instanceof THREE.MeshPhongMaterial ||
material instanceof THREE.MeshLambertMaterial ||
material instanceof THREE.MeshShaderMaterial ||
material.skinning ) {
if( p_uniforms.viewMatrix !== null ) {
_gl.uniformMatrix4fv( p_uniforms.viewMatrix, false, _viewMatrixArray );
}
}
if ( material instanceof THREE.ShadowVolumeDynamicMaterial ) {
var dirLight = m_uniforms.directionalLightDirection.value;
dirLight[ 0 ] = -lights[ 1 ].position.x;
dirLight[ 1 ] = -lights[ 1 ].position.y;
dirLight[ 2 ] = -lights[ 1 ].position.z;
_gl.uniform3fv( p_uniforms.directionalLightDirection, dirLight );
_gl.uniformMatrix4fv( p_uniforms.objectMatrix, false, object._objectMatrixArray );
_gl.uniformMatrix4fv( p_uniforms.viewMatrix, false, _viewMatrixArray );
}
if ( material.skinning ) {
loadUniformsSkinning( p_uniforms, object );
}
return program;
};
function renderBuffer( camera, lights, fog, material, geometryGroup, object ) {
if ( material.opacity == 0 ) return;
var program, attributes, linewidth, primitives, a, attribute;
program = setProgram( camera, lights, fog, material, object );
attributes = program.attributes;
// vertices
if ( !material.morphTargets && attributes.position >= 0 ) {
_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglVertexBuffer );
_gl.vertexAttribPointer( attributes.position, 3, _gl.FLOAT, false, 0, 0 );
} else {
if ( object.morphTargetBase ) {
setupMorphTargets( material, geometryGroup, object );
}
}
// custom attributes
// Use the per-geometryGroup custom attribute arrays which are setup in initMeshBuffers
if ( geometryGroup.__webglCustomAttributes ) {
for( a in geometryGroup.__webglCustomAttributes ) {
if( attributes[ a ] >= 0 ) {
attribute = geometryGroup.__webglCustomAttributes[ a ];
_gl.bindBuffer( _gl.ARRAY_BUFFER, attribute.buffer );
_gl.vertexAttribPointer( attributes[ a ], attribute.size, _gl.FLOAT, false, 0, 0 );
}
}
}
/* if ( material.attributes ) {
for( a in material.attributes ) {
if( attributes[ a ] !== undefined && attributes[ a ] >= 0 ) {
attribute = material.attributes[ a ];
if( attribute.buffer ) {
_gl.bindBuffer( _gl.ARRAY_BUFFER, attribute.buffer );
_gl.vertexAttribPointer( attributes[ a ], attribute.size, _gl.FLOAT, false, 0, 0 );
}
}
}
}*/
// colors
if ( attributes.color >= 0 ) {
_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglColorBuffer );
_gl.vertexAttribPointer( attributes.color, 3, _gl.FLOAT, false, 0, 0 );
}
// normals
if ( attributes.normal >= 0 ) {
_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglNormalBuffer );
_gl.vertexAttribPointer( attributes.normal, 3, _gl.FLOAT, false, 0, 0 );
}
// tangents
if ( attributes.tangent >= 0 ) {
_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglTangentBuffer );
_gl.vertexAttribPointer( attributes.tangent, 4, _gl.FLOAT, false, 0, 0 );
}
// uvs
if ( attributes.uv >= 0 ) {
if ( geometryGroup.__webglUVBuffer ) {
_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglUVBuffer );
_gl.vertexAttribPointer( attributes.uv, 2, _gl.FLOAT, false, 0, 0 );
_gl.enableVertexAttribArray( attributes.uv );
} else {
_gl.disableVertexAttribArray( attributes.uv );
}
}
if ( attributes.uv2 >= 0 ) {
if ( geometryGroup.__webglUV2Buffer ) {
_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglUV2Buffer );
_gl.vertexAttribPointer( attributes.uv2, 2, _gl.FLOAT, false, 0, 0 );
_gl.enableVertexAttribArray( attributes.uv2 );
} else {
_gl.disableVertexAttribArray( attributes.uv2 );
}
}
if ( material.skinning &&
attributes.skinVertexA >= 0 && attributes.skinVertexB >= 0 &&
attributes.skinIndex >= 0 && attributes.skinWeight >= 0 ) {
_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglSkinVertexABuffer );
_gl.vertexAttribPointer( attributes.skinVertexA, 4, _gl.FLOAT, false, 0, 0 );
_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglSkinVertexBBuffer );
_gl.vertexAttribPointer( attributes.skinVertexB, 4, _gl.FLOAT, false, 0, 0 );
_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglSkinIndicesBuffer );
_gl.vertexAttribPointer( attributes.skinIndex, 4, _gl.FLOAT, false, 0, 0 );
_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglSkinWeightsBuffer );
_gl.vertexAttribPointer( attributes.skinWeight, 4, _gl.FLOAT, false, 0, 0 );
}
// render mesh
if ( object instanceof THREE.Mesh ) {
// wireframe
if ( material.wireframe ) {
_gl.lineWidth( material.wireframeLinewidth );
_gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, geometryGroup.__webglLineBuffer );
_gl.drawElements( _gl.LINES, geometryGroup.__webglLineCount, _gl.UNSIGNED_SHORT, 0 );
// triangles
} else {
_gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, geometryGroup.__webglFaceBuffer );
_gl.drawElements( _gl.TRIANGLES, geometryGroup.__webglFaceCount, _gl.UNSIGNED_SHORT, 0 );
}
_this.data.vertices += geometryGroup.__webglFaceCount;
_this.data.faces += geometryGroup.__webglFaceCount / 3;
_this.data.drawCalls ++;
// render lines
} else if ( object instanceof THREE.Line ) {
primitives = ( object.type == THREE.LineStrip ) ? _gl.LINE_STRIP : _gl.LINES;
_gl.lineWidth( material.linewidth );
_gl.drawArrays( primitives, 0, geometryGroup.__webglLineCount );
_this.data.drawCalls ++;
// render particles
} else if ( object instanceof THREE.ParticleSystem ) {
_gl.drawArrays( _gl.POINTS, 0, geometryGroup.__webglParticleCount );
_this.data.drawCalls ++;
// render ribbon
} else if ( object instanceof THREE.Ribbon ) {
_gl.drawArrays( _gl.TRIANGLE_STRIP, 0, geometryGroup.__webglVertexCount );
_this.data.drawCalls ++;
}
};
function setupMorphTargets( material, geometryGroup, object ) {
// set base
var attributes = material.program.attributes;
if ( object.morphTargetBase !== - 1 ) {
_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphTargetsBuffers[ object.morphTargetBase ] );
_gl.vertexAttribPointer( attributes.position, 3, _gl.FLOAT, false, 0, 0 );
} else if ( attributes.position >= 0 ) {
_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglVertexBuffer );
_gl.vertexAttribPointer( attributes.position, 3, _gl.FLOAT, false, 0, 0 );
}
if ( object.morphTargetForcedOrder.length ) {
// set forced order
var m = 0;
var order = object.morphTargetForcedOrder;
var influences = object.morphTargetInfluences;
while ( m < material.numSupportedMorphTargets && m < order.length ) {
_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphTargetsBuffers[ order[ m ] ] );
_gl.vertexAttribPointer( attributes[ "morphTarget" + m ], 3, _gl.FLOAT, false, 0, 0 );
object.__webglMorphTargetInfluences[ m ] = influences[ order[ m ] ];
m ++;
}
} else {
// find most influencing
var used = [];
var candidateInfluence = - 1;
var candidate = 0;
var influences = object.morphTargetInfluences;
var i, il = influences.length;
var m = 0;
if ( object.morphTargetBase !== - 1 ) {
used[ object.morphTargetBase ] = true;
}
while ( m < material.numSupportedMorphTargets ) {
for ( i = 0; i < il; i ++ ) {
if ( !used[ i ] && influences[ i ] > candidateInfluence ) {
candidate = i;
candidateInfluence = influences[ candidate ];
}
}
_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphTargetsBuffers[ candidate ] );
_gl.vertexAttribPointer( attributes[ "morphTarget" + m ], 3, _gl.FLOAT, false, 0, 0 );
object.__webglMorphTargetInfluences[ m ] = candidateInfluence;
used[ candidate ] = 1;
candidateInfluence = -1;
m ++;
}
}
// load updated influences uniform
if( material.program.uniforms.morphTargetInfluences !== null ) {
_gl.uniform1fv( material.program.uniforms.morphTargetInfluences, object.__webglMorphTargetInfluences );
}
}
function renderBufferImmediate( object, program, shading ) {
if ( ! object.__webglVertexBuffer ) object.__webglVertexBuffer = _gl.createBuffer();
if ( ! object.__webglNormalBuffer ) object.__webglNormalBuffer = _gl.createBuffer();
if ( object.hasPos ) {
_gl.bindBuffer( _gl.ARRAY_BUFFER, object.__webglVertexBuffer );
_gl.bufferData( _gl.ARRAY_BUFFER, object.positionArray, _gl.DYNAMIC_DRAW );
_gl.enableVertexAttribArray( program.attributes.position );
_gl.vertexAttribPointer( program.attributes.position, 3, _gl.FLOAT, false, 0, 0 );
}
if ( object.hasNormal ) {
_gl.bindBuffer( _gl.ARRAY_BUFFER, object.__webglNormalBuffer );
if ( shading == THREE.FlatShading ) {
var nx, ny, nz,
nax, nbx, ncx, nay, nby, ncy, naz, nbz, ncz,
normalArray,
i, il = object.count * 3;
for( i = 0; i < il; i += 9 ) {
normalArray = object.normalArray;
nax = normalArray[ i ];
nay = normalArray[ i + 1 ];
naz = normalArray[ i + 2 ];
nbx = normalArray[ i + 3 ];
nby = normalArray[ i + 4 ];
nbz = normalArray[ i + 5 ];
ncx = normalArray[ i + 6 ];
ncy = normalArray[ i + 7 ];
ncz = normalArray[ i + 8 ];
nx = ( nax + nbx + ncx ) / 3;
ny = ( nay + nby + ncy ) / 3;
nz = ( naz + nbz + ncz ) / 3;
normalArray[ i ] = nx;
normalArray[ i + 1 ] = ny;
normalArray[ i + 2 ] = nz;
normalArray[ i + 3 ] = nx;
normalArray[ i + 4 ] = ny;
normalArray[ i + 5 ] = nz;
normalArray[ i + 6 ] = nx;
normalArray[ i + 7 ] = ny;
normalArray[ i + 8 ] = nz;
}
}
_gl.bufferData( _gl.ARRAY_BUFFER, object.normalArray, _gl.DYNAMIC_DRAW );
_gl.enableVertexAttribArray( program.attributes.normal );
_gl.vertexAttribPointer( program.attributes.normal, 3, _gl.FLOAT, false, 0, 0 );
}
_gl.drawArrays( _gl.TRIANGLES, 0, object.count );
object.count = 0;
};
function setObjectFaces( object ) {
if ( _oldDoubleSided != object.doubleSided ) {
if( object.doubleSided ) {
_gl.disable( _gl.CULL_FACE );
} else {
_gl.enable( _gl.CULL_FACE );
}
_oldDoubleSided = object.doubleSided;
}
if ( _oldFlipSided != object.flipSided ) {
if( object.flipSided ) {
_gl.frontFace( _gl.CW );
} else {
_gl.frontFace( _gl.CCW );
}
_oldFlipSided = object.flipSided;
}
};
function setDepthTest( test ) {
if ( _oldDepth != test ) {
if( test ) {
_gl.enable( _gl.DEPTH_TEST );
} else {
_gl.disable( _gl.DEPTH_TEST );
}
_oldDepth = test;
}
};
function setPolygonOffset ( polygonoffset, factor, units ) {
if ( _oldPolygonOffset != polygonoffset ) {
if ( polygonoffset ) {
_gl.enable( _gl.POLYGON_OFFSET_FILL );
} else {
_gl.disable( _gl.POLYGON_OFFSET_FILL );
}
_oldPolygonOffset = polygonoffset;
}
if ( polygonoffset && ( _oldPolygonOffsetFactor != factor || _oldPolygonOffsetUnits != units ) ) {
_gl.polygonOffset( factor, units );
_oldPolygonOffsetFactor = factor;
_oldPolygonOffsetUnits = units;
}
};
function computeFrustum( m ) {
_frustum[ 0 ].set( m.n41 - m.n11, m.n42 - m.n12, m.n43 - m.n13, m.n44 - m.n14 );
_frustum[ 1 ].set( m.n41 + m.n11, m.n42 + m.n12, m.n43 + m.n13, m.n44 + m.n14 );
_frustum[ 2 ].set( m.n41 + m.n21, m.n42 + m.n22, m.n43 + m.n23, m.n44 + m.n24 );
_frustum[ 3 ].set( m.n41 - m.n21, m.n42 - m.n22, m.n43 - m.n23, m.n44 - m.n24 );
_frustum[ 4 ].set( m.n41 - m.n31, m.n42 - m.n32, m.n43 - m.n33, m.n44 - m.n34 );
_frustum[ 5 ].set( m.n41 + m.n31, m.n42 + m.n32, m.n43 + m.n33, m.n44 + m.n34 );
var i, plane;
for ( i = 0; i < 6; i ++ ) {
plane = _frustum[ i ];
plane.divideScalar( Math.sqrt( plane.x * plane.x + plane.y * plane.y + plane.z * plane.z ) );
}
};
function isInFrustum( object ) {
var distance, matrix = object.matrixWorld,
radius = - object.geometry.boundingSphere.radius * Math.max( object.scale.x, Math.max( object.scale.y, object.scale.z ) );
for ( var i = 0; i < 6; i ++ ) {
distance = _frustum[ i ].x * matrix.n14 + _frustum[ i ].y * matrix.n24 + _frustum[ i ].z * matrix.n34 + _frustum[ i ].w;
if ( distance <= radius ) return false;
}
return true;
};
function addToFixedArray( where, what ) {
where.list[ where.count ] = what;
where.count += 1;
};
function unrollImmediateBufferMaterials( globject ) {
var i, l, m, ml, material,
object = globject.object,
opaque = globject.opaque,
transparent = globject.transparent;
transparent.count = 0;
opaque.count = 0;
for ( m = 0, ml = object.materials.length; m < ml; m++ ) {
material = object.materials[ m ];
material.transparent ? addToFixedArray( transparent, material ) : addToFixedArray( opaque, material );
}
};
function unrollBufferMaterials( globject ) {
var i, l, m, ml, material, meshMaterial,
object = globject.object,
buffer = globject.buffer,
opaque = globject.opaque,
transparent = globject.transparent;
transparent.count = 0;
opaque.count = 0;
for ( m = 0, ml = object.materials.length; m < ml; m++ ) {
meshMaterial = object.materials[ m ];
if ( meshMaterial instanceof THREE.MeshFaceMaterial ) {
for ( i = 0, l = buffer.materials.length; i < l; i++ ) {
material = buffer.materials[ i ];
if ( material ) material.transparent ? addToFixedArray( transparent, material ) : addToFixedArray( opaque, material );
}
} else {
material = meshMaterial;
if ( material ) material.transparent ? addToFixedArray( transparent, material ) : addToFixedArray( opaque, material );
}
}
};
function painterSort( a, b ) {
return b.z - a.z;
};
this.render = function( scene, camera, renderTarget, forceClear ) {
var i, program, opaque, transparent, material,
o, ol, oil, webglObject, object, buffer,
lights = scene.lights,
fog = scene.fog;
_this.data.vertices = 0;
_this.data.faces = 0;
_this.data.drawCalls = 0;
camera.matrixAutoUpdate && camera.update( undefined, true );
scene.update( undefined, false, camera );
camera.matrixWorldInverse.flattenToArray( _viewMatrixArray );
camera.projectionMatrix.flattenToArray( _projectionMatrixArray );
_projScreenMatrix.multiply( camera.projectionMatrix, camera.matrixWorldInverse );
computeFrustum( _projScreenMatrix );
this.initWebGLObjects( scene );
setRenderTarget( renderTarget );
if ( this.autoClear || forceClear ) {
this.clear();
}
// set matrices
ol = scene.__webglObjects.length;
for ( o = 0; o < ol; o++ ) {
webglObject = scene.__webglObjects[ o ];
object = webglObject.object;
if ( object.visible ) {
if ( ! ( object instanceof THREE.Mesh ) || isInFrustum( object ) ) {
object.matrixWorld.flattenToArray( object._objectMatrixArray );
setupMatrices( object, camera );
unrollBufferMaterials( webglObject );
webglObject.render = true;
if ( this.sortObjects ) {
if ( webglObject.object.renderDepth ) {
webglObject.z = webglObject.object.renderDepth;
} else {
_vector3.copy( object.position );
_projScreenMatrix.multiplyVector3( _vector3 );
webglObject.z = _vector3.z;
}
}
} else {
webglObject.render = false;
}
} else {
webglObject.render = false;
}
}
if ( this.sortObjects ) {
scene.__webglObjects.sort( painterSort );
}
oil = scene.__webglObjectsImmediate.length;
for ( o = 0; o < oil; o++ ) {
webglObject = scene.__webglObjectsImmediate[ o ];
object = webglObject.object;
if ( object.visible ) {
if( object.matrixAutoUpdate ) {
object.matrixWorld.flattenToArray( object._objectMatrixArray );
}
setupMatrices( object, camera );
unrollImmediateBufferMaterials( webglObject );
}
}
if ( scene.overrideMaterial ) {
setDepthTest( scene.overrideMaterial.depthTest );
setBlending( scene.overrideMaterial.blending );
for ( o = 0; o < ol; o ++ ) {
webglObject = scene.__webglObjects[ o ];
if ( webglObject.render ) {
object = webglObject.object;
buffer = webglObject.buffer;
setObjectFaces( object );
renderBuffer( camera, lights, fog, scene.overrideMaterial, buffer, object );
}
}
for ( o = 0; o < oil; o++ ) {
webglObject = scene.__webglObjectsImmediate[ o ];
object = webglObject.object;
if ( object.visible ) {
setObjectFaces( object );
program = setProgram( camera, lights, fog, scene.overrideMaterial, object );
object.render( function( object ) { renderBufferImmediate( object, program, scene.overrideMaterial.shading ); } );
}
}
} else {
// opaque pass
setBlending( THREE.NormalBlending );
for ( o = 0; o < ol; o ++ ) {
webglObject = scene.__webglObjects[ o ];
if ( webglObject.render ) {
object = webglObject.object;
buffer = webglObject.buffer;
opaque = webglObject.opaque;
setObjectFaces( object );
for ( i = 0; i < opaque.count; i ++ ) {
material = opaque.list[ i ];
setDepthTest( material.depthTest );
setPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits );
renderBuffer( camera, lights, fog, material, buffer, object );
}
}
}
// opaque pass (immediate simulator)
for ( o = 0; o < oil; o++ ) {
webglObject = scene.__webglObjectsImmediate[ o ];
object = webglObject.object;
if ( object.visible ) {
opaque = webglObject.opaque;
setObjectFaces( object );
for( i = 0; i < opaque.count; i++ ) {
material = opaque.list[ i ];
setDepthTest( material.depthTest );
setPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits );
program = setProgram( camera, lights, fog, material, object );
object.render( function( object ) { renderBufferImmediate( object, program, material.shading ); } );
}
}
}
// transparent pass
for ( o = 0; o < ol; o ++ ) {
webglObject = scene.__webglObjects[ o ];
if ( webglObject.render ) {
object = webglObject.object;
buffer = webglObject.buffer;
transparent = webglObject.transparent;
setObjectFaces( object );
for ( i = 0; i < transparent.count; i ++ ) {
material = transparent.list[ i ];
setBlending( material.blending );
setDepthTest( material.depthTest );
setPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits );
renderBuffer( camera, lights, fog, material, buffer, object );
}
}
}
// transparent pass (immediate simulator)
for ( o = 0; o < oil; o++ ) {
webglObject = scene.__webglObjectsImmediate[ o ];
object = webglObject.object;
if ( object.visible ) {
transparent = webglObject.transparent;
setObjectFaces( object );
for ( i = 0; i < transparent.count; i ++ ) {
material = transparent.list[ i ];
setBlending( material.blending );
setDepthTest( material.depthTest );
setPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits );
program = setProgram( camera, lights, fog, material, object );
object.render( function( object ) { renderBufferImmediate( object, program, material.shading ); } );
}
}
}
}
// render 2d
if ( scene.__webglSprites.length ) {
renderSprites( scene, camera );
}
// render stencil shadows
if ( _stencil && scene.__webglShadowVolumes.length && scene.lights.length ) {
renderStencilShadows( scene );
}
// render lens flares
if ( scene.__webglLensFlares.length ) {
renderLensFlares( scene, camera );
}
// Generate mipmap if we're using any kind of mipmap filtering
if ( renderTarget && renderTarget.minFilter !== THREE.NearestFilter && renderTarget.minFilter !== THREE.LinearFilter ) {
updateRenderTargetMipmap( renderTarget );
}
//_gl.finish();
};
/*
* Stencil Shadows
* method: we're rendering the world in light, then the shadow
* volumes into the stencil and last a big darkening
* quad over the whole thing. This is not how "you're
* supposed to" do stencil shadows but is much faster
*
*/
function renderStencilShadows( scene ) {
// setup stencil
_gl.enable( _gl.POLYGON_OFFSET_FILL );
_gl.polygonOffset( 0.1, 1.0 );
_gl.enable( _gl.STENCIL_TEST );
_gl.enable( _gl.DEPTH_TEST );
_gl.depthMask( false );
_gl.colorMask( false, false, false, false );
_gl.stencilFunc( _gl.ALWAYS, 1, 0xFF );
_gl.stencilOpSeparate( _gl.BACK, _gl.KEEP, _gl.INCR, _gl.KEEP );
_gl.stencilOpSeparate( _gl.FRONT, _gl.KEEP, _gl.DECR, _gl.KEEP );
// loop through all directional lights
var l, ll = scene.lights.length;
var p;
var light, lights = scene.lights;
var dirLight = [];
var object, geometryGroup, material;
var program;
var p_uniforms;
var m_uniforms;
var attributes;
var o, ol = scene.__webglShadowVolumes.length;
for ( l = 0; l < ll; l++ ) {
light = scene.lights[ l ];
if ( light instanceof THREE.DirectionalLight && light.castShadow ) {
dirLight[ 0 ] = -light.position.x;
dirLight[ 1 ] = -light.position.y;
dirLight[ 2 ] = -light.position.z;
// render all volumes
for ( o = 0; o < ol; o++ ) {
object = scene.__webglShadowVolumes[ o ].object;
geometryGroup = scene.__webglShadowVolumes[ o ].buffer;
material = object.materials[ 0 ];
if ( !material.program ) _this.initMaterial( material, lights, undefined, object );
program = material.program,
p_uniforms = program.uniforms,
m_uniforms = material.uniforms,
attributes = program.attributes;
if ( _currentProgram !== program ) {
_gl.useProgram( program );
_currentProgram = program;
_gl.uniformMatrix4fv( p_uniforms.projectionMatrix, false, _projectionMatrixArray );
_gl.uniformMatrix4fv( p_uniforms.viewMatrix, false, _viewMatrixArray );
_gl.uniform3fv( p_uniforms.directionalLightDirection, dirLight );
}
object.matrixWorld.flattenToArray( object._objectMatrixArray );
_gl.uniformMatrix4fv( p_uniforms.objectMatrix, false, object._objectMatrixArray );
_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglVertexBuffer );
_gl.vertexAttribPointer( attributes.position, 3, _gl.FLOAT, false, 0, 0 );
_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglNormalBuffer );
_gl.vertexAttribPointer( attributes.normal, 3, _gl.FLOAT, false, 0, 0 );
_gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, geometryGroup.__webglFaceBuffer );
_gl.cullFace( _gl.FRONT );
_gl.drawElements( _gl.TRIANGLES, geometryGroup.__webglFaceCount, _gl.UNSIGNED_SHORT, 0 );
_gl.cullFace( _gl.BACK );
_gl.drawElements( _gl.TRIANGLES, geometryGroup.__webglFaceCount, _gl.UNSIGNED_SHORT, 0 );
}
}
}
// setup color+stencil
_gl.disable( _gl.POLYGON_OFFSET_FILL );
_gl.colorMask( true, true, true, true );
_gl.stencilFunc( _gl.NOTEQUAL, 0, 0xFF );
_gl.stencilOp( _gl.KEEP, _gl.KEEP, _gl.KEEP );
_gl.disable( _gl.DEPTH_TEST );
// draw darkening polygon
_oldBlending = -1;
_oldDepth = -1;
_currentProgram = _stencilShadow.program;
_gl.useProgram( _stencilShadow.program );
_gl.uniformMatrix4fv( _stencilShadow.projectionLocation, false, _projectionMatrixArray );
_gl.uniform1f( _stencilShadow.darknessLocation, _stencilShadow.darkness );
_gl.bindBuffer( _gl.ARRAY_BUFFER, _stencilShadow.vertexBuffer );
_gl.vertexAttribPointer( _stencilShadow.vertexLocation, 3, _gl.FLOAT, false, 0, 0 );
_gl.enableVertexAttribArray( _stencilShadow.vertexLocation );
_gl.blendFunc( _gl.ONE, _gl.ONE_MINUS_SRC_ALPHA );
_gl.blendEquation( _gl.FUNC_ADD );
_gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, _stencilShadow.elementBuffer );
_gl.drawElements( _gl.TRIANGLES, 6, _gl.UNSIGNED_SHORT, 0 );
// disable stencil
_gl.disable( _gl.STENCIL_TEST );
_gl.enable( _gl.DEPTH_TEST );
_gl.depthMask( _currentDepthMask );
}
/*
* Render sprites
*
*/
function renderSprites( scene, camera ) {
var o, ol, object;
var attributes = _sprite.attributes;
var uniforms = _sprite.uniforms;
var anyCustom = false;
var invAspect = _viewportHeight / _viewportWidth;
var size, scale = [];
var screenPosition;
var halfViewportWidth = _viewportWidth * 0.5;
var halfViewportHeight = _viewportHeight * 0.5;
var mergeWith3D = true;
// setup gl
_gl.useProgram( _sprite.program );
_currentProgram = _sprite.program;
_oldBlending = -1;
_oldDepth = -1;
if ( !_spriteAttributesEnabled ) {
_gl.enableVertexAttribArray( _sprite.attributes.position );
_gl.enableVertexAttribArray( _sprite.attributes.uv );
_spriteAttributesEnabled = true;
}
_gl.disable( _gl.CULL_FACE );
_gl.enable( _gl.BLEND );
_gl.depthMask( true );
_gl.bindBuffer( _gl.ARRAY_BUFFER, _sprite.vertexBuffer );
_gl.vertexAttribPointer( attributes.position, 2, _gl.FLOAT, false, 2 * 8, 0 );
_gl.vertexAttribPointer( attributes.uv, 2, _gl.FLOAT, false, 2 * 8, 8 );
_gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, _sprite.elementBuffer );
_gl.uniformMatrix4fv( uniforms.projectionMatrix, false, _projectionMatrixArray );
_gl.activeTexture( _gl.TEXTURE0 );
_gl.uniform1i( uniforms.map, 0 );
// update positions and sort
for( o = 0, ol = scene.__webglSprites.length; o < ol; o++ ) {
object = scene.__webglSprites[ o ];
if( !object.useScreenCoordinates ) {
object._modelViewMatrix.multiplyToArray( camera.matrixWorldInverse, object.matrixWorld, object._modelViewMatrixArray );
object.z = -object._modelViewMatrix.n34;
} else {
object.z = -object.position.z;
}
}
scene.__webglSprites.sort( painterSort );
// render all non-custom shader sprites
for ( o = 0, ol = scene.__webglSprites.length; o < ol; o++ ) {
object = scene.__webglSprites[ o ];
if ( object.material === undefined ) {
if ( object.map && object.map.image && object.map.image.width ) {
if ( object.useScreenCoordinates ) {
_gl.uniform1i( uniforms.useScreenCoordinates, 1 );
_gl.uniform3f( uniforms.screenPosition, ( object.position.x - halfViewportWidth ) / halfViewportWidth,
( halfViewportHeight - object.position.y ) / halfViewportHeight,
Math.max( 0, Math.min( 1, object.position.z )));
} else {
_gl.uniform1i( uniforms.useScreenCoordinates, 0 );
_gl.uniform1i( uniforms.affectedByDistance, object.affectedByDistance ? 1 : 0 );
_gl.uniformMatrix4fv( uniforms.modelViewMatrix, false, object._modelViewMatrixArray );
}
size = object.map.image.width / ( object.scaleByViewport ? _viewportHeight : 1 );
scale[ 0 ] = size * invAspect * object.scale.x;
scale[ 1 ] = size * object.scale.y;
_gl.uniform2f( uniforms.uvScale, object.uvScale.x, object.uvScale.y );
_gl.uniform2f( uniforms.uvOffset, object.uvOffset.x, object.uvOffset.y );
_gl.uniform2f( uniforms.alignment, object.alignment.x, object.alignment.y );
_gl.uniform1f( uniforms.opacity, object.opacity );
_gl.uniform1f( uniforms.rotation, object.rotation );
_gl.uniform2fv( uniforms.scale, scale );
if ( object.mergeWith3D && !mergeWith3D ) {
_gl.enable( _gl.DEPTH_TEST );
mergeWith3D = true;
} else if ( !object.mergeWith3D && mergeWith3D ) {
_gl.disable( _gl.DEPTH_TEST );
mergeWith3D = false;
}
setBlending( object.blending );
setTexture( object.map, 0 );
_gl.drawElements( _gl.TRIANGLES, 6, _gl.UNSIGNED_SHORT, 0 );
}
} else {
anyCustom = true;
}
}
// loop through all custom
/*
if( anyCustom ) {
}
*/
// restore gl
_gl.enable( _gl.CULL_FACE );
_gl.enable( _gl.DEPTH_TEST );
_gl.depthMask( _currentDepthMask );
}
/*
* Render lens flares
* Method: renders 16x16 0xff00ff-colored points scattered over the light source area,
* reads these back and calculates occlusion.
* Then LensFlare.updateLensFlares() is called to re-position and
* update transparency of flares. Then they are rendered.
*
*/
function renderLensFlares( scene, camera ) {
var object, objectZ, geometryGroup, material;
var o, ol = scene.__webglLensFlares.length;
var f, fl, flare;
var tempPosition = new THREE.Vector3();
var invAspect = _viewportHeight / _viewportWidth;
var halfViewportWidth = _viewportWidth * 0.5;
var halfViewportHeight = _viewportHeight * 0.5;
var size = 16 / _viewportHeight;
var scale = [ size * invAspect, size ];
var screenPosition = [ 1, 1, 0 ];
var screenPositionPixels = [ 1, 1 ];
var sampleX, sampleY, readBackPixels = _lensFlare.readBackPixels;
var sampleMidX = 7 * 4;
var sampleMidY = 7 * 16 * 4;
var sampleIndex, visibility;
var uniforms = _lensFlare.uniforms;
var attributes = _lensFlare.attributes;
// set lensflare program and reset blending
_gl.useProgram( _lensFlare.program );
_currentProgram = _lensFlare.program;
_oldBlending = -1;
_oldDepth = -1;
if ( ! _lensFlareAttributesEnabled ) {
_gl.enableVertexAttribArray( _lensFlare.attributes.vertex );
_gl.enableVertexAttribArray( _lensFlare.attributes.uv );
_lensFlareAttributesEnabled = true;
}
// loop through all lens flares to update their occlusion and positions
// setup gl and common used attribs/unforms
_gl.uniform1i( uniforms.occlusionMap, 0 );
_gl.uniform1i( uniforms.map, 1 );
_gl.bindBuffer( _gl.ARRAY_BUFFER, _lensFlare.vertexBuffer );
_gl.vertexAttribPointer( attributes.vertex, 2, _gl.FLOAT, false, 2 * 8, 0 );
_gl.vertexAttribPointer( attributes.uv, 2, _gl.FLOAT, false, 2 * 8, 8 );
_gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, _lensFlare.elementBuffer );
_gl.disable( _gl.CULL_FACE );
_gl.depthMask( false );
_gl.activeTexture( _gl.TEXTURE0 );
_gl.bindTexture( _gl.TEXTURE_2D, _lensFlare.occlusionTexture );
_gl.activeTexture( _gl.TEXTURE1 );
for ( o = 0; o < ol; o ++ ) {
// calc object screen position
object = scene.__webglLensFlares[ o ].object;
tempPosition.set( object.matrixWorld.n14, object.matrixWorld.n24, object.matrixWorld.n34 );
camera.matrixWorldInverse.multiplyVector3( tempPosition );
objectZ = tempPosition.z;
camera.projectionMatrix.multiplyVector3( tempPosition );
// setup arrays for gl programs
screenPosition[ 0 ] = tempPosition.x;
screenPosition[ 1 ] = tempPosition.y;
screenPosition[ 2 ] = tempPosition.z;
screenPositionPixels[ 0 ] = screenPosition[ 0 ] * halfViewportWidth + halfViewportWidth;
screenPositionPixels[ 1 ] = screenPosition[ 1 ] * halfViewportHeight + halfViewportHeight;
// screen cull
if ( _lensFlare.hasVertexTexture || ( screenPositionPixels[ 0 ] > 0 &&
screenPositionPixels[ 0 ] < _viewportWidth &&
screenPositionPixels[ 1 ] > 0 &&
screenPositionPixels[ 1 ] < _viewportHeight )) {
// save current RGB to temp texture
_gl.bindTexture( _gl.TEXTURE_2D, _lensFlare.tempTexture );
_gl.copyTexImage2D( _gl.TEXTURE_2D, 0, _gl.RGB, screenPositionPixels[ 0 ] - 8, screenPositionPixels[ 1 ] - 8, 16, 16, 0 );
// render pink quad
_gl.uniform1i( uniforms.renderType, 0 );
_gl.uniform2fv( uniforms.scale, scale );
_gl.uniform3fv( uniforms.screenPosition, screenPosition );
_gl.disable( _gl.BLEND );
_gl.enable( _gl.DEPTH_TEST );
_gl.drawElements( _gl.TRIANGLES, 6, _gl.UNSIGNED_SHORT, 0 );
// copy result to occlusionMap
_gl.bindTexture( _gl.TEXTURE_2D, _lensFlare.occlusionTexture );
_gl.copyTexImage2D( _gl.TEXTURE_2D, 0, _gl.RGBA, screenPositionPixels[ 0 ] - 8, screenPositionPixels[ 1 ] - 8, 16, 16, 0 );
// restore graphics
_gl.uniform1i( uniforms.renderType, 1 );
_gl.disable( _gl.DEPTH_TEST );
_gl.bindTexture( _gl.TEXTURE_2D, _lensFlare.tempTexture );
_gl.drawElements( _gl.TRIANGLES, 6, _gl.UNSIGNED_SHORT, 0 );
// update object positions
object.positionScreen.x = screenPosition[ 0 ];
object.positionScreen.y = screenPosition[ 1 ];
object.positionScreen.z = screenPosition[ 2 ];
if ( object.customUpdateCallback ) {
object.customUpdateCallback( object );
} else {
object.updateLensFlares();
}
// render flares
_gl.uniform1i( uniforms.renderType, 2 );
_gl.enable( _gl.BLEND );
for ( f = 0, fl = object.lensFlares.length; f < fl; f ++ ) {
flare = object.lensFlares[ f ];
if ( flare.opacity > 0.001 && flare.scale > 0.001 ) {
screenPosition[ 0 ] = flare.x;
screenPosition[ 1 ] = flare.y;
screenPosition[ 2 ] = flare.z;
size = flare.size * flare.scale / _viewportHeight;
scale[ 0 ] = size * invAspect;
scale[ 1 ] = size;
_gl.uniform3fv( uniforms.screenPosition, screenPosition );
_gl.uniform2fv( uniforms.scale, scale );
_gl.uniform1f( uniforms.rotation, flare.rotation );
_gl.uniform1f( uniforms.opacity, flare.opacity );
setBlending( flare.blending );
setTexture( flare.texture, 1 );
_gl.drawElements( _gl.TRIANGLES, 6, _gl.UNSIGNED_SHORT, 0 );
}
}
}
}
// restore gl
_gl.enable( _gl.CULL_FACE );
_gl.enable( _gl.DEPTH_TEST );
_gl.depthMask( _currentDepthMask );
};
function setupMatrices( object, camera ) {
object._modelViewMatrix.multiplyToArray( camera.matrixWorldInverse, object.matrixWorld, object._modelViewMatrixArray );
THREE.Matrix4.makeInvert3x3( object._modelViewMatrix ).transposeIntoArray( object._normalMatrixArray );
};
this.initWebGLObjects = function ( scene ) {
if ( !scene.__webglObjects ) {
scene.__webglObjects = [];
scene.__webglObjectsImmediate = [];
scene.__webglShadowVolumes = [];
scene.__webglLensFlares = [];
scene.__webglSprites = [];
}
while ( scene.__objectsAdded.length ) {
addObject( scene.__objectsAdded[ 0 ], scene );
scene.__objectsAdded.splice( 0, 1 );
}
while ( scene.__objectsRemoved.length ) {
removeObject( scene.__objectsRemoved[ 0 ], scene );
scene.__objectsRemoved.splice( 0, 1 );
}
// update must be called after objects adding / removal
for ( var o = 0, ol = scene.__webglObjects.length; o < ol; o ++ ) {
updateObject( scene.__webglObjects[ o ].object, scene );
}
for ( var o = 0, ol = scene.__webglShadowVolumes.length; o < ol; o ++ ) {
updateObject( scene.__webglShadowVolumes[ o ].object, scene );
}
for ( var o = 0, ol = scene.__webglLensFlares.length; o < ol; o ++ ) {
updateObject( scene.__webglLensFlares[ o ].object, scene );
}
/*
for ( var o = 0, ol = scene.__webglSprites.length; o < ol; o ++ ) {
updateObject( scene.__webglSprites[ o ].object, scene );
}
*/
};
function addObject( object, scene ) {
var g, geometry, geometryGroup;
if ( object._modelViewMatrix == undefined ) {
object._modelViewMatrix = new THREE.Matrix4();
object._normalMatrixArray = new Float32Array( 9 );
object._modelViewMatrixArray = new Float32Array( 16 );
object._objectMatrixArray = new Float32Array( 16 );
object.matrixWorld.flattenToArray( object._objectMatrixArray );
}
if ( object instanceof THREE.Mesh ) {
geometry = object.geometry;
if ( geometry.geometryGroups == undefined ) {
sortFacesByMaterial( geometry );
}
// create separate VBOs per geometry chunk
for ( g in geometry.geometryGroups ) {
geometryGroup = geometry.geometryGroups[ g ];
// initialise VBO on the first access
if ( ! geometryGroup.__webglVertexBuffer ) {
createMeshBuffers( geometryGroup );
initMeshBuffers( geometryGroup, object );
geometry.__dirtyVertices = true;
geometry.__dirtyMorphTargets = true;
geometry.__dirtyElements = true;
geometry.__dirtyUvs = true;
geometry.__dirtyNormals = true;
geometry.__dirtyTangents = true;
geometry.__dirtyColors = true;
}
// create separate wrapper per each use of VBO
if ( object instanceof THREE.ShadowVolume ) {
addBuffer( scene.__webglShadowVolumes, geometryGroup, object );
} else {
addBuffer( scene.__webglObjects, geometryGroup, object );
}
}
} else if ( object instanceof THREE.LensFlare ) {
addBuffer( scene.__webglLensFlares, undefined, object );
} else if ( object instanceof THREE.Ribbon ) {
geometry = object.geometry;
if( ! geometry.__webglVertexBuffer ) {
createRibbonBuffers( geometry );
initRibbonBuffers( geometry );
geometry.__dirtyVertices = true;
geometry.__dirtyColors = true;
}
addBuffer( scene.__webglObjects, geometry, object );
} else if ( object instanceof THREE.Line ) {
geometry = object.geometry;
if( ! geometry.__webglVertexBuffer ) {
createLineBuffers( geometry );
initLineBuffers( geometry );
geometry.__dirtyVertices = true;
geometry.__dirtyColors = true;
}
addBuffer( scene.__webglObjects, geometry, object );
} else if ( object instanceof THREE.ParticleSystem ) {
geometry = object.geometry;
if ( ! geometry.__webglVertexBuffer ) {
createParticleBuffers( geometry );
initParticleBuffers( geometry, object );
geometry.__dirtyVertices = true;
geometry.__dirtyColors = true;
}
addBuffer( scene.__webglObjects, geometry, object );
} else if ( THREE.MarchingCubes !== undefined && object instanceof THREE.MarchingCubes ) {
addBufferImmediate( scene.__webglObjectsImmediate, object );
} else if ( object instanceof THREE.Sprite ) {
scene.__webglSprites.push( object );
}
/*else if ( object instanceof THREE.Particle ) {
}*/
};
function areCustomAttributesDirty( geometryGroup ) {
var a, m, ml, material, materials;
materials = geometryGroup.__materials;
for ( m = 0, ml = materials.length; m < ml; m ++ ) {
material = materials[ m ];
if ( material.attributes ) {
for ( a in material.attributes ) {
if ( material.attributes[ a ].needsUpdate ) return true;
}
}
}
return false;
};
function clearCustomAttributes( geometryGroup ) {
var a, m, ml, material, materials;
materials = geometryGroup.__materials;
for ( m = 0, ml = materials.length; m < ml; m ++ ) {
material = materials[ m ];
if ( material.attributes ) {
for ( a in material.attributes ) {
material.attributes[ a ].needsUpdate = false;
}
}
}
};
function updateObject( object, scene ) {
var g, geometry, geometryGroup, a, customAttributeDirty;
if ( object instanceof THREE.Mesh ) {
geometry = object.geometry;
// check all geometry groups
for ( g in geometry.geometryGroups ) {
geometryGroup = geometry.geometryGroups[ g ];
customAttributeDirty = areCustomAttributesDirty( geometryGroup );
if ( geometry.__dirtyVertices || geometry.__dirtyMorphTargets || geometry.__dirtyElements ||
geometry.__dirtyUvs || geometry.__dirtyNormals ||
geometry.__dirtyColors || geometry.__dirtyTangents || customAttributeDirty ) {
setMeshBuffers( geometryGroup, object, _gl.DYNAMIC_DRAW );
}
}
geometry.__dirtyVertices = false;
geometry.__dirtyMorphTargets = false;
geometry.__dirtyElements = false;
geometry.__dirtyUvs = false;
geometry.__dirtyNormals = false;
geometry.__dirtyTangents = false;
geometry.__dirtyColors = false;
clearCustomAttributes( geometryGroup );
} else if ( object instanceof THREE.Ribbon ) {
geometry = object.geometry;
if( geometry.__dirtyVertices || geometry.__dirtyColors ) {
setRibbonBuffers( geometry, _gl.DYNAMIC_DRAW );
}
geometry.__dirtyVertices = false;
geometry.__dirtyColors = false;
} else if ( object instanceof THREE.Line ) {
geometry = object.geometry;
if( geometry.__dirtyVertices || geometry.__dirtyColors ) {
setLineBuffers( geometry, _gl.DYNAMIC_DRAW );
}
geometry.__dirtyVertices = false;
geometry.__dirtyColors = false;
} else if ( object instanceof THREE.ParticleSystem ) {
geometry = object.geometry;
customAttributeDirty = areCustomAttributesDirty( geometry );
if ( geometry.__dirtyVertices || geometry.__dirtyColors || object.sortParticles || customAttributeDirty ) {
setParticleBuffers( geometry, _gl.DYNAMIC_DRAW, object );
}
geometry.__dirtyVertices = false;
geometry.__dirtyColors = false;
clearCustomAttributes( geometry );
}/* else if ( THREE.MarchingCubes !== undefined && object instanceof THREE.MarchingCubes ) {
// it updates itself in render callback
} else if ( object instanceof THREE.Particle ) {
}*/
/*
delete geometry.vertices;
delete geometry.faces;
delete geometryGroup.faces;
*/
};
function removeInstances( objlist, object ) {
var o, ol;
for ( o = objlist.length - 1; o >= 0; o -- ) {
if ( objlist[ o ].object == object ) {
objlist.splice( o, 1 );
}
}
};
function removeInstancesDirect( objlist, object ) {
var o, ol;
for ( o = objlist.length - 1; o >= 0; o -- ) {
if ( objlist[ o ] == object ) {
objlist.splice( o, 1 );
}
}
};
function removeObject( object, scene ) {
// must check as shadow volume before mesh (as they are also meshes)
if ( object instanceof THREE.ShadowVolume ) {
removeInstances( scene.__webglShadowVolumes, object );
} else if ( object instanceof THREE.Mesh ||
object instanceof THREE.ParticleSystem ||
object instanceof THREE.Ribbon ||
object instanceof THREE.Line ) {
removeInstances( scene.__webglObjects, object );
} else if ( object instanceof THREE.Sprite ) {
removeInstancesDirect( scene.__webglSprites, object );
} else if ( object instanceof THREE.LensFlare ) {
removeInstances( scene.__webglLensFlares, object );
} else if ( object instanceof THREE.MarchingCubes ) {
removeInstances( scene.__webglObjectsImmediate, object );
}
};
function sortFacesByMaterial( geometry ) {
// TODO
// Should optimize by grouping faces with ColorFill / ColorStroke materials
// which could then use vertex color attributes instead of each being
// in its separate VBO
var i, l, f, fl, face, material, materials, vertices, mhash, ghash, hash_map = {};
var numMorphTargets = geometry.morphTargets !== undefined ? geometry.morphTargets.length : 0;
geometry.geometryGroups = {};
function materialHash( material ) {
var hash_array = [];
for ( i = 0, l = material.length; i < l; i++ ) {
if ( material[ i ] == undefined ) {
hash_array.push( "undefined" );
} else {
hash_array.push( material[ i ].id );
}
}
return hash_array.join( '_' );
}
for ( f = 0, fl = geometry.faces.length; f < fl; f++ ) {
face = geometry.faces[ f ];
materials = face.materials;
mhash = materialHash( materials );
if ( hash_map[ mhash ] == undefined ) {
hash_map[ mhash ] = { 'hash': mhash, 'counter': 0 };
}
ghash = hash_map[ mhash ].hash + '_' + hash_map[ mhash ].counter;
if ( geometry.geometryGroups[ ghash ] == undefined ) {
geometry.geometryGroups[ ghash ] = { 'faces': [], 'materials': materials, 'vertices': 0, 'numMorphTargets': numMorphTargets };
}
vertices = face instanceof THREE.Face3 ? 3 : 4;
if ( geometry.geometryGroups[ ghash ].vertices + vertices > 65535 ) {
hash_map[ mhash ].counter += 1;
ghash = hash_map[ mhash ].hash + '_' + hash_map[ mhash ].counter;
if ( geometry.geometryGroups[ ghash ] == undefined ) {
geometry.geometryGroups[ ghash ] = { 'faces': [], 'materials': materials, 'vertices': 0, 'numMorphTargets': numMorphTargets };
}
}
geometry.geometryGroups[ ghash ].faces.push( f );
geometry.geometryGroups[ ghash ].vertices += vertices;
}
};
function addBuffer( objlist, buffer, object ) {
objlist.push( {
buffer: buffer, object: object,
opaque: { list: [], count: 0 },
transparent: { list: [], count: 0 }
} );
};
function addBufferImmediate( objlist, object ) {
objlist.push( {
object: object,
opaque: { list: [], count: 0 },
transparent: { list: [], count: 0 }
} );
};
this.setFaceCulling = function ( cullFace, frontFace ) {
if ( cullFace ) {
if ( !frontFace || frontFace == "ccw" ) {
_gl.frontFace( _gl.CCW );
} else {
_gl.frontFace( _gl.CW );
}
if( cullFace == "back" ) {
_gl.cullFace( _gl.BACK );
} else if( cullFace == "front" ) {
_gl.cullFace( _gl.FRONT );
} else {
_gl.cullFace( _gl.FRONT_AND_BACK );
}
_gl.enable( _gl.CULL_FACE );
} else {
_gl.disable( _gl.CULL_FACE );
}
};
this.supportsVertexTextures = function () {
return _supportsVertexTextures;
};
function maxVertexTextures() {
return _gl.getParameter( _gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS );
};
function buildProgram( shaderID, fragmentShader, vertexShader, uniforms, attributes, parameters ) {
var p, pl, program, code;
var chunks = [];
// Generate code
if ( shaderID ) {
chunks.push( shaderID );
} else {
chunks.push( fragmentShader );
chunks.push( vertexShader );
}
for ( p in parameters ) {
chunks.push( p );
chunks.push( parameters[ p ] );
}
code = chunks.join();
// Check if code has been already compiled
for ( p = 0, pl = _programs.length; p < pl; p ++ ) {
if ( _programs[ p ].code == code ) {
// console.log( "Code already compiled." /*: \n\n" + code*/ );
return _programs[ p ].program;
}
}
//console.log( "building new program " );
//
program = _gl.createProgram();
var prefix_vertex = [
_supportsVertexTextures ? "#define VERTEX_TEXTURES" : "",
"#define MAX_DIR_LIGHTS " + parameters.maxDirLights,
"#define MAX_POINT_LIGHTS " + parameters.maxPointLights,
"#define MAX_BONES " + parameters.maxBones,
parameters.map ? "#define USE_MAP" : "",
parameters.envMap ? "#define USE_ENVMAP" : "",
parameters.lightMap ? "#define USE_LIGHTMAP" : "",
parameters.vertexColors ? "#define USE_COLOR" : "",
parameters.skinning ? "#define USE_SKINNING" : "",
parameters.morphTargets ? "#define USE_MORPHTARGETS" : "",
parameters.sizeAttenuation ? "#define USE_SIZEATTENUATION" : "",
"uniform mat4 objectMatrix;",
"uniform mat4 modelViewMatrix;",
"uniform mat4 projectionMatrix;",
"uniform mat4 viewMatrix;",
"uniform mat3 normalMatrix;",
"uniform vec3 cameraPosition;",
"uniform mat4 cameraInverseMatrix;",
"attribute vec3 position;",
"attribute vec3 normal;",
"attribute vec2 uv;",
"attribute vec2 uv2;",
"#ifdef USE_COLOR",
"attribute vec3 color;",
"#endif",
"#ifdef USE_MORPHTARGETS",
"attribute vec3 morphTarget0;",
"attribute vec3 morphTarget1;",
"attribute vec3 morphTarget2;",
"attribute vec3 morphTarget3;",
"attribute vec3 morphTarget4;",
"attribute vec3 morphTarget5;",
"attribute vec3 morphTarget6;",
"attribute vec3 morphTarget7;",
"#endif",
"#ifdef USE_SKINNING",
"attribute vec4 skinVertexA;",
"attribute vec4 skinVertexB;",
"attribute vec4 skinIndex;",
"attribute vec4 skinWeight;",
"#endif",
""
].join("\n");
var prefix_fragment = [
"#ifdef GL_ES",
"precision highp float;",
"#endif",
"#define MAX_DIR_LIGHTS " + parameters.maxDirLights,
"#define MAX_POINT_LIGHTS " + parameters.maxPointLights,
parameters.fog ? "#define USE_FOG" : "",
parameters.fog instanceof THREE.FogExp2 ? "#define FOG_EXP2" : "",
parameters.map ? "#define USE_MAP" : "",
parameters.envMap ? "#define USE_ENVMAP" : "",
parameters.lightMap ? "#define USE_LIGHTMAP" : "",
parameters.vertexColors ? "#define USE_COLOR" : "",
"uniform mat4 viewMatrix;",
"uniform vec3 cameraPosition;",
""
].join("\n");
_gl.attachShader( program, getShader( "fragment", prefix_fragment + fragmentShader ) );
_gl.attachShader( program, getShader( "vertex", prefix_vertex + vertexShader ) );
_gl.linkProgram( program );
if ( !_gl.getProgramParameter( program, _gl.LINK_STATUS ) ) {
console.error( "Could not initialise shader\n" + "VALIDATE_STATUS: " + _gl.getProgramParameter( program, _gl.VALIDATE_STATUS ) + ", gl error [" + _gl.getError() + "]" );
}
//console.log( prefix_fragment + fragmentShader );
//console.log( prefix_vertex + vertexShader );
program.uniforms = {};
program.attributes = {};
var identifiers, u, a, i;
// cache uniform locations
identifiers = [
'viewMatrix', 'modelViewMatrix', 'projectionMatrix', 'normalMatrix', 'objectMatrix', 'cameraPosition',
'cameraInverseMatrix', 'boneGlobalMatrices', 'morphTargetInfluences'
];
for ( u in uniforms ) {
identifiers.push( u );
}
cacheUniformLocations( program, identifiers );
// cache attributes locations
identifiers = [
"position", "normal", "uv", "uv2", "tangent", "color",
"skinVertexA", "skinVertexB", "skinIndex", "skinWeight"
];
for ( i = 0; i < parameters.maxMorphTargets; i++ ) {
identifiers.push( "morphTarget" + i );
}
for ( a in attributes ) {
identifiers.push( a );
}
cacheAttributeLocations( program, identifiers );
_programs.push( { program: program, code: code } );
return program;
};
function loadUniformsSkinning( uniforms, object ) {
_gl.uniformMatrix4fv( uniforms.cameraInverseMatrix, false, _viewMatrixArray );
_gl.uniformMatrix4fv( uniforms.boneGlobalMatrices, false, object.boneMatrices );
};
function loadUniformsMatrices( uniforms, object ) {
_gl.uniformMatrix4fv( uniforms.modelViewMatrix, false, object._modelViewMatrixArray );
_gl.uniformMatrix3fv( uniforms.normalMatrix, false, object._normalMatrixArray );
};
function loadUniformsGeneric( program, uniforms ) {
var u, uniform, value, type, location, texture;
for( u in uniforms ) {
location = program.uniforms[u];
if ( !location ) continue;
uniform = uniforms[u];
type = uniform.type;
value = uniform.value;
if( type == "i" ) {
_gl.uniform1i( location, value );
} else if( type == "f" ) {
_gl.uniform1f( location, value );
} else if( type == "fv1" ) {
_gl.uniform1fv( location, value );
} else if( type == "fv" ) {
_gl.uniform3fv( location, value );
} else if( type == "v2" ) {
_gl.uniform2f( location, value.x, value.y );
} else if( type == "v3" ) {
_gl.uniform3f( location, value.x, value.y, value.z );
} else if( type == "v4" ) {
_gl.uniform4f( location, value.x, value.y, value.z, value.w );
} else if( type == "m4" ) {
if ( ! uniform._array ) {
uniform._array = new Float32Array( 16 );
}
value.flattenToArray( uniform._array );
_gl.uniformMatrix4fv( location, false, uniform._array );
} else if( type == "c" ) {
_gl.uniform3f( location, value.r, value.g, value.b );
} else if( type == "t" ) {
_gl.uniform1i( location, value );
texture = uniform.texture;
if ( !texture ) continue;
if ( texture.image instanceof Array && texture.image.length == 6 ) {
setCubeTexture( texture, value );
} else {
setTexture( texture, value );
}
}
}
};
function setBlending( blending ) {
if ( blending != _oldBlending ) {
switch ( blending ) {
case THREE.AdditiveBlending:
_gl.blendEquation( _gl.FUNC_ADD );
_gl.blendFunc( _gl.SRC_ALPHA, _gl.ONE );
break;
case THREE.SubtractiveBlending:
// TODO: Find blendFuncSeparate() combination
_gl.blendEquation( _gl.FUNC_ADD );
_gl.blendFunc( _gl.ZERO, _gl.ONE_MINUS_SRC_COLOR );
break;
case THREE.MultiplyBlending:
// TODO: Find blendFuncSeparate() combination
_gl.blendEquation( _gl.FUNC_ADD );
_gl.blendFunc( _gl.ZERO, _gl.SRC_COLOR );
break;
default:
_gl.blendEquationSeparate( _gl.FUNC_ADD, _gl.FUNC_ADD );
_gl.blendFuncSeparate( _gl.SRC_ALPHA, _gl.ONE_MINUS_SRC_ALPHA, _gl.ONE, _gl.ONE_MINUS_SRC_ALPHA );
break;
}
_oldBlending = blending;
}
};
function setTextureParameters( textureType, texture, image ) {
if ( isPowerOfTwo( image.width ) && isPowerOfTwo( image.height ) ) {
_gl.texParameteri( textureType, _gl.TEXTURE_WRAP_S, paramThreeToGL( texture.wrapS ) );
_gl.texParameteri( textureType, _gl.TEXTURE_WRAP_T, paramThreeToGL( texture.wrapT ) );
_gl.texParameteri( textureType, _gl.TEXTURE_MAG_FILTER, paramThreeToGL( texture.magFilter ) );
_gl.texParameteri( textureType, _gl.TEXTURE_MIN_FILTER, paramThreeToGL( texture.minFilter ) );
_gl.generateMipmap( textureType );
} else {
_gl.texParameteri( textureType, _gl.TEXTURE_WRAP_S, _gl.CLAMP_TO_EDGE );
_gl.texParameteri( textureType, _gl.TEXTURE_WRAP_T, _gl.CLAMP_TO_EDGE );
_gl.texParameteri( textureType, _gl.TEXTURE_MAG_FILTER, filterFallback( texture.magFilter ) );
_gl.texParameteri( textureType, _gl.TEXTURE_MIN_FILTER, filterFallback( texture.minFilter ) );
}
};
function setTexture( texture, slot ) {
if ( texture.needsUpdate ) {
if ( !texture.__webglInit ) {
texture.__webglTexture = _gl.createTexture();
_gl.bindTexture( _gl.TEXTURE_2D, texture.__webglTexture );
// _gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, true );
_gl.texImage2D( _gl.TEXTURE_2D, 0, _gl.RGBA, _gl.RGBA, _gl.UNSIGNED_BYTE, texture.image );
texture.__webglInit = true;
} else {
_gl.bindTexture( _gl.TEXTURE_2D, texture.__webglTexture );
// _gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, true );
_gl.texImage2D( _gl.TEXTURE_2D, 0, _gl.RGBA, _gl.RGBA, _gl.UNSIGNED_BYTE, texture.image );
// _gl.texSubImage2D( _gl.TEXTURE_2D, 0, 0, 0, _gl.RGBA, _gl.UNSIGNED_BYTE, texture.image );
}
setTextureParameters( _gl.TEXTURE_2D, texture, texture.image );
_gl.bindTexture( _gl.TEXTURE_2D, null );
texture.needsUpdate = false;
}
/*
if ( texture.needsUpdate ) {
if ( texture.__webglTexture ) {
texture.__webglTexture = _gl.deleteTexture( texture.__webglTexture );
}
texture.__webglTexture = _gl.createTexture();
_gl.bindTexture( _gl.TEXTURE_2D, texture.__webglTexture );
_gl.texImage2D( _gl.TEXTURE_2D, 0, _gl.RGBA, _gl.RGBA, _gl.UNSIGNED_BYTE, texture.image );
setTextureParameters( _gl.TEXTURE_2D, texture, texture.image );
_gl.bindTexture( _gl.TEXTURE_2D, null );
texture.needsUpdate = false;
}
*/
_gl.activeTexture( _gl.TEXTURE0 + slot );
_gl.bindTexture( _gl.TEXTURE_2D, texture.__webglTexture );
};
function setCubeTexture( texture, slot ) {
if ( texture.image.length == 6 ) {
if ( texture.needsUpdate ) {
if ( !texture.__webglInit ) {
texture.image.__webglTextureCube = _gl.createTexture();
_gl.bindTexture( _gl.TEXTURE_CUBE_MAP, texture.image.__webglTextureCube );
for ( var i = 0; i < 6; ++i ) {
_gl.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, _gl.RGBA, _gl.RGBA, _gl.UNSIGNED_BYTE, texture.image[ i ] );
}
texture.__webglInit = true;
} else {
_gl.bindTexture( _gl.TEXTURE_CUBE_MAP, texture.image.__webglTextureCube );
for ( var i = 0; i < 6; ++i ) {
// _gl.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, _gl.RGBA, _gl.RGBA, _gl.UNSIGNED_BYTE, texture.image[ i ] );
_gl.texSubImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, 0, 0, _gl.RGBA, _gl.UNSIGNED_BYTE, texture.image[ i ] );
}
}
setTextureParameters( _gl.TEXTURE_CUBE_MAP, texture, texture.image[0] );
_gl.bindTexture( _gl.TEXTURE_CUBE_MAP, null );
texture.needsUpdate = false;
}
_gl.activeTexture( _gl.TEXTURE0 + slot );
_gl.bindTexture( _gl.TEXTURE_CUBE_MAP, texture.image.__webglTextureCube );
}
};
function setRenderTarget( renderTexture ) {
if ( renderTexture && !renderTexture.__webglFramebuffer ) {
if( renderTexture.depthBuffer === undefined ) renderTexture.depthBuffer = true;
if( renderTexture.stencilBuffer === undefined ) renderTexture.stencilBuffer = true;
renderTexture.__webglFramebuffer = _gl.createFramebuffer();
renderTexture.__webglRenderbuffer = _gl.createRenderbuffer();
renderTexture.__webglTexture = _gl.createTexture();
// Setup texture
_gl.bindTexture( _gl.TEXTURE_2D, renderTexture.__webglTexture );
_gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_WRAP_S, paramThreeToGL( renderTexture.wrapS ) );
_gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_WRAP_T, paramThreeToGL( renderTexture.wrapT ) );
_gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_MAG_FILTER, paramThreeToGL( renderTexture.magFilter ) );
_gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_MIN_FILTER, paramThreeToGL( renderTexture.minFilter ) );
_gl.texImage2D( _gl.TEXTURE_2D, 0, paramThreeToGL( renderTexture.format ), renderTexture.width, renderTexture.height, 0, paramThreeToGL( renderTexture.format ), paramThreeToGL( renderTexture.type ), null );
// Setup render and frame buffer
_gl.bindRenderbuffer( _gl.RENDERBUFFER, renderTexture.__webglRenderbuffer );
_gl.bindFramebuffer( _gl.FRAMEBUFFER, renderTexture.__webglFramebuffer );
_gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_2D, renderTexture.__webglTexture, 0 );
if ( renderTexture.depthBuffer && !renderTexture.stencilBuffer ) {
_gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.DEPTH_COMPONENT16, renderTexture.width, renderTexture.height );
_gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.RENDERBUFFER, renderTexture.__webglRenderbuffer );
/* For some reason this is not working. Defaulting to RGBA4.
} else if( !renderTexture.depthBuffer && renderTexture.stencilBuffer ) {
_gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.STENCIL_INDEX8, renderTexture.width, renderTexture.height );
_gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.STENCIL_ATTACHMENT, _gl.RENDERBUFFER, renderTexture.__webglRenderbuffer );
*/
} else if( renderTexture.depthBuffer && renderTexture.stencilBuffer ) {
_gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.DEPTH_STENCIL, renderTexture.width, renderTexture.height );
_gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.RENDERBUFFER, renderTexture.__webglRenderbuffer );
} else {
_gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.RGBA4, renderTexture.width, renderTexture.height );
}
// Release everything
_gl.bindTexture( _gl.TEXTURE_2D, null );
_gl.bindRenderbuffer( _gl.RENDERBUFFER, null );
_gl.bindFramebuffer( _gl.FRAMEBUFFER, null);
}
var framebuffer, width, height;
if ( renderTexture ) {
framebuffer = renderTexture.__webglFramebuffer;
width = renderTexture.width;
height = renderTexture.height;
} else {
framebuffer = null;
width = _viewportWidth;
height = _viewportHeight;
}
if ( framebuffer != _currentFramebuffer ) {
_gl.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );
_gl.viewport( _viewportX, _viewportY, width, height );
_currentFramebuffer = framebuffer;
}
};
function updateRenderTargetMipmap( renderTarget ) {
_gl.bindTexture( _gl.TEXTURE_2D, renderTarget.__webglTexture );
_gl.generateMipmap( _gl.TEXTURE_2D );
_gl.bindTexture( _gl.TEXTURE_2D, null );
};
function cacheUniformLocations( program, identifiers ) {
var i, l, id;
for( i = 0, l = identifiers.length; i < l; i++ ) {
id = identifiers[ i ];
program.uniforms[ id ] = _gl.getUniformLocation( program, id );
}
};
function cacheAttributeLocations( program, identifiers ) {
var i, l, id;
for( i = 0, l = identifiers.length; i < l; i++ ) {
id = identifiers[ i ];
program.attributes[ id ] = _gl.getAttribLocation( program, id );
}
};
function getShader( type, string ) {
var shader;
if ( type == "fragment" ) {
shader = _gl.createShader( _gl.FRAGMENT_SHADER );
} else if ( type == "vertex" ) {
shader = _gl.createShader( _gl.VERTEX_SHADER );
}
_gl.shaderSource( shader, string );
_gl.compileShader( shader );
if ( !_gl.getShaderParameter( shader, _gl.COMPILE_STATUS ) ) {
console.error( _gl.getShaderInfoLog( shader ) );
console.error( string );
return null;
}
return shader;
};
// fallback filters for non-power-of-2 textures
function filterFallback( f ) {
switch ( f ) {
case THREE.NearestFilter:
case THREE.NearestMipMapNearestFilter:
case THREE.NearestMipMapLinearFilter: return _gl.NEAREST; break;
case THREE.LinearFilter:
case THREE.LinearMipMapNearestFilter:
case THREE.LinearMipMapLinearFilter:
default:
return _gl.LINEAR; break;
}
};
function paramThreeToGL( p ) {
switch ( p ) {
case THREE.RepeatWrapping: return _gl.REPEAT; break;
case THREE.ClampToEdgeWrapping: return _gl.CLAMP_TO_EDGE; break;
case THREE.MirroredRepeatWrapping: return _gl.MIRRORED_REPEAT; break;
case THREE.NearestFilter: return _gl.NEAREST; break;
case THREE.NearestMipMapNearestFilter: return _gl.NEAREST_MIPMAP_NEAREST; break;
case THREE.NearestMipMapLinearFilter: return _gl.NEAREST_MIPMAP_LINEAR; break;
case THREE.LinearFilter: return _gl.LINEAR; break;
case THREE.LinearMipMapNearestFilter: return _gl.LINEAR_MIPMAP_NEAREST; break;
case THREE.LinearMipMapLinearFilter: return _gl.LINEAR_MIPMAP_LINEAR; break;
case THREE.ByteType: return _gl.BYTE; break;
case THREE.UnsignedByteType: return _gl.UNSIGNED_BYTE; break;
case THREE.ShortType: return _gl.SHORT; break;
case THREE.UnsignedShortType: return _gl.UNSIGNED_SHORT; break;
case THREE.IntType: return _gl.INT; break;
case THREE.UnsignedShortType: return _gl.UNSIGNED_INT; break;
case THREE.FloatType: return _gl.FLOAT; break;
case THREE.AlphaFormat: return _gl.ALPHA; break;
case THREE.RGBFormat: return _gl.RGB; break;
case THREE.RGBAFormat: return _gl.RGBA; break;
case THREE.LuminanceFormat: return _gl.LUMINANCE; break;
case THREE.LuminanceAlphaFormat: return _gl.LUMINANCE_ALPHA; break;
}
return 0;
};
function isPowerOfTwo( value ) {
return ( value & ( value - 1 ) ) == 0;
};
function materialNeedsSmoothNormals( material ) {
return material && material.shading != undefined && material.shading == THREE.SmoothShading;
};
function bufferNeedsSmoothNormals( geometryGroup, object ) {
var m, ml, i, l, meshMaterial, needsSmoothNormals = false;
for ( m = 0, ml = object.materials.length; m < ml; m++ ) {
meshMaterial = object.materials[ m ];
if ( meshMaterial instanceof THREE.MeshFaceMaterial ) {
for ( i = 0, l = geometryGroup.materials.length; i < l; i++ ) {
if ( materialNeedsSmoothNormals( geometryGroup.materials[ i ] ) ) {
needsSmoothNormals = true;
break;
}
}
} else {
if ( materialNeedsSmoothNormals( meshMaterial ) ) {
needsSmoothNormals = true;
break;
}
}
if ( needsSmoothNormals ) break;
}
return needsSmoothNormals;
};
function unrollGroupMaterials( geometryGroup, object ) {
var m, ml, i, il,
material, meshMaterial,
materials = [];
for ( m = 0, ml = object.materials.length; m < ml; m++ ) {
meshMaterial = object.materials[ m ];
if ( meshMaterial instanceof THREE.MeshFaceMaterial ) {
for ( i = 0, l = geometryGroup.materials.length; i < l; i++ ) {
material = geometryGroup.materials[ i ];
if ( material ) {
materials.push( material );
}
}
} else {
material = meshMaterial;
if ( material ) {
materials.push( material );
}
}
}
return materials;
};
function bufferGuessVertexColorType( materials, geometryGroup, object ) {
var i, m, ml = materials.length;
// use vertexColor type from the first material in unrolled materials
for ( i = 0; i < ml; i++ ) {
m = materials[ i ];
if ( m.vertexColors ) {
return m.vertexColors;
}
}
return false;
};
function bufferGuessNormalType( materials, geometryGroup, object ) {
var i, m, ml = materials.length;
// only MeshBasicMaterial and MeshDepthMaterial don't need normals
for ( i = 0; i < ml; i++ ) {
m = materials[ i ];
if ( ( m instanceof THREE.MeshBasicMaterial && !m.envMap ) || m instanceof THREE.MeshDepthMaterial ) continue;
if ( materialNeedsSmoothNormals( m ) ) {
return THREE.SmoothShading;
} else {
return THREE.FlatShading;
}
}
return false;
};
function bufferGuessUVType( materials, geometryGroup, object ) {
var i, m, ml = materials.length;
// material must use some texture to require uvs
for ( i = 0; i < ml; i++ ) {
m = materials[ i ];
if ( m.map || m.lightMap || m instanceof THREE.MeshShaderMaterial ) {
return true;
}
}
return false;
};
function allocateBones( object ) {
// 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 maxBones = 50;
if ( object !== undefined && object instanceof THREE.SkinnedMesh ) {
maxBones = object.bones.length;
}
return maxBones;
};
function allocateLights( lights, maxLights ) {
var l, ll, light, dirLights, pointLights, maxDirLights, maxPointLights;
dirLights = pointLights = maxDirLights = maxPointLights = 0;
for ( l = 0, ll = lights.length; l < ll; l++ ) {
light = lights[ l ];
if ( light instanceof THREE.DirectionalLight ) dirLights++;
if ( light instanceof THREE.PointLight ) pointLights++;
}
if ( ( pointLights + dirLights ) <= maxLights ) {
maxDirLights = dirLights;
maxPointLights = pointLights;
} else {
maxDirLights = Math.ceil( maxLights * dirLights / ( pointLights + dirLights ) );
maxPointLights = maxLights - maxDirLights;
}
return { 'directional' : maxDirLights, 'point' : maxPointLights };
};
/* DEBUG
function getGLParams() {
var params = {
'MAX_VARYING_VECTORS': _gl.getParameter( _gl.MAX_VARYING_VECTORS ),
'MAX_VERTEX_ATTRIBS': _gl.getParameter( _gl.MAX_VERTEX_ATTRIBS ),
'MAX_TEXTURE_IMAGE_UNITS': _gl.getParameter( _gl.MAX_TEXTURE_IMAGE_UNITS ),
'MAX_VERTEX_TEXTURE_IMAGE_UNITS': _gl.getParameter( _gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS ),
'MAX_COMBINED_TEXTURE_IMAGE_UNITS' : _gl.getParameter( _gl.MAX_COMBINED_TEXTURE_IMAGE_UNITS ),
'MAX_VERTEX_UNIFORM_VECTORS': _gl.getParameter( _gl.MAX_VERTEX_UNIFORM_VECTORS ),
'MAX_FRAGMENT_UNIFORM_VECTORS': _gl.getParameter( _gl.MAX_FRAGMENT_UNIFORM_VECTORS )
}
return params;
};
function dumpObject( obj ) {
var p, str = "";
for ( p in obj ) {
str += p + ": " + obj[p] + "\n";
}
return str;
}
*/
};