mirror of
https://github.com/wahyd4/three.js.git
synced 2026-08-09 04:56:01 +10:00
Work in progress. For the moment works just with CTMLoader. Still not sure where some pieces of code would go. Upsides: - initialization time cut down significantly (1.8 seconds => 0.7 seconds for CTM example) - much smaller GL buffers thanks to fully used indexing (Walt has 6x less vertices) - consequently much smaller memory footprint all around, both for main and GPU memories, which means less swapping and better vertex caching Downsides: - can't have anymore sharp per-face effects like flat shading (at least if mesh is not constructed in a way where each face has own vertices) - can't have multiple materials per mesh - no more easy manipulation of anything (for the moment actually no runtime manipulation at all, typed arrays are just thrown away, dynamic geometries code path not yet implemented)
5763 lines
135 KiB
JavaScript
5763 lines
135 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 ) {
|
|
|
|
// constructor parameters
|
|
|
|
var parameters = parameters || {},
|
|
|
|
_canvas = parameters.canvas !== undefined ? parameters.canvas : document.createElement( 'canvas' ),
|
|
|
|
_precision = parameters.precision !== undefined ? parameters.precision : 'mediump',
|
|
_antialias = parameters.antialias !== undefined ? parameters.antialias : false,
|
|
_stencil = parameters.stencil !== undefined ? parameters.stencil : true,
|
|
_preserveDrawingBuffer = parameters.preserveDrawingBuffer !== undefined ? parameters.preserveDrawingBuffer : false,
|
|
|
|
_clearColor = parameters.clearColor !== undefined ? new THREE.Color( parameters.clearColor ) : new THREE.Color( 0x000000 ),
|
|
_clearAlpha = parameters.clearAlpha !== undefined ? parameters.clearAlpha : 0,
|
|
|
|
_maxLights = parameters.maxLights !== undefined ? parameters.maxLights : 4;
|
|
|
|
// public properties
|
|
|
|
this.domElement = _canvas;
|
|
this.context = null;
|
|
|
|
// clearing
|
|
|
|
this.autoClear = true;
|
|
this.autoClearColor = true;
|
|
this.autoClearDepth = true;
|
|
this.autoClearStencil = true;
|
|
|
|
// scene graph
|
|
|
|
this.sortObjects = true;
|
|
|
|
this.autoUpdateObjects = true;
|
|
this.autoUpdateScene = true;
|
|
|
|
// physically based shading
|
|
|
|
this.gammaInput = false;
|
|
this.gammaOutput = false;
|
|
this.physicallyBasedShading = false;
|
|
|
|
// shadow map
|
|
|
|
this.shadowMapBias = 0.0039;
|
|
this.shadowMapDarkness = 0.5;
|
|
this.shadowMapWidth = 512;
|
|
this.shadowMapHeight = 512;
|
|
|
|
this.shadowCameraNear = 1;
|
|
this.shadowCameraFar = 5000;
|
|
this.shadowCameraFov = 50;
|
|
|
|
this.shadowMapEnabled = false;
|
|
this.shadowMapAutoUpdate = true;
|
|
this.shadowMapSoft = true;
|
|
|
|
// morphs
|
|
|
|
this.maxMorphTargets = 8;
|
|
|
|
// custom render plugins
|
|
|
|
this.renderPluginsPre = [];
|
|
this.renderPluginsPost = [];
|
|
|
|
// info
|
|
|
|
this.info = {
|
|
|
|
memory: {
|
|
|
|
programs: 0,
|
|
geometries: 0,
|
|
textures: 0
|
|
|
|
},
|
|
|
|
render: {
|
|
|
|
calls: 0,
|
|
vertices: 0,
|
|
faces: 0,
|
|
points: 0
|
|
|
|
}
|
|
|
|
};
|
|
|
|
// internal properties
|
|
|
|
var _this = this,
|
|
|
|
_gl,
|
|
|
|
_programs = [],
|
|
|
|
// internal state cache
|
|
|
|
_currentProgram = null,
|
|
_currentFramebuffer = null,
|
|
_currentMaterialId = -1,
|
|
_currentGeometryGroupHash = null,
|
|
_geometryGroupCounter = 0,
|
|
|
|
// GL state cache
|
|
|
|
_oldDoubleSided = null,
|
|
_oldFlipSided = null,
|
|
_oldBlending = null,
|
|
_oldDepthTest = null,
|
|
_oldDepthWrite = null,
|
|
_oldPolygonOffset = null,
|
|
_oldPolygonOffsetFactor = null,
|
|
_oldPolygonOffsetUnits = null,
|
|
_oldLineWidth = null,
|
|
|
|
_viewportX = 0,
|
|
_viewportY = 0,
|
|
_viewportWidth = 0,
|
|
_viewportHeight = 0,
|
|
_currentWidth = 0,
|
|
_currentHeight = 0,
|
|
|
|
// frustum
|
|
|
|
_frustum = new THREE.Frustum(),
|
|
|
|
// camera matrices cache
|
|
|
|
_projScreenMatrix = new THREE.Matrix4(),
|
|
|
|
_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() }
|
|
|
|
};
|
|
|
|
// initialize
|
|
|
|
_gl = initGL();
|
|
|
|
setDefaultGLState();
|
|
|
|
this.context = _gl;
|
|
|
|
var _supportsVertexTextures = ( maxVertexTextures() > 0 );
|
|
|
|
// API
|
|
|
|
this.getContext = function () {
|
|
|
|
return _gl;
|
|
|
|
};
|
|
|
|
this.supportsVertexTextures = function () {
|
|
|
|
return _supportsVertexTextures;
|
|
|
|
};
|
|
|
|
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 ) {
|
|
|
|
enable ? _gl.enable( _gl.SCISSOR_TEST ) : _gl.disable( _gl.SCISSOR_TEST );
|
|
|
|
};
|
|
|
|
// Clearing
|
|
|
|
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.getClearColor = function () {
|
|
|
|
return _clearColor;
|
|
|
|
};
|
|
|
|
this.getClearAlpha = function () {
|
|
|
|
return _clearAlpha;
|
|
|
|
};
|
|
|
|
this.clear = function ( color, depth, stencil ) {
|
|
|
|
var bits = 0;
|
|
|
|
if ( color === undefined || color ) bits |= _gl.COLOR_BUFFER_BIT;
|
|
if ( depth === undefined || depth ) bits |= _gl.DEPTH_BUFFER_BIT;
|
|
if ( stencil === undefined || stencil ) bits |= _gl.STENCIL_BUFFER_BIT;
|
|
|
|
_gl.clear( bits );
|
|
|
|
};
|
|
|
|
this.clearTarget = function ( renderTarget, color, depth, stencil ) {
|
|
|
|
this.setRenderTarget( renderTarget );
|
|
this.clear( color, depth, stencil );
|
|
|
|
};
|
|
|
|
// Plugins
|
|
|
|
this.addPostPlugin = function ( plugin ) {
|
|
|
|
plugin.init( this );
|
|
this.renderPluginsPost.push( plugin );
|
|
|
|
};
|
|
|
|
this.addPrePlugin = function ( plugin ) {
|
|
|
|
plugin.init( this );
|
|
this.renderPluginsPre.push( plugin );
|
|
|
|
};
|
|
|
|
// Deallocation
|
|
|
|
this.deallocateObject = function ( object ) {
|
|
|
|
if ( ! object.__webglInit ) return;
|
|
|
|
object.__webglInit = false;
|
|
|
|
delete object._modelViewMatrix;
|
|
|
|
delete object._normalMatrixArray;
|
|
delete object._modelViewMatrixArray;
|
|
delete object._objectMatrixArray;
|
|
|
|
if ( object instanceof THREE.Mesh ) {
|
|
|
|
for ( var g in object.geometry.geometryGroups ) {
|
|
|
|
deleteMeshBuffers( object.geometry.geometryGroups[ g ] );
|
|
|
|
}
|
|
|
|
} else if ( object instanceof THREE.Ribbon ) {
|
|
|
|
deleteRibbonBuffers( object.geometry );
|
|
|
|
} else if ( object instanceof THREE.Line ) {
|
|
|
|
deleteLineBuffers( object.geometry );
|
|
|
|
} else if ( object instanceof THREE.ParticleSystem ) {
|
|
|
|
deleteParticleBuffers( object.geometry );
|
|
|
|
}
|
|
|
|
};
|
|
|
|
this.deallocateTexture = function ( texture ) {
|
|
|
|
if ( ! texture.__webglInit ) return;
|
|
|
|
texture.__webglInit = false;
|
|
_gl.deleteTexture( texture.__webglTexture );
|
|
|
|
_this.info.memory.textures --;
|
|
|
|
};
|
|
|
|
// Rendering
|
|
|
|
this.updateShadowMap = function ( scene, camera ) {
|
|
|
|
_currentProgram = null;
|
|
_oldBlending = -1;
|
|
_oldDepthTest = -1;
|
|
_oldDepthWrite = -1;
|
|
_currentGeometryGroupHash = -1;
|
|
_currentMaterialId = -1;
|
|
|
|
this.shadowMapPlugin.update( scene, camera );
|
|
|
|
};
|
|
|
|
// Internal functions
|
|
|
|
// Buffer allocation
|
|
|
|
function createParticleBuffers ( geometry ) {
|
|
|
|
geometry.__webglVertexBuffer = _gl.createBuffer();
|
|
geometry.__webglColorBuffer = _gl.createBuffer();
|
|
|
|
_this.info.geometries ++;
|
|
|
|
};
|
|
|
|
function createLineBuffers ( geometry ) {
|
|
|
|
geometry.__webglVertexBuffer = _gl.createBuffer();
|
|
geometry.__webglColorBuffer = _gl.createBuffer();
|
|
|
|
_this.info.memory.geometries ++;
|
|
|
|
};
|
|
|
|
function createRibbonBuffers ( geometry ) {
|
|
|
|
geometry.__webglVertexBuffer = _gl.createBuffer();
|
|
geometry.__webglColorBuffer = _gl.createBuffer();
|
|
|
|
_this.info.memory.geometries ++;
|
|
|
|
};
|
|
|
|
function createMeshBuffers ( geometryGroup ) {
|
|
|
|
geometryGroup.__webglVertexBuffer = _gl.createBuffer();
|
|
geometryGroup.__webglNormalBuffer = _gl.createBuffer();
|
|
geometryGroup.__webglTangentBuffer = _gl.createBuffer();
|
|
geometryGroup.__webglColorBuffer = _gl.createBuffer();
|
|
geometryGroup.__webglUVBuffer = _gl.createBuffer();
|
|
geometryGroup.__webglUV2Buffer = _gl.createBuffer();
|
|
|
|
geometryGroup.__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() );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_this.info.memory.geometries ++;
|
|
|
|
};
|
|
|
|
// Buffer deallocation
|
|
|
|
function deleteParticleBuffers ( geometry ) {
|
|
|
|
_gl.deleteBuffer( geometry.__webglVertexBuffer );
|
|
_gl.deleteBuffer( geometry.__webglColorBuffer );
|
|
|
|
_this.info.memory.geometries --;
|
|
|
|
};
|
|
|
|
function deleteLineBuffers ( geometry ) {
|
|
|
|
_gl.deleteBuffer( geometry.__webglVertexBuffer );
|
|
_gl.deleteBuffer( geometry.__webglColorBuffer );
|
|
|
|
_this.info.memory.geometries --;
|
|
|
|
};
|
|
|
|
function deleteRibbonBuffers ( geometry ) {
|
|
|
|
_gl.deleteBuffer( geometry.__webglVertexBuffer );
|
|
_gl.deleteBuffer( geometry.__webglColorBuffer );
|
|
|
|
_this.info.memory.geometries --;
|
|
|
|
};
|
|
|
|
function deleteMeshBuffers ( geometryGroup ) {
|
|
|
|
_gl.deleteBuffer( geometryGroup.__webglVertexBuffer );
|
|
_gl.deleteBuffer( geometryGroup.__webglNormalBuffer );
|
|
_gl.deleteBuffer( geometryGroup.__webglTangentBuffer );
|
|
_gl.deleteBuffer( geometryGroup.__webglColorBuffer );
|
|
_gl.deleteBuffer( geometryGroup.__webglUVBuffer );
|
|
_gl.deleteBuffer( geometryGroup.__webglUV2Buffer );
|
|
|
|
_gl.deleteBuffer( geometryGroup.__webglSkinVertexABuffer );
|
|
_gl.deleteBuffer( geometryGroup.__webglSkinVertexBBuffer );
|
|
_gl.deleteBuffer( geometryGroup.__webglSkinIndicesBuffer );
|
|
_gl.deleteBuffer( geometryGroup.__webglSkinWeightsBuffer );
|
|
|
|
_gl.deleteBuffer( geometryGroup.__webglFaceBuffer );
|
|
_gl.deleteBuffer( geometryGroup.__webglLineBuffer );
|
|
|
|
if ( geometryGroup.numMorphTargets ) {
|
|
|
|
for ( var m = 0, ml = geometryGroup.numMorphTargets; m < ml; m ++ ) {
|
|
|
|
_gl.deleteBuffer( geometryGroup.__webglMorphTargetsBuffers[ m ] );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
if ( geometryGroup.__webglCustomAttributesList ) {
|
|
|
|
for ( var id in geometryGroup.__webglCustomAttributesList ) {
|
|
|
|
_gl.deleteBuffer( geometryGroup.__webglCustomAttributesList[ id ].buffer );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_this.info.memory.geometries --;
|
|
|
|
};
|
|
|
|
// Buffer initialization
|
|
|
|
function initCustomAttributes ( geometry, object ) {
|
|
|
|
var nvertices = geometry.vertices.length;
|
|
|
|
var material = object.material;
|
|
|
|
if ( material.attributes ) {
|
|
|
|
if ( geometry.__webglCustomAttributesList === undefined ) {
|
|
|
|
geometry.__webglCustomAttributesList = [];
|
|
|
|
}
|
|
|
|
for ( var a in material.attributes ) {
|
|
|
|
var attribute = material.attributes[ a ];
|
|
|
|
if( !attribute.__webglInitialized || attribute.createUniqueBuffers ) {
|
|
|
|
attribute.__webglInitialized = true;
|
|
|
|
var size = 1; // "f" and "i"
|
|
|
|
if ( attribute.type === "v2" ) size = 2;
|
|
else if ( attribute.type === "v3" ) size = 3;
|
|
else if ( attribute.type === "v4" ) size = 4;
|
|
else if ( attribute.type === "c" ) size = 3;
|
|
|
|
attribute.size = size;
|
|
|
|
attribute.array = new Float32Array( nvertices * size );
|
|
|
|
attribute.buffer = _gl.createBuffer();
|
|
attribute.buffer.belongsToAttribute = a;
|
|
|
|
attribute.needsUpdate = true;
|
|
|
|
}
|
|
|
|
geometry.__webglCustomAttributesList.push( attribute );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
function initParticleBuffers ( geometry, object ) {
|
|
|
|
var nvertices = geometry.vertices.length;
|
|
|
|
geometry.__vertexArray = new Float32Array( nvertices * 3 );
|
|
geometry.__colorArray = new Float32Array( nvertices * 3 );
|
|
|
|
geometry.__sortArray = [];
|
|
|
|
geometry.__webglParticleCount = nvertices;
|
|
|
|
initCustomAttributes ( geometry, object );
|
|
|
|
};
|
|
|
|
function initLineBuffers ( geometry, object ) {
|
|
|
|
var nvertices = geometry.vertices.length;
|
|
|
|
geometry.__vertexArray = new Float32Array( nvertices * 3 );
|
|
geometry.__colorArray = new Float32Array( nvertices * 3 );
|
|
|
|
geometry.__webglLineCount = nvertices;
|
|
|
|
initCustomAttributes ( geometry, object );
|
|
|
|
};
|
|
|
|
function initRibbonBuffers ( geometry ) {
|
|
|
|
var nvertices = geometry.vertices.length;
|
|
|
|
geometry.__vertexArray = new Float32Array( nvertices * 3 );
|
|
geometry.__colorArray = new Float32Array( nvertices * 3 );
|
|
|
|
geometry.__webglVertexCount = nvertices;
|
|
|
|
};
|
|
|
|
function initMeshBuffers ( geometryGroup, object ) {
|
|
|
|
var geometry = object.geometry,
|
|
faces3 = geometryGroup.faces3,
|
|
faces4 = geometryGroup.faces4,
|
|
|
|
nvertices = faces3.length * 3 + faces4.length * 4,
|
|
ntris = faces3.length * 1 + faces4.length * 2,
|
|
nlines = faces3.length * 3 + faces4.length * 4,
|
|
|
|
material = getBufferMaterial( object, geometryGroup ),
|
|
|
|
uvType = bufferGuessUVType( material ),
|
|
normalType = bufferGuessNormalType( material ),
|
|
vertexColorType = bufferGuessVertexColorType( material );
|
|
|
|
//console.log( "uvType", uvType, "normalType", normalType, "vertexColorType", vertexColorType, object, geometryGroup, material );
|
|
|
|
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 );
|
|
geometryGroup.__lineArray = new Uint16Array( nlines * 2 );
|
|
|
|
if ( geometryGroup.numMorphTargets ) {
|
|
|
|
geometryGroup.__morphTargetsArrays = [];
|
|
|
|
for ( var m = 0, ml = geometryGroup.numMorphTargets; m < ml; m ++ ) {
|
|
|
|
geometryGroup.__morphTargetsArrays.push( new Float32Array( nvertices * 3 ) );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
geometryGroup.__webglFaceCount = ntris * 3;
|
|
geometryGroup.__webglLineCount = nlines * 2;
|
|
|
|
|
|
// custom attributes
|
|
|
|
if ( material.attributes ) {
|
|
|
|
if ( geometryGroup.__webglCustomAttributesList === undefined ) {
|
|
|
|
geometryGroup.__webglCustomAttributesList = [];
|
|
|
|
}
|
|
|
|
for ( var 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
|
|
|
|
var originalAttribute = material.attributes[ a ];
|
|
|
|
var attribute = {};
|
|
|
|
for ( var property in originalAttribute ) {
|
|
|
|
attribute[ property ] = originalAttribute[ property ];
|
|
|
|
}
|
|
|
|
if( !attribute.__webglInitialized || attribute.createUniqueBuffers ) {
|
|
|
|
attribute.__webglInitialized = true;
|
|
|
|
var size = 1; // "f" and "i"
|
|
|
|
if( attribute.type === "v2" ) size = 2;
|
|
else if( attribute.type === "v3" ) size = 3;
|
|
else if( attribute.type === "v4" ) size = 4;
|
|
else if( attribute.type === "c" ) size = 3;
|
|
|
|
attribute.size = size;
|
|
|
|
attribute.array = new Float32Array( nvertices * size );
|
|
|
|
attribute.buffer = _gl.createBuffer();
|
|
attribute.buffer.belongsToAttribute = a;
|
|
|
|
originalAttribute.needsUpdate = true;
|
|
attribute.__original = originalAttribute;
|
|
|
|
}
|
|
|
|
geometryGroup.__webglCustomAttributesList.push( attribute );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
geometryGroup.__inittedArrays = true;
|
|
|
|
};
|
|
|
|
function getBufferMaterial( object, geometryGroup ) {
|
|
|
|
if ( object.material && ! ( object.material instanceof THREE.MeshFaceMaterial ) ) {
|
|
|
|
return object.material;
|
|
|
|
} else if ( geometryGroup.materialIndex >= 0 ) {
|
|
|
|
return object.geometry.materials[ geometryGroup.materialIndex ];
|
|
|
|
}
|
|
|
|
};
|
|
|
|
function materialNeedsSmoothNormals ( material ) {
|
|
|
|
return material && material.shading !== undefined && material.shading === THREE.SmoothShading;
|
|
|
|
};
|
|
|
|
function bufferGuessNormalType ( material ) {
|
|
|
|
// only MeshBasicMaterial and MeshDepthMaterial don't need normals
|
|
|
|
if ( ( material instanceof THREE.MeshBasicMaterial && !material.envMap ) || material instanceof THREE.MeshDepthMaterial ) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if ( materialNeedsSmoothNormals( material ) ) {
|
|
|
|
return THREE.SmoothShading;
|
|
|
|
} else {
|
|
|
|
return THREE.FlatShading;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
function bufferGuessVertexColorType ( material ) {
|
|
|
|
if ( material.vertexColors ) {
|
|
|
|
return material.vertexColors;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
};
|
|
|
|
function bufferGuessUVType ( material ) {
|
|
|
|
// material must use some texture to require uvs
|
|
|
|
if ( material.map || material.lightMap || material instanceof THREE.ShaderMaterial ) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
};
|
|
|
|
// Buffer setting
|
|
|
|
function setParticleBuffers ( geometry, hint, object ) {
|
|
|
|
var v, c, vertex, offset, index, color,
|
|
|
|
vertices = geometry.vertices,
|
|
vl = vertices.length,
|
|
|
|
colors = geometry.colors,
|
|
cl = colors.length,
|
|
|
|
vertexArray = geometry.__vertexArray,
|
|
colorArray = geometry.__colorArray,
|
|
|
|
sortArray = geometry.__sortArray,
|
|
|
|
dirtyVertices = geometry.__dirtyVertices,
|
|
dirtyElements = geometry.__dirtyElements,
|
|
dirtyColors = geometry.__dirtyColors,
|
|
|
|
customAttributes = geometry.__webglCustomAttributesList,
|
|
i, il,
|
|
a, ca, cal, value,
|
|
customAttribute;
|
|
|
|
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 ( i = 0, il = customAttributes.length; i < il; i ++ ) {
|
|
|
|
customAttribute = customAttributes[ i ];
|
|
|
|
if ( ! ( customAttribute.boundTo === undefined || customAttribute.boundTo === "vertices" ) ) continue;
|
|
|
|
offset = 0;
|
|
|
|
cal = customAttribute.value.length;
|
|
|
|
if ( customAttribute.size === 1 ) {
|
|
|
|
for ( ca = 0; ca < cal; ca ++ ) {
|
|
|
|
index = sortArray[ ca ][ 1 ];
|
|
|
|
customAttribute.array[ ca ] = customAttribute.value[ index ];
|
|
|
|
}
|
|
|
|
} else if ( customAttribute.size === 2 ) {
|
|
|
|
for ( ca = 0; ca < cal; ca ++ ) {
|
|
|
|
index = sortArray[ ca ][ 1 ];
|
|
|
|
value = customAttribute.value[ index ];
|
|
|
|
customAttribute.array[ offset ] = value.x;
|
|
customAttribute.array[ offset + 1 ] = value.y;
|
|
|
|
offset += 2;
|
|
|
|
}
|
|
|
|
} else if ( customAttribute.size === 3 ) {
|
|
|
|
if ( customAttribute.type === "c" ) {
|
|
|
|
for ( ca = 0; ca < cal; ca ++ ) {
|
|
|
|
index = sortArray[ ca ][ 1 ];
|
|
|
|
value = customAttribute.value[ index ];
|
|
|
|
customAttribute.array[ offset ] = value.r;
|
|
customAttribute.array[ offset + 1 ] = value.g;
|
|
customAttribute.array[ offset + 2 ] = value.b;
|
|
|
|
offset += 3;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
for ( ca = 0; ca < cal; ca ++ ) {
|
|
|
|
index = sortArray[ ca ][ 1 ];
|
|
|
|
value = customAttribute.value[ index ];
|
|
|
|
customAttribute.array[ offset ] = value.x;
|
|
customAttribute.array[ offset + 1 ] = value.y;
|
|
customAttribute.array[ offset + 2 ] = value.z;
|
|
|
|
offset += 3;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if ( customAttribute.size === 4 ) {
|
|
|
|
for ( ca = 0; ca < cal; ca ++ ) {
|
|
|
|
index = sortArray[ ca ][ 1 ];
|
|
|
|
value = customAttribute.value[ index ];
|
|
|
|
customAttribute.array[ offset ] = value.x;
|
|
customAttribute.array[ offset + 1 ] = value.y;
|
|
customAttribute.array[ offset + 2 ] = value.z;
|
|
customAttribute.array[ offset + 3 ] = value.w;
|
|
|
|
offset += 4;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if ( dirtyVertices ) {
|
|
|
|
for ( v = 0; v < vl; v ++ ) {
|
|
|
|
vertex = vertices[ v ].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 ( i = 0, il = customAttributes.length; i < il; i ++ ) {
|
|
|
|
customAttribute = customAttributes[ i ];
|
|
|
|
if ( customAttribute.needsUpdate &&
|
|
( customAttribute.boundTo === undefined ||
|
|
customAttribute.boundTo === "vertices") ) {
|
|
|
|
cal = customAttribute.value.length;
|
|
|
|
offset = 0;
|
|
|
|
if ( customAttribute.size === 1 ) {
|
|
|
|
for ( ca = 0; ca < cal; ca ++ ) {
|
|
|
|
customAttribute.array[ ca ] = customAttribute.value[ ca ];
|
|
|
|
}
|
|
|
|
} else if ( customAttribute.size === 2 ) {
|
|
|
|
for ( ca = 0; ca < cal; ca ++ ) {
|
|
|
|
value = customAttribute.value[ ca ];
|
|
|
|
customAttribute.array[ offset ] = value.x;
|
|
customAttribute.array[ offset + 1 ] = value.y;
|
|
|
|
offset += 2;
|
|
|
|
}
|
|
|
|
} else if ( customAttribute.size === 3 ) {
|
|
|
|
if ( customAttribute.type === "c" ) {
|
|
|
|
for ( ca = 0; ca < cal; ca ++ ) {
|
|
|
|
value = customAttribute.value[ ca ];
|
|
|
|
customAttribute.array[ offset ] = value.r;
|
|
customAttribute.array[ offset + 1 ] = value.g;
|
|
customAttribute.array[ offset + 2 ] = value.b;
|
|
|
|
offset += 3;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
for ( ca = 0; ca < cal; ca ++ ) {
|
|
|
|
value = customAttribute.value[ ca ];
|
|
|
|
customAttribute.array[ offset ] = value.x;
|
|
customAttribute.array[ offset + 1 ] = value.y;
|
|
customAttribute.array[ offset + 2 ] = value.z;
|
|
|
|
offset += 3;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if ( customAttribute.size === 4 ) {
|
|
|
|
for ( ca = 0; ca < cal; ca ++ ) {
|
|
|
|
value = customAttribute.value[ ca ];
|
|
|
|
customAttribute.array[ offset ] = value.x;
|
|
customAttribute.array[ offset + 1 ] = value.y;
|
|
customAttribute.array[ offset + 2 ] = value.z;
|
|
customAttribute.array[ offset + 3 ] = value.w;
|
|
|
|
offset += 4;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ( dirtyVertices || object.sortParticles ) {
|
|
|
|
_gl.bindBuffer( _gl.ARRAY_BUFFER, geometry.__webglVertexBuffer );
|
|
_gl.bufferData( _gl.ARRAY_BUFFER, vertexArray, hint );
|
|
|
|
}
|
|
|
|
if ( dirtyColors || object.sortParticles ) {
|
|
|
|
_gl.bindBuffer( _gl.ARRAY_BUFFER, geometry.__webglColorBuffer );
|
|
_gl.bufferData( _gl.ARRAY_BUFFER, colorArray, hint );
|
|
|
|
}
|
|
|
|
if ( customAttributes ) {
|
|
|
|
for ( i = 0, il = customAttributes.length; i < il; i ++ ) {
|
|
|
|
customAttribute = customAttributes[ i ];
|
|
|
|
if ( customAttribute.needsUpdate || object.sortParticles ) {
|
|
|
|
_gl.bindBuffer( _gl.ARRAY_BUFFER, customAttribute.buffer );
|
|
_gl.bufferData( _gl.ARRAY_BUFFER, customAttribute.array, hint );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
function setLineBuffers ( geometry, hint ) {
|
|
|
|
var v, c, vertex, offset, color,
|
|
|
|
vertices = geometry.vertices,
|
|
colors = geometry.colors,
|
|
vl = vertices.length,
|
|
cl = colors.length,
|
|
|
|
vertexArray = geometry.__vertexArray,
|
|
colorArray = geometry.__colorArray,
|
|
|
|
dirtyVertices = geometry.__dirtyVertices,
|
|
dirtyColors = geometry.__dirtyColors,
|
|
|
|
customAttributes = geometry.__webglCustomAttributesList,
|
|
|
|
i, il,
|
|
a, ca, cal, value,
|
|
customAttribute;
|
|
|
|
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 );
|
|
|
|
}
|
|
|
|
if ( customAttributes ) {
|
|
|
|
for ( i = 0, il = customAttributes.length; i < il; i ++ ) {
|
|
|
|
customAttribute = customAttributes[ i ];
|
|
|
|
if ( customAttribute.needsUpdate &&
|
|
( customAttribute.boundTo === undefined ||
|
|
customAttribute.boundTo === "vertices" ) ) {
|
|
|
|
offset = 0;
|
|
|
|
cal = customAttribute.value.length;
|
|
|
|
if ( customAttribute.size === 1 ) {
|
|
|
|
for ( ca = 0; ca < cal; ca ++ ) {
|
|
|
|
customAttribute.array[ ca ] = customAttribute.value[ ca ];
|
|
|
|
}
|
|
|
|
} else if ( customAttribute.size === 2 ) {
|
|
|
|
for ( ca = 0; ca < cal; ca ++ ) {
|
|
|
|
value = customAttribute.value[ ca ];
|
|
|
|
customAttribute.array[ offset ] = value.x;
|
|
customAttribute.array[ offset + 1 ] = value.y;
|
|
|
|
offset += 2;
|
|
|
|
}
|
|
|
|
} else if ( customAttribute.size === 3 ) {
|
|
|
|
if ( customAttribute.type === "c" ) {
|
|
|
|
for ( ca = 0; ca < cal; ca ++ ) {
|
|
|
|
value = customAttribute.value[ ca ];
|
|
|
|
customAttribute.array[ offset ] = value.r;
|
|
customAttribute.array[ offset + 1 ] = value.g;
|
|
customAttribute.array[ offset + 2 ] = value.b;
|
|
|
|
offset += 3;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
for ( ca = 0; ca < cal; ca ++ ) {
|
|
|
|
value = customAttribute.value[ ca ];
|
|
|
|
customAttribute.array[ offset ] = value.x;
|
|
customAttribute.array[ offset + 1 ] = value.y;
|
|
customAttribute.array[ offset + 2 ] = value.z;
|
|
|
|
offset += 3;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if ( customAttribute.size === 4 ) {
|
|
|
|
for ( ca = 0; ca < cal; ca ++ ) {
|
|
|
|
value = customAttribute.value[ ca ];
|
|
|
|
customAttribute.array[ offset ] = value.x;
|
|
customAttribute.array[ offset + 1 ] = value.y;
|
|
customAttribute.array[ offset + 2 ] = value.z;
|
|
customAttribute.array[ offset + 3 ] = value.w;
|
|
|
|
offset += 4;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_gl.bindBuffer( _gl.ARRAY_BUFFER, customAttribute.buffer );
|
|
_gl.bufferData( _gl.ARRAY_BUFFER, customAttribute.array, hint );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
function setRibbonBuffers ( geometry, hint ) {
|
|
|
|
var v, c, vertex, offset, color,
|
|
|
|
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 setMeshBuffers( geometryGroup, object, hint, dispose, material ) {
|
|
|
|
if ( ! geometryGroup.__inittedArrays ) {
|
|
|
|
// console.log( object );
|
|
return;
|
|
|
|
}
|
|
|
|
var normalType = bufferGuessNormalType( material ),
|
|
vertexColorType = bufferGuessVertexColorType( material ),
|
|
uvType = bufferGuessUVType( material ),
|
|
|
|
needsSmoothNormals = ( normalType === THREE.SmoothShading );
|
|
|
|
var f, fl, fi, face,
|
|
vertexNormals, faceNormal, normal,
|
|
vertexColors, faceColor,
|
|
vertexTangents,
|
|
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, il,
|
|
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,
|
|
|
|
value,
|
|
|
|
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.__webglCustomAttributesList,
|
|
customAttribute,
|
|
|
|
faceArray = geometryGroup.__faceArray,
|
|
lineArray = geometryGroup.__lineArray,
|
|
|
|
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_faces3 = geometryGroup.faces3,
|
|
chunk_faces4 = geometryGroup.faces4,
|
|
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,
|
|
|
|
morphTargets = geometry.morphTargets;
|
|
|
|
if ( dirtyVertices ) {
|
|
|
|
for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
|
|
|
|
face = obj_faces[ chunk_faces3[ f ] ];
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) {
|
|
|
|
face = obj_faces[ chunk_faces4[ f ] ];
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglVertexBuffer );
|
|
_gl.bufferData( _gl.ARRAY_BUFFER, vertexArray, hint );
|
|
|
|
}
|
|
|
|
if ( dirtyMorphTargets ) {
|
|
|
|
for ( vk = 0, vkl = morphTargets.length; vk < vkl; vk ++ ) {
|
|
|
|
offset_morphTarget = 0;
|
|
|
|
for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
|
|
|
|
face = obj_faces[ chunk_faces3[ f ] ];
|
|
|
|
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 ] = 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;
|
|
|
|
}
|
|
|
|
for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) {
|
|
|
|
face = obj_faces[ chunk_faces4[ f ] ];
|
|
|
|
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 ] = 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;
|
|
|
|
}
|
|
|
|
_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphTargetsBuffers[ vk ] );
|
|
_gl.bufferData( _gl.ARRAY_BUFFER, morphTargetsArrays[ vk ], hint );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ( obj_skinWeights.length ) {
|
|
|
|
for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
|
|
|
|
face = obj_faces[ chunk_faces3[ f ] ];
|
|
|
|
// weights
|
|
|
|
sw1 = obj_skinWeights[ face.a ];
|
|
sw2 = obj_skinWeights[ face.b ];
|
|
sw3 = obj_skinWeights[ face.c ];
|
|
|
|
skinWeightArray[ offset_skin ] = sw1.x;
|
|
skinWeightArray[ offset_skin + 1 ] = sw1.y;
|
|
skinWeightArray[ offset_skin + 2 ] = sw1.z;
|
|
skinWeightArray[ offset_skin + 3 ] = sw1.w;
|
|
|
|
skinWeightArray[ offset_skin + 4 ] = sw2.x;
|
|
skinWeightArray[ offset_skin + 5 ] = sw2.y;
|
|
skinWeightArray[ offset_skin + 6 ] = sw2.z;
|
|
skinWeightArray[ offset_skin + 7 ] = sw2.w;
|
|
|
|
skinWeightArray[ offset_skin + 8 ] = sw3.x;
|
|
skinWeightArray[ offset_skin + 9 ] = sw3.y;
|
|
skinWeightArray[ offset_skin + 10 ] = sw3.z;
|
|
skinWeightArray[ offset_skin + 11 ] = sw3.w;
|
|
|
|
// indices
|
|
|
|
si1 = obj_skinIndices[ face.a ];
|
|
si2 = obj_skinIndices[ face.b ];
|
|
si3 = obj_skinIndices[ face.c ];
|
|
|
|
skinIndexArray[ offset_skin ] = si1.x;
|
|
skinIndexArray[ offset_skin + 1 ] = si1.y;
|
|
skinIndexArray[ offset_skin + 2 ] = si1.z;
|
|
skinIndexArray[ offset_skin + 3 ] = si1.w;
|
|
|
|
skinIndexArray[ offset_skin + 4 ] = si2.x;
|
|
skinIndexArray[ offset_skin + 5 ] = si2.y;
|
|
skinIndexArray[ offset_skin + 6 ] = si2.z;
|
|
skinIndexArray[ offset_skin + 7 ] = si2.w;
|
|
|
|
skinIndexArray[ offset_skin + 8 ] = si3.x;
|
|
skinIndexArray[ offset_skin + 9 ] = si3.y;
|
|
skinIndexArray[ offset_skin + 10 ] = si3.z;
|
|
skinIndexArray[ offset_skin + 11 ] = si3.w;
|
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) {
|
|
|
|
face = obj_faces[ chunk_faces4[ f ] ];
|
|
|
|
// 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 ( 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 ( dirtyColors && vertexColorType ) {
|
|
|
|
for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
|
|
|
|
face = obj_faces[ chunk_faces3[ f ] ];
|
|
|
|
vertexColors = face.vertexColors;
|
|
faceColor = face.color;
|
|
|
|
if ( vertexColors.length === 3 && 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;
|
|
|
|
}
|
|
|
|
for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) {
|
|
|
|
face = obj_faces[ chunk_faces4[ f ] ];
|
|
|
|
vertexColors = face.vertexColors;
|
|
faceColor = face.color;
|
|
|
|
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 ( offset_color > 0 ) {
|
|
|
|
_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglColorBuffer );
|
|
_gl.bufferData( _gl.ARRAY_BUFFER, colorArray, hint );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ( dirtyTangents && geometry.hasTangents ) {
|
|
|
|
for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
|
|
|
|
face = obj_faces[ chunk_faces3[ f ] ];
|
|
|
|
vertexTangents = face.vertexTangents;
|
|
|
|
t1 = vertexTangents[ 0 ];
|
|
t2 = vertexTangents[ 1 ];
|
|
t3 = vertexTangents[ 2 ];
|
|
|
|
tangentArray[ offset_tangent ] = t1.x;
|
|
tangentArray[ offset_tangent + 1 ] = t1.y;
|
|
tangentArray[ offset_tangent + 2 ] = t1.z;
|
|
tangentArray[ offset_tangent + 3 ] = t1.w;
|
|
|
|
tangentArray[ offset_tangent + 4 ] = t2.x;
|
|
tangentArray[ offset_tangent + 5 ] = t2.y;
|
|
tangentArray[ offset_tangent + 6 ] = t2.z;
|
|
tangentArray[ offset_tangent + 7 ] = t2.w;
|
|
|
|
tangentArray[ offset_tangent + 8 ] = t3.x;
|
|
tangentArray[ offset_tangent + 9 ] = t3.y;
|
|
tangentArray[ offset_tangent + 10 ] = t3.z;
|
|
tangentArray[ offset_tangent + 11 ] = t3.w;
|
|
|
|
offset_tangent += 12;
|
|
|
|
}
|
|
|
|
for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) {
|
|
|
|
face = obj_faces[ chunk_faces4[ f ] ];
|
|
|
|
vertexTangents = face.vertexTangents;
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglTangentBuffer );
|
|
_gl.bufferData( _gl.ARRAY_BUFFER, tangentArray, hint );
|
|
|
|
}
|
|
|
|
if ( dirtyNormals && normalType ) {
|
|
|
|
for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
|
|
|
|
face = obj_faces[ chunk_faces3[ f ] ];
|
|
|
|
vertexNormals = face.vertexNormals;
|
|
faceNormal = face.normal;
|
|
|
|
if ( vertexNormals.length === 3 && needsSmoothNormals ) {
|
|
|
|
for ( i = 0; i < 3; i ++ ) {
|
|
|
|
vn = vertexNormals[ i ];
|
|
|
|
normalArray[ offset_normal ] = vn.x;
|
|
normalArray[ offset_normal + 1 ] = vn.y;
|
|
normalArray[ offset_normal + 2 ] = vn.z;
|
|
|
|
offset_normal += 3;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
for ( i = 0; i < 3; i ++ ) {
|
|
|
|
normalArray[ offset_normal ] = faceNormal.x;
|
|
normalArray[ offset_normal + 1 ] = faceNormal.y;
|
|
normalArray[ offset_normal + 2 ] = faceNormal.z;
|
|
|
|
offset_normal += 3;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) {
|
|
|
|
face = obj_faces[ chunk_faces4[ f ] ];
|
|
|
|
vertexNormals = face.vertexNormals;
|
|
faceNormal = face.normal;
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglNormalBuffer );
|
|
_gl.bufferData( _gl.ARRAY_BUFFER, normalArray, hint );
|
|
|
|
}
|
|
|
|
if ( dirtyUvs && obj_uvs && uvType ) {
|
|
|
|
for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
|
|
|
|
fi = chunk_faces3[ f ];
|
|
|
|
face = obj_faces[ fi ];
|
|
uv = obj_uvs[ fi ];
|
|
|
|
if ( uv === undefined ) continue;
|
|
|
|
for ( i = 0; i < 3; i ++ ) {
|
|
|
|
uvi = uv[ i ];
|
|
|
|
uvArray[ offset_uv ] = uvi.u;
|
|
uvArray[ offset_uv + 1 ] = uvi.v;
|
|
|
|
offset_uv += 2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) {
|
|
|
|
fi = chunk_faces4[ f ];
|
|
|
|
face = obj_faces[ fi ];
|
|
uv = obj_uvs[ fi ];
|
|
|
|
if ( uv === undefined ) continue;
|
|
|
|
for ( i = 0; i < 4; i ++ ) {
|
|
|
|
uvi = uv[ i ];
|
|
|
|
uvArray[ offset_uv ] = uvi.u;
|
|
uvArray[ offset_uv + 1 ] = uvi.v;
|
|
|
|
offset_uv += 2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ( offset_uv > 0 ) {
|
|
|
|
_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglUVBuffer );
|
|
_gl.bufferData( _gl.ARRAY_BUFFER, uvArray, hint );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ( dirtyUvs && obj_uvs2 && uvType ) {
|
|
|
|
for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
|
|
|
|
fi = chunk_faces3[ f ];
|
|
|
|
face = obj_faces[ fi ];
|
|
uv2 = obj_uvs2[ fi ];
|
|
|
|
if ( uv2 === undefined ) continue;
|
|
|
|
for ( i = 0; i < 3; i ++ ) {
|
|
|
|
uv2i = uv2[ i ];
|
|
|
|
uv2Array[ offset_uv2 ] = uv2i.u;
|
|
uv2Array[ offset_uv2 + 1 ] = uv2i.v;
|
|
|
|
offset_uv2 += 2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) {
|
|
|
|
fi = chunk_faces4[ f ];
|
|
|
|
face = obj_faces[ fi ];
|
|
uv2 = obj_uvs2[ fi ];
|
|
|
|
if ( uv2 === undefined ) continue;
|
|
|
|
for ( i = 0; i < 4; i ++ ) {
|
|
|
|
uv2i = uv2[ i ];
|
|
|
|
uv2Array[ offset_uv2 ] = uv2i.u;
|
|
uv2Array[ offset_uv2 + 1 ] = uv2i.v;
|
|
|
|
offset_uv2 += 2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ( offset_uv2 > 0 ) {
|
|
|
|
_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglUV2Buffer );
|
|
_gl.bufferData( _gl.ARRAY_BUFFER, uv2Array, hint );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ( dirtyElements ) {
|
|
|
|
for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
|
|
|
|
face = obj_faces[ chunk_faces3[ f ] ];
|
|
|
|
faceArray[ offset_face ] = vertexIndex;
|
|
faceArray[ offset_face + 1 ] = vertexIndex + 1;
|
|
faceArray[ offset_face + 2 ] = vertexIndex + 2;
|
|
|
|
offset_face += 3;
|
|
|
|
lineArray[ offset_line ] = vertexIndex;
|
|
lineArray[ offset_line + 1 ] = vertexIndex + 1;
|
|
|
|
lineArray[ offset_line + 2 ] = vertexIndex;
|
|
lineArray[ offset_line + 3 ] = vertexIndex + 2;
|
|
|
|
lineArray[ offset_line + 4 ] = vertexIndex + 1;
|
|
lineArray[ offset_line + 5 ] = vertexIndex + 2;
|
|
|
|
offset_line += 6;
|
|
|
|
vertexIndex += 3;
|
|
|
|
}
|
|
|
|
for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) {
|
|
|
|
face = obj_faces[ chunk_faces4[ f ] ];
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
_gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, geometryGroup.__webglFaceBuffer );
|
|
_gl.bufferData( _gl.ELEMENT_ARRAY_BUFFER, faceArray, hint );
|
|
|
|
_gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, geometryGroup.__webglLineBuffer );
|
|
_gl.bufferData( _gl.ELEMENT_ARRAY_BUFFER, lineArray, hint );
|
|
|
|
}
|
|
|
|
if ( customAttributes ) {
|
|
|
|
for ( i = 0, il = customAttributes.length; i < il; i ++ ) {
|
|
|
|
customAttribute = customAttributes[ i ];
|
|
|
|
if ( ! customAttribute.__original.needsUpdate ) continue;
|
|
|
|
offset_custom = 0;
|
|
offset_customSrc = 0;
|
|
|
|
if ( customAttribute.size === 1 ) {
|
|
|
|
if ( customAttribute.boundTo === undefined || customAttribute.boundTo === "vertices" ) {
|
|
|
|
for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
|
|
|
|
face = obj_faces[ chunk_faces3[ f ] ];
|
|
|
|
customAttribute.array[ offset_custom ] = customAttribute.value[ face.a ];
|
|
customAttribute.array[ offset_custom + 1 ] = customAttribute.value[ face.b ];
|
|
customAttribute.array[ offset_custom + 2 ] = customAttribute.value[ face.c ];
|
|
|
|
offset_custom += 3;
|
|
|
|
}
|
|
|
|
for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) {
|
|
|
|
face = obj_faces[ chunk_faces4[ f ] ];
|
|
|
|
customAttribute.array[ offset_custom ] = customAttribute.value[ face.a ];
|
|
customAttribute.array[ offset_custom + 1 ] = customAttribute.value[ face.b ];
|
|
customAttribute.array[ offset_custom + 2 ] = customAttribute.value[ face.c ];
|
|
customAttribute.array[ offset_custom + 3 ] = customAttribute.value[ face.d ];
|
|
|
|
offset_custom += 4;
|
|
|
|
}
|
|
|
|
} else if ( customAttribute.boundTo === "faces" ) {
|
|
|
|
for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
|
|
|
|
value = customAttribute.value[ chunk_faces3[ f ] ];
|
|
|
|
customAttribute.array[ offset_custom ] = value;
|
|
customAttribute.array[ offset_custom + 1 ] = value;
|
|
customAttribute.array[ offset_custom + 2 ] = value;
|
|
|
|
offset_custom += 3;
|
|
|
|
}
|
|
|
|
for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) {
|
|
|
|
value = customAttribute.value[ chunk_faces4[ f ] ];
|
|
|
|
customAttribute.array[ offset_custom ] = value;
|
|
customAttribute.array[ offset_custom + 1 ] = value;
|
|
customAttribute.array[ offset_custom + 2 ] = value;
|
|
customAttribute.array[ offset_custom + 3 ] = value;
|
|
|
|
offset_custom += 4;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if ( customAttribute.size === 2 ) {
|
|
|
|
if ( customAttribute.boundTo === undefined || customAttribute.boundTo === "vertices" ) {
|
|
|
|
for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
|
|
|
|
face = obj_faces[ chunk_faces3[ f ] ];
|
|
|
|
v1 = customAttribute.value[ face.a ];
|
|
v2 = customAttribute.value[ face.b ];
|
|
v3 = customAttribute.value[ face.c ];
|
|
|
|
customAttribute.array[ offset_custom ] = v1.x;
|
|
customAttribute.array[ offset_custom + 1 ] = v1.y;
|
|
|
|
customAttribute.array[ offset_custom + 2 ] = v2.x;
|
|
customAttribute.array[ offset_custom + 3 ] = v2.y;
|
|
|
|
customAttribute.array[ offset_custom + 4 ] = v3.x;
|
|
customAttribute.array[ offset_custom + 5 ] = v3.y;
|
|
|
|
offset_custom += 6;
|
|
|
|
}
|
|
|
|
for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) {
|
|
|
|
face = obj_faces[ chunk_faces4[ f ] ];
|
|
|
|
v1 = customAttribute.value[ face.a ];
|
|
v2 = customAttribute.value[ face.b ];
|
|
v3 = customAttribute.value[ face.c ];
|
|
v4 = customAttribute.value[ face.d ];
|
|
|
|
customAttribute.array[ offset_custom ] = v1.x;
|
|
customAttribute.array[ offset_custom + 1 ] = v1.y;
|
|
|
|
customAttribute.array[ offset_custom + 2 ] = v2.x;
|
|
customAttribute.array[ offset_custom + 3 ] = v2.y;
|
|
|
|
customAttribute.array[ offset_custom + 4 ] = v3.x;
|
|
customAttribute.array[ offset_custom + 5 ] = v3.y;
|
|
|
|
customAttribute.array[ offset_custom + 6 ] = v4.x;
|
|
customAttribute.array[ offset_custom + 7 ] = v4.y;
|
|
|
|
offset_custom += 8;
|
|
|
|
}
|
|
|
|
} else if ( customAttribute.boundTo === "faces" ) {
|
|
|
|
for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
|
|
|
|
value = customAttribute.value[ chunk_faces3[ f ] ];
|
|
|
|
v1 = value;
|
|
v2 = value;
|
|
v3 = value;
|
|
|
|
customAttribute.array[ offset_custom ] = v1.x;
|
|
customAttribute.array[ offset_custom + 1 ] = v1.y;
|
|
|
|
customAttribute.array[ offset_custom + 2 ] = v2.x;
|
|
customAttribute.array[ offset_custom + 3 ] = v2.y;
|
|
|
|
customAttribute.array[ offset_custom + 4 ] = v3.x;
|
|
customAttribute.array[ offset_custom + 5 ] = v3.y;
|
|
|
|
offset_custom += 6;
|
|
|
|
}
|
|
|
|
for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) {
|
|
|
|
value = customAttribute.value[ chunk_faces4[ f ] ];
|
|
|
|
v1 = value;
|
|
v2 = value;
|
|
v3 = value;
|
|
v4 = value;
|
|
|
|
customAttribute.array[ offset_custom ] = v1.x;
|
|
customAttribute.array[ offset_custom + 1 ] = v1.y;
|
|
|
|
customAttribute.array[ offset_custom + 2 ] = v2.x;
|
|
customAttribute.array[ offset_custom + 3 ] = v2.y;
|
|
|
|
customAttribute.array[ offset_custom + 4 ] = v3.x;
|
|
customAttribute.array[ offset_custom + 5 ] = v3.y;
|
|
|
|
customAttribute.array[ offset_custom + 6 ] = v4.x;
|
|
customAttribute.array[ offset_custom + 7 ] = v4.y;
|
|
|
|
offset_custom += 8;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if ( customAttribute.size === 3 ) {
|
|
|
|
var pp;
|
|
|
|
if ( customAttribute.type === "c" ) {
|
|
|
|
pp = [ "r", "g", "b" ];
|
|
|
|
} else {
|
|
|
|
pp = [ "x", "y", "z" ];
|
|
|
|
}
|
|
|
|
if ( customAttribute.boundTo === undefined || customAttribute.boundTo === "vertices" ) {
|
|
|
|
for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
|
|
|
|
face = obj_faces[ chunk_faces3[ f ] ];
|
|
|
|
v1 = customAttribute.value[ face.a ];
|
|
v2 = customAttribute.value[ face.b ];
|
|
v3 = customAttribute.value[ face.c ];
|
|
|
|
customAttribute.array[ offset_custom ] = v1[ pp[ 0 ] ];
|
|
customAttribute.array[ offset_custom + 1 ] = v1[ pp[ 1 ] ];
|
|
customAttribute.array[ offset_custom + 2 ] = v1[ pp[ 2 ] ];
|
|
|
|
customAttribute.array[ offset_custom + 3 ] = v2[ pp[ 0 ] ];
|
|
customAttribute.array[ offset_custom + 4 ] = v2[ pp[ 1 ] ];
|
|
customAttribute.array[ offset_custom + 5 ] = v2[ pp[ 2 ] ];
|
|
|
|
customAttribute.array[ offset_custom + 6 ] = v3[ pp[ 0 ] ];
|
|
customAttribute.array[ offset_custom + 7 ] = v3[ pp[ 1 ] ];
|
|
customAttribute.array[ offset_custom + 8 ] = v3[ pp[ 2 ] ];
|
|
|
|
offset_custom += 9;
|
|
|
|
}
|
|
|
|
for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) {
|
|
|
|
face = obj_faces[ chunk_faces4[ f ] ];
|
|
|
|
v1 = customAttribute.value[ face.a ];
|
|
v2 = customAttribute.value[ face.b ];
|
|
v3 = customAttribute.value[ face.c ];
|
|
v4 = customAttribute.value[ face.d ];
|
|
|
|
customAttribute.array[ offset_custom ] = v1[ pp[ 0 ] ];
|
|
customAttribute.array[ offset_custom + 1 ] = v1[ pp[ 1 ] ];
|
|
customAttribute.array[ offset_custom + 2 ] = v1[ pp[ 2 ] ];
|
|
|
|
customAttribute.array[ offset_custom + 3 ] = v2[ pp[ 0 ] ];
|
|
customAttribute.array[ offset_custom + 4 ] = v2[ pp[ 1 ] ];
|
|
customAttribute.array[ offset_custom + 5 ] = v2[ pp[ 2 ] ];
|
|
|
|
customAttribute.array[ offset_custom + 6 ] = v3[ pp[ 0 ] ];
|
|
customAttribute.array[ offset_custom + 7 ] = v3[ pp[ 1 ] ];
|
|
customAttribute.array[ offset_custom + 8 ] = v3[ pp[ 2 ] ];
|
|
|
|
customAttribute.array[ offset_custom + 9 ] = v4[ pp[ 0 ] ];
|
|
customAttribute.array[ offset_custom + 10 ] = v4[ pp[ 1 ] ];
|
|
customAttribute.array[ offset_custom + 11 ] = v4[ pp[ 2 ] ];
|
|
|
|
offset_custom += 12;
|
|
|
|
}
|
|
|
|
} else if ( customAttribute.boundTo === "faces" ) {
|
|
|
|
for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
|
|
|
|
value = customAttribute.value[ chunk_faces3[ f ] ];
|
|
|
|
v1 = value;
|
|
v2 = value;
|
|
v3 = value;
|
|
|
|
customAttribute.array[ offset_custom ] = v1[ pp[ 0 ] ];
|
|
customAttribute.array[ offset_custom + 1 ] = v1[ pp[ 1 ] ];
|
|
customAttribute.array[ offset_custom + 2 ] = v1[ pp[ 2 ] ];
|
|
|
|
customAttribute.array[ offset_custom + 3 ] = v2[ pp[ 0 ] ];
|
|
customAttribute.array[ offset_custom + 4 ] = v2[ pp[ 1 ] ];
|
|
customAttribute.array[ offset_custom + 5 ] = v2[ pp[ 2 ] ];
|
|
|
|
customAttribute.array[ offset_custom + 6 ] = v3[ pp[ 0 ] ];
|
|
customAttribute.array[ offset_custom + 7 ] = v3[ pp[ 1 ] ];
|
|
customAttribute.array[ offset_custom + 8 ] = v3[ pp[ 2 ] ];
|
|
|
|
offset_custom += 9;
|
|
|
|
}
|
|
|
|
for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) {
|
|
|
|
value = customAttribute.value[ chunk_faces4[ f ] ];
|
|
|
|
v1 = value;
|
|
v2 = value;
|
|
v3 = value;
|
|
v4 = value;
|
|
|
|
customAttribute.array[ offset_custom ] = v1[ pp[ 0 ] ];
|
|
customAttribute.array[ offset_custom + 1 ] = v1[ pp[ 1 ] ];
|
|
customAttribute.array[ offset_custom + 2 ] = v1[ pp[ 2 ] ];
|
|
|
|
customAttribute.array[ offset_custom + 3 ] = v2[ pp[ 0 ] ];
|
|
customAttribute.array[ offset_custom + 4 ] = v2[ pp[ 1 ] ];
|
|
customAttribute.array[ offset_custom + 5 ] = v2[ pp[ 2 ] ];
|
|
|
|
customAttribute.array[ offset_custom + 6 ] = v3[ pp[ 0 ] ];
|
|
customAttribute.array[ offset_custom + 7 ] = v3[ pp[ 1 ] ];
|
|
customAttribute.array[ offset_custom + 8 ] = v3[ pp[ 2 ] ];
|
|
|
|
customAttribute.array[ offset_custom + 9 ] = v4[ pp[ 0 ] ];
|
|
customAttribute.array[ offset_custom + 10 ] = v4[ pp[ 1 ] ];
|
|
customAttribute.array[ offset_custom + 11 ] = v4[ pp[ 2 ] ];
|
|
|
|
offset_custom += 12;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if ( customAttribute.size === 4 ) {
|
|
|
|
if ( customAttribute.boundTo === undefined || customAttribute.boundTo === "vertices" ) {
|
|
|
|
for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
|
|
|
|
face = obj_faces[ chunk_faces3[ f ] ];
|
|
|
|
v1 = customAttribute.value[ face.a ];
|
|
v2 = customAttribute.value[ face.b ];
|
|
v3 = customAttribute.value[ face.c ];
|
|
|
|
customAttribute.array[ offset_custom ] = v1.x;
|
|
customAttribute.array[ offset_custom + 1 ] = v1.y;
|
|
customAttribute.array[ offset_custom + 2 ] = v1.z;
|
|
customAttribute.array[ offset_custom + 3 ] = v1.w;
|
|
|
|
customAttribute.array[ offset_custom + 4 ] = v2.x;
|
|
customAttribute.array[ offset_custom + 5 ] = v2.y;
|
|
customAttribute.array[ offset_custom + 6 ] = v2.z;
|
|
customAttribute.array[ offset_custom + 7 ] = v2.w;
|
|
|
|
customAttribute.array[ offset_custom + 8 ] = v3.x;
|
|
customAttribute.array[ offset_custom + 9 ] = v3.y;
|
|
customAttribute.array[ offset_custom + 10 ] = v3.z;
|
|
customAttribute.array[ offset_custom + 11 ] = v3.w;
|
|
|
|
offset_custom += 12;
|
|
|
|
}
|
|
|
|
for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) {
|
|
|
|
face = obj_faces[ chunk_faces4[ f ] ];
|
|
|
|
v1 = customAttribute.value[ face.a ];
|
|
v2 = customAttribute.value[ face.b ];
|
|
v3 = customAttribute.value[ face.c ];
|
|
v4 = customAttribute.value[ face.d ];
|
|
|
|
customAttribute.array[ offset_custom ] = v1.x;
|
|
customAttribute.array[ offset_custom + 1 ] = v1.y;
|
|
customAttribute.array[ offset_custom + 2 ] = v1.z;
|
|
customAttribute.array[ offset_custom + 3 ] = v1.w;
|
|
|
|
customAttribute.array[ offset_custom + 4 ] = v2.x;
|
|
customAttribute.array[ offset_custom + 5 ] = v2.y;
|
|
customAttribute.array[ offset_custom + 6 ] = v2.z;
|
|
customAttribute.array[ offset_custom + 7 ] = v2.w;
|
|
|
|
customAttribute.array[ offset_custom + 8 ] = v3.x;
|
|
customAttribute.array[ offset_custom + 9 ] = v3.y;
|
|
customAttribute.array[ offset_custom + 10 ] = v3.z;
|
|
customAttribute.array[ offset_custom + 11 ] = v3.w;
|
|
|
|
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;
|
|
|
|
offset_custom += 16;
|
|
|
|
}
|
|
|
|
} else if ( customAttribute.boundTo === "faces" ) {
|
|
|
|
for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
|
|
|
|
value = customAttribute.value[ chunk_faces3[ f ] ];
|
|
|
|
v1 = value;
|
|
v2 = value;
|
|
v3 = value;
|
|
|
|
customAttribute.array[ offset_custom ] = v1.x;
|
|
customAttribute.array[ offset_custom + 1 ] = v1.y;
|
|
customAttribute.array[ offset_custom + 2 ] = v1.z;
|
|
customAttribute.array[ offset_custom + 3 ] = v1.w;
|
|
|
|
customAttribute.array[ offset_custom + 4 ] = v2.x;
|
|
customAttribute.array[ offset_custom + 5 ] = v2.y;
|
|
customAttribute.array[ offset_custom + 6 ] = v2.z;
|
|
customAttribute.array[ offset_custom + 7 ] = v2.w;
|
|
|
|
customAttribute.array[ offset_custom + 8 ] = v3.x;
|
|
customAttribute.array[ offset_custom + 9 ] = v3.y;
|
|
customAttribute.array[ offset_custom + 10 ] = v3.z;
|
|
customAttribute.array[ offset_custom + 11 ] = v3.w;
|
|
|
|
offset_custom += 12;
|
|
|
|
}
|
|
|
|
for ( f = 0, fl = chunk_faces4.length; f < fl; f ++ ) {
|
|
|
|
value = customAttribute.value[ chunk_faces4[ f ] ];
|
|
|
|
v1 = value;
|
|
v2 = value;
|
|
v3 = value;
|
|
v4 = value;
|
|
|
|
customAttribute.array[ offset_custom ] = v1.x;
|
|
customAttribute.array[ offset_custom + 1 ] = v1.y;
|
|
customAttribute.array[ offset_custom + 2 ] = v1.z;
|
|
customAttribute.array[ offset_custom + 3 ] = v1.w;
|
|
|
|
customAttribute.array[ offset_custom + 4 ] = v2.x;
|
|
customAttribute.array[ offset_custom + 5 ] = v2.y;
|
|
customAttribute.array[ offset_custom + 6 ] = v2.z;
|
|
customAttribute.array[ offset_custom + 7 ] = v2.w;
|
|
|
|
customAttribute.array[ offset_custom + 8 ] = v3.x;
|
|
customAttribute.array[ offset_custom + 9 ] = v3.y;
|
|
customAttribute.array[ offset_custom + 10 ] = v3.z;
|
|
customAttribute.array[ offset_custom + 11 ] = v3.w;
|
|
|
|
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;
|
|
|
|
offset_custom += 16;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_gl.bindBuffer( _gl.ARRAY_BUFFER, customAttribute.buffer );
|
|
_gl.bufferData( _gl.ARRAY_BUFFER, customAttribute.array, hint );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ( dispose ) {
|
|
|
|
delete geometryGroup.__inittedArrays;
|
|
delete geometryGroup.__colorArray;
|
|
delete geometryGroup.__normalArray;
|
|
delete geometryGroup.__tangentArray;
|
|
delete geometryGroup.__uvArray;
|
|
delete geometryGroup.__uv2Array;
|
|
delete geometryGroup.__faceArray;
|
|
delete geometryGroup.__vertexArray;
|
|
delete geometryGroup.__lineArray;
|
|
delete geometryGroup.__skinVertexAArray;
|
|
delete geometryGroup.__skinVertexBArray;
|
|
delete geometryGroup.__skinIndexArray;
|
|
delete geometryGroup.__skinWeightArray;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
// Buffer rendering
|
|
|
|
this.renderBufferImmediate = function ( 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;
|
|
|
|
};
|
|
|
|
this.renderBufferDirect = function ( camera, lights, fog, material, geometryGroup, object ) {
|
|
|
|
if ( material.opacity === 0 ) return;
|
|
|
|
var program, attributes, linewidth, primitives, a, attribute, i, il;
|
|
|
|
program = setProgram( camera, lights, fog, material, object );
|
|
|
|
attributes = program.attributes;
|
|
|
|
var updateBuffers = false,
|
|
wireframeBit = material.wireframe ? 1 : 0,
|
|
geometryGroupHash = ( geometryGroup.id * 0xffffff ) + ( program.id * 2 ) + wireframeBit;
|
|
|
|
if ( geometryGroupHash !== _currentGeometryGroupHash ) {
|
|
|
|
_currentGeometryGroupHash = geometryGroupHash;
|
|
updateBuffers = true;
|
|
|
|
}
|
|
|
|
// render mesh
|
|
|
|
if ( object instanceof THREE.Mesh ) {
|
|
|
|
var offsets = geometryGroup.offsets;
|
|
|
|
for ( var i = 0; i < offsets.length; ++ i ) {
|
|
|
|
if ( updateBuffers ) {
|
|
|
|
// vertices
|
|
|
|
_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.vertexPositionBuffer );
|
|
_gl.vertexAttribPointer( attributes.position, geometryGroup.vertexPositionBuffer.itemSize, _gl.FLOAT, false, 0, offsets[ i ].index * 4 * 3 );
|
|
|
|
// normals
|
|
|
|
if ( attributes.normal >= 0 && geometryGroup.vertexNormalBuffer ) {
|
|
|
|
_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.vertexNormalBuffer );
|
|
_gl.vertexAttribPointer( attributes.normal, geometryGroup.vertexNormalBuffer.itemSize, _gl.FLOAT, false, 0, offsets[ i ].index * 4 * 3 );
|
|
|
|
}
|
|
|
|
// uvs
|
|
|
|
if ( attributes.uv >= 0 && geometryGroup.vertexUvBuffer ) {
|
|
|
|
if ( geometryGroup.vertexUvBuffer ) {
|
|
|
|
_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.vertexUvBuffer );
|
|
_gl.vertexAttribPointer( attributes.uv, geometryGroup.vertexUvBuffer.itemSize, _gl.FLOAT, false, 0, offsets[ i ].index * 4 * 2 );
|
|
|
|
_gl.enableVertexAttribArray( attributes.uv );
|
|
|
|
} else {
|
|
|
|
_gl.disableVertexAttribArray( attributes.uv );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// colors
|
|
|
|
if ( attributes.color >= 0 && geometryGroup.vertexColorBuffer ) {
|
|
|
|
_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.vertexColorBuffer );
|
|
_gl.vertexAttribPointer( attributes.color, geometryGroup.vertexColorBuffer.itemSize, _gl.FLOAT, false, 0, offsets[ i ].index * 4 * 4 );
|
|
|
|
|
|
}
|
|
|
|
_gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, geometryGroup.vertexIndexBuffer );
|
|
|
|
}
|
|
|
|
// render indexed triangles
|
|
|
|
_gl.drawElements( _gl.TRIANGLES, offsets[ i ].count, _gl.UNSIGNED_SHORT, offsets[ i ].start * 2 ); // 2 = Uint16
|
|
|
|
_this.info.render.calls ++;
|
|
_this.info.render.vertices += offsets[ i ].count; // not really true, here vertices can be shared
|
|
_this.info.render.faces += offsets[ i ].count / 3;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
this.renderBuffer = function ( camera, lights, fog, material, geometryGroup, object ) {
|
|
|
|
if ( material.opacity === 0 ) return;
|
|
|
|
var program, attributes, linewidth, primitives, a, attribute, i, il;
|
|
|
|
program = setProgram( camera, lights, fog, material, object );
|
|
|
|
attributes = program.attributes;
|
|
|
|
var updateBuffers = false,
|
|
wireframeBit = material.wireframe ? 1 : 0,
|
|
geometryGroupHash = ( geometryGroup.id * 0xffffff ) + ( program.id * 2 ) + wireframeBit;
|
|
|
|
if ( geometryGroupHash !== _currentGeometryGroupHash ) {
|
|
|
|
_currentGeometryGroupHash = geometryGroupHash;
|
|
updateBuffers = true;
|
|
|
|
}
|
|
|
|
// vertices
|
|
|
|
if ( !material.morphTargets && attributes.position >= 0 ) {
|
|
|
|
if ( updateBuffers ) {
|
|
|
|
_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 );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
if ( updateBuffers ) {
|
|
|
|
// custom attributes
|
|
|
|
// Use the per-geometryGroup custom attribute arrays which are setup in initMeshBuffers
|
|
|
|
if ( geometryGroup.__webglCustomAttributesList ) {
|
|
|
|
for ( i = 0, il = geometryGroup.__webglCustomAttributesList.length; i < il; i ++ ) {
|
|
|
|
attribute = geometryGroup.__webglCustomAttributesList[ i ];
|
|
|
|
if( attributes[ attribute.buffer.belongsToAttribute ] >= 0 ) {
|
|
|
|
_gl.bindBuffer( _gl.ARRAY_BUFFER, attribute.buffer );
|
|
_gl.vertexAttribPointer( attributes[ attribute.buffer.belongsToAttribute ], 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 ) {
|
|
|
|
setLineWidth( material.wireframeLinewidth );
|
|
|
|
if ( updateBuffers ) _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, geometryGroup.__webglLineBuffer );
|
|
_gl.drawElements( _gl.LINES, geometryGroup.__webglLineCount, _gl.UNSIGNED_SHORT, 0 );
|
|
|
|
// triangles
|
|
|
|
} else {
|
|
|
|
if ( updateBuffers ) _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, geometryGroup.__webglFaceBuffer );
|
|
_gl.drawElements( _gl.TRIANGLES, geometryGroup.__webglFaceCount, _gl.UNSIGNED_SHORT, 0 );
|
|
|
|
}
|
|
|
|
_this.info.render.calls ++;
|
|
_this.info.render.vertices += geometryGroup.__webglFaceCount;
|
|
_this.info.render.faces += geometryGroup.__webglFaceCount / 3;
|
|
|
|
// render lines
|
|
|
|
} else if ( object instanceof THREE.Line ) {
|
|
|
|
primitives = ( object.type === THREE.LineStrip ) ? _gl.LINE_STRIP : _gl.LINES;
|
|
|
|
setLineWidth( material.linewidth );
|
|
|
|
_gl.drawArrays( primitives, 0, geometryGroup.__webglLineCount );
|
|
|
|
_this.info.render.calls ++;
|
|
|
|
// render particles
|
|
|
|
} else if ( object instanceof THREE.ParticleSystem ) {
|
|
|
|
_gl.drawArrays( _gl.POINTS, 0, geometryGroup.__webglParticleCount );
|
|
|
|
_this.info.render.calls ++;
|
|
_this.info.render.points += geometryGroup.__webglParticleCount;
|
|
|
|
// render ribbon
|
|
|
|
} else if ( object instanceof THREE.Ribbon ) {
|
|
|
|
_gl.drawArrays( _gl.TRIANGLE_STRIP, 0, geometryGroup.__webglVertexCount );
|
|
|
|
_this.info.render.calls ++;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
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 painterSort ( a, b ) {
|
|
|
|
return b.z - a.z;
|
|
|
|
};
|
|
|
|
// Rendering
|
|
|
|
this.render = function ( scene, camera, renderTarget, forceClear ) {
|
|
|
|
var i, il,
|
|
|
|
program, material,
|
|
webglObject, object,
|
|
renderList,
|
|
|
|
lights = scene.lights,
|
|
fog = scene.fog;
|
|
|
|
_currentMaterialId = -1;
|
|
|
|
if ( this.autoUpdateObjects ) this.initWebGLObjects( scene );
|
|
|
|
if ( camera.parent === undefined ) {
|
|
|
|
console.warn( 'DEPRECATED: Camera hasn\'t been added to a Scene. Adding it...' );
|
|
scene.add( camera );
|
|
|
|
}
|
|
|
|
if ( this.autoUpdateScene ) scene.updateMatrixWorld();
|
|
|
|
// custom render plugins (pre pass)
|
|
|
|
renderPlugins( this.renderPluginsPre, scene, camera );
|
|
|
|
_this.info.render.calls = 0;
|
|
_this.info.render.vertices = 0;
|
|
_this.info.render.faces = 0;
|
|
_this.info.render.points = 0;
|
|
|
|
camera.matrixWorldInverse.getInverse( camera.matrixWorld );
|
|
|
|
if ( ! camera._viewMatrixArray ) camera._viewMatrixArray = new Float32Array( 16 );
|
|
camera.matrixWorldInverse.flattenToArray( camera._viewMatrixArray );
|
|
|
|
if ( ! camera._projectionMatrixArray ) camera._projectionMatrixArray = new Float32Array( 16 );
|
|
camera.projectionMatrix.flattenToArray( camera._projectionMatrixArray );
|
|
|
|
_projScreenMatrix.multiply( camera.projectionMatrix, camera.matrixWorldInverse );
|
|
_frustum.setFromMatrix( _projScreenMatrix );
|
|
|
|
this.setRenderTarget( renderTarget );
|
|
|
|
if ( this.autoClear || forceClear ) {
|
|
|
|
this.clear( this.autoClearColor, this.autoClearDepth, this.autoClearStencil );
|
|
|
|
}
|
|
|
|
// set matrices for regular objects (frustum culled)
|
|
|
|
renderList = scene.__webglObjects;
|
|
|
|
for ( i = 0, il = renderList.length; i < il; i ++ ) {
|
|
|
|
webglObject = renderList[ i ];
|
|
object = webglObject.object;
|
|
|
|
webglObject.render = false;
|
|
|
|
if ( object.visible ) {
|
|
|
|
if ( ! ( object instanceof THREE.Mesh || object instanceof THREE.ParticleSystem ) || ! ( object.frustumCulled ) || _frustum.contains( object ) ) {
|
|
|
|
object.matrixWorld.flattenToArray( object._objectMatrixArray );
|
|
|
|
setupMatrices( object, camera );
|
|
|
|
unrollBufferMaterial( webglObject );
|
|
|
|
webglObject.render = true;
|
|
|
|
if ( this.sortObjects ) {
|
|
|
|
if ( object.renderDepth ) {
|
|
|
|
webglObject.z = object.renderDepth;
|
|
|
|
} else {
|
|
|
|
_vector3.copy( object.position );
|
|
_projScreenMatrix.multiplyVector3( _vector3 );
|
|
|
|
webglObject.z = _vector3.z;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ( this.sortObjects ) {
|
|
|
|
renderList.sort( painterSort );
|
|
|
|
}
|
|
|
|
// set matrices for immediate objects
|
|
|
|
renderList = scene.__webglObjectsImmediate;
|
|
|
|
for ( i = 0, il = renderList.length; i < il; i ++ ) {
|
|
|
|
webglObject = renderList[ i ];
|
|
object = webglObject.object;
|
|
|
|
if ( object.visible ) {
|
|
|
|
if( object.matrixAutoUpdate ) {
|
|
|
|
object.matrixWorld.flattenToArray( object._objectMatrixArray );
|
|
|
|
}
|
|
|
|
setupMatrices( object, camera );
|
|
|
|
unrollImmediateBufferMaterial( webglObject );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ( scene.overrideMaterial ) {
|
|
|
|
this.setBlending( scene.overrideMaterial.blending );
|
|
this.setDepthTest( scene.overrideMaterial.depthTest );
|
|
setDepthWrite( scene.overrideMaterial.depthWrite );
|
|
setPolygonOffset( scene.overrideMaterial.polygonOffset, scene.overrideMaterial.polygonOffsetFactor, scene.overrideMaterial.polygonOffsetUnits );
|
|
|
|
renderObjects( scene.__webglObjects, false, "", camera, lights, fog, true, scene.overrideMaterial );
|
|
renderObjectsImmediate( scene.__webglObjectsImmediate, "", camera, lights, fog, false, scene.overrideMaterial );
|
|
|
|
} else {
|
|
|
|
// opaque pass (front-to-back order)
|
|
|
|
this.setBlending( THREE.NormalBlending );
|
|
|
|
renderObjects( scene.__webglObjects, true, "opaque", camera, lights, fog, false );
|
|
renderObjectsImmediate( scene.__webglObjectsImmediate, "opaque", camera, lights, fog, false );
|
|
|
|
// transparent pass (back-to-front order)
|
|
|
|
renderObjects( scene.__webglObjects, false, "transparent", camera, lights, fog, true );
|
|
renderObjectsImmediate( scene.__webglObjectsImmediate, "transparent", camera, lights, fog, true );
|
|
|
|
}
|
|
|
|
// custom render plugins (post pass)
|
|
|
|
renderPlugins( this.renderPluginsPost, 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();
|
|
|
|
};
|
|
|
|
function renderPlugins( plugins, scene, camera ) {
|
|
|
|
if ( ! plugins.length ) return;
|
|
|
|
for ( var i = 0, il = plugins.length; i < il; i ++ ) {
|
|
|
|
_currentProgram = null;
|
|
_oldBlending = -1;
|
|
_oldDepthTest = -1;
|
|
_oldDepthWrite = -1;
|
|
_currentGeometryGroupHash = -1;
|
|
_currentMaterialId = -1;
|
|
|
|
plugins[ i ].render( scene, camera, _currentWidth, _currentHeight );
|
|
|
|
_currentProgram = null;
|
|
_oldBlending = -1;
|
|
_oldDepthTest = -1;
|
|
_oldDepthWrite = -1;
|
|
_currentGeometryGroupHash = -1;
|
|
_currentMaterialId = -1;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
function renderObjects ( renderList, reverse, materialType, camera, lights, fog, useBlending, overrideMaterial ) {
|
|
|
|
var webglObject, object, buffer, material, start, end, delta;
|
|
|
|
if ( reverse ) {
|
|
|
|
start = renderList.length - 1;
|
|
end = -1;
|
|
delta = -1;
|
|
|
|
} else {
|
|
|
|
start = 0;
|
|
end = renderList.length;
|
|
delta = 1;
|
|
}
|
|
|
|
for ( var i = start; i !== end; i += delta ) {
|
|
|
|
webglObject = renderList[ i ];
|
|
|
|
if ( webglObject.render ) {
|
|
|
|
object = webglObject.object;
|
|
buffer = webglObject.buffer;
|
|
|
|
if ( overrideMaterial ) {
|
|
|
|
material = overrideMaterial;
|
|
|
|
} else {
|
|
|
|
material = webglObject[ materialType ];
|
|
|
|
if ( ! material ) continue;
|
|
|
|
if ( useBlending ) _this.setBlending( material.blending );
|
|
|
|
_this.setDepthTest( material.depthTest );
|
|
setDepthWrite( material.depthWrite );
|
|
setPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits );
|
|
|
|
}
|
|
|
|
_this.setObjectFaces( object );
|
|
|
|
if ( buffer instanceof THREE.BufferGeometry ) {
|
|
|
|
_this.renderBufferDirect( camera, lights, fog, material, buffer, object );
|
|
|
|
} else {
|
|
|
|
_this.renderBuffer( camera, lights, fog, material, buffer, object );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
function renderObjectsImmediate ( renderList, materialType, camera, lights, fog, useBlending, overrideMaterial ) {
|
|
|
|
var webglObject, object, material, program;
|
|
|
|
for ( var i = 0, il = renderList.length; i < il; i ++ ) {
|
|
|
|
webglObject = renderList[ i ];
|
|
object = webglObject.object;
|
|
|
|
if ( object.visible ) {
|
|
|
|
if ( overrideMaterial ) {
|
|
|
|
material = overrideMaterial;
|
|
|
|
} else {
|
|
|
|
material = webglObject[ materialType ];
|
|
|
|
if ( ! material ) continue;
|
|
|
|
if ( useBlending ) _this.setBlending( material.blending );
|
|
|
|
_this.setDepthTest( material.depthTest );
|
|
setDepthWrite( material.depthWrite );
|
|
setPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits );
|
|
|
|
}
|
|
|
|
_this.renderImmediateObject( camera, lights, fog, material, object );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
this.renderImmediateObject = function ( camera, lights, fog, material, object ) {
|
|
|
|
var program = setProgram( camera, lights, fog, material, object );
|
|
|
|
_currentGeometryGroupHash = -1;
|
|
|
|
_this.setObjectFaces( object );
|
|
|
|
if ( object.immediateRenderCallback ) {
|
|
|
|
object.immediateRenderCallback( program, _gl, _frustum );
|
|
|
|
} else {
|
|
|
|
object.render( function( object ) { _this.renderBufferImmediate( object, program, material.shading ); } );
|
|
|
|
}
|
|
|
|
};
|
|
|
|
function unrollImmediateBufferMaterial ( globject ) {
|
|
|
|
var object = globject.object,
|
|
material = object.material;
|
|
|
|
if ( material.transparent ) {
|
|
|
|
globject.transparent = material;
|
|
globject.opaque = null;
|
|
|
|
} else {
|
|
|
|
globject.opaque = material;
|
|
globject.transparent = null;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
function unrollBufferMaterial ( globject ) {
|
|
|
|
var object = globject.object,
|
|
buffer = globject.buffer,
|
|
material, materialIndex, meshMaterial;
|
|
|
|
meshMaterial = object.material;
|
|
|
|
if ( meshMaterial instanceof THREE.MeshFaceMaterial ) {
|
|
|
|
materialIndex = buffer.materialIndex;
|
|
|
|
if ( materialIndex >= 0 ) {
|
|
|
|
material = object.geometry.materials[ materialIndex ];
|
|
|
|
if ( material.transparent ) {
|
|
|
|
globject.transparent = material;
|
|
globject.opaque = null;
|
|
|
|
} else {
|
|
|
|
globject.opaque = material;
|
|
globject.transparent = null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
material = meshMaterial;
|
|
|
|
if ( material ) {
|
|
|
|
if ( material.transparent ) {
|
|
|
|
globject.transparent = material;
|
|
globject.opaque = null;
|
|
|
|
} else {
|
|
|
|
globject.opaque = material;
|
|
globject.transparent = null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
// Geometry splitting
|
|
|
|
function sortFacesByMaterial ( geometry ) {
|
|
|
|
var f, fl, face, materialIndex, vertices,
|
|
materialHash, groupHash,
|
|
hash_map = {};
|
|
|
|
var numMorphTargets = geometry.morphTargets.length;
|
|
|
|
geometry.geometryGroups = {};
|
|
|
|
for ( f = 0, fl = geometry.faces.length; f < fl; f ++ ) {
|
|
|
|
face = geometry.faces[ f ];
|
|
materialIndex = face.materialIndex;
|
|
|
|
materialHash = ( materialIndex !== undefined ) ? materialIndex : -1;
|
|
|
|
if ( hash_map[ materialHash ] === undefined ) {
|
|
|
|
hash_map[ materialHash ] = { 'hash': materialHash, 'counter': 0 };
|
|
|
|
}
|
|
|
|
groupHash = hash_map[ materialHash ].hash + '_' + hash_map[ materialHash ].counter;
|
|
|
|
if ( geometry.geometryGroups[ groupHash ] === undefined ) {
|
|
|
|
geometry.geometryGroups[ groupHash ] = { 'faces3': [], 'faces4': [], 'materialIndex': materialIndex, 'vertices': 0, 'numMorphTargets': numMorphTargets };
|
|
|
|
}
|
|
|
|
vertices = face instanceof THREE.Face3 ? 3 : 4;
|
|
|
|
if ( geometry.geometryGroups[ groupHash ].vertices + vertices > 65535 ) {
|
|
|
|
hash_map[ materialHash ].counter += 1;
|
|
groupHash = hash_map[ materialHash ].hash + '_' + hash_map[ materialHash ].counter;
|
|
|
|
if ( geometry.geometryGroups[ groupHash ] === undefined ) {
|
|
|
|
geometry.geometryGroups[ groupHash ] = { 'faces3': [], 'faces4': [], 'materialIndex': materialIndex, 'vertices': 0, 'numMorphTargets': numMorphTargets };
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ( face instanceof THREE.Face3 ) {
|
|
|
|
geometry.geometryGroups[ groupHash ].faces3.push( f );
|
|
|
|
} else {
|
|
|
|
geometry.geometryGroups[ groupHash ].faces4.push( f );
|
|
|
|
}
|
|
|
|
geometry.geometryGroups[ groupHash ].vertices += vertices;
|
|
|
|
}
|
|
|
|
geometry.geometryGroupsList = [];
|
|
|
|
for ( var g in geometry.geometryGroups ) {
|
|
|
|
geometry.geometryGroups[ g ].id = _geometryGroupCounter ++;
|
|
|
|
geometry.geometryGroupsList.push( geometry.geometryGroups[ g ] );
|
|
|
|
}
|
|
|
|
};
|
|
|
|
// Objects refresh
|
|
|
|
this.initWebGLObjects = function ( scene ) {
|
|
|
|
if ( !scene.__webglObjects ) {
|
|
|
|
scene.__webglObjects = [];
|
|
scene.__webglObjectsImmediate = [];
|
|
scene.__webglSprites = [];
|
|
scene.__webglFlares = [];
|
|
|
|
}
|
|
|
|
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 );
|
|
|
|
}
|
|
|
|
};
|
|
|
|
// Objects adding
|
|
|
|
function addObject ( object, scene ) {
|
|
|
|
var g, geometry, geometryGroup;
|
|
|
|
if ( ! object.__webglInit ) {
|
|
|
|
object.__webglInit = true;
|
|
|
|
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 instanceof THREE.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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if ( object instanceof THREE.Ribbon ) {
|
|
|
|
geometry = object.geometry;
|
|
|
|
if( ! geometry.__webglVertexBuffer ) {
|
|
|
|
createRibbonBuffers( geometry );
|
|
initRibbonBuffers( geometry );
|
|
|
|
geometry.__dirtyVertices = true;
|
|
geometry.__dirtyColors = true;
|
|
|
|
}
|
|
|
|
} else if ( object instanceof THREE.Line ) {
|
|
|
|
geometry = object.geometry;
|
|
|
|
if( ! geometry.__webglVertexBuffer ) {
|
|
|
|
createLineBuffers( geometry );
|
|
initLineBuffers( geometry, object );
|
|
|
|
geometry.__dirtyVertices = true;
|
|
geometry.__dirtyColors = true;
|
|
|
|
}
|
|
|
|
} else if ( object instanceof THREE.ParticleSystem ) {
|
|
|
|
geometry = object.geometry;
|
|
|
|
if ( ! geometry.__webglVertexBuffer ) {
|
|
|
|
createParticleBuffers( geometry );
|
|
initParticleBuffers( geometry, object );
|
|
|
|
geometry.__dirtyVertices = true;
|
|
geometry.__dirtyColors = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ( ! object.__webglActive ) {
|
|
|
|
if ( object instanceof THREE.Mesh ) {
|
|
|
|
geometry = object.geometry;
|
|
|
|
if ( geometry instanceof THREE.BufferGeometry ) {
|
|
|
|
addBuffer( scene.__webglObjects, geometry, object );
|
|
|
|
} else {
|
|
|
|
for ( g in geometry.geometryGroups ) {
|
|
|
|
geometryGroup = geometry.geometryGroups[ g ];
|
|
|
|
addBuffer( scene.__webglObjects, geometryGroup, object );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if ( object instanceof THREE.Ribbon ||
|
|
object instanceof THREE.Line ||
|
|
object instanceof THREE.ParticleSystem ) {
|
|
|
|
geometry = object.geometry;
|
|
addBuffer( scene.__webglObjects, geometry, object );
|
|
|
|
} else if ( THREE.MarchingCubes !== undefined && object instanceof THREE.MarchingCubes || object.immediateRenderCallback ) {
|
|
|
|
addBufferImmediate( scene.__webglObjectsImmediate, object );
|
|
|
|
} else if ( object instanceof THREE.Sprite ) {
|
|
|
|
scene.__webglSprites.push( object );
|
|
|
|
} else if ( object instanceof THREE.LensFlare ) {
|
|
|
|
scene.__webglFlares.push( object );
|
|
|
|
}
|
|
|
|
object.__webglActive = true;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
function addBuffer ( objlist, buffer, object ) {
|
|
|
|
objlist.push(
|
|
{
|
|
buffer: buffer,
|
|
object: object,
|
|
opaque: null,
|
|
transparent: null
|
|
}
|
|
);
|
|
|
|
};
|
|
|
|
function addBufferImmediate ( objlist, object ) {
|
|
|
|
objlist.push(
|
|
{
|
|
object: object,
|
|
opaque: null,
|
|
transparent: null
|
|
}
|
|
);
|
|
|
|
};
|
|
|
|
// Objects updates
|
|
|
|
function updateObject ( object ) {
|
|
|
|
var geometry = object.geometry,
|
|
geometryGroup, customAttributesDirty, material;
|
|
|
|
if ( object instanceof THREE.Mesh ) {
|
|
|
|
if ( geometry instanceof THREE.BufferGeometry ) {
|
|
|
|
if ( geometry.__dirtyVertices || geometry.__dirtyElements ||
|
|
geometry.__dirtyUvs || geometry.__dirtyNormals ||
|
|
geometry.__dirtyColors ) {
|
|
|
|
// TODO
|
|
// set buffers from typed arrays
|
|
|
|
}
|
|
|
|
geometry.__dirtyVertices = false;
|
|
geometry.__dirtyElements = false;
|
|
geometry.__dirtyUvs = false;
|
|
geometry.__dirtyNormals = false;
|
|
geometry.__dirtyColors = false;
|
|
|
|
} else {
|
|
|
|
// check all geometry groups
|
|
|
|
for( var i = 0, il = geometry.geometryGroupsList.length; i < il; i ++ ) {
|
|
|
|
geometryGroup = geometry.geometryGroupsList[ i ];
|
|
|
|
material = getBufferMaterial( object, geometryGroup );
|
|
|
|
customAttributesDirty = material.attributes && areCustomAttributesDirty( material );
|
|
|
|
if ( geometry.__dirtyVertices || geometry.__dirtyMorphTargets || geometry.__dirtyElements ||
|
|
geometry.__dirtyUvs || geometry.__dirtyNormals ||
|
|
geometry.__dirtyColors || geometry.__dirtyTangents || customAttributesDirty ) {
|
|
|
|
setMeshBuffers( geometryGroup, object, _gl.DYNAMIC_DRAW, !geometry.dynamic, material );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
geometry.__dirtyVertices = false;
|
|
geometry.__dirtyMorphTargets = false;
|
|
geometry.__dirtyElements = false;
|
|
geometry.__dirtyUvs = false;
|
|
geometry.__dirtyNormals = false;
|
|
geometry.__dirtyColors = false;
|
|
geometry.__dirtyTangents = false;
|
|
|
|
material.attributes && clearCustomAttributes( material );
|
|
|
|
}
|
|
|
|
} else if ( object instanceof THREE.Ribbon ) {
|
|
|
|
if ( geometry.__dirtyVertices || geometry.__dirtyColors ) {
|
|
|
|
setRibbonBuffers( geometry, _gl.DYNAMIC_DRAW );
|
|
|
|
}
|
|
|
|
geometry.__dirtyVertices = false;
|
|
geometry.__dirtyColors = false;
|
|
|
|
} else if ( object instanceof THREE.Line ) {
|
|
|
|
material = getBufferMaterial( object, geometryGroup );
|
|
|
|
customAttributesDirty = material.attributes && areCustomAttributesDirty( material );
|
|
|
|
if ( geometry.__dirtyVertices || geometry.__dirtyColors || customAttributesDirty ) {
|
|
|
|
setLineBuffers( geometry, _gl.DYNAMIC_DRAW );
|
|
|
|
}
|
|
|
|
geometry.__dirtyVertices = false;
|
|
geometry.__dirtyColors = false;
|
|
|
|
material.attributes && clearCustomAttributes( material );
|
|
|
|
} else if ( object instanceof THREE.ParticleSystem ) {
|
|
|
|
material = getBufferMaterial( object, geometryGroup );
|
|
|
|
customAttributesDirty = material.attributes && areCustomAttributesDirty( material );
|
|
|
|
if ( geometry.__dirtyVertices || geometry.__dirtyColors || object.sortParticles || customAttributesDirty ) {
|
|
|
|
setParticleBuffers( geometry, _gl.DYNAMIC_DRAW, object );
|
|
|
|
}
|
|
|
|
geometry.__dirtyVertices = false;
|
|
geometry.__dirtyColors = false;
|
|
|
|
material.attributes && clearCustomAttributes( material );
|
|
|
|
}
|
|
|
|
};
|
|
|
|
// Objects updates - custom attributes check
|
|
|
|
function areCustomAttributesDirty ( material ) {
|
|
|
|
for ( var a in material.attributes ) {
|
|
|
|
if ( material.attributes[ a ].needsUpdate ) return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
};
|
|
|
|
function clearCustomAttributes ( material ) {
|
|
|
|
for ( var a in material.attributes ) {
|
|
|
|
material.attributes[ a ].needsUpdate = false;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
// Objects removal
|
|
|
|
function removeObject ( object, scene ) {
|
|
|
|
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 ) {
|
|
|
|
removeInstancesDirect( scene.__webglFlares, object );
|
|
|
|
} else if ( object instanceof THREE.MarchingCubes || object.immediateRenderCallback ) {
|
|
|
|
removeInstances( scene.__webglObjectsImmediate, object );
|
|
|
|
}
|
|
|
|
object.__webglActive = false;
|
|
|
|
};
|
|
|
|
function removeInstances ( objlist, object ) {
|
|
|
|
for ( var o = objlist.length - 1; o >= 0; o -- ) {
|
|
|
|
if ( objlist[ o ].object === object ) {
|
|
|
|
objlist.splice( o, 1 );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
function removeInstancesDirect ( objlist, object ) {
|
|
|
|
for ( var o = objlist.length - 1; o >= 0; o -- ) {
|
|
|
|
if ( objlist[ o ] === object ) {
|
|
|
|
objlist.splice( o, 1 );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
// Materials
|
|
|
|
this.initMaterial = function ( material, lights, fog, object ) {
|
|
|
|
var u, a, identifiers, i, parameters, maxLightCount, maxBones, maxShadows, shaderID;
|
|
|
|
if ( material instanceof THREE.MeshDepthMaterial ) {
|
|
|
|
shaderID = 'depth';
|
|
|
|
} else if ( material instanceof THREE.MeshNormalMaterial ) {
|
|
|
|
shaderID = 'normal';
|
|
|
|
} else if ( material instanceof THREE.MeshBasicMaterial ) {
|
|
|
|
shaderID = 'basic';
|
|
|
|
} else if ( material instanceof THREE.MeshLambertMaterial ) {
|
|
|
|
shaderID = 'lambert';
|
|
|
|
} else if ( material instanceof THREE.MeshPhongMaterial ) {
|
|
|
|
shaderID = 'phong';
|
|
|
|
} else if ( material instanceof THREE.LineBasicMaterial ) {
|
|
|
|
shaderID = 'basic';
|
|
|
|
} else if ( material instanceof THREE.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 );
|
|
|
|
maxShadows = allocateShadows( lights );
|
|
|
|
maxBones = allocateBones( object );
|
|
|
|
parameters = {
|
|
|
|
map: !!material.map, envMap: !!material.envMap, lightMap: !!material.lightMap,
|
|
vertexColors: material.vertexColors,
|
|
fog: fog, useFog: material.fog,
|
|
sizeAttenuation: material.sizeAttenuation,
|
|
skinning: material.skinning,
|
|
morphTargets: material.morphTargets,
|
|
maxMorphTargets: this.maxMorphTargets,
|
|
maxDirLights: maxLightCount.directional, maxPointLights: maxLightCount.point,
|
|
maxBones: maxBones,
|
|
shadowMapEnabled: this.shadowMapEnabled && object.receiveShadow,
|
|
shadowMapSoft: this.shadowMapSoft,
|
|
shadowMapWidth: this.shadowMapWidth,
|
|
shadowMapHeight: this.shadowMapHeight,
|
|
maxShadows: maxShadows,
|
|
alphaTest: material.alphaTest,
|
|
metal: material.metal,
|
|
perPixel: material.perPixel
|
|
|
|
};
|
|
|
|
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;
|
|
|
|
var id, base = "morphTarget";
|
|
|
|
for ( i = 0; i < this.maxMorphTargets; i ++ ) {
|
|
|
|
id = base + i;
|
|
|
|
if ( attributes[ id ] >= 0 ) {
|
|
|
|
_gl.enableVertexAttribArray( attributes[ id ] );
|
|
material.numSupportedMorphTargets ++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
material.uniformsList = [];
|
|
|
|
for ( u in material.uniforms ) {
|
|
|
|
material.uniformsList.push( [ material.uniforms[ u ], u ] );
|
|
|
|
}
|
|
|
|
};
|
|
|
|
function setMaterialShaders ( material, shaders ) {
|
|
|
|
material.uniforms = THREE.UniformsUtils.clone( shaders.uniforms );
|
|
material.vertexShader = shaders.vertexShader;
|
|
material.fragmentShader = shaders.fragmentShader;
|
|
|
|
};
|
|
|
|
function setProgram ( camera, lights, fog, material, object ) {
|
|
|
|
if ( ! material.program ) {
|
|
|
|
_this.initMaterial( material, lights, fog, object );
|
|
|
|
}
|
|
|
|
if ( material.morphTargets ) {
|
|
|
|
if ( ! object.__webglMorphTargetInfluences ) {
|
|
|
|
object.__webglMorphTargetInfluences = new Float32Array( _this.maxMorphTargets );
|
|
|
|
for ( var i = 0, il = _this.maxMorphTargets; i < il; i ++ ) {
|
|
|
|
object.__webglMorphTargetInfluences[ i ] = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
var refreshMaterial = false;
|
|
|
|
var program = material.program,
|
|
p_uniforms = program.uniforms,
|
|
m_uniforms = material.uniforms;
|
|
|
|
if ( program !== _currentProgram ) {
|
|
|
|
_gl.useProgram( program );
|
|
_currentProgram = program;
|
|
|
|
refreshMaterial = true;
|
|
|
|
}
|
|
|
|
if ( material.id !== _currentMaterialId ) {
|
|
|
|
_currentMaterialId = material.id;
|
|
refreshMaterial = true;
|
|
|
|
}
|
|
|
|
if ( refreshMaterial ) {
|
|
|
|
_gl.uniformMatrix4fv( p_uniforms.projectionMatrix, false, camera._projectionMatrixArray );
|
|
|
|
// refresh uniforms common to several materials
|
|
|
|
if ( fog && material.fog ) {
|
|
|
|
refreshUniformsFog( m_uniforms, fog );
|
|
|
|
}
|
|
|
|
if ( material instanceof THREE.MeshPhongMaterial ||
|
|
material instanceof THREE.MeshLambertMaterial ||
|
|
material.lights ) {
|
|
|
|
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.MeshLambertMaterial ) {
|
|
|
|
refreshUniformsLambert( m_uniforms, material );
|
|
|
|
} else if ( material instanceof THREE.MeshDepthMaterial ) {
|
|
|
|
m_uniforms.mNear.value = camera.near;
|
|
m_uniforms.mFar.value = camera.far;
|
|
m_uniforms.opacity.value = material.opacity;
|
|
|
|
} else if ( material instanceof THREE.MeshNormalMaterial ) {
|
|
|
|
m_uniforms.opacity.value = material.opacity;
|
|
|
|
}
|
|
|
|
if ( object.receiveShadow && ! material._shadowPass ) {
|
|
|
|
refreshUniformsShadow( m_uniforms, material );
|
|
|
|
}
|
|
|
|
// load common uniforms
|
|
|
|
loadUniformsGeneric( program, material.uniformsList );
|
|
|
|
// load material specific uniforms
|
|
// (shader material also gets them for the sake of genericity)
|
|
|
|
if ( material instanceof THREE.ShaderMaterial ||
|
|
material instanceof THREE.MeshPhongMaterial ||
|
|
material.envMap ) {
|
|
|
|
if( p_uniforms.cameraPosition !== null ) {
|
|
|
|
_gl.uniform3f( p_uniforms.cameraPosition, camera.position.x, camera.position.y, camera.position.z );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ( material instanceof THREE.MeshPhongMaterial ||
|
|
material instanceof THREE.MeshLambertMaterial ||
|
|
material instanceof THREE.ShaderMaterial ||
|
|
material.skinning ) {
|
|
|
|
if( p_uniforms.viewMatrix !== null ) {
|
|
|
|
_gl.uniformMatrix4fv( p_uniforms.viewMatrix, false, camera._viewMatrixArray );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ( material.skinning ) {
|
|
|
|
loadUniformsSkinning( p_uniforms, object, camera );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
loadUniformsMatrices( p_uniforms, object );
|
|
|
|
if ( material instanceof THREE.ShaderMaterial ||
|
|
material.envMap ||
|
|
material.skinning ||
|
|
object.receiveShadow ) {
|
|
|
|
if ( p_uniforms.objectMatrix !== null ) {
|
|
|
|
_gl.uniformMatrix4fv( p_uniforms.objectMatrix, false, object._objectMatrixArray );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return program;
|
|
|
|
};
|
|
|
|
// Uniforms (refresh uniforms objects)
|
|
|
|
function refreshUniformsCommon ( uniforms, material ) {
|
|
|
|
uniforms.opacity.value = material.opacity;
|
|
|
|
if ( _this.gammaInput ) {
|
|
|
|
uniforms.diffuse.value.copyGammaToLinear( material.color );
|
|
|
|
} else {
|
|
|
|
uniforms.diffuse.value = material.color;
|
|
|
|
}
|
|
|
|
uniforms.map.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.flipEnvMap.value = ( material.envMap instanceof THREE.WebGLRenderTargetCube ) ? 1 : -1;
|
|
|
|
if ( _this.gammaInput ) {
|
|
|
|
//uniforms.reflectivity.value = material.reflectivity * material.reflectivity;
|
|
uniforms.reflectivity.value = material.reflectivity;
|
|
|
|
} else {
|
|
|
|
uniforms.reflectivity.value = material.reflectivity;
|
|
|
|
}
|
|
|
|
uniforms.refractionRatio.value = material.refractionRatio;
|
|
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.shininess.value = material.shininess;
|
|
|
|
if ( _this.gammaInput ) {
|
|
|
|
uniforms.ambient.value.copyGammaToLinear( material.ambient );
|
|
uniforms.specular.value.copyGammaToLinear( material.specular );
|
|
|
|
} else {
|
|
|
|
uniforms.ambient.value = material.ambient;
|
|
uniforms.specular.value = material.specular;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
function refreshUniformsLambert ( uniforms, material ) {
|
|
|
|
if ( _this.gammaInput ) {
|
|
|
|
uniforms.ambient.value.copyGammaToLinear( material.ambient );
|
|
|
|
} else {
|
|
|
|
uniforms.ambient.value = material.ambient;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
function refreshUniformsLights ( uniforms, lights ) {
|
|
|
|
uniforms.ambientLightColor.value = lights.ambient;
|
|
|
|
uniforms.directionalLightColor.value = lights.directional.colors;
|
|
uniforms.directionalLightDirection.value = lights.directional.positions;
|
|
|
|
uniforms.pointLightColor.value = lights.point.colors;
|
|
uniforms.pointLightPosition.value = lights.point.positions;
|
|
uniforms.pointLightDistance.value = lights.point.distances;
|
|
|
|
};
|
|
|
|
function refreshUniformsShadow ( uniforms, material ) {
|
|
|
|
if ( uniforms.shadowMatrix ) {
|
|
|
|
for ( var i = 0; i < _this.shadowMapPlugin.shadowMatrix.length; i ++ ) {
|
|
|
|
uniforms.shadowMatrix.value[ i ] = _this.shadowMapPlugin.shadowMatrix[ i ];
|
|
uniforms.shadowMap.texture[ i ] = _this.shadowMapPlugin.shadowMap[ i ];
|
|
|
|
|
|
}
|
|
|
|
uniforms.shadowDarkness.value = _this.shadowMapDarkness;
|
|
uniforms.shadowBias.value = _this.shadowMapBias;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
// Uniforms (load to GPU)
|
|
|
|
function loadUniformsSkinning ( uniforms, object, camera ) {
|
|
|
|
_gl.uniformMatrix4fv( uniforms.cameraInverseMatrix, false, camera._viewMatrixArray );
|
|
_gl.uniformMatrix4fv( uniforms.boneGlobalMatrices, false, object.boneMatrices );
|
|
|
|
};
|
|
|
|
|
|
function loadUniformsMatrices ( uniforms, object ) {
|
|
|
|
_gl.uniformMatrix4fv( uniforms.modelViewMatrix, false, object._modelViewMatrixArray );
|
|
|
|
if ( uniforms.normalMatrix ) {
|
|
|
|
_gl.uniformMatrix3fv( uniforms.normalMatrix, false, object._normalMatrixArray );
|
|
|
|
}
|
|
|
|
};
|
|
|
|
function loadUniformsGeneric ( program, uniforms ) {
|
|
|
|
var uniform, value, type, location, texture, i, il, j, jl, offset;
|
|
|
|
for( j = 0, jl = uniforms.length; j < jl; j ++ ) {
|
|
|
|
location = program.uniforms[ uniforms[ j ][ 1 ] ];
|
|
if ( !location ) continue;
|
|
|
|
uniform = uniforms[ j ][ 0 ];
|
|
|
|
type = uniform.type;
|
|
value = uniform.value;
|
|
|
|
// single integer
|
|
|
|
if( type === "i" ) {
|
|
|
|
_gl.uniform1i( location, value );
|
|
|
|
// single float
|
|
|
|
} else if( type === "f" ) {
|
|
|
|
_gl.uniform1f( location, value );
|
|
|
|
// single THREE.Vector2
|
|
|
|
} else if( type === "v2" ) {
|
|
|
|
_gl.uniform2f( location, value.x, value.y );
|
|
|
|
// single THREE.Vector3
|
|
|
|
} else if( type === "v3" ) {
|
|
|
|
_gl.uniform3f( location, value.x, value.y, value.z );
|
|
|
|
// single THREE.Vector4
|
|
|
|
} else if( type === "v4" ) {
|
|
|
|
_gl.uniform4f( location, value.x, value.y, value.z, value.w );
|
|
|
|
// single THREE.Color
|
|
|
|
} else if( type === "c" ) {
|
|
|
|
_gl.uniform3f( location, value.r, value.g, value.b );
|
|
|
|
// flat array of floats (JS or typed array)
|
|
|
|
} else if( type === "fv1" ) {
|
|
|
|
_gl.uniform1fv( location, value );
|
|
|
|
// flat array of floats with 3 x N size (JS or typed array)
|
|
|
|
} else if( type === "fv" ) {
|
|
|
|
_gl.uniform3fv( location, value );
|
|
|
|
// array of THREE.Vector3
|
|
|
|
} else if( type === "v3v" ) {
|
|
|
|
if ( ! uniform._array ) {
|
|
|
|
uniform._array = new Float32Array( 3 * value.length );
|
|
|
|
}
|
|
|
|
for ( i = 0, il = value.length; i < il; i ++ ) {
|
|
|
|
offset = i * 3;
|
|
|
|
uniform._array[ offset ] = value[ i ].x;
|
|
uniform._array[ offset + 1 ] = value[ i ].y;
|
|
uniform._array[ offset + 2 ] = value[ i ].z;
|
|
|
|
}
|
|
|
|
_gl.uniform3fv( location, uniform._array );
|
|
|
|
// single THREE.Matrix4
|
|
|
|
} else if( type === "m4" ) {
|
|
|
|
if ( ! uniform._array ) {
|
|
|
|
uniform._array = new Float32Array( 16 );
|
|
|
|
}
|
|
|
|
value.flattenToArray( uniform._array );
|
|
_gl.uniformMatrix4fv( location, false, uniform._array );
|
|
|
|
// array of THREE.Matrix4
|
|
|
|
} else if( type === "m4v" ) {
|
|
|
|
if ( ! uniform._array ) {
|
|
|
|
uniform._array = new Float32Array( 16 * value.length );
|
|
|
|
}
|
|
|
|
for ( i = 0, il = value.length; i < il; i ++ ) {
|
|
|
|
value[ i ].flattenToArrayOffset( uniform._array, i * 16 );
|
|
|
|
}
|
|
|
|
_gl.uniformMatrix4fv( location, false, uniform._array );
|
|
|
|
|
|
// single THREE.Texture (2d or cube)
|
|
|
|
} 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 if ( texture instanceof THREE.WebGLRenderTargetCube ) {
|
|
|
|
setCubeTextureDynamic( texture, value );
|
|
|
|
} else {
|
|
|
|
_this.setTexture( texture, value );
|
|
|
|
}
|
|
|
|
// array of THREE.Texture (2d)
|
|
|
|
} else if( type === "tv" ) {
|
|
|
|
if ( ! uniform._array ) {
|
|
|
|
uniform._array = [];
|
|
|
|
for( i = 0, il = uniform.texture.length; i < il; i ++ ) {
|
|
|
|
uniform._array[ i ] = value + i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_gl.uniform1iv( location, uniform._array );
|
|
|
|
for( i = 0, il = uniform.texture.length; i < il; i ++ ) {
|
|
|
|
texture = uniform.texture[ i ];
|
|
|
|
if ( !texture ) continue;
|
|
|
|
_this.setTexture( texture, uniform._array[ i ] );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
function setupMatrices ( object, camera ) {
|
|
|
|
object._modelViewMatrix.multiplyToArray( camera.matrixWorldInverse, object.matrixWorld, object._modelViewMatrixArray );
|
|
|
|
var inverseMatrix = THREE.Matrix4.makeInvert3x3( object._modelViewMatrix );
|
|
|
|
if ( inverseMatrix ) {
|
|
|
|
inverseMatrix.transposeIntoArray( object._normalMatrixArray );
|
|
|
|
}
|
|
|
|
};
|
|
|
|
function setupLights ( program, lights ) {
|
|
|
|
var l, ll, light, n,
|
|
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;
|
|
|
|
intensity = light.intensity;
|
|
distance = light.distance;
|
|
|
|
if ( light instanceof THREE.AmbientLight ) {
|
|
|
|
if ( _this.gammaInput ) {
|
|
|
|
r += color.r * color.r;
|
|
g += color.g * color.g;
|
|
b += color.b * color.b;
|
|
|
|
} else {
|
|
|
|
r += color.r;
|
|
g += color.g;
|
|
b += color.b;
|
|
|
|
}
|
|
|
|
} else if ( light instanceof THREE.DirectionalLight ) {
|
|
|
|
doffset = dlength * 3;
|
|
|
|
if ( _this.gammaInput ) {
|
|
|
|
dcolors[ doffset ] = color.r * color.r * intensity * intensity;
|
|
dcolors[ doffset + 1 ] = color.g * color.g * intensity * intensity;
|
|
dcolors[ doffset + 2 ] = color.b * color.b * intensity * intensity;
|
|
|
|
} else {
|
|
|
|
dcolors[ doffset ] = color.r * intensity;
|
|
dcolors[ doffset + 1 ] = color.g * intensity;
|
|
dcolors[ doffset + 2 ] = color.b * intensity;
|
|
|
|
}
|
|
|
|
position = light.matrixWorld.getPosition();
|
|
|
|
n = 1 / position.length();
|
|
|
|
dpositions[ doffset ] = position.x * n;
|
|
dpositions[ doffset + 1 ] = position.y * n;
|
|
dpositions[ doffset + 2 ] = position.z * n;
|
|
|
|
dlength += 1;
|
|
|
|
} else if ( light instanceof THREE.SpotLight ) { // hack, not a proper spotlight
|
|
|
|
doffset = dlength * 3;
|
|
|
|
if ( _this.gammaInput ) {
|
|
|
|
dcolors[ doffset ] = color.r * color.r * intensity * intensity;
|
|
dcolors[ doffset + 1 ] = color.g * color.g * intensity * intensity;
|
|
dcolors[ doffset + 2 ] = color.b * color.b * intensity * intensity;
|
|
|
|
} else {
|
|
|
|
dcolors[ doffset ] = color.r * intensity;
|
|
dcolors[ doffset + 1 ] = color.g * intensity;
|
|
dcolors[ doffset + 2 ] = color.b * intensity;
|
|
|
|
}
|
|
|
|
position = light.matrixWorld.getPosition();
|
|
|
|
n = 1 / position.length();
|
|
|
|
dpositions[ doffset ] = position.x * n;
|
|
dpositions[ doffset + 1 ] = position.y * n;
|
|
dpositions[ doffset + 2 ] = position.z * n;
|
|
|
|
dlength += 1;
|
|
|
|
} else if( light instanceof THREE.PointLight ) {
|
|
|
|
poffset = plength * 3;
|
|
|
|
if ( _this.gammaInput ) {
|
|
|
|
pcolors[ poffset ] = color.r * color.r * intensity * intensity;
|
|
pcolors[ poffset + 1 ] = color.g * color.g * intensity * intensity;
|
|
pcolors[ poffset + 2 ] = color.b * color.b * intensity * intensity;
|
|
|
|
} else {
|
|
|
|
pcolors[ poffset ] = color.r * intensity;
|
|
pcolors[ poffset + 1 ] = color.g * intensity;
|
|
pcolors[ poffset + 2 ] = color.b * intensity;
|
|
|
|
}
|
|
|
|
position = light.matrixWorld.getPosition();
|
|
|
|
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, ll = dcolors.length; l < ll; l ++ ) dcolors[ l ] = 0.0;
|
|
for ( l = plength * 3, ll = pcolors.length; l < ll; 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;
|
|
|
|
};
|
|
|
|
// GL state setting
|
|
|
|
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.setObjectFaces = function ( 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;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
this.setDepthTest = function ( depthTest ) {
|
|
|
|
if ( _oldDepthTest !== depthTest ) {
|
|
|
|
if( depthTest ) {
|
|
|
|
_gl.enable( _gl.DEPTH_TEST );
|
|
|
|
} else {
|
|
|
|
_gl.disable( _gl.DEPTH_TEST );
|
|
|
|
}
|
|
|
|
_oldDepthTest = depthTest;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
function setLineWidth ( width ) {
|
|
|
|
if ( width !== _oldLineWidth ) {
|
|
|
|
_gl.lineWidth( width );
|
|
|
|
_oldLineWidth = width;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
function setDepthWrite ( depthWrite ) {
|
|
|
|
if ( _oldDepthWrite !== depthWrite ) {
|
|
|
|
_gl.depthMask( depthWrite );
|
|
_oldDepthWrite = depthWrite;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
function setPolygonOffset ( polygonoffset, factor, units ) {
|
|
|
|
if ( _oldPolygonOffset !== polygonoffset ) {
|
|
|
|
if ( polygonoffset ) {
|
|
|
|
_gl.enable( _gl.POLYGON_OFFSET_FILL );
|
|
|
|
} else {
|
|
|
|
_gl.disable( _gl.POLYGON_OFFSET_FILL );
|
|
|
|
}
|
|
|
|
_oldPolygonOffset = polygonoffset;
|
|
|
|
}
|
|
|
|
if ( polygonoffset && ( _oldPolygonOffsetFactor !== factor || _oldPolygonOffsetUnits !== units ) ) {
|
|
|
|
_gl.polygonOffset( factor, units );
|
|
|
|
_oldPolygonOffsetFactor = factor;
|
|
_oldPolygonOffsetUnits = units;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
this.setBlending = function ( blending ) {
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
// Shaders
|
|
|
|
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" : "",
|
|
|
|
_this.gammaInput ? "#define GAMMA_INPUT" : "",
|
|
_this.gammaOutput ? "#define GAMMA_OUTPUT" : "",
|
|
_this.physicallyBasedShading ? "#define PHYSICALLY_BASED_SHADING" : "",
|
|
|
|
"#define MAX_DIR_LIGHTS " + parameters.maxDirLights,
|
|
"#define MAX_POINT_LIGHTS " + parameters.maxPointLights,
|
|
|
|
"#define MAX_SHADOWS " + parameters.maxShadows,
|
|
|
|
"#define MAX_BONES " + parameters.maxBones,
|
|
|
|
parameters.map ? "#define USE_MAP" : "",
|
|
parameters.envMap ? "#define USE_ENVMAP" : "",
|
|
parameters.lightMap ? "#define USE_LIGHTMAP" : "",
|
|
parameters.vertexColors ? "#define USE_COLOR" : "",
|
|
parameters.skinning ? "#define USE_SKINNING" : "",
|
|
parameters.morphTargets ? "#define USE_MORPHTARGETS" : "",
|
|
parameters.perPixel ? "#define PHONG_PER_PIXEL" : "",
|
|
|
|
parameters.shadowMapEnabled ? "#define USE_SHADOWMAP" : "",
|
|
parameters.shadowMapSoft ? "#define SHADOWMAP_SOFT" : "",
|
|
|
|
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 = [
|
|
|
|
"precision " + _precision + " float;",
|
|
|
|
"#define MAX_DIR_LIGHTS " + parameters.maxDirLights,
|
|
"#define MAX_POINT_LIGHTS " + parameters.maxPointLights,
|
|
|
|
"#define MAX_SHADOWS " + parameters.maxShadows,
|
|
|
|
parameters.alphaTest ? "#define ALPHATEST " + parameters.alphaTest: "",
|
|
|
|
_this.gammaInput ? "#define GAMMA_INPUT" : "",
|
|
_this.gammaOutput ? "#define GAMMA_OUTPUT" : "",
|
|
_this.physicallyBasedShading ? "#define PHYSICALLY_BASED_SHADING" : "",
|
|
|
|
( parameters.useFog && parameters.fog ) ? "#define USE_FOG" : "",
|
|
( parameters.useFog && 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" : "",
|
|
|
|
parameters.metal ? "#define METAL" : "",
|
|
parameters.perPixel ? "#define PHONG_PER_PIXEL" : "",
|
|
|
|
parameters.shadowMapEnabled ? "#define USE_SHADOWMAP" : "",
|
|
parameters.shadowMapSoft ? "#define SHADOWMAP_SOFT" : "",
|
|
parameters.shadowMapSoft ? "#define SHADOWMAP_WIDTH " + parameters.shadowMapWidth.toFixed( 1 ) : "",
|
|
parameters.shadowMapSoft ? "#define SHADOWMAP_HEIGHT " + parameters.shadowMapHeight.toFixed( 1 ) : "",
|
|
|
|
"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 );
|
|
|
|
program.id = _programs.length;
|
|
|
|
_programs.push( { program: program, code: code } );
|
|
|
|
_this.info.memory.programs = _programs.length;
|
|
|
|
return program;
|
|
|
|
};
|
|
|
|
// Shader parameters cache
|
|
|
|
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;
|
|
|
|
};
|
|
|
|
// Textures
|
|
|
|
|
|
function isPowerOfTwo ( value ) {
|
|
|
|
return ( value & ( value - 1 ) ) === 0;
|
|
|
|
};
|
|
|
|
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 ) );
|
|
|
|
return true;
|
|
|
|
} 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 ) );
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
this.setTexture = function ( texture, slot ) {
|
|
|
|
if ( texture.needsUpdate ) {
|
|
|
|
if ( ! texture.__webglInit ) {
|
|
|
|
texture.__webglInit = true;
|
|
texture.__webglTexture = _gl.createTexture();
|
|
|
|
_this.info.memory.textures ++;
|
|
|
|
}
|
|
|
|
_gl.activeTexture( _gl.TEXTURE0 + slot );
|
|
_gl.bindTexture( _gl.TEXTURE_2D, texture.__webglTexture );
|
|
|
|
var needsMipMaps = setTextureParameters( _gl.TEXTURE_2D, texture, texture.image );
|
|
|
|
if ( texture instanceof THREE.DataTexture ) {
|
|
|
|
_gl.texImage2D( _gl.TEXTURE_2D, 0, paramThreeToGL( texture.format ), texture.image.width, texture.image.height, 0, paramThreeToGL( texture.format ), _gl.UNSIGNED_BYTE, texture.image.data );
|
|
|
|
} else {
|
|
|
|
_gl.texImage2D( _gl.TEXTURE_2D, 0, _gl.RGBA, _gl.RGBA, _gl.UNSIGNED_BYTE, texture.image );
|
|
|
|
}
|
|
|
|
if ( needsMipMaps ) {
|
|
|
|
_gl.generateMipmap( _gl.TEXTURE_2D );
|
|
|
|
}
|
|
|
|
texture.needsUpdate = false;
|
|
|
|
if ( texture.onUpdated ) texture.onUpdated();
|
|
|
|
} else {
|
|
|
|
_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.image.__webglTextureCube ) {
|
|
|
|
texture.image.__webglTextureCube = _gl.createTexture();
|
|
|
|
}
|
|
|
|
_gl.activeTexture( _gl.TEXTURE0 + slot );
|
|
_gl.bindTexture( _gl.TEXTURE_CUBE_MAP, texture.image.__webglTextureCube );
|
|
|
|
var needsMipMaps = setTextureParameters( _gl.TEXTURE_CUBE_MAP, texture, texture.image[ 0 ] );
|
|
|
|
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 ] );
|
|
|
|
}
|
|
|
|
if ( needsMipMaps ) {
|
|
|
|
_gl.generateMipmap( _gl.TEXTURE_CUBE_MAP );
|
|
|
|
}
|
|
|
|
texture.needsUpdate = false;
|
|
|
|
} else {
|
|
|
|
_gl.activeTexture( _gl.TEXTURE0 + slot );
|
|
_gl.bindTexture( _gl.TEXTURE_CUBE_MAP, texture.image.__webglTextureCube );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
function setCubeTextureDynamic ( texture, slot ) {
|
|
|
|
_gl.activeTexture( _gl.TEXTURE0 + slot );
|
|
_gl.bindTexture( _gl.TEXTURE_CUBE_MAP, texture.__webglTexture );
|
|
|
|
};
|
|
|
|
// Render targets
|
|
|
|
function setupFrameBuffer ( framebuffer, renderTarget, textureTarget ) {
|
|
|
|
_gl.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );
|
|
_gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, textureTarget, renderTarget.__webglTexture, 0 );
|
|
|
|
};
|
|
|
|
function setupRenderBuffer ( renderbuffer, renderTarget ) {
|
|
|
|
_gl.bindRenderbuffer( _gl.RENDERBUFFER, renderbuffer );
|
|
|
|
if ( renderTarget.depthBuffer && ! renderTarget.stencilBuffer ) {
|
|
|
|
_gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.DEPTH_COMPONENT16, renderTarget.width, renderTarget.height );
|
|
_gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer );
|
|
|
|
/* For some reason this is not working. Defaulting to RGBA4.
|
|
} else if( ! renderTarget.depthBuffer && renderTarget.stencilBuffer ) {
|
|
|
|
_gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.STENCIL_INDEX8, renderTarget.width, renderTarget.height );
|
|
_gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.STENCIL_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer );
|
|
*/
|
|
} else if( renderTarget.depthBuffer && renderTarget.stencilBuffer ) {
|
|
|
|
_gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.DEPTH_STENCIL, renderTarget.width, renderTarget.height );
|
|
_gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer );
|
|
|
|
} else {
|
|
|
|
_gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.RGBA4, renderTarget.width, renderTarget.height );
|
|
|
|
}
|
|
|
|
};
|
|
|
|
this.setRenderTarget = function ( renderTarget ) {
|
|
|
|
var isCube = ( renderTarget instanceof THREE.WebGLRenderTargetCube );
|
|
|
|
if ( renderTarget && ! renderTarget.__webglFramebuffer ) {
|
|
|
|
if( renderTarget.depthBuffer === undefined ) renderTarget.depthBuffer = true;
|
|
if( renderTarget.stencilBuffer === undefined ) renderTarget.stencilBuffer = true;
|
|
|
|
renderTarget.__webglTexture = _gl.createTexture();
|
|
|
|
// Setup texture, create render and frame buffers
|
|
|
|
if ( isCube ) {
|
|
|
|
renderTarget.__webglFramebuffer = [];
|
|
renderTarget.__webglRenderbuffer = [];
|
|
|
|
_gl.bindTexture( _gl.TEXTURE_CUBE_MAP, renderTarget.__webglTexture );
|
|
setTextureParameters( _gl.TEXTURE_CUBE_MAP, renderTarget, renderTarget );
|
|
|
|
for ( var i = 0; i < 6; i ++ ) {
|
|
|
|
renderTarget.__webglFramebuffer[ i ] = _gl.createFramebuffer();
|
|
renderTarget.__webglRenderbuffer[ i ] = _gl.createRenderbuffer();
|
|
|
|
_gl.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, paramThreeToGL( renderTarget.format ), renderTarget.width, renderTarget.height, 0, paramThreeToGL( renderTarget.format ), paramThreeToGL( renderTarget.type ), null );
|
|
|
|
setupFrameBuffer( renderTarget.__webglFramebuffer[ i ], renderTarget, _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i );
|
|
setupRenderBuffer( renderTarget.__webglRenderbuffer[ i ], renderTarget );
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
renderTarget.__webglFramebuffer = _gl.createFramebuffer();
|
|
renderTarget.__webglRenderbuffer = _gl.createRenderbuffer();
|
|
|
|
_gl.bindTexture( _gl.TEXTURE_2D, renderTarget.__webglTexture );
|
|
setTextureParameters( _gl.TEXTURE_2D, renderTarget, renderTarget );
|
|
|
|
_gl.texImage2D( _gl.TEXTURE_2D, 0, paramThreeToGL( renderTarget.format ), renderTarget.width, renderTarget.height, 0, paramThreeToGL( renderTarget.format ), paramThreeToGL( renderTarget.type ), null );
|
|
|
|
setupFrameBuffer( renderTarget.__webglFramebuffer, renderTarget, _gl.TEXTURE_2D );
|
|
setupRenderBuffer( renderTarget.__webglRenderbuffer, renderTarget );
|
|
|
|
}
|
|
|
|
// Release everything
|
|
|
|
if ( isCube ) {
|
|
|
|
_gl.bindTexture( _gl.TEXTURE_CUBE_MAP, null );
|
|
|
|
} else {
|
|
|
|
_gl.bindTexture( _gl.TEXTURE_2D, null );
|
|
|
|
}
|
|
|
|
_gl.bindRenderbuffer( _gl.RENDERBUFFER, null );
|
|
_gl.bindFramebuffer( _gl.FRAMEBUFFER, null);
|
|
|
|
}
|
|
|
|
var framebuffer, width, height, vx, vy;
|
|
|
|
if ( renderTarget ) {
|
|
|
|
if ( isCube ) {
|
|
|
|
framebuffer = renderTarget.__webglFramebuffer[ renderTarget.activeCubeFace ];
|
|
|
|
} else {
|
|
|
|
framebuffer = renderTarget.__webglFramebuffer;
|
|
|
|
}
|
|
|
|
width = renderTarget.width;
|
|
height = renderTarget.height;
|
|
|
|
vx = 0;
|
|
vy = 0;
|
|
|
|
} else {
|
|
|
|
framebuffer = null;
|
|
|
|
width = _viewportWidth;
|
|
height = _viewportHeight;
|
|
|
|
vx = _viewportX;
|
|
vy = _viewportY;
|
|
|
|
}
|
|
|
|
if ( framebuffer !== _currentFramebuffer ) {
|
|
|
|
_gl.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );
|
|
_gl.viewport( vx, vy, width, height );
|
|
|
|
_currentFramebuffer = framebuffer;
|
|
|
|
}
|
|
|
|
_currentWidth = width;
|
|
_currentHeight = height;
|
|
|
|
};
|
|
|
|
function updateRenderTargetMipmap ( renderTarget ) {
|
|
|
|
if ( renderTarget instanceof THREE.WebGLRenderTargetCube ) {
|
|
|
|
_gl.bindTexture( _gl.TEXTURE_CUBE_MAP, renderTarget.__webglTexture );
|
|
_gl.generateMipmap( _gl.TEXTURE_CUBE_MAP );
|
|
_gl.bindTexture( _gl.TEXTURE_CUBE_MAP, null );
|
|
|
|
} else {
|
|
|
|
_gl.bindTexture( _gl.TEXTURE_2D, renderTarget.__webglTexture );
|
|
_gl.generateMipmap( _gl.TEXTURE_2D );
|
|
_gl.bindTexture( _gl.TEXTURE_2D, null );
|
|
|
|
}
|
|
|
|
};
|
|
|
|
// Fallback filters for non-power-of-2 textures
|
|
|
|
function filterFallback ( f ) {
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
// Map three.js constants to WebGL constants
|
|
|
|
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;
|
|
|
|
};
|
|
|
|
// Allocations
|
|
|
|
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 ) {
|
|
|
|
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.SpotLight ) dirLights ++; // hack, not a proper spotlight
|
|
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 };
|
|
|
|
};
|
|
|
|
function allocateShadows ( lights ) {
|
|
|
|
var l, ll, light, maxShadows = 0;
|
|
|
|
for ( l = 0, ll = lights.length; l < ll; l++ ) {
|
|
|
|
light = lights[ l ];
|
|
|
|
if ( light instanceof THREE.SpotLight && light.castShadow ) maxShadows ++;
|
|
|
|
}
|
|
|
|
return maxShadows;
|
|
|
|
};
|
|
|
|
function maxVertexTextures () {
|
|
|
|
return _gl.getParameter( _gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS );
|
|
|
|
};
|
|
|
|
// Initialization
|
|
|
|
function initGL () {
|
|
|
|
var gl;
|
|
|
|
try {
|
|
|
|
if ( ! ( gl = _canvas.getContext( 'experimental-webgl', { antialias: _antialias, stencil: _stencil, preserveDrawingBuffer: _preserveDrawingBuffer } ) ) ) {
|
|
|
|
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 );
|
|
|
|
}
|
|
|
|
return gl;
|
|
|
|
};
|
|
|
|
function setDefaultGLState () {
|
|
|
|
_gl.clearColor( 0, 0, 0, 1 );
|
|
_gl.clearDepth( 1 );
|
|
_gl.clearStencil( 0 );
|
|
|
|
_gl.enable( _gl.DEPTH_TEST );
|
|
_gl.depthFunc( _gl.LEQUAL );
|
|
|
|
_gl.frontFace( _gl.CCW );
|
|
_gl.cullFace( _gl.BACK );
|
|
_gl.enable( _gl.CULL_FACE );
|
|
|
|
_gl.enable( _gl.BLEND );
|
|
_gl.blendEquation( _gl.FUNC_ADD );
|
|
_gl.blendFunc( _gl.SRC_ALPHA, _gl.ONE_MINUS_SRC_ALPHA );
|
|
|
|
_gl.clearColor( _clearColor.r, _clearColor.g, _clearColor.b, _clearAlpha );
|
|
|
|
};
|
|
|
|
// default plugins (order is important)
|
|
|
|
this.shadowMapPlugin = new THREE.ShadowMapPlugin();
|
|
this.addPrePlugin( this.shadowMapPlugin );
|
|
|
|
this.addPostPlugin( new THREE.SpritePlugin() );
|
|
this.addPostPlugin( new THREE.LensFlarePlugin() );
|
|
|
|
};
|