mirror of
https://github.com/wahyd4/three.js.git
synced 2026-08-17 00:45:55 +10:00
3987 lines
92 KiB
JavaScript
3987 lines
92 KiB
JavaScript
/**
|
|
* @author supereggbert / http://www.paulbrunt.co.uk/
|
|
* @author mrdoob / http://mrdoob.com/
|
|
* @author alteredq / http://alteredqualia.com/
|
|
* @author szimek / https://github.com/szimek/
|
|
*/
|
|
|
|
THREE.WebGLRenderer = function ( parameters ) {
|
|
|
|
// Currently you can use just up to 4 directional / point lights total.
|
|
// Chrome barfs on shader linking when there are more than 4 lights :(
|
|
|
|
// The problem comes from shader using too many varying vectors.
|
|
|
|
// This is not GPU limitation as the same shader works ok in Firefox
|
|
// and Chrome with "--use-gl=desktop" flag.
|
|
|
|
// Difference comes from Chrome on Windows using by default ANGLE,
|
|
// thus going DirectX9 route (while FF uses OpenGL).
|
|
|
|
// See http://code.google.com/p/chromium/issues/detail?id=63491
|
|
|
|
var _canvas = document.createElement( 'canvas' ), _gl,
|
|
_oldProgram = null,
|
|
_oldFramebuffer = null,
|
|
|
|
_this = this,
|
|
|
|
// gl state cache
|
|
|
|
_oldDoubleSided = null,
|
|
_oldFlipSided = null,
|
|
_oldBlending = null,
|
|
_oldDepth = null,
|
|
|
|
_viewportX = 0,
|
|
_viewportY = 0,
|
|
_viewportWidth = 0,
|
|
_viewportHeight = 0,
|
|
|
|
// camera matrices caches
|
|
|
|
_frustum = [
|
|
new THREE.Vector4(),
|
|
new THREE.Vector4(),
|
|
new THREE.Vector4(),
|
|
new THREE.Vector4(),
|
|
new THREE.Vector4(),
|
|
new THREE.Vector4()
|
|
],
|
|
|
|
_projScreenMatrix = new THREE.Matrix4(),
|
|
_projectionMatrixArray = new Float32Array( 16 ),
|
|
_viewMatrixArray = new Float32Array( 16 ),
|
|
|
|
_vector3 = new THREE.Vector4(),
|
|
|
|
// light arrays cache
|
|
|
|
_lights = {
|
|
|
|
ambient: [ 0, 0, 0 ],
|
|
directional: { length: 0, colors: new Array(), positions: new Array() },
|
|
point: { length: 0, colors: new Array(), positions: new Array() }
|
|
|
|
},
|
|
|
|
// parameters defaults
|
|
|
|
antialias = true,
|
|
clearColor = new THREE.Color( 0x000000 ),
|
|
clearAlpha = 0;
|
|
|
|
if ( parameters ) {
|
|
|
|
if ( parameters.antialias !== undefined ) antialias = parameters.antialias;
|
|
if ( parameters.clearColor !== undefined ) clearColor.setHex( parameters.clearColor );
|
|
if ( parameters.clearAlpha !== undefined ) clearAlpha = parameters.clearAlpha;
|
|
|
|
}
|
|
|
|
this.domElement = _canvas;
|
|
this.autoClear = true;
|
|
this.sortObjects = true;
|
|
|
|
initGL( antialias, clearColor, clearAlpha );
|
|
|
|
this.context = _gl;
|
|
|
|
//alert( dumpObject( getGLParams() ) );
|
|
|
|
this.setSize = function ( width, height ) {
|
|
|
|
_canvas.width = width;
|
|
_canvas.height = height;
|
|
|
|
this.setViewport( 0, 0, _canvas.width, _canvas.height );
|
|
|
|
};
|
|
|
|
this.setViewport = function ( x, y, width, height ) {
|
|
|
|
_viewportX = x;
|
|
_viewportY = y;
|
|
|
|
_viewportWidth = width;
|
|
_viewportHeight = height;
|
|
|
|
_gl.viewport( _viewportX, _viewportY, _viewportWidth, _viewportHeight );
|
|
|
|
};
|
|
|
|
this.setScissor = function ( x, y, width, height ) {
|
|
|
|
_gl.scissor( x, y, width, height );
|
|
|
|
};
|
|
|
|
this.enableScissorTest = function ( enable ) {
|
|
|
|
if ( enable )
|
|
_gl.enable( _gl.SCISSOR_TEST );
|
|
else
|
|
_gl.disable( _gl.SCISSOR_TEST );
|
|
|
|
};
|
|
|
|
this.enableDepthBufferWrite = function ( enable ) {
|
|
|
|
_gl.depthMask( enable );
|
|
|
|
};
|
|
|
|
this.setClearColorHex = function ( hex, alpha ) {
|
|
|
|
var color = new THREE.Color( hex );
|
|
_gl.clearColor( color.r, color.g, color.b, alpha );
|
|
|
|
};
|
|
|
|
this.setClearColor = function ( color, alpha ) {
|
|
|
|
_gl.clearColor( color.r, color.g, color.b, alpha );
|
|
|
|
};
|
|
|
|
this.clear = function () {
|
|
|
|
_gl.clear( _gl.COLOR_BUFFER_BIT | _gl.DEPTH_BUFFER_BIT );
|
|
|
|
};
|
|
|
|
|
|
function setupLights ( program, lights ) {
|
|
|
|
var l, ll, light, r = 0, g = 0, b = 0,
|
|
color, position, intensity,
|
|
|
|
zlights = _lights,
|
|
|
|
dcolors = zlights.directional.colors,
|
|
dpositions = zlights.directional.positions,
|
|
|
|
pcolors = zlights.point.colors,
|
|
ppositions = zlights.point.positions,
|
|
|
|
dlength = 0,
|
|
plength = 0,
|
|
|
|
doffset = 0,
|
|
poffset = 0;
|
|
|
|
for ( l = 0, ll = lights.length; l < ll; l++ ) {
|
|
|
|
light = lights[ l ];
|
|
color = light.color;
|
|
position = light.position;
|
|
intensity = light.intensity;
|
|
|
|
if ( light instanceof THREE.AmbientLight ) {
|
|
|
|
r += color.r;
|
|
g += color.g;
|
|
b += color.b;
|
|
|
|
} else if ( light instanceof THREE.DirectionalLight ) {
|
|
|
|
doffset = dlength * 3;
|
|
|
|
dcolors[ doffset ] = color.r * intensity;
|
|
dcolors[ doffset + 1 ] = color.g * intensity;
|
|
dcolors[ doffset + 2 ] = color.b * intensity;
|
|
|
|
dpositions[ doffset ] = position.x;
|
|
dpositions[ doffset + 1 ] = position.y;
|
|
dpositions[ doffset + 2 ] = position.z;
|
|
|
|
dlength += 1;
|
|
|
|
} else if( light instanceof THREE.PointLight ) {
|
|
|
|
poffset = plength * 3;
|
|
|
|
pcolors[ poffset ] = color.r * intensity;
|
|
pcolors[ poffset + 1 ] = color.g * intensity;
|
|
pcolors[ poffset + 2 ] = color.b * intensity;
|
|
|
|
ppositions[ poffset ] = position.x;
|
|
ppositions[ poffset + 1 ] = position.y;
|
|
ppositions[ poffset + 2 ] = position.z;
|
|
|
|
plength += 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// null eventual remains from removed lights
|
|
// (this is to avoid if in shader)
|
|
|
|
for( l = dlength * 3; l < dcolors.length; l++ ) dcolors[ l ] = 0.0;
|
|
for( l = plength * 3; l < pcolors.length; l++ ) pcolors[ l ] = 0.0;
|
|
|
|
zlights.point.length = plength;
|
|
zlights.directional.length = dlength;
|
|
|
|
zlights.ambient[ 0 ] = r;
|
|
zlights.ambient[ 1 ] = g;
|
|
zlights.ambient[ 2 ] = b;
|
|
|
|
};
|
|
|
|
function createParticleBuffers ( geometry ) {
|
|
|
|
geometry.__webGLVertexBuffer = _gl.createBuffer();
|
|
geometry.__webGLColorBuffer = _gl.createBuffer();
|
|
|
|
};
|
|
|
|
function createLineBuffers ( geometry ) {
|
|
|
|
geometry.__webGLVertexBuffer = _gl.createBuffer();
|
|
geometry.__webGLColorBuffer = _gl.createBuffer();
|
|
|
|
};
|
|
|
|
function createRibbonBuffers ( geometry ) {
|
|
|
|
geometry.__webGLVertexBuffer = _gl.createBuffer();
|
|
geometry.__webGLColorBuffer = _gl.createBuffer();
|
|
|
|
};
|
|
|
|
function createMeshBuffers( geometryGroup ) {
|
|
|
|
geometryGroup.__webGLVertexBuffer = _gl.createBuffer();
|
|
geometryGroup.__webGLNormalBuffer = _gl.createBuffer();
|
|
geometryGroup.__webGLTangentBuffer = _gl.createBuffer();
|
|
geometryGroup.__webGLColorBuffer = _gl.createBuffer();
|
|
geometryGroup.__webGLUVBuffer = _gl.createBuffer();
|
|
geometryGroup.__webGLUV2Buffer = _gl.createBuffer();
|
|
|
|
geometryGroup.__webGLSkinVertexABuffer = _gl.createBuffer();
|
|
geometryGroup.__webGLSkinVertexBBuffer = _gl.createBuffer();
|
|
geometryGroup.__webGLSkinIndicesBuffer = _gl.createBuffer();
|
|
geometryGroup.__webGLSkinWeightsBuffer = _gl.createBuffer();
|
|
|
|
geometryGroup.__webGLFaceBuffer = _gl.createBuffer();
|
|
geometryGroup.__webGLLineBuffer = _gl.createBuffer();
|
|
|
|
};
|
|
|
|
function initLineBuffers( geometry ) {
|
|
|
|
var nvertices = geometry.vertices.length;
|
|
|
|
geometry.__vertexArray = new Float32Array( nvertices * 3 );
|
|
geometry.__colorArray = new Float32Array( nvertices * 3 );
|
|
|
|
geometry.__webGLLineCount = nvertices;
|
|
|
|
};
|
|
|
|
function initRibbonBuffers( geometry ) {
|
|
|
|
var nvertices = geometry.vertices.length;
|
|
|
|
geometry.__vertexArray = new Float32Array( nvertices * 3 );
|
|
geometry.__colorArray = new Float32Array( nvertices * 3 );
|
|
|
|
geometry.__webGLVertexCount = nvertices;
|
|
|
|
};
|
|
|
|
function initParticleBuffers( geometry ) {
|
|
|
|
var nvertices = geometry.vertices.length;
|
|
|
|
geometry.__vertexArray = new Float32Array( nvertices * 3 );
|
|
geometry.__colorArray = new Float32Array( nvertices * 3 );
|
|
|
|
geometry.__sortArray = [];
|
|
|
|
geometry.__webGLParticleCount = nvertices;
|
|
|
|
};
|
|
|
|
function initMeshBuffers( geometryGroup, object ) {
|
|
|
|
var f, fl, nvertices = 0, ntris = 0, nlines = 0,
|
|
obj_faces = object.geometry.faces,
|
|
chunk_faces = geometryGroup.faces;
|
|
|
|
for ( f = 0, fl = chunk_faces.length; f < fl; f++ ) {
|
|
|
|
fi = chunk_faces[ f ];
|
|
face = obj_faces[ fi ];
|
|
|
|
if ( face instanceof THREE.Face3 ) {
|
|
|
|
nvertices += 3;
|
|
ntris += 1;
|
|
nlines += 3;
|
|
|
|
} else if ( face instanceof THREE.Face4 ) {
|
|
|
|
nvertices += 4;
|
|
ntris += 2;
|
|
nlines += 4;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// TODO: only create arrays for attributes existing in the object
|
|
|
|
geometryGroup.__vertexArray = new Float32Array( nvertices * 3 );
|
|
geometryGroup.__normalArray = new Float32Array( nvertices * 3 );
|
|
geometryGroup.__tangentArray = new Float32Array( nvertices * 4 );
|
|
geometryGroup.__colorArray = new Float32Array( nvertices * 3 );
|
|
geometryGroup.__uvArray = new Float32Array( nvertices * 2 );
|
|
geometryGroup.__uv2Array = new Float32Array( nvertices * 2 );
|
|
|
|
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 );
|
|
|
|
geometryGroup.__needsSmoothNormals = bufferNeedsSmoothNormals ( geometryGroup, object );
|
|
|
|
geometryGroup.__webGLFaceCount = ntris * 3;
|
|
geometryGroup.__webGLLineCount = nlines * 2;
|
|
|
|
};
|
|
|
|
function setMeshBuffers( geometryGroup, object, hint ) {
|
|
|
|
var f, fl, fi, face, vertexNormals, faceNormal, normal,
|
|
uv, uv2, v1, v2, v3, v4, t1, t2, t3, t4,
|
|
c1, c2, c3, c4,
|
|
sw1, sw2, sw3, sw4,
|
|
si1, si2, si3, si4,
|
|
sa1, sa2, sa3, sa4,
|
|
sb1, sb2, sb3, sb4,
|
|
m, ml, i,
|
|
vn, uvi, uv2i,
|
|
|
|
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,
|
|
|
|
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,
|
|
|
|
faceArray = geometryGroup.__faceArray,
|
|
lineArray = geometryGroup.__lineArray,
|
|
|
|
needsSmoothNormals = geometryGroup.__needsSmoothNormals,
|
|
|
|
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,
|
|
|
|
vertices = geometry.vertices,
|
|
chunk_faces = geometryGroup.faces,
|
|
obj_faces = geometry.faces,
|
|
obj_uvs = geometry.uvs,
|
|
obj_uvs2 = geometry.uvs2,
|
|
obj_colors = geometry.colors,
|
|
|
|
obj_skinVerticesA = geometry.skinVerticesA,
|
|
obj_skinVerticesB = geometry.skinVerticesB,
|
|
obj_skinIndices = geometry.skinIndices,
|
|
obj_skinWeights = geometry.skinWeights;
|
|
|
|
for ( f = 0, fl = chunk_faces.length; f < fl; f++ ) {
|
|
|
|
fi = chunk_faces[ f ];
|
|
face = obj_faces[ fi ];
|
|
uv = obj_uvs[ fi ];
|
|
uv2 = obj_uvs2[ fi ];
|
|
|
|
vertexNormals = face.vertexNormals;
|
|
faceNormal = face.normal;
|
|
|
|
if ( face instanceof THREE.Face3 ) {
|
|
|
|
if ( dirtyVertices ) {
|
|
|
|
v1 = vertices[ face.a ].position;
|
|
v2 = vertices[ face.b ].position;
|
|
v3 = vertices[ face.c ].position;
|
|
|
|
vertexArray[ offset ] = v1.x;
|
|
vertexArray[ offset + 1 ] = v1.y;
|
|
vertexArray[ offset + 2 ] = v1.z;
|
|
|
|
vertexArray[ offset + 3 ] = v2.x;
|
|
vertexArray[ offset + 4 ] = v2.y;
|
|
vertexArray[ offset + 5 ] = v2.z;
|
|
|
|
vertexArray[ offset + 6 ] = v3.x;
|
|
vertexArray[ offset + 7 ] = v3.y;
|
|
vertexArray[ offset + 8 ] = v3.z;
|
|
|
|
offset += 9;
|
|
|
|
}
|
|
|
|
if ( obj_skinWeights.length ) {
|
|
|
|
// weights
|
|
|
|
sw1 = obj_skinWeights[ face.a ];
|
|
sw2 = obj_skinWeights[ face.b ];
|
|
sw3 = obj_skinWeights[ face.c ];
|
|
|
|
skinWeightArray[ offset_skin ] = sw1.x;
|
|
skinWeightArray[ offset_skin + 1 ] = sw1.y;
|
|
skinWeightArray[ offset_skin + 2 ] = sw1.z;
|
|
skinWeightArray[ offset_skin + 3 ] = sw1.w;
|
|
|
|
skinWeightArray[ offset_skin + 4 ] = sw2.x;
|
|
skinWeightArray[ offset_skin + 5 ] = sw2.y;
|
|
skinWeightArray[ offset_skin + 6 ] = sw2.z;
|
|
skinWeightArray[ offset_skin + 7 ] = sw2.w;
|
|
|
|
skinWeightArray[ offset_skin + 8 ] = sw3.x;
|
|
skinWeightArray[ offset_skin + 9 ] = sw3.y;
|
|
skinWeightArray[ offset_skin + 10 ] = sw3.z;
|
|
skinWeightArray[ offset_skin + 11 ] = sw3.w;
|
|
|
|
// indices
|
|
|
|
si1 = obj_skinIndices[ face.a ];
|
|
si2 = obj_skinIndices[ face.b ];
|
|
si3 = obj_skinIndices[ face.c ];
|
|
|
|
skinIndexArray[ offset_skin ] = si1.x;
|
|
skinIndexArray[ offset_skin + 1 ] = si1.y;
|
|
skinIndexArray[ offset_skin + 2 ] = si1.z;
|
|
skinIndexArray[ offset_skin + 3 ] = si1.w;
|
|
|
|
skinIndexArray[ offset_skin + 4 ] = si2.x;
|
|
skinIndexArray[ offset_skin + 5 ] = si2.y;
|
|
skinIndexArray[ offset_skin + 6 ] = si2.z;
|
|
skinIndexArray[ offset_skin + 7 ] = si2.w;
|
|
|
|
skinIndexArray[ offset_skin + 8 ] = si3.x;
|
|
skinIndexArray[ offset_skin + 9 ] = si3.y;
|
|
skinIndexArray[ offset_skin + 10 ] = si3.z;
|
|
skinIndexArray[ offset_skin + 11 ] = si3.w;
|
|
|
|
// vertices A
|
|
|
|
sa1 = obj_skinVerticesA[ face.a ];
|
|
sa2 = obj_skinVerticesA[ face.b ];
|
|
sa3 = obj_skinVerticesA[ face.c ];
|
|
|
|
skinVertexAArray[ offset_skin ] = sa1.x;
|
|
skinVertexAArray[ offset_skin + 1 ] = sa1.y;
|
|
skinVertexAArray[ offset_skin + 2 ] = sa1.z;
|
|
skinVertexAArray[ offset_skin + 3 ] = 1; // pad for faster vertex shader
|
|
|
|
skinVertexAArray[ offset_skin + 4 ] = sa2.x;
|
|
skinVertexAArray[ offset_skin + 5 ] = sa2.y;
|
|
skinVertexAArray[ offset_skin + 6 ] = sa2.z;
|
|
skinVertexAArray[ offset_skin + 7 ] = 1;
|
|
|
|
skinVertexAArray[ offset_skin + 8 ] = sa3.x;
|
|
skinVertexAArray[ offset_skin + 9 ] = sa3.y;
|
|
skinVertexAArray[ offset_skin + 10 ] = sa3.z;
|
|
skinVertexAArray[ offset_skin + 11 ] = 1;
|
|
|
|
// vertices B
|
|
|
|
sb1 = obj_skinVerticesB[ face.a ];
|
|
sb2 = obj_skinVerticesB[ face.b ];
|
|
sb3 = obj_skinVerticesB[ face.c ];
|
|
|
|
skinVertexBArray[ offset_skin ] = sb1.x;
|
|
skinVertexBArray[ offset_skin + 1 ] = sb1.y;
|
|
skinVertexBArray[ offset_skin + 2 ] = sb1.z;
|
|
skinVertexBArray[ offset_skin + 3 ] = 1; // pad for faster vertex shader
|
|
|
|
skinVertexBArray[ offset_skin + 4 ] = sb2.x;
|
|
skinVertexBArray[ offset_skin + 5 ] = sb2.y;
|
|
skinVertexBArray[ offset_skin + 6 ] = sb2.z;
|
|
skinVertexBArray[ offset_skin + 7 ] = 1;
|
|
|
|
skinVertexBArray[ offset_skin + 8 ] = sb3.x;
|
|
skinVertexBArray[ offset_skin + 9 ] = sb3.y;
|
|
skinVertexBArray[ offset_skin + 10 ] = sb3.z;
|
|
skinVertexBArray[ offset_skin + 11 ] = 1;
|
|
|
|
offset_skin += 12;
|
|
|
|
}
|
|
|
|
if ( dirtyColors && obj_colors.length ) {
|
|
|
|
c1 = obj_colors[ face.a ];
|
|
c2 = obj_colors[ face.b ];
|
|
c3 = obj_colors[ face.c ];
|
|
|
|
colorArray[ offset_color ] = c1.r;
|
|
colorArray[ offset_color + 1 ] = c1.g;
|
|
colorArray[ offset_color + 2 ] = c1.b;
|
|
|
|
colorArray[ offset_color + 3 ] = c2.r;
|
|
colorArray[ offset_color + 4 ] = c2.g;
|
|
colorArray[ offset_color + 5 ] = c2.b;
|
|
|
|
colorArray[ offset_color + 6 ] = c3.r;
|
|
colorArray[ offset_color + 7 ] = c3.g;
|
|
colorArray[ offset_color + 8 ] = c3.b;
|
|
|
|
offset_color += 9;
|
|
|
|
}
|
|
|
|
if ( dirtyTangents && geometry.hasTangents ) {
|
|
|
|
t1 = vertices[ face.a ].tangent;
|
|
t2 = vertices[ face.b ].tangent;
|
|
t3 = vertices[ face.c ].tangent;
|
|
|
|
tangentArray[ offset_tangent ] = t1.x;
|
|
tangentArray[ offset_tangent + 1 ] = t1.y;
|
|
tangentArray[ offset_tangent + 2 ] = t1.z;
|
|
tangentArray[ offset_tangent + 3 ] = t1.w;
|
|
|
|
tangentArray[ offset_tangent + 4 ] = t2.x;
|
|
tangentArray[ offset_tangent + 5 ] = t2.y;
|
|
tangentArray[ offset_tangent + 6 ] = t2.z;
|
|
tangentArray[ offset_tangent + 7 ] = t2.w;
|
|
|
|
tangentArray[ offset_tangent + 8 ] = t3.x;
|
|
tangentArray[ offset_tangent + 9 ] = t3.y;
|
|
tangentArray[ offset_tangent + 10 ] = t3.z;
|
|
tangentArray[ offset_tangent + 11 ] = t3.w;
|
|
|
|
offset_tangent += 12;
|
|
|
|
}
|
|
|
|
if ( dirtyNormals ) {
|
|
|
|
if ( vertexNormals.length == 3 && needsSmoothNormals ) {
|
|
|
|
for ( i = 0; i < 3; i ++ ) {
|
|
|
|
vn = vertexNormals[ i ];
|
|
|
|
normalArray[ offset_normal ] = vn.x;
|
|
normalArray[ offset_normal + 1 ] = vn.y;
|
|
normalArray[ offset_normal + 2 ] = vn.z;
|
|
|
|
offset_normal += 3;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
for ( i = 0; i < 3; i ++ ) {
|
|
|
|
normalArray[ offset_normal ] = faceNormal.x;
|
|
normalArray[ offset_normal + 1 ] = faceNormal.y;
|
|
normalArray[ offset_normal + 2 ] = faceNormal.z;
|
|
|
|
offset_normal += 3;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ( dirtyUvs && uv ) {
|
|
|
|
for ( i = 0; i < 3; i ++ ) {
|
|
|
|
uvi = uv[ i ];
|
|
|
|
uvArray[ offset_uv ] = uvi.u;
|
|
uvArray[ offset_uv + 1 ] = uvi.v;
|
|
|
|
offset_uv += 2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ( dirtyUvs && uv2 ) {
|
|
|
|
for ( i = 0; i < 3; i ++ ) {
|
|
|
|
uv2i = uv2[ i ];
|
|
|
|
uv2Array[ offset_uv2 ] = uv2i.u;
|
|
uv2Array[ offset_uv2 + 1 ] = uv2i.v;
|
|
|
|
offset_uv2 += 2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if( dirtyElements ) {
|
|
|
|
faceArray[ offset_face ] = vertexIndex;
|
|
faceArray[ offset_face + 1 ] = vertexIndex + 1;
|
|
faceArray[ offset_face + 2 ] = vertexIndex + 2;
|
|
|
|
offset_face += 3;
|
|
|
|
lineArray[ offset_line ] = vertexIndex;
|
|
lineArray[ offset_line + 1 ] = vertexIndex + 1;
|
|
|
|
lineArray[ offset_line + 2 ] = vertexIndex;
|
|
lineArray[ offset_line + 3 ] = vertexIndex + 2;
|
|
|
|
lineArray[ offset_line + 4 ] = vertexIndex + 1;
|
|
lineArray[ offset_line + 5 ] = vertexIndex + 2;
|
|
|
|
offset_line += 6;
|
|
|
|
vertexIndex += 3;
|
|
|
|
}
|
|
|
|
|
|
} else if ( face instanceof THREE.Face4 ) {
|
|
|
|
if ( dirtyVertices ) {
|
|
|
|
v1 = vertices[ face.a ].position;
|
|
v2 = vertices[ face.b ].position;
|
|
v3 = vertices[ face.c ].position;
|
|
v4 = vertices[ face.d ].position;
|
|
|
|
vertexArray[ offset ] = v1.x;
|
|
vertexArray[ offset + 1 ] = v1.y;
|
|
vertexArray[ offset + 2 ] = v1.z;
|
|
|
|
vertexArray[ offset + 3 ] = v2.x;
|
|
vertexArray[ offset + 4 ] = v2.y;
|
|
vertexArray[ offset + 5 ] = v2.z;
|
|
|
|
vertexArray[ offset + 6 ] = v3.x;
|
|
vertexArray[ offset + 7 ] = v3.y;
|
|
vertexArray[ offset + 8 ] = v3.z;
|
|
|
|
vertexArray[ offset + 9 ] = v4.x;
|
|
vertexArray[ offset + 10 ] = v4.y;
|
|
vertexArray[ offset + 11 ] = v4.z;
|
|
|
|
offset += 12;
|
|
|
|
}
|
|
|
|
if ( obj_skinWeights.length ) {
|
|
|
|
// weights
|
|
|
|
sw1 = obj_skinWeights[ face.a ];
|
|
sw2 = obj_skinWeights[ face.b ];
|
|
sw3 = obj_skinWeights[ face.c ];
|
|
sw4 = obj_skinWeights[ face.d ];
|
|
|
|
skinWeightArray[ offset_skin ] = sw1.x;
|
|
skinWeightArray[ offset_skin + 1 ] = sw1.y;
|
|
skinWeightArray[ offset_skin + 2 ] = sw1.z;
|
|
skinWeightArray[ offset_skin + 3 ] = sw1.w;
|
|
|
|
skinWeightArray[ offset_skin + 4 ] = sw2.x;
|
|
skinWeightArray[ offset_skin + 5 ] = sw2.y;
|
|
skinWeightArray[ offset_skin + 6 ] = sw2.z;
|
|
skinWeightArray[ offset_skin + 7 ] = sw2.w;
|
|
|
|
skinWeightArray[ offset_skin + 8 ] = sw3.x;
|
|
skinWeightArray[ offset_skin + 9 ] = sw3.y;
|
|
skinWeightArray[ offset_skin + 10 ] = sw3.z;
|
|
skinWeightArray[ offset_skin + 11 ] = sw3.w;
|
|
|
|
skinWeightArray[ offset_skin + 12 ] = sw4.x;
|
|
skinWeightArray[ offset_skin + 13 ] = sw4.y;
|
|
skinWeightArray[ offset_skin + 14 ] = sw4.z;
|
|
skinWeightArray[ offset_skin + 15 ] = sw4.w;
|
|
|
|
// indices
|
|
|
|
si1 = obj_skinIndices[ face.a ];
|
|
si2 = obj_skinIndices[ face.b ];
|
|
si3 = obj_skinIndices[ face.c ];
|
|
si4 = obj_skinIndices[ face.d ];
|
|
|
|
skinIndexArray[ offset_skin ] = si1.x;
|
|
skinIndexArray[ offset_skin + 1 ] = si1.y;
|
|
skinIndexArray[ offset_skin + 2 ] = si1.z;
|
|
skinIndexArray[ offset_skin + 3 ] = si1.w;
|
|
|
|
skinIndexArray[ offset_skin + 4 ] = si2.x;
|
|
skinIndexArray[ offset_skin + 5 ] = si2.y;
|
|
skinIndexArray[ offset_skin + 6 ] = si2.z;
|
|
skinIndexArray[ offset_skin + 7 ] = si2.w;
|
|
|
|
skinIndexArray[ offset_skin + 8 ] = si3.x;
|
|
skinIndexArray[ offset_skin + 9 ] = si3.y;
|
|
skinIndexArray[ offset_skin + 10 ] = si3.z;
|
|
skinIndexArray[ offset_skin + 11 ] = si3.w;
|
|
|
|
skinIndexArray[ offset_skin + 12 ] = si4.x;
|
|
skinIndexArray[ offset_skin + 13 ] = si4.y;
|
|
skinIndexArray[ offset_skin + 14 ] = si4.z;
|
|
skinIndexArray[ offset_skin + 15 ] = si4.w;
|
|
|
|
// vertices A
|
|
|
|
sa1 = obj_skinVerticesA[ face.a ];
|
|
sa2 = obj_skinVerticesA[ face.b ];
|
|
sa3 = obj_skinVerticesA[ face.c ];
|
|
sa4 = obj_skinVerticesA[ face.d ];
|
|
|
|
skinVertexAArray[ offset_skin ] = sa1.x;
|
|
skinVertexAArray[ offset_skin + 1 ] = sa1.y;
|
|
skinVertexAArray[ offset_skin + 2 ] = sa1.z;
|
|
skinVertexAArray[ offset_skin + 3 ] = 1; // pad for faster vertex shader
|
|
|
|
skinVertexAArray[ offset_skin + 4 ] = sa2.x;
|
|
skinVertexAArray[ offset_skin + 5 ] = sa2.y;
|
|
skinVertexAArray[ offset_skin + 6 ] = sa2.z;
|
|
skinVertexAArray[ offset_skin + 7 ] = 1;
|
|
|
|
skinVertexAArray[ offset_skin + 8 ] = sa3.x;
|
|
skinVertexAArray[ offset_skin + 9 ] = sa3.y;
|
|
skinVertexAArray[ offset_skin + 10 ] = sa3.z;
|
|
skinVertexAArray[ offset_skin + 11 ] = 1;
|
|
|
|
skinVertexAArray[ offset_skin + 12 ] = sa4.x;
|
|
skinVertexAArray[ offset_skin + 13 ] = sa4.y;
|
|
skinVertexAArray[ offset_skin + 14 ] = sa4.z;
|
|
skinVertexAArray[ offset_skin + 15 ] = 1;
|
|
|
|
// vertices B
|
|
|
|
sb1 = obj_skinVerticesB[ face.a ];
|
|
sb2 = obj_skinVerticesB[ face.b ];
|
|
sb3 = obj_skinVerticesB[ face.c ];
|
|
sb4 = obj_skinVerticesB[ face.d ];
|
|
|
|
skinVertexBArray[ offset_skin ] = sb1.x;
|
|
skinVertexBArray[ offset_skin + 1 ] = sb1.y;
|
|
skinVertexBArray[ offset_skin + 2 ] = sb1.z;
|
|
skinVertexBArray[ offset_skin + 3 ] = 1; // pad for faster vertex shader
|
|
|
|
skinVertexBArray[ offset_skin + 4 ] = sb2.x;
|
|
skinVertexBArray[ offset_skin + 5 ] = sb2.y;
|
|
skinVertexBArray[ offset_skin + 6 ] = sb2.z;
|
|
skinVertexBArray[ offset_skin + 7 ] = 1;
|
|
|
|
skinVertexBArray[ offset_skin + 8 ] = sb3.x;
|
|
skinVertexBArray[ offset_skin + 9 ] = sb3.y;
|
|
skinVertexBArray[ offset_skin + 10 ] = sb3.z;
|
|
skinVertexBArray[ offset_skin + 11 ] = 1;
|
|
|
|
skinVertexBArray[ offset_skin + 12 ] = sb4.x;
|
|
skinVertexBArray[ offset_skin + 13 ] = sb4.y;
|
|
skinVertexBArray[ offset_skin + 14 ] = sb4.z;
|
|
skinVertexBArray[ offset_skin + 15 ] = 1;
|
|
|
|
offset_skin += 16;
|
|
|
|
}
|
|
|
|
if ( dirtyColors && obj_colors.length ) {
|
|
|
|
c1 = obj_colors[ face.a ];
|
|
c2 = obj_colors[ face.b ];
|
|
c3 = obj_colors[ face.c ];
|
|
c4 = obj_colors[ face.d ];
|
|
|
|
colorArray[ offset_color ] = c1.r;
|
|
colorArray[ offset_color + 1 ] = c1.g;
|
|
colorArray[ offset_color + 2 ] = c1.b;
|
|
|
|
colorArray[ offset_color + 3 ] = c2.r;
|
|
colorArray[ offset_color + 4 ] = c2.g;
|
|
colorArray[ offset_color + 5 ] = c2.b;
|
|
|
|
colorArray[ offset_color + 6 ] = c3.r;
|
|
colorArray[ offset_color + 7 ] = c3.g;
|
|
colorArray[ offset_color + 8 ] = c3.b;
|
|
|
|
colorArray[ offset_color + 9 ] = c4.r;
|
|
colorArray[ offset_color + 10 ] = c4.g;
|
|
colorArray[ offset_color + 11 ] = c4.b;
|
|
|
|
offset_color += 12;
|
|
|
|
}
|
|
|
|
if ( dirtyTangents && geometry.hasTangents ) {
|
|
|
|
t1 = vertices[ face.a ].tangent;
|
|
t2 = vertices[ face.b ].tangent;
|
|
t3 = vertices[ face.c ].tangent;
|
|
t4 = vertices[ face.d ].tangent;
|
|
|
|
tangentArray[ offset_tangent ] = t1.x;
|
|
tangentArray[ offset_tangent + 1 ] = t1.y;
|
|
tangentArray[ offset_tangent + 2 ] = t1.z;
|
|
tangentArray[ offset_tangent + 3 ] = t1.w;
|
|
|
|
tangentArray[ offset_tangent + 4 ] = t2.x;
|
|
tangentArray[ offset_tangent + 5 ] = t2.y;
|
|
tangentArray[ offset_tangent + 6 ] = t2.z;
|
|
tangentArray[ offset_tangent + 7 ] = t2.w;
|
|
|
|
tangentArray[ offset_tangent + 8 ] = t3.x;
|
|
tangentArray[ offset_tangent + 9 ] = t3.y;
|
|
tangentArray[ offset_tangent + 10 ] = t3.z;
|
|
tangentArray[ offset_tangent + 11 ] = t3.w;
|
|
|
|
tangentArray[ offset_tangent + 12 ] = t4.x;
|
|
tangentArray[ offset_tangent + 13 ] = t4.y;
|
|
tangentArray[ offset_tangent + 14 ] = t4.z;
|
|
tangentArray[ offset_tangent + 15 ] = t4.w;
|
|
|
|
offset_tangent += 16;
|
|
|
|
}
|
|
|
|
if( dirtyNormals ) {
|
|
|
|
if ( vertexNormals.length == 4 && needsSmoothNormals ) {
|
|
|
|
for ( i = 0; i < 4; i ++ ) {
|
|
|
|
vn = vertexNormals[ i ];
|
|
|
|
normalArray[ offset_normal ] = vn.x;
|
|
normalArray[ offset_normal + 1 ] = vn.y;
|
|
normalArray[ offset_normal + 2 ] = vn.z;
|
|
|
|
offset_normal += 3;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
for ( i = 0; i < 4; i ++ ) {
|
|
|
|
normalArray[ offset_normal ] = faceNormal.x;
|
|
normalArray[ offset_normal + 1 ] = faceNormal.y;
|
|
normalArray[ offset_normal + 2 ] = faceNormal.z;
|
|
|
|
offset_normal += 3;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ( dirtyUvs && uv ) {
|
|
|
|
for ( i = 0; i < 4; i ++ ) {
|
|
|
|
uvi = uv[ i ];
|
|
|
|
uvArray[ offset_uv ] = uvi.u;
|
|
uvArray[ offset_uv + 1 ] = uvi.v;
|
|
|
|
offset_uv += 2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ( dirtyUvs && uv2 ) {
|
|
|
|
for ( i = 0; i < 4; i ++ ) {
|
|
|
|
uv2i = uv2[ i ];
|
|
|
|
uv2Array[ offset_uv2 ] = uv2i.u;
|
|
uv2Array[ offset_uv2 + 1 ] = uv2i.v;
|
|
|
|
offset_uv2 += 2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if( dirtyElements ) {
|
|
|
|
faceArray[ offset_face ] = vertexIndex;
|
|
faceArray[ offset_face + 1 ] = vertexIndex + 1;
|
|
faceArray[ offset_face + 2 ] = vertexIndex + 2;
|
|
|
|
faceArray[ offset_face + 3 ] = vertexIndex;
|
|
faceArray[ offset_face + 4 ] = vertexIndex + 2;
|
|
faceArray[ offset_face + 5 ] = vertexIndex + 3;
|
|
|
|
offset_face += 6;
|
|
|
|
lineArray[ offset_line ] = vertexIndex;
|
|
lineArray[ offset_line + 1 ] = vertexIndex + 1;
|
|
|
|
lineArray[ offset_line + 2 ] = vertexIndex;
|
|
lineArray[ offset_line + 3 ] = vertexIndex + 3;
|
|
|
|
lineArray[ offset_line + 4 ] = vertexIndex + 1;
|
|
lineArray[ offset_line + 5 ] = vertexIndex + 2;
|
|
|
|
lineArray[ offset_line + 6 ] = vertexIndex + 2;
|
|
lineArray[ offset_line + 7 ] = vertexIndex + 3;
|
|
|
|
offset_line += 8;
|
|
|
|
vertexIndex += 4;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ( dirtyVertices ) {
|
|
|
|
_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webGLVertexBuffer );
|
|
_gl.bufferData( _gl.ARRAY_BUFFER, vertexArray, hint );
|
|
|
|
}
|
|
|
|
if ( dirtyColors && obj_colors.length ) {
|
|
|
|
_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webGLColorBuffer );
|
|
_gl.bufferData( _gl.ARRAY_BUFFER, colorArray, hint );
|
|
|
|
}
|
|
|
|
if ( dirtyNormals ) {
|
|
|
|
_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webGLNormalBuffer );
|
|
_gl.bufferData( _gl.ARRAY_BUFFER, normalArray, hint );
|
|
|
|
}
|
|
|
|
if ( dirtyTangents && geometry.hasTangents ) {
|
|
|
|
_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webGLTangentBuffer );
|
|
_gl.bufferData( _gl.ARRAY_BUFFER, tangentArray, hint );
|
|
|
|
}
|
|
|
|
if ( dirtyUvs && offset_uv > 0 ) {
|
|
|
|
_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webGLUVBuffer );
|
|
_gl.bufferData( _gl.ARRAY_BUFFER, uvArray, hint );
|
|
|
|
}
|
|
|
|
if ( dirtyUvs && offset_uv2 > 0 ) {
|
|
|
|
_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webGLUV2Buffer );
|
|
_gl.bufferData( _gl.ARRAY_BUFFER, uv2Array, hint );
|
|
|
|
}
|
|
|
|
if ( dirtyElements ) {
|
|
|
|
_gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, geometryGroup.__webGLFaceBuffer );
|
|
_gl.bufferData( _gl.ELEMENT_ARRAY_BUFFER, faceArray, hint );
|
|
|
|
_gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, geometryGroup.__webGLLineBuffer );
|
|
_gl.bufferData( _gl.ELEMENT_ARRAY_BUFFER, lineArray, hint );
|
|
|
|
}
|
|
|
|
if ( offset_skin > 0 ) {
|
|
|
|
_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webGLSkinVertexABuffer );
|
|
_gl.bufferData( _gl.ARRAY_BUFFER, skinVertexAArray, hint );
|
|
|
|
_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webGLSkinVertexBBuffer );
|
|
_gl.bufferData( _gl.ARRAY_BUFFER, skinVertexBArray, hint );
|
|
|
|
_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webGLSkinIndicesBuffer );
|
|
_gl.bufferData( _gl.ARRAY_BUFFER, skinIndexArray, hint );
|
|
|
|
_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webGLSkinWeightsBuffer );
|
|
_gl.bufferData( _gl.ARRAY_BUFFER, skinWeightArray, hint );
|
|
|
|
}
|
|
|
|
};
|
|
|
|
function setLineBuffers( geometry, hint ) {
|
|
|
|
var v, c, vertex, offset,
|
|
vertices = geometry.vertices,
|
|
colors = geometry.colors,
|
|
vl = vertices.length,
|
|
cl = colors.length,
|
|
|
|
vertexArray = geometry.__vertexArray,
|
|
colorArray = geometry.__colorArray,
|
|
|
|
dirtyVertices = geometry.__dirtyVertices,
|
|
dirtyColors = geometry.__dirtyColors;
|
|
|
|
if ( dirtyVertices ) {
|
|
|
|
for ( v = 0; v < vl; v++ ) {
|
|
|
|
vertex = vertices[ v ].position;
|
|
|
|
offset = v * 3;
|
|
|
|
vertexArray[ offset ] = vertex.x;
|
|
vertexArray[ offset + 1 ] = vertex.y;
|
|
vertexArray[ offset + 2 ] = vertex.z;
|
|
|
|
}
|
|
|
|
_gl.bindBuffer( _gl.ARRAY_BUFFER, geometry.__webGLVertexBuffer );
|
|
_gl.bufferData( _gl.ARRAY_BUFFER, vertexArray, hint );
|
|
|
|
}
|
|
|
|
if ( dirtyColors ) {
|
|
|
|
for ( c = 0; c < cl; c++ ) {
|
|
|
|
color = colors[ c ];
|
|
|
|
offset = c * 3;
|
|
|
|
colorArray[ offset ] = color.r;
|
|
colorArray[ offset + 1 ] = color.g;
|
|
colorArray[ offset + 2 ] = color.b;
|
|
|
|
}
|
|
|
|
_gl.bindBuffer( _gl.ARRAY_BUFFER, geometry.__webGLColorBuffer );
|
|
_gl.bufferData( _gl.ARRAY_BUFFER, colorArray, hint );
|
|
|
|
}
|
|
|
|
};
|
|
|
|
function setRibbonBuffers( geometry, hint ) {
|
|
|
|
var v, c, vertex, offset,
|
|
vertices = geometry.vertices,
|
|
colors = geometry.colors,
|
|
vl = vertices.length,
|
|
cl = colors.length,
|
|
|
|
vertexArray = geometry.__vertexArray,
|
|
colorArray = geometry.__colorArray,
|
|
|
|
dirtyVertices = geometry.__dirtyVertices,
|
|
dirtyColors = geometry.__dirtyColors;
|
|
|
|
if ( dirtyVertices ) {
|
|
|
|
for ( v = 0; v < vl; v++ ) {
|
|
|
|
vertex = vertices[ v ].position;
|
|
|
|
offset = v * 3;
|
|
|
|
vertexArray[ offset ] = vertex.x;
|
|
vertexArray[ offset + 1 ] = vertex.y;
|
|
vertexArray[ offset + 2 ] = vertex.z;
|
|
|
|
}
|
|
|
|
_gl.bindBuffer( _gl.ARRAY_BUFFER, geometry.__webGLVertexBuffer );
|
|
_gl.bufferData( _gl.ARRAY_BUFFER, vertexArray, hint );
|
|
|
|
}
|
|
|
|
if ( dirtyColors ) {
|
|
|
|
for ( c = 0; c < cl; c++ ) {
|
|
|
|
color = colors[ c ];
|
|
|
|
offset = c * 3;
|
|
|
|
colorArray[ offset ] = color.r;
|
|
colorArray[ offset + 1 ] = color.g;
|
|
colorArray[ offset + 2 ] = color.b;
|
|
|
|
}
|
|
|
|
_gl.bindBuffer( _gl.ARRAY_BUFFER, geometry.__webGLColorBuffer );
|
|
_gl.bufferData( _gl.ARRAY_BUFFER, colorArray, hint );
|
|
|
|
}
|
|
|
|
};
|
|
|
|
function setParticleBuffers( geometry, hint, object ) {
|
|
|
|
var v, c, vertex, offset,
|
|
vertices = geometry.vertices,
|
|
vl = vertices.length,
|
|
|
|
colors = geometry.colors,
|
|
cl = colors.length,
|
|
|
|
vertexArray = geometry.__vertexArray,
|
|
colorArray = geometry.__colorArray,
|
|
|
|
sortArray = geometry.__sortArray,
|
|
|
|
dirtyVertices = geometry.__dirtyVertices,
|
|
dirtyElements = geometry.__dirtyElements,
|
|
dirtyColors = geometry.__dirtyColors;
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
} 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 ( 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 );
|
|
|
|
}
|
|
|
|
};
|
|
|
|
function setMaterialShaders( material, shaders ) {
|
|
|
|
material.fragmentShader = shaders.fragmentShader;
|
|
material.vertexShader = shaders.vertexShader;
|
|
material.uniforms = Uniforms.clone( shaders.uniforms );
|
|
|
|
};
|
|
|
|
function refreshUniformsCommon( uniforms, material ) {
|
|
|
|
// premultiply alpha
|
|
uniforms.diffuse.value.setRGB( material.color.r * material.opacity, material.color.g * material.opacity, material.color.b * material.opacity );
|
|
|
|
// pure color
|
|
//uniforms.color.value.setHex( material.color.hex );
|
|
|
|
uniforms.opacity.value = material.opacity;
|
|
uniforms.map.texture = material.map;
|
|
|
|
uniforms.lightMap.texture = material.lightMap;
|
|
|
|
uniforms.envMap.texture = material.envMap;
|
|
uniforms.reflectivity.value = material.reflectivity;
|
|
uniforms.refractionRatio.value = material.refractionRatio;
|
|
uniforms.combine.value = material.combine;
|
|
uniforms.useRefract.value = material.envMap && material.envMap.mapping instanceof THREE.CubeRefractionMapping;
|
|
|
|
};
|
|
|
|
function refreshUniformsLine( uniforms, material ) {
|
|
|
|
uniforms.diffuse.value.setRGB( material.color.r * material.opacity, material.color.g * material.opacity, material.color.b * material.opacity );
|
|
uniforms.opacity.value = material.opacity;
|
|
|
|
};
|
|
|
|
function refreshUniformsParticle( uniforms, material ) {
|
|
|
|
uniforms.psColor.value.setRGB( material.color.r * material.opacity, material.color.g * material.opacity, material.color.b * material.opacity );
|
|
uniforms.opacity.value = material.opacity;
|
|
uniforms.size.value = material.size;
|
|
uniforms.map.texture = material.map;
|
|
|
|
};
|
|
|
|
function refreshUniformsFog( uniforms, fog ) {
|
|
|
|
uniforms.fogColor.value.setHex( fog.color.hex );
|
|
|
|
if ( fog instanceof THREE.Fog ) {
|
|
|
|
uniforms.fogNear.value = fog.near;
|
|
uniforms.fogFar.value = fog.far;
|
|
|
|
} else if ( fog instanceof THREE.FogExp2 ) {
|
|
|
|
uniforms.fogDensity.value = fog.density;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
function refreshUniformsPhong( uniforms, material ) {
|
|
|
|
//uniforms.ambient.value.setHex( material.ambient.hex );
|
|
//uniforms.specular.value.setHex( material.specular.hex );
|
|
uniforms.ambient.value.setRGB( material.ambient.r, material.ambient.g, material.ambient.b );
|
|
uniforms.specular.value.setRGB( material.specular.r, material.specular.g, material.specular.b );
|
|
uniforms.shininess.value = material.shininess;
|
|
|
|
};
|
|
|
|
|
|
function refreshUniformsLights( uniforms, lights ) {
|
|
|
|
uniforms.enableLighting.value = lights.directional.length + lights.point.length;
|
|
uniforms.ambientLightColor.value = lights.ambient;
|
|
uniforms.directionalLightColor.value = lights.directional.colors;
|
|
uniforms.directionalLightDirection.value = lights.directional.positions;
|
|
uniforms.pointLightColor.value = lights.point.colors;
|
|
uniforms.pointLightPosition.value = lights.point.positions;
|
|
|
|
};
|
|
|
|
this.initMaterial = function( material, lights, fog ) {
|
|
|
|
var u, identifiers, parameters, maxLightCount;
|
|
|
|
if ( material instanceof THREE.MeshDepthMaterial ) {
|
|
|
|
setMaterialShaders( material, THREE.ShaderLib[ 'depth' ] );
|
|
|
|
} else if ( material instanceof THREE.MeshNormalMaterial ) {
|
|
|
|
setMaterialShaders( material, THREE.ShaderLib[ 'normal' ] );
|
|
|
|
} else if ( material instanceof THREE.MeshBasicMaterial ) {
|
|
|
|
setMaterialShaders( material, THREE.ShaderLib[ 'basic' ] );
|
|
|
|
} else if ( material instanceof THREE.MeshLambertMaterial ) {
|
|
|
|
setMaterialShaders( material, THREE.ShaderLib[ 'lambert' ] );
|
|
|
|
} else if ( material instanceof THREE.MeshPhongMaterial ) {
|
|
|
|
setMaterialShaders( material, THREE.ShaderLib[ 'phong' ] );
|
|
|
|
} else if ( material instanceof THREE.LineBasicMaterial ) {
|
|
|
|
setMaterialShaders( material, THREE.ShaderLib[ 'basic' ] );
|
|
|
|
} else if ( material instanceof THREE.ParticleBasicMaterial ) {
|
|
|
|
setMaterialShaders( material, THREE.ShaderLib[ 'particle_basic' ] );
|
|
|
|
}
|
|
|
|
// heuristics to create shader parameters according to lights in the scene
|
|
// (not to blow over maxLights budget)
|
|
|
|
maxLightCount = allocateLights( lights, 4 );
|
|
|
|
parameters = { fog: fog, map: material.map, envMap: material.envMap, lightMap: material.lightMap, vertexColors: material.vertexColors,
|
|
skinning: material.skinning,
|
|
maxDirLights: maxLightCount.directional, maxPointLights: maxLightCount.point };
|
|
|
|
material.program = buildProgram( material.fragmentShader, material.vertexShader, parameters );
|
|
|
|
identifiers = [ 'viewMatrix', 'modelViewMatrix', 'projectionMatrix', 'normalMatrix', 'objectMatrix', 'cameraPosition',
|
|
'cameraInverseMatrix', 'boneGlobalMatrices'
|
|
];
|
|
|
|
for( u in material.uniforms ) {
|
|
|
|
identifiers.push(u);
|
|
|
|
}
|
|
|
|
cacheUniformLocations( material.program, identifiers );
|
|
cacheAttributeLocations( material.program, [ "position", "normal", "uv", "uv2", "tangent", "color",
|
|
"skinVertexA", "skinVertexB", "skinIndex", "skinWeight" ] );
|
|
|
|
var attributes = material.program.attributes;
|
|
|
|
_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 );
|
|
|
|
}
|
|
|
|
};
|
|
|
|
function setProgram( camera, lights, fog, material, object ) {
|
|
|
|
if ( !material.program ) _this.initMaterial( material, lights, fog );
|
|
|
|
var program = material.program,
|
|
p_uniforms = program.uniforms,
|
|
m_uniforms = material.uniforms;
|
|
|
|
if( program != _oldProgram ) {
|
|
|
|
_gl.useProgram( program );
|
|
_oldProgram = program;
|
|
|
|
_gl.uniformMatrix4fv( p_uniforms.projectionMatrix, false, _projectionMatrixArray );
|
|
|
|
}
|
|
|
|
// refresh uniforms common to several materials
|
|
|
|
if ( fog && (
|
|
material instanceof THREE.MeshBasicMaterial ||
|
|
material instanceof THREE.MeshLambertMaterial ||
|
|
material instanceof THREE.MeshPhongMaterial ||
|
|
material instanceof THREE.LineBasicMaterial ||
|
|
material instanceof THREE.ParticleBasicMaterial )
|
|
) {
|
|
|
|
refreshUniformsFog( m_uniforms, fog );
|
|
|
|
}
|
|
|
|
if ( material instanceof THREE.MeshPhongMaterial ||
|
|
material instanceof THREE.MeshLambertMaterial ) {
|
|
|
|
setupLights( program, lights );
|
|
refreshUniformsLights( m_uniforms, _lights );
|
|
|
|
}
|
|
|
|
if ( material instanceof THREE.MeshBasicMaterial ||
|
|
material instanceof THREE.MeshLambertMaterial ||
|
|
material instanceof THREE.MeshPhongMaterial ) {
|
|
|
|
refreshUniformsCommon( m_uniforms, material );
|
|
|
|
}
|
|
|
|
// refresh single material specific uniforms
|
|
|
|
if ( material instanceof THREE.LineBasicMaterial ) {
|
|
|
|
refreshUniformsLine( m_uniforms, material );
|
|
|
|
} else if ( material instanceof THREE.ParticleBasicMaterial ) {
|
|
|
|
refreshUniformsParticle( m_uniforms, material );
|
|
|
|
} else if ( material instanceof THREE.MeshPhongMaterial ) {
|
|
|
|
refreshUniformsPhong( m_uniforms, material );
|
|
|
|
} else if ( material instanceof THREE.MeshDepthMaterial ) {
|
|
|
|
m_uniforms.mNear.value = camera.near;
|
|
m_uniforms.mFar.value = camera.far;
|
|
m_uniforms.opacity.value = material.opacity;
|
|
|
|
} else if ( material instanceof THREE.MeshNormalMaterial ) {
|
|
|
|
m_uniforms.opacity.value = material.opacity;
|
|
|
|
}
|
|
|
|
// load common uniforms
|
|
|
|
loadUniformsGeneric( program, m_uniforms );
|
|
loadUniformsMatrices( p_uniforms, object );
|
|
|
|
// load material specific uniforms
|
|
// (shader material also gets them for the sake of genericity)
|
|
|
|
if ( material instanceof THREE.MeshShaderMaterial ||
|
|
material instanceof THREE.MeshPhongMaterial ||
|
|
material.envMap ) {
|
|
|
|
_gl.uniform3f( p_uniforms.cameraPosition, camera.position.x, camera.position.y, camera.position.z );
|
|
|
|
}
|
|
|
|
if ( material instanceof THREE.MeshShaderMaterial ||
|
|
material.envMap ||
|
|
material.skinning ) {
|
|
|
|
_gl.uniformMatrix4fv( p_uniforms.objectMatrix, false, object._objectMatrixArray );
|
|
|
|
}
|
|
|
|
if ( material instanceof THREE.MeshPhongMaterial ||
|
|
material instanceof THREE.MeshLambertMaterial ||
|
|
material instanceof THREE.MeshShaderMaterial ||
|
|
material.skinning ) {
|
|
|
|
_gl.uniformMatrix4fv( p_uniforms.viewMatrix, false, _viewMatrixArray );
|
|
|
|
}
|
|
|
|
if ( material.skinning ) {
|
|
|
|
loadUniformsSkinning( p_uniforms, object );
|
|
|
|
}
|
|
|
|
return program;
|
|
|
|
};
|
|
|
|
function renderBuffer( camera, lights, fog, material, geometryGroup, object ) {
|
|
|
|
var program, attributes, linewidth, primitives;
|
|
|
|
program = setProgram( camera, lights, fog, material, object );
|
|
|
|
attributes = program.attributes;
|
|
|
|
// vertices
|
|
|
|
_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webGLVertexBuffer );
|
|
_gl.vertexAttribPointer( attributes.position, 3, _gl.FLOAT, false, 0, 0 );
|
|
|
|
// colors
|
|
|
|
if ( attributes.color >= 0 ) {
|
|
|
|
_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webGLColorBuffer );
|
|
_gl.vertexAttribPointer( attributes.color, 3, _gl.FLOAT, false, 0, 0 );
|
|
|
|
}
|
|
|
|
// normals
|
|
|
|
if ( attributes.normal >= 0 ) {
|
|
|
|
_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webGLNormalBuffer );
|
|
_gl.vertexAttribPointer( attributes.normal, 3, _gl.FLOAT, false, 0, 0 );
|
|
|
|
}
|
|
|
|
// tangents
|
|
|
|
if ( attributes.tangent >= 0 ) {
|
|
|
|
_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webGLTangentBuffer );
|
|
_gl.vertexAttribPointer( attributes.tangent, 4, _gl.FLOAT, false, 0, 0 );
|
|
|
|
}
|
|
|
|
// uvs
|
|
|
|
if ( attributes.uv >= 0 ) {
|
|
|
|
if ( geometryGroup.__webGLUVBuffer ) {
|
|
|
|
_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webGLUVBuffer );
|
|
_gl.vertexAttribPointer( attributes.uv, 2, _gl.FLOAT, false, 0, 0 );
|
|
|
|
_gl.enableVertexAttribArray( attributes.uv );
|
|
|
|
} else {
|
|
|
|
_gl.disableVertexAttribArray( attributes.uv );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ( attributes.uv2 >= 0 ) {
|
|
|
|
if ( geometryGroup.__webGLUV2Buffer ) {
|
|
|
|
_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webGLUV2Buffer );
|
|
_gl.vertexAttribPointer( attributes.uv2, 2, _gl.FLOAT, false, 0, 0 );
|
|
|
|
_gl.enableVertexAttribArray( attributes.uv2 );
|
|
|
|
} else {
|
|
|
|
_gl.disableVertexAttribArray( attributes.uv2 );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ( material.skinning &&
|
|
attributes.skinVertexA >=0 && attributes.skinVertexB >= 0 &&
|
|
attributes.skinIndex >= 0 && attributes.skinWeight >= 0 ) {
|
|
|
|
_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webGLSkinVertexABuffer );
|
|
_gl.vertexAttribPointer( attributes.skinVertexA, 4, _gl.FLOAT, false, 0, 0 );
|
|
|
|
_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webGLSkinVertexBBuffer );
|
|
_gl.vertexAttribPointer( attributes.skinVertexB, 4, _gl.FLOAT, false, 0, 0 );
|
|
|
|
_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webGLSkinIndicesBuffer );
|
|
_gl.vertexAttribPointer( attributes.skinIndex, 4, _gl.FLOAT, false, 0, 0 );
|
|
|
|
_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webGLSkinWeightsBuffer );
|
|
_gl.vertexAttribPointer( attributes.skinWeight, 4, _gl.FLOAT, false, 0, 0 );
|
|
|
|
}
|
|
|
|
// render mesh
|
|
|
|
if ( object instanceof THREE.Mesh ) {
|
|
|
|
// wireframe
|
|
|
|
if ( material.wireframe ) {
|
|
|
|
_gl.lineWidth( material.wireframeLinewidth );
|
|
_gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, geometryGroup.__webGLLineBuffer );
|
|
_gl.drawElements( _gl.LINES, geometryGroup.__webGLLineCount, _gl.UNSIGNED_SHORT, 0 );
|
|
|
|
// triangles
|
|
|
|
} else {
|
|
|
|
_gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, geometryGroup.__webGLFaceBuffer );
|
|
_gl.drawElements( _gl.TRIANGLES, geometryGroup.__webGLFaceCount, _gl.UNSIGNED_SHORT, 0 );
|
|
|
|
}
|
|
|
|
// render lines
|
|
|
|
} else if ( object instanceof THREE.Line ) {
|
|
|
|
primitives = ( object.type == THREE.LineStrip ) ? _gl.LINE_STRIP : _gl.LINES;
|
|
|
|
_gl.lineWidth( material.linewidth );
|
|
_gl.drawArrays( primitives, 0, geometryGroup.__webGLLineCount );
|
|
|
|
// render particles
|
|
|
|
} else if ( object instanceof THREE.ParticleSystem ) {
|
|
|
|
_gl.drawArrays( _gl.POINTS, 0, geometryGroup.__webGLParticleCount );
|
|
|
|
// render ribbon
|
|
|
|
} else if ( object instanceof THREE.Ribbon ) {
|
|
|
|
_gl.drawArrays( _gl.TRIANGLE_STRIP, 0, geometryGroup.__webGLVertexCount );
|
|
|
|
}
|
|
|
|
};
|
|
|
|
function renderBufferImmediate( object, program ) {
|
|
|
|
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 );
|
|
_gl.bufferData( _gl.ARRAY_BUFFER, object.normalArray, _gl.DYNAMIC_DRAW );
|
|
_gl.enableVertexAttribArray( program.attributes.normal );
|
|
_gl.vertexAttribPointer( program.attributes.normal, 3, _gl.FLOAT, false, 0, 0 );
|
|
|
|
}
|
|
|
|
_gl.drawArrays( _gl.TRIANGLES, 0, object.count );
|
|
|
|
object.count = 0;
|
|
|
|
};
|
|
|
|
function setObjectFaces( object ) {
|
|
|
|
if ( _oldDoubleSided != object.doubleSided ) {
|
|
|
|
if( object.doubleSided ) {
|
|
|
|
_gl.disable( _gl.CULL_FACE );
|
|
|
|
} else {
|
|
|
|
_gl.enable( _gl.CULL_FACE );
|
|
|
|
}
|
|
|
|
_oldDoubleSided = object.doubleSided;
|
|
|
|
}
|
|
|
|
if ( _oldFlipSided != object.flipSided ) {
|
|
|
|
if( object.flipSided ) {
|
|
|
|
_gl.frontFace( _gl.CW );
|
|
|
|
} else {
|
|
|
|
_gl.frontFace( _gl.CCW );
|
|
|
|
}
|
|
|
|
_oldFlipSided = object.flipSided;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
function setDepthTest( test ) {
|
|
|
|
if ( _oldDepth != test ) {
|
|
|
|
if( test ) {
|
|
|
|
_gl.enable( _gl.DEPTH_TEST );
|
|
|
|
} else {
|
|
|
|
_gl.disable( _gl.DEPTH_TEST );
|
|
|
|
}
|
|
|
|
_oldDepth = test;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
function computeFrustum( m ) {
|
|
|
|
_frustum[ 0 ].set( m.n41 - m.n11, m.n42 - m.n12, m.n43 - m.n13, m.n44 - m.n14 );
|
|
_frustum[ 1 ].set( m.n41 + m.n11, m.n42 + m.n12, m.n43 + m.n13, m.n44 + m.n14 );
|
|
_frustum[ 2 ].set( m.n41 + m.n21, m.n42 + m.n22, m.n43 + m.n23, m.n44 + m.n24 );
|
|
_frustum[ 3 ].set( m.n41 - m.n21, m.n42 - m.n22, m.n43 - m.n23, m.n44 - m.n24 );
|
|
_frustum[ 4 ].set( m.n41 - m.n31, m.n42 - m.n32, m.n43 - m.n33, m.n44 - m.n34 );
|
|
_frustum[ 5 ].set( m.n41 + m.n31, m.n42 + m.n32, m.n43 + m.n33, m.n44 + m.n34 );
|
|
|
|
var i, plane;
|
|
|
|
for ( i = 0; i < 6; i ++ ) {
|
|
|
|
plane = _frustum[ i ];
|
|
plane.divideScalar( Math.sqrt( plane.x * plane.x + plane.y * plane.y + plane.z * plane.z ) );
|
|
|
|
}
|
|
|
|
};
|
|
|
|
function isInFrustum( object ) {
|
|
|
|
var distance, matrix = object.matrixWorld,
|
|
radius = - object.geometry.boundingSphere.radius * Math.max( object.scale.x, Math.max( object.scale.y, object.scale.z ) );
|
|
|
|
for ( var i = 0; i < 6; i ++ ) {
|
|
|
|
distance = _frustum[ i ].x * matrix.n14 + _frustum[ i ].y * matrix.n24 + _frustum[ i ].z * matrix.n34 + _frustum[ i ].w;
|
|
if ( distance <= radius ) return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
};
|
|
|
|
function addToFixedArray( where, what ) {
|
|
|
|
where.list[ where.count ] = what;
|
|
where.count += 1;
|
|
|
|
};
|
|
|
|
function unrollImmediateBufferMaterials( globject ) {
|
|
|
|
var i, l, m, ml, material,
|
|
object = globject.object,
|
|
opaque = globject.opaque,
|
|
transparent = globject.transparent;
|
|
|
|
transparent.count = 0;
|
|
opaque.count = 0;
|
|
|
|
for ( m = 0, ml = object.materials.length; m < ml; m++ ) {
|
|
|
|
material = object.materials[ m ];
|
|
|
|
if ( ( material.opacity && material.opacity < 1.0 ) || material.blending != THREE.NormalBlending )
|
|
addToFixedArray( transparent, material );
|
|
else
|
|
addToFixedArray( opaque, material );
|
|
|
|
}
|
|
|
|
};
|
|
|
|
function unrollBufferMaterials( globject ) {
|
|
|
|
var i, l, m, ml, material, meshMaterial,
|
|
object = globject.object,
|
|
buffer = globject.buffer,
|
|
opaque = globject.opaque,
|
|
transparent = globject.transparent;
|
|
|
|
transparent.count = 0;
|
|
opaque.count = 0;
|
|
|
|
for ( m = 0, ml = object.materials.length; m < ml; m++ ) {
|
|
|
|
meshMaterial = object.materials[ m ];
|
|
|
|
if ( meshMaterial instanceof THREE.MeshFaceMaterial ) {
|
|
|
|
for ( i = 0, l = buffer.materials.length; i < l; i++ ) {
|
|
|
|
material = buffer.materials[ i ];
|
|
|
|
if ( material ) {
|
|
|
|
if ( ( material.opacity && material.opacity < 1.0 ) || material.blending != THREE.NormalBlending )
|
|
addToFixedArray( transparent, material );
|
|
else
|
|
addToFixedArray( opaque, material );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
material = meshMaterial;
|
|
|
|
if ( ( material.opacity && material.opacity < 1.0 ) || material.blending != THREE.NormalBlending ) {
|
|
|
|
addToFixedArray( transparent, material );
|
|
|
|
} else {
|
|
|
|
addToFixedArray( opaque, material );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
function painterSort( a, b ) {
|
|
|
|
return b.z - a.z;
|
|
|
|
};
|
|
|
|
this.render = function( scene, camera, renderTarget, forceClear ) {
|
|
|
|
var i, program, opaque, transparent, material,
|
|
o, ol, oil, webglObject, object, buffer,
|
|
lights = scene.lights,
|
|
fog = scene.fog,
|
|
ol;
|
|
|
|
camera.matrixAutoUpdate && camera.update();
|
|
|
|
camera.matrixWorldInverse.flattenToArray( _viewMatrixArray );
|
|
camera.projectionMatrix.flattenToArray( _projectionMatrixArray );
|
|
|
|
_projScreenMatrix.multiply( camera.projectionMatrix, camera.matrixWorldInverse );
|
|
computeFrustum( _projScreenMatrix );
|
|
|
|
scene.update( undefined, false, camera );
|
|
|
|
this.initWebGLObjects( scene );
|
|
|
|
setRenderTarget( renderTarget );
|
|
|
|
if ( this.autoClear || forceClear ) {
|
|
|
|
this.clear();
|
|
|
|
}
|
|
|
|
// set matrices
|
|
|
|
ol = scene.__webglObjects.length;
|
|
|
|
for ( o = 0; o < ol; o++ ) {
|
|
|
|
webglObject = scene.__webglObjects[ o ];
|
|
object = webglObject.object;
|
|
|
|
if ( object.visible ) {
|
|
|
|
if ( ! ( object instanceof THREE.Mesh ) || isInFrustum( object ) ) {
|
|
|
|
object.matrixWorld.flattenToArray( object._objectMatrixArray );
|
|
|
|
setupMatrices( object, camera );
|
|
|
|
unrollBufferMaterials( webglObject );
|
|
|
|
webglObject.render = true;
|
|
|
|
if ( this.sortObjects ) {
|
|
|
|
_vector3.copy( object.position );
|
|
_projScreenMatrix.multiplyVector3( _vector3 );
|
|
|
|
webglObject.z = _vector3.z;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
webglObject.render = false;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
webglObject.render = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ( this.sortObjects ) {
|
|
|
|
scene.__webglObjects.sort( painterSort );
|
|
|
|
}
|
|
|
|
oil = scene.__webglObjectsImmediate.length;
|
|
|
|
for ( o = 0; o < oil; o++ ) {
|
|
|
|
webglObject = scene.__webglObjectsImmediate[ o ];
|
|
object = webglObject.object;
|
|
|
|
if ( object.visible ) {
|
|
|
|
if( object.matrixAutoUpdate ) {
|
|
|
|
object.matrixWorld.flattenToArray( object._objectMatrixArray );
|
|
|
|
}
|
|
|
|
setupMatrices( object, camera );
|
|
|
|
unrollImmediateBufferMaterials( webglObject );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// opaque pass
|
|
|
|
setBlending( THREE.NormalBlending );
|
|
|
|
for ( o = 0; o < ol; o++ ) {
|
|
|
|
webglObject = scene.__webglObjects[ o ];
|
|
|
|
if ( webglObject.render ) {
|
|
|
|
object = webglObject.object;
|
|
buffer = webglObject.buffer;
|
|
opaque = webglObject.opaque;
|
|
|
|
setObjectFaces( object );
|
|
|
|
for( i = 0; i < opaque.count; i++ ) {
|
|
|
|
material = opaque.list[ i ];
|
|
|
|
setDepthTest( material.depthTest );
|
|
renderBuffer( camera, lights, fog, material, buffer, object );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// opaque pass (immediate simulator)
|
|
|
|
for ( o = 0; o < oil; o++ ) {
|
|
|
|
webglObject = scene.__webglObjectsImmediate[ o ];
|
|
object = webglObject.object;
|
|
|
|
if ( object.visible ) {
|
|
|
|
opaque = webglObject.opaque;
|
|
|
|
setObjectFaces( object );
|
|
|
|
for( i = 0; i < opaque.count; i++ ) {
|
|
|
|
material = opaque.list[ i ];
|
|
|
|
setDepthTest( material.depthTest );
|
|
|
|
program = setProgram( camera, lights, fog, material, object );
|
|
object.render( function( object ) { renderBufferImmediate( object, program ); } );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// transparent pass
|
|
|
|
for ( o = 0; o < ol; o++ ) {
|
|
|
|
webglObject = scene.__webglObjects[ o ];
|
|
|
|
if ( webglObject.render ) {
|
|
|
|
object = webglObject.object;
|
|
buffer = webglObject.buffer;
|
|
transparent = webglObject.transparent;
|
|
|
|
setObjectFaces( object );
|
|
|
|
for( i = 0; i < transparent.count; i++ ) {
|
|
|
|
material = transparent.list[ i ];
|
|
|
|
setBlending( material.blending );
|
|
setDepthTest( material.depthTest );
|
|
|
|
renderBuffer( camera, lights, fog, material, buffer, object );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// transparent pass (immediate simulator)
|
|
|
|
for ( o = 0; o < oil; o++ ) {
|
|
|
|
webglObject = scene.__webglObjectsImmediate[ o ];
|
|
object = webglObject.object;
|
|
|
|
if ( object.visible ) {
|
|
|
|
transparent = webglObject.transparent;
|
|
|
|
setObjectFaces( object );
|
|
|
|
for( i = 0; i < transparent.count; i++ ) {
|
|
|
|
material = transparent.list[ i ];
|
|
|
|
setBlending( material.blending );
|
|
setDepthTest( material.depthTest );
|
|
|
|
program = setProgram( camera, lights, fog, material, object );
|
|
object.render( function( object ) { renderBufferImmediate( object, program ); } );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Generate mipmap if we're using any kind of mipmap filtering
|
|
|
|
if ( renderTarget && renderTarget.minFilter !== THREE.NearestFilter && renderTarget.minFilter !== THREE.LinearFilter ) {
|
|
|
|
updateRenderTargetMipmap( renderTarget );
|
|
|
|
}
|
|
|
|
};
|
|
|
|
function setupMatrices( object, camera ) {
|
|
|
|
object._modelViewMatrix.multiplyToArray( camera.matrixWorldInverse, object.matrixWorld, object._modelViewMatrixArray );
|
|
THREE.Matrix4.makeInvert3x3( object._modelViewMatrix ).transposeIntoArray( object._normalMatrixArray );
|
|
|
|
};
|
|
|
|
this.initWebGLObjects = function ( scene ) {
|
|
|
|
if ( !scene.__webglObjects ) {
|
|
|
|
scene.__webglObjects = [];
|
|
scene.__webglObjectsImmediate = [];
|
|
|
|
}
|
|
|
|
while ( scene.__objectsAdded.length ) {
|
|
|
|
addObject( scene.__objectsAdded[ 0 ], scene );
|
|
scene.__objectsAdded.splice( 0, 1 );
|
|
|
|
}
|
|
|
|
while ( scene.__objectsRemoved.length ) {
|
|
|
|
removeObject( scene.__objectsRemoved[ 0 ], scene );
|
|
scene.__objectsRemoved.splice( 0, 1 );
|
|
|
|
}
|
|
|
|
// update must be called after objects adding / removal
|
|
|
|
for ( var o = 0, ol = scene.__webglObjects.length; o < ol; o ++ ) {
|
|
|
|
updateObject( scene.__webglObjects[ o ].object, scene );
|
|
|
|
}
|
|
|
|
};
|
|
|
|
function addObject( object, scene ) {
|
|
|
|
var g, geometry, geometryGroup;
|
|
|
|
if ( object._modelViewMatrix == undefined ) {
|
|
|
|
object._modelViewMatrix = new THREE.Matrix4();
|
|
|
|
object._normalMatrixArray = new Float32Array( 9 );
|
|
object._modelViewMatrixArray = new Float32Array( 16 );
|
|
object._objectMatrixArray = new Float32Array( 16 );
|
|
|
|
object.matrixWorld.flattenToArray( object._objectMatrixArray );
|
|
|
|
}
|
|
|
|
if ( object instanceof THREE.Mesh ) {
|
|
|
|
geometry = object.geometry;
|
|
|
|
if ( geometry.geometryGroups == undefined ) {
|
|
|
|
sortFacesByMaterial( geometry );
|
|
|
|
}
|
|
|
|
// create separate VBOs per geometry chunk
|
|
|
|
for ( g in geometry.geometryGroups ) {
|
|
|
|
geometryGroup = geometry.geometryGroups[ g ];
|
|
|
|
// initialise VBO on the first access
|
|
|
|
if ( ! geometryGroup.__webGLVertexBuffer ) {
|
|
|
|
createMeshBuffers( geometryGroup );
|
|
initMeshBuffers( geometryGroup, object );
|
|
|
|
geometry.__dirtyVertices = true;
|
|
geometry.__dirtyElements = true;
|
|
geometry.__dirtyUvs = true;
|
|
geometry.__dirtyNormals = true;
|
|
geometry.__dirtyTangents = true;
|
|
geometry.__dirtyColors = true;
|
|
|
|
}
|
|
|
|
// create separate wrapper per each use of VBO
|
|
|
|
addBuffer( scene.__webglObjects, geometryGroup, object );
|
|
|
|
}
|
|
|
|
} else if ( object instanceof THREE.Ribbon ) {
|
|
|
|
geometry = object.geometry;
|
|
|
|
if( ! geometry.__webGLVertexBuffer ) {
|
|
|
|
createRibbonBuffers( geometry );
|
|
initRibbonBuffers( geometry );
|
|
|
|
geometry.__dirtyVertices = true;
|
|
geometry.__dirtyColors = true;
|
|
|
|
}
|
|
|
|
addBuffer( scene.__webglObjects, geometry, object );
|
|
|
|
} else if ( object instanceof THREE.Line ) {
|
|
|
|
geometry = object.geometry;
|
|
|
|
if( ! geometry.__webGLVertexBuffer ) {
|
|
|
|
createLineBuffers( geometry );
|
|
initLineBuffers( geometry );
|
|
|
|
geometry.__dirtyVertices = true;
|
|
geometry.__dirtyColors = true;
|
|
|
|
}
|
|
|
|
addBuffer( scene.__webglObjects, geometry, object );
|
|
|
|
} else if ( object instanceof THREE.ParticleSystem ) {
|
|
|
|
geometry = object.geometry;
|
|
|
|
if ( ! geometry.__webGLVertexBuffer ) {
|
|
|
|
createParticleBuffers( geometry );
|
|
initParticleBuffers( geometry );
|
|
|
|
geometry.__dirtyVertices = true;
|
|
geometry.__dirtyColors = true;
|
|
|
|
}
|
|
|
|
addBuffer( scene.__webglObjects, geometry, object );
|
|
|
|
} else if ( THREE.MarchingCubes !== undefined && object instanceof THREE.MarchingCubes ) {
|
|
|
|
addBufferImmediate( scene.__webglObjectsImmediate, object );
|
|
|
|
}/*else if ( object instanceof THREE.Particle ) {
|
|
|
|
}*/
|
|
|
|
};
|
|
|
|
function updateObject( object, scene ) {
|
|
|
|
var g, geometry, geometryGroup;
|
|
|
|
if ( object instanceof THREE.Mesh ) {
|
|
|
|
geometry = object.geometry;
|
|
|
|
// check all geometry groups
|
|
|
|
for ( g in geometry.geometryGroups ) {
|
|
|
|
geometryGroup = geometry.geometryGroups[ g ];
|
|
|
|
if ( geometry.__dirtyVertices || geometry.__dirtyElements ||
|
|
geometry.__dirtyUvs || geometry.__dirtyNormals ||
|
|
geometry.__dirtyColors || geometry.__dirtyTangents ) {
|
|
|
|
setMeshBuffers( geometryGroup, object, _gl.DYNAMIC_DRAW );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
geometry.__dirtyVertices = false;
|
|
geometry.__dirtyElements = false;
|
|
geometry.__dirtyUvs = false;
|
|
geometry.__dirtyNormals = false;
|
|
geometry.__dirtyTangents = false;
|
|
geometry.__dirtyColors = false;
|
|
|
|
} else if ( object instanceof THREE.Ribbon ) {
|
|
|
|
geometry = object.geometry;
|
|
|
|
if( geometry.__dirtyVertices || geometry.__dirtyColors ) {
|
|
|
|
setRibbonBuffers( geometry, _gl.DYNAMIC_DRAW );
|
|
|
|
}
|
|
|
|
geometry.__dirtyVertices = false;
|
|
geometry.__dirtyColors = false;
|
|
|
|
} else if ( object instanceof THREE.Line ) {
|
|
|
|
geometry = object.geometry;
|
|
|
|
if( geometry.__dirtyVertices || geometry.__dirtyColors ) {
|
|
|
|
setLineBuffers( geometry, _gl.DYNAMIC_DRAW );
|
|
|
|
}
|
|
|
|
geometry.__dirtyVertices = false;
|
|
geometry.__dirtyColors = false;
|
|
|
|
} else if ( object instanceof THREE.ParticleSystem ) {
|
|
|
|
geometry = object.geometry;
|
|
|
|
if ( geometry.__dirtyVertices || geometry.__dirtyColors || object.sortParticles ) {
|
|
|
|
setParticleBuffers( geometry, _gl.DYNAMIC_DRAW, object );
|
|
|
|
}
|
|
|
|
geometry.__dirtyVertices = false;
|
|
geometry.__dirtyColors = false;
|
|
|
|
}/* else if ( THREE.MarchingCubes !== undefined && object instanceof THREE.MarchingCubes ) {
|
|
|
|
// it updates itself in render callback
|
|
|
|
} else if ( object instanceof THREE.Particle ) {
|
|
|
|
}*/
|
|
|
|
};
|
|
|
|
function removeObject( object, scene ) {
|
|
|
|
var o, ol, zobject;
|
|
|
|
for ( o = scene.__webglObjects.length - 1; o >= 0; o-- ) {
|
|
|
|
zobject = scene.__webglObjects[ o ].object;
|
|
|
|
if ( object == zobject ) {
|
|
|
|
scene.__webglObjects.splice( o, 1 );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
function sortFacesByMaterial( geometry ) {
|
|
|
|
// TODO
|
|
// Should optimize by grouping faces with ColorFill / ColorStroke materials
|
|
// which could then use vertex color attributes instead of each being
|
|
// in its separate VBO
|
|
|
|
var i, l, f, fl, face, material, materials, vertices, mhash, ghash, hash_map = {};
|
|
|
|
geometry.geometryGroups = {};
|
|
|
|
function materialHash( material ) {
|
|
|
|
var hash_array = [];
|
|
|
|
for ( i = 0, l = material.length; i < l; i++ ) {
|
|
|
|
if ( material[ i ] == undefined ) {
|
|
|
|
hash_array.push( "undefined" );
|
|
|
|
} else {
|
|
|
|
hash_array.push( material[ i ].id );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return hash_array.join( '_' );
|
|
|
|
}
|
|
|
|
for ( f = 0, fl = geometry.faces.length; f < fl; f++ ) {
|
|
|
|
face = geometry.faces[ f ];
|
|
materials = face.materials;
|
|
|
|
mhash = materialHash( materials );
|
|
|
|
if ( hash_map[ mhash ] == undefined ) {
|
|
|
|
hash_map[ mhash ] = { 'hash': mhash, 'counter': 0 };
|
|
|
|
}
|
|
|
|
ghash = hash_map[ mhash ].hash + '_' + hash_map[ mhash ].counter;
|
|
|
|
if ( geometry.geometryGroups[ ghash ] == undefined ) {
|
|
|
|
geometry.geometryGroups[ ghash ] = { 'faces': [], 'materials': materials, 'vertices': 0 };
|
|
|
|
}
|
|
|
|
vertices = face instanceof THREE.Face3 ? 3 : 4;
|
|
|
|
if ( geometry.geometryGroups[ ghash ].vertices + vertices > 65535 ) {
|
|
|
|
hash_map[ mhash ].counter += 1;
|
|
ghash = hash_map[ mhash ].hash + '_' + hash_map[ mhash ].counter;
|
|
|
|
if ( geometry.geometryGroups[ ghash ] == undefined ) {
|
|
|
|
geometry.geometryGroups[ ghash ] = { 'faces': [], 'materials': materials, 'vertices': 0 };
|
|
|
|
}
|
|
|
|
}
|
|
|
|
geometry.geometryGroups[ ghash ].faces.push( f );
|
|
geometry.geometryGroups[ ghash ].vertices += vertices;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
function addBuffer( objlist, buffer, object ) {
|
|
|
|
objlist.push( { buffer: buffer, object: object,
|
|
opaque: { list: [], count: 0 },
|
|
transparent: { list: [], count: 0 }
|
|
} );
|
|
|
|
};
|
|
|
|
function addBufferImmediate( objlist, object ) {
|
|
|
|
objlist.push( { object: object,
|
|
opaque: { list: [], count: 0 },
|
|
transparent: { list: [], count: 0 }
|
|
} );
|
|
|
|
};
|
|
|
|
this.setFaceCulling = function( cullFace, frontFace ) {
|
|
|
|
if ( cullFace ) {
|
|
|
|
if ( !frontFace || frontFace == "ccw" ) {
|
|
|
|
_gl.frontFace( _gl.CCW );
|
|
|
|
} else {
|
|
|
|
_gl.frontFace( _gl.CW );
|
|
|
|
}
|
|
|
|
if( cullFace == "back" ) {
|
|
|
|
_gl.cullFace( _gl.BACK );
|
|
|
|
} else if( cullFace == "front" ) {
|
|
|
|
_gl.cullFace( _gl.FRONT );
|
|
|
|
} else {
|
|
|
|
_gl.cullFace( _gl.FRONT_AND_BACK );
|
|
|
|
}
|
|
|
|
_gl.enable( _gl.CULL_FACE );
|
|
|
|
} else {
|
|
|
|
_gl.disable( _gl.CULL_FACE );
|
|
|
|
}
|
|
|
|
};
|
|
|
|
this.supportsVertexTextures = function() {
|
|
|
|
return maxVertexTextures() > 0;
|
|
|
|
};
|
|
|
|
function maxVertexTextures() {
|
|
|
|
return _gl.getParameter( _gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS );
|
|
|
|
};
|
|
|
|
function initGL( antialias, clearColor, clearAlpha ) {
|
|
|
|
try {
|
|
|
|
if ( ! ( _gl = _canvas.getContext( 'experimental-webgl', { antialias: antialias } ) ) ) {
|
|
|
|
throw 'Error creating WebGL context.';
|
|
|
|
}
|
|
|
|
} catch ( e ) {
|
|
|
|
console.error( e );
|
|
|
|
}
|
|
|
|
_gl.clearColor( 0, 0, 0, 1 );
|
|
_gl.clearDepth( 1 );
|
|
|
|
_gl.enable( _gl.DEPTH_TEST );
|
|
_gl.depthFunc( _gl.LEQUAL );
|
|
|
|
_gl.frontFace( _gl.CCW );
|
|
_gl.cullFace( _gl.BACK );
|
|
_gl.enable( _gl.CULL_FACE );
|
|
|
|
_gl.enable( _gl.BLEND );
|
|
_gl.blendFunc( _gl.ONE, _gl.ONE_MINUS_SRC_ALPHA );
|
|
_gl.clearColor( clearColor.r, clearColor.g, clearColor.b, clearAlpha );
|
|
|
|
_cullEnabled = true;
|
|
|
|
};
|
|
|
|
function buildProgram( fragmentShader, vertexShader, parameters ) {
|
|
|
|
var program = _gl.createProgram(),
|
|
|
|
prefix_fragment = [
|
|
"#ifdef GL_ES",
|
|
"precision highp float;",
|
|
"#endif",
|
|
|
|
"#define MAX_DIR_LIGHTS " + parameters.maxDirLights,
|
|
"#define MAX_POINT_LIGHTS " + parameters.maxPointLights,
|
|
|
|
parameters.fog ? "#define USE_FOG" : "",
|
|
parameters.fog instanceof THREE.FogExp2 ? "#define FOG_EXP2" : "",
|
|
|
|
parameters.map ? "#define USE_MAP" : "",
|
|
parameters.envMap ? "#define USE_ENVMAP" : "",
|
|
parameters.lightMap ? "#define USE_LIGHTMAP" : "",
|
|
parameters.vertexColors ? "#define USE_COLOR" : "",
|
|
|
|
"uniform mat4 viewMatrix;",
|
|
"uniform vec3 cameraPosition;",
|
|
""
|
|
].join("\n"),
|
|
|
|
prefix_vertex = [
|
|
maxVertexTextures() > 0 ? "#define VERTEX_TEXTURES" : "",
|
|
|
|
"#define MAX_DIR_LIGHTS " + parameters.maxDirLights,
|
|
"#define MAX_POINT_LIGHTS " + parameters.maxPointLights,
|
|
|
|
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" : "",
|
|
|
|
"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 vec3 color;",
|
|
"attribute vec2 uv;",
|
|
"attribute vec2 uv2;",
|
|
|
|
"attribute vec4 skinVertexA;",
|
|
"attribute vec4 skinVertexB;",
|
|
"attribute vec4 skinIndex;",
|
|
"attribute vec4 skinWeight;",
|
|
""
|
|
].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 ) ) {
|
|
|
|
alert( "Could not initialise shaders\n"+
|
|
"VALIDATE_STATUS: " + _gl.getProgramParameter( program, _gl.VALIDATE_STATUS ) + ", gl error [" + _gl.getError() + "]" );
|
|
|
|
//console.log( prefix_fragment + fragmentShader );
|
|
//console.log( prefix_vertex + vertexShader );
|
|
|
|
}
|
|
|
|
//console.log( prefix_fragment + fragmentShader );
|
|
//console.log( prefix_vertex + vertexShader );
|
|
|
|
program.uniforms = {};
|
|
program.attributes = {};
|
|
|
|
return program;
|
|
|
|
};
|
|
|
|
function loadUniformsSkinning( uniforms, object ) {
|
|
|
|
_gl.uniformMatrix4fv( uniforms.cameraInverseMatrix, false, _viewMatrixArray );
|
|
_gl.uniformMatrix4fv( uniforms.boneGlobalMatrices, false, object.boneMatrices );
|
|
|
|
};
|
|
|
|
function loadUniformsMatrices( uniforms, object ) {
|
|
|
|
_gl.uniformMatrix4fv( uniforms.modelViewMatrix, false, object._modelViewMatrixArray );
|
|
_gl.uniformMatrix3fv( uniforms.normalMatrix, false, object._normalMatrixArray );
|
|
|
|
};
|
|
|
|
function loadUniformsGeneric( program, uniforms ) {
|
|
|
|
var u, uniform, value, type, location, texture;
|
|
|
|
for( u in uniforms ) {
|
|
|
|
location = program.uniforms[u];
|
|
if ( !location ) continue;
|
|
|
|
uniform = uniforms[u];
|
|
|
|
type = uniform.type;
|
|
value = uniform.value;
|
|
|
|
if( type == "i" ) {
|
|
|
|
_gl.uniform1i( location, value );
|
|
|
|
} else if( type == "f" ) {
|
|
|
|
_gl.uniform1f( location, value );
|
|
|
|
} else if( type == "fv1" ) {
|
|
|
|
_gl.uniform1fv( location, value );
|
|
|
|
} else if( type == "fv" ) {
|
|
|
|
_gl.uniform3fv( location, value );
|
|
|
|
} else if( type == "v2" ) {
|
|
|
|
_gl.uniform2f( location, value.x, value.y );
|
|
|
|
} else if( type == "v3" ) {
|
|
|
|
_gl.uniform3f( location, value.x, value.y, value.z );
|
|
|
|
} else if( type == "c" ) {
|
|
|
|
_gl.uniform3f( location, value.r, value.g, value.b );
|
|
|
|
} else if( type == "t" ) {
|
|
|
|
_gl.uniform1i( location, value );
|
|
|
|
texture = uniform.texture;
|
|
|
|
if ( !texture ) continue;
|
|
|
|
if ( texture.image instanceof Array && texture.image.length == 6 ) {
|
|
|
|
setCubeTexture( texture, value );
|
|
|
|
} else {
|
|
|
|
setTexture( texture, value );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
function setBlending( blending ) {
|
|
|
|
if ( blending != _oldBlending ) {
|
|
|
|
switch ( blending ) {
|
|
|
|
case THREE.AdditiveBlending:
|
|
|
|
_gl.blendEquation( _gl.FUNC_ADD );
|
|
_gl.blendFunc( _gl.ONE, _gl.ONE );
|
|
|
|
break;
|
|
|
|
case THREE.SubtractiveBlending:
|
|
|
|
//_gl.blendEquation( _gl.FUNC_SUBTRACT );
|
|
_gl.blendFunc( _gl.DST_COLOR, _gl.ZERO );
|
|
|
|
break;
|
|
|
|
case THREE.BillboardBlending:
|
|
|
|
_gl.blendEquation( _gl.FUNC_ADD );
|
|
_gl.blendFunc( _gl.SRC_ALPHA, _gl.ONE_MINUS_SRC_ALPHA);
|
|
|
|
break;
|
|
|
|
case THREE.ReverseSubtractiveBlending:
|
|
|
|
_gl.blendEquation( _gl.FUNC_REVERSE_SUBTRACT );
|
|
_gl.blendFunc( _gl.ONE, _gl.ONE );
|
|
|
|
break;
|
|
default:
|
|
|
|
_gl.blendEquation( _gl.FUNC_ADD );
|
|
_gl.blendFunc( _gl.ONE, _gl.ONE_MINUS_SRC_ALPHA );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
_oldBlending = blending;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
function setTextureParameters( textureType, texture, image ) {
|
|
|
|
if ( isPowerOfTwo( image.width ) && isPowerOfTwo( image.height ) ) {
|
|
|
|
_gl.texParameteri( textureType, _gl.TEXTURE_WRAP_S, paramThreeToGL( texture.wrapS ) );
|
|
_gl.texParameteri( textureType, _gl.TEXTURE_WRAP_T, paramThreeToGL( texture.wrapT ) );
|
|
|
|
_gl.texParameteri( textureType, _gl.TEXTURE_MAG_FILTER, paramThreeToGL( texture.magFilter ) );
|
|
_gl.texParameteri( textureType, _gl.TEXTURE_MIN_FILTER, paramThreeToGL( texture.minFilter ) );
|
|
|
|
_gl.generateMipmap( textureType );
|
|
|
|
} else {
|
|
|
|
_gl.texParameteri( textureType, _gl.TEXTURE_WRAP_S, _gl.CLAMP_TO_EDGE );
|
|
_gl.texParameteri( textureType, _gl.TEXTURE_WRAP_T, _gl.CLAMP_TO_EDGE );
|
|
|
|
_gl.texParameteri( textureType, _gl.TEXTURE_MAG_FILTER, filterFallback( texture.magFilter ) );
|
|
_gl.texParameteri( textureType, _gl.TEXTURE_MIN_FILTER, filterFallback( texture.minFilter ) );
|
|
|
|
}
|
|
|
|
};
|
|
|
|
function setTexture( texture, slot ) {
|
|
|
|
if ( texture.needsUpdate ) {
|
|
|
|
if ( !texture.__wasSetOnce ) {
|
|
|
|
texture.__webGLTexture = _gl.createTexture();
|
|
|
|
_gl.bindTexture( _gl.TEXTURE_2D, texture.__webGLTexture );
|
|
_gl.texImage2D( _gl.TEXTURE_2D, 0, _gl.RGBA, _gl.RGBA, _gl.UNSIGNED_BYTE, texture.image );
|
|
|
|
texture.__wasSetOnce = true;
|
|
|
|
} else {
|
|
|
|
_gl.bindTexture( _gl.TEXTURE_2D, texture.__webGLTexture );
|
|
_gl.texSubImage2D( _gl.TEXTURE_2D, 0, 0, 0, _gl.RGBA, _gl.UNSIGNED_BYTE, texture.image );
|
|
|
|
}
|
|
|
|
setTextureParameters( _gl.TEXTURE_2D, texture, texture.image );
|
|
_gl.bindTexture( _gl.TEXTURE_2D, null );
|
|
|
|
texture.needsUpdate = false;
|
|
|
|
}
|
|
|
|
_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.__wasSetOnce ) {
|
|
|
|
texture.image.__webGLTextureCube = _gl.createTexture();
|
|
|
|
_gl.bindTexture( _gl.TEXTURE_CUBE_MAP, texture.image.__webGLTextureCube );
|
|
|
|
for ( var i = 0; i < 6; ++i ) {
|
|
|
|
_gl.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, _gl.RGBA, _gl.RGBA, _gl.UNSIGNED_BYTE, texture.image[ i ] );
|
|
|
|
}
|
|
|
|
texture.__wasSetOnce = true;
|
|
|
|
} else {
|
|
|
|
_gl.bindTexture( _gl.TEXTURE_CUBE_MAP, texture.image.__webGLTextureCube );
|
|
|
|
for ( var i = 0; i < 6; ++i ) {
|
|
|
|
_gl.texSubImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, 0, 0, _gl.RGBA, _gl.UNSIGNED_BYTE, texture.image[ i ] );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
setTextureParameters( _gl.TEXTURE_CUBE_MAP, texture, texture.image[0] );
|
|
_gl.bindTexture( _gl.TEXTURE_CUBE_MAP, null );
|
|
|
|
texture.needsUpdate = false;
|
|
|
|
}
|
|
|
|
_gl.activeTexture( _gl.TEXTURE0 + slot );
|
|
_gl.bindTexture( _gl.TEXTURE_CUBE_MAP, texture.image.__webGLTextureCube );
|
|
|
|
}
|
|
|
|
};
|
|
|
|
function setRenderTarget( renderTexture ) {
|
|
|
|
if ( renderTexture && !renderTexture.__webGLFramebuffer ) {
|
|
|
|
renderTexture.__webGLFramebuffer = _gl.createFramebuffer();
|
|
renderTexture.__webGLRenderbuffer = _gl.createRenderbuffer();
|
|
renderTexture.__webGLTexture = _gl.createTexture();
|
|
|
|
// Setup renderbuffer
|
|
|
|
_gl.bindRenderbuffer( _gl.RENDERBUFFER, renderTexture.__webGLRenderbuffer );
|
|
_gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.DEPTH_COMPONENT16, renderTexture.width, renderTexture.height );
|
|
|
|
// Setup texture
|
|
|
|
_gl.bindTexture( _gl.TEXTURE_2D, renderTexture.__webGLTexture );
|
|
_gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_WRAP_S, paramThreeToGL( renderTexture.wrapS ) );
|
|
_gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_WRAP_T, paramThreeToGL( renderTexture.wrapT ) );
|
|
_gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_MAG_FILTER, paramThreeToGL( renderTexture.magFilter ) );
|
|
_gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_MIN_FILTER, paramThreeToGL( renderTexture.minFilter ) );
|
|
_gl.texImage2D( _gl.TEXTURE_2D, 0, paramThreeToGL( renderTexture.format ), renderTexture.width, renderTexture.height, 0, paramThreeToGL( renderTexture.format ), paramThreeToGL( renderTexture.type ), null );
|
|
|
|
// Setup framebuffer
|
|
|
|
_gl.bindFramebuffer( _gl.FRAMEBUFFER, renderTexture.__webGLFramebuffer );
|
|
_gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_2D, renderTexture.__webGLTexture, 0 );
|
|
_gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.RENDERBUFFER, renderTexture.__webGLRenderbuffer );
|
|
|
|
// Release everything
|
|
|
|
_gl.bindTexture( _gl.TEXTURE_2D, null );
|
|
_gl.bindRenderbuffer( _gl.RENDERBUFFER, null );
|
|
_gl.bindFramebuffer( _gl.FRAMEBUFFER, null);
|
|
|
|
}
|
|
|
|
var framebuffer, width, height;
|
|
|
|
if ( renderTexture ) {
|
|
|
|
framebuffer = renderTexture.__webGLFramebuffer;
|
|
width = renderTexture.width;
|
|
height = renderTexture.height;
|
|
|
|
} else {
|
|
|
|
framebuffer = null;
|
|
width = _viewportWidth;
|
|
height = _viewportHeight;
|
|
|
|
}
|
|
|
|
if( framebuffer != _oldFramebuffer ) {
|
|
|
|
_gl.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );
|
|
_gl.viewport( _viewportX, _viewportY, width, height );
|
|
|
|
_oldFramebuffer = framebuffer;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
function updateRenderTargetMipmap( renderTarget ) {
|
|
|
|
_gl.bindTexture( _gl.TEXTURE_2D, renderTarget.__webGLTexture );
|
|
_gl.generateMipmap( _gl.TEXTURE_2D );
|
|
_gl.bindTexture( _gl.TEXTURE_2D, null );
|
|
|
|
};
|
|
|
|
function cacheUniformLocations( program, identifiers ) {
|
|
|
|
var i, l, id;
|
|
|
|
for( i = 0, l = identifiers.length; i < l; i++ ) {
|
|
|
|
id = identifiers[ i ];
|
|
program.uniforms[ id ] = _gl.getUniformLocation( program, id );
|
|
|
|
}
|
|
|
|
};
|
|
|
|
function cacheAttributeLocations( program, identifiers ) {
|
|
|
|
var i, l, id;
|
|
|
|
for( i = 0, l = identifiers.length; i < l; i++ ) {
|
|
|
|
id = identifiers[ i ];
|
|
program.attributes[ id ] = _gl.getAttribLocation( program, id );
|
|
|
|
}
|
|
|
|
};
|
|
|
|
function getShader( type, string ) {
|
|
|
|
var shader;
|
|
|
|
if ( type == "fragment" ) {
|
|
|
|
shader = _gl.createShader( _gl.FRAGMENT_SHADER );
|
|
|
|
} else if ( type == "vertex" ) {
|
|
|
|
shader = _gl.createShader( _gl.VERTEX_SHADER );
|
|
|
|
}
|
|
|
|
_gl.shaderSource( shader, string );
|
|
_gl.compileShader( shader );
|
|
|
|
if ( !_gl.getShaderParameter( shader, _gl.COMPILE_STATUS ) ) {
|
|
|
|
alert( _gl.getShaderInfoLog( shader ) );
|
|
return null;
|
|
|
|
}
|
|
|
|
return shader;
|
|
|
|
};
|
|
|
|
// fallback filters for non-power-of-2 textures
|
|
|
|
function filterFallback ( f ) {
|
|
|
|
switch ( f ) {
|
|
|
|
case THREE.NearestFilter:
|
|
case THREE.NearestMipMapNearestFilter:
|
|
case THREE.NearestMipMapLinearFilter: return _gl.NEAREST; break;
|
|
|
|
case THREE.LinearFilter:
|
|
case THREE.LinearMipMapNearestFilter:
|
|
case THREE.LinearMipMapLinearFilter: return _gl.LINEAR; break;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
function paramThreeToGL( p ) {
|
|
|
|
switch ( p ) {
|
|
|
|
case THREE.RepeatWrapping: return _gl.REPEAT; break;
|
|
case THREE.ClampToEdgeWrapping: return _gl.CLAMP_TO_EDGE; break;
|
|
case THREE.MirroredRepeatWrapping: return _gl.MIRRORED_REPEAT; break;
|
|
|
|
case THREE.NearestFilter: return _gl.NEAREST; break;
|
|
case THREE.NearestMipMapNearestFilter: return _gl.NEAREST_MIPMAP_NEAREST; break;
|
|
case THREE.NearestMipMapLinearFilter: return _gl.NEAREST_MIPMAP_LINEAR; break;
|
|
|
|
case THREE.LinearFilter: return _gl.LINEAR; break;
|
|
case THREE.LinearMipMapNearestFilter: return _gl.LINEAR_MIPMAP_NEAREST; break;
|
|
case THREE.LinearMipMapLinearFilter: return _gl.LINEAR_MIPMAP_LINEAR; break;
|
|
|
|
case THREE.ByteType: return _gl.BYTE; break;
|
|
case THREE.UnsignedByteType: return _gl.UNSIGNED_BYTE; break;
|
|
case THREE.ShortType: return _gl.SHORT; break;
|
|
case THREE.UnsignedShortType: return _gl.UNSIGNED_SHORT; break;
|
|
case THREE.IntType: return _gl.INT; break;
|
|
case THREE.UnsignedShortType: return _gl.UNSIGNED_INT; break;
|
|
case THREE.FloatType: return _gl.FLOAT; break;
|
|
|
|
case THREE.AlphaFormat: return _gl.ALPHA; break;
|
|
case THREE.RGBFormat: return _gl.RGB; break;
|
|
case THREE.RGBAFormat: return _gl.RGBA; break;
|
|
case THREE.LuminanceFormat: return _gl.LUMINANCE; break;
|
|
case THREE.LuminanceAlphaFormat: return _gl.LUMINANCE_ALPHA; break;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
};
|
|
|
|
function isPowerOfTwo( value ) {
|
|
|
|
return ( value & ( value - 1 ) ) == 0;
|
|
|
|
};
|
|
|
|
function materialNeedsSmoothNormals( material ) {
|
|
|
|
return material && material.shading != undefined && material.shading == THREE.SmoothShading;
|
|
|
|
};
|
|
|
|
function bufferNeedsSmoothNormals( geometryGroup, object ) {
|
|
|
|
var m, ml, i, l, meshMaterial, needsSmoothNormals = false;
|
|
|
|
for ( m = 0, ml = object.materials.length; m < ml; m++ ) {
|
|
|
|
meshMaterial = object.materials[ m ];
|
|
|
|
if ( meshMaterial instanceof THREE.MeshFaceMaterial ) {
|
|
|
|
for ( i = 0, l = geometryGroup.materials.length; i < l; i++ ) {
|
|
|
|
if ( materialNeedsSmoothNormals( geometryGroup.materials[ i ] ) ) {
|
|
|
|
needsSmoothNormals = true;
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if ( materialNeedsSmoothNormals( meshMaterial ) ) {
|
|
|
|
needsSmoothNormals = true;
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ( needsSmoothNormals ) break;
|
|
|
|
}
|
|
|
|
return needsSmoothNormals;
|
|
|
|
};
|
|
|
|
function allocateLights( lights, maxLights ) {
|
|
|
|
var l, ll, light, dirLights, pointLights, maxDirLights, maxPointLights;
|
|
dirLights = pointLights = maxDirLights = maxPointLights = 0;
|
|
|
|
for ( l = 0, ll = lights.length; l < ll; l++ ) {
|
|
|
|
light = lights[ l ];
|
|
|
|
if ( light instanceof THREE.DirectionalLight ) dirLights++;
|
|
if ( light instanceof THREE.PointLight ) pointLights++;
|
|
|
|
}
|
|
|
|
if ( ( pointLights + dirLights ) <= maxLights ) {
|
|
|
|
maxDirLights = dirLights;
|
|
maxPointLights = pointLights;
|
|
|
|
} else {
|
|
|
|
maxDirLights = Math.ceil( maxLights * dirLights / ( pointLights + dirLights ) );
|
|
maxPointLights = maxLights - maxDirLights;
|
|
|
|
}
|
|
|
|
return { 'directional' : maxDirLights, 'point' : maxPointLights };
|
|
|
|
};
|
|
|
|
/* DEBUG
|
|
function getGLParams() {
|
|
|
|
var params = {
|
|
|
|
'MAX_VARYING_VECTORS': _gl.getParameter( _gl.MAX_VARYING_VECTORS ),
|
|
'MAX_VERTEX_ATTRIBS': _gl.getParameter( _gl.MAX_VERTEX_ATTRIBS ),
|
|
|
|
'MAX_TEXTURE_IMAGE_UNITS': _gl.getParameter( _gl.MAX_TEXTURE_IMAGE_UNITS ),
|
|
'MAX_VERTEX_TEXTURE_IMAGE_UNITS': _gl.getParameter( _gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS ),
|
|
'MAX_COMBINED_TEXTURE_IMAGE_UNITS' : _gl.getParameter( _gl.MAX_COMBINED_TEXTURE_IMAGE_UNITS ),
|
|
|
|
'MAX_VERTEX_UNIFORM_VECTORS': _gl.getParameter( _gl.MAX_VERTEX_UNIFORM_VECTORS ),
|
|
'MAX_FRAGMENT_UNIFORM_VECTORS': _gl.getParameter( _gl.MAX_FRAGMENT_UNIFORM_VECTORS )
|
|
}
|
|
|
|
return params;
|
|
};
|
|
|
|
function dumpObject( obj ) {
|
|
|
|
var p, str = "";
|
|
for ( p in obj ) {
|
|
|
|
str += p + ": " + obj[p] + "\n";
|
|
|
|
}
|
|
|
|
return str;
|
|
}
|
|
*/
|
|
|
|
};
|
|
|
|
THREE.Snippets = {
|
|
|
|
// FOG
|
|
|
|
fog_pars_fragment: [
|
|
|
|
"#ifdef USE_FOG",
|
|
|
|
"uniform vec3 fogColor;",
|
|
|
|
"#ifdef FOG_EXP2",
|
|
"uniform float fogDensity;",
|
|
"#else",
|
|
"uniform float fogNear;",
|
|
"uniform float fogFar;",
|
|
"#endif",
|
|
|
|
"#endif"
|
|
|
|
].join("\n"),
|
|
|
|
fog_fragment: [
|
|
|
|
"#ifdef USE_FOG",
|
|
|
|
"float depth = gl_FragCoord.z / gl_FragCoord.w;",
|
|
|
|
"#ifdef FOG_EXP2",
|
|
"const float LOG2 = 1.442695;",
|
|
"float fogFactor = exp2( - fogDensity * fogDensity * depth * depth * LOG2 );",
|
|
"fogFactor = 1.0 - clamp( fogFactor, 0.0, 1.0 );",
|
|
"#else",
|
|
"float fogFactor = smoothstep( fogNear, fogFar, depth );",
|
|
"#endif",
|
|
|
|
"gl_FragColor = mix( gl_FragColor, vec4( fogColor, gl_FragColor.w ), fogFactor );",
|
|
|
|
"#endif"
|
|
|
|
].join("\n"),
|
|
|
|
// ENVIRONMENT MAP
|
|
|
|
envmap_pars_fragment: [
|
|
|
|
"#ifdef USE_ENVMAP",
|
|
|
|
"varying vec3 vReflect;",
|
|
"uniform float reflectivity;",
|
|
"uniform samplerCube envMap;",
|
|
"uniform int combine;",
|
|
|
|
"#endif"
|
|
|
|
].join("\n"),
|
|
|
|
envmap_fragment: [
|
|
|
|
"#ifdef USE_ENVMAP",
|
|
|
|
"vec4 cubeColor = textureCube( envMap, vec3( -vReflect.x, vReflect.yz ) );",
|
|
|
|
"if ( combine == 1 ) {",
|
|
|
|
//"gl_FragColor = mix( gl_FragColor, cubeColor, reflectivity );",
|
|
"gl_FragColor = vec4( mix( gl_FragColor.xyz, cubeColor.xyz, reflectivity ), opacity );",
|
|
|
|
"} else {",
|
|
|
|
"gl_FragColor = gl_FragColor * cubeColor;",
|
|
|
|
"}",
|
|
|
|
"#endif"
|
|
|
|
].join("\n"),
|
|
|
|
envmap_pars_vertex: [
|
|
|
|
"#ifdef USE_ENVMAP",
|
|
|
|
"varying vec3 vReflect;",
|
|
"uniform float refractionRatio;",
|
|
"uniform bool useRefract;",
|
|
|
|
"#endif"
|
|
|
|
].join("\n"),
|
|
|
|
envmap_vertex : [
|
|
|
|
"#ifdef USE_ENVMAP",
|
|
|
|
"vec4 mPosition = objectMatrix * vec4( position, 1.0 );",
|
|
"vec3 nWorld = mat3( objectMatrix[0].xyz, objectMatrix[1].xyz, objectMatrix[2].xyz ) * normal;",
|
|
|
|
"if ( useRefract ) {",
|
|
|
|
"vReflect = refract( normalize( mPosition.xyz - cameraPosition ), normalize( nWorld.xyz ), refractionRatio );",
|
|
|
|
"} else {",
|
|
|
|
"vReflect = reflect( normalize( mPosition.xyz - cameraPosition ), normalize( nWorld.xyz ) );",
|
|
|
|
"}",
|
|
|
|
"#endif"
|
|
|
|
].join("\n"),
|
|
|
|
// COLOR MAP (particles)
|
|
|
|
map_particle_pars_fragment: [
|
|
|
|
"#ifdef USE_MAP",
|
|
|
|
"uniform sampler2D map;",
|
|
|
|
"#endif"
|
|
|
|
].join("\n"),
|
|
|
|
|
|
map_particle_fragment: [
|
|
|
|
"#ifdef USE_MAP",
|
|
|
|
"gl_FragColor = gl_FragColor * texture2D( map, gl_PointCoord );",
|
|
|
|
"#endif"
|
|
|
|
].join("\n"),
|
|
|
|
// COLOR MAP (triangles)
|
|
|
|
map_pars_fragment: [
|
|
|
|
"#ifdef USE_MAP",
|
|
|
|
"varying vec2 vUv;",
|
|
"uniform sampler2D map;",
|
|
|
|
"#endif"
|
|
|
|
].join("\n"),
|
|
|
|
map_pars_vertex: [
|
|
|
|
"#ifdef USE_MAP",
|
|
|
|
"varying vec2 vUv;",
|
|
|
|
"#endif"
|
|
|
|
].join("\n"),
|
|
|
|
map_fragment: [
|
|
|
|
"#ifdef USE_MAP",
|
|
|
|
"gl_FragColor = gl_FragColor * texture2D( map, vUv );",
|
|
|
|
"#endif"
|
|
|
|
].join("\n"),
|
|
|
|
map_vertex: [
|
|
|
|
"#ifdef USE_MAP",
|
|
|
|
"vUv = uv;",
|
|
|
|
"#endif"
|
|
|
|
].join("\n"),
|
|
|
|
// LIGHT MAP
|
|
|
|
lightmap_pars_fragment: [
|
|
|
|
"#ifdef USE_LIGHTMAP",
|
|
|
|
"varying vec2 vUv2;",
|
|
"uniform sampler2D lightMap;",
|
|
|
|
"#endif"
|
|
|
|
].join("\n"),
|
|
|
|
lightmap_pars_vertex: [
|
|
|
|
"#ifdef USE_LIGHTMAP",
|
|
|
|
"varying vec2 vUv2;",
|
|
|
|
"#endif"
|
|
|
|
].join("\n"),
|
|
|
|
lightmap_fragment: [
|
|
|
|
"#ifdef USE_LIGHTMAP",
|
|
|
|
"gl_FragColor = gl_FragColor * texture2D( lightMap, vUv2 );",
|
|
|
|
"#endif"
|
|
|
|
].join("\n"),
|
|
|
|
lightmap_vertex: [
|
|
|
|
"#ifdef USE_LIGHTMAP",
|
|
|
|
"vUv2 = uv2;",
|
|
|
|
"#endif"
|
|
|
|
].join("\n"),
|
|
|
|
lights_pars_vertex: [
|
|
|
|
"uniform bool enableLighting;",
|
|
"uniform vec3 ambientLightColor;",
|
|
|
|
"#if MAX_DIR_LIGHTS > 0",
|
|
|
|
"uniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];",
|
|
"uniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];",
|
|
|
|
"#endif",
|
|
|
|
"#if MAX_POINT_LIGHTS > 0",
|
|
|
|
"uniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];",
|
|
"uniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];",
|
|
|
|
"#ifdef PHONG",
|
|
"varying vec3 vPointLightVector[ MAX_POINT_LIGHTS ];",
|
|
"#endif",
|
|
|
|
"#endif"
|
|
|
|
].join("\n"),
|
|
|
|
// LIGHTS
|
|
|
|
lights_vertex: [
|
|
|
|
"if ( !enableLighting ) {",
|
|
|
|
"vLightWeighting = vec3( 1.0 );",
|
|
|
|
"} else {",
|
|
|
|
"vLightWeighting = ambientLightColor;",
|
|
|
|
"#if MAX_DIR_LIGHTS > 0",
|
|
|
|
"for( int i = 0; i < MAX_DIR_LIGHTS; i++ ) {",
|
|
|
|
"vec4 lDirection = viewMatrix * vec4( directionalLightDirection[ i ], 0.0 );",
|
|
"float directionalLightWeighting = max( dot( transformedNormal, normalize( lDirection.xyz ) ), 0.0 );",
|
|
"vLightWeighting += directionalLightColor[ i ] * directionalLightWeighting;",
|
|
|
|
"}",
|
|
|
|
"#endif",
|
|
|
|
"#if MAX_POINT_LIGHTS > 0",
|
|
|
|
"for( int i = 0; i < MAX_POINT_LIGHTS; i++ ) {",
|
|
|
|
"vec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );",
|
|
"vec3 pointLightVector = normalize( lPosition.xyz - mvPosition.xyz );",
|
|
"float pointLightWeighting = max( dot( transformedNormal, pointLightVector ), 0.0 );",
|
|
"vLightWeighting += pointLightColor[ i ] * pointLightWeighting;",
|
|
|
|
"#ifdef PHONG",
|
|
"vPointLightVector[ i ] = pointLightVector;",
|
|
"#endif",
|
|
|
|
"}",
|
|
|
|
"#endif",
|
|
|
|
"}"
|
|
|
|
].join("\n"),
|
|
|
|
lights_pars_fragment: [
|
|
|
|
"#if MAX_DIR_LIGHTS > 0",
|
|
"uniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];",
|
|
"#endif",
|
|
|
|
"#if MAX_POINT_LIGHTS > 0",
|
|
"varying vec3 vPointLightVector[ MAX_POINT_LIGHTS ];",
|
|
"#endif",
|
|
|
|
"varying vec3 vViewPosition;",
|
|
"varying vec3 vNormal;"
|
|
|
|
].join("\n"),
|
|
|
|
lights_fragment: [
|
|
|
|
"vec3 normal = normalize( vNormal );",
|
|
"vec3 viewPosition = normalize( vViewPosition );",
|
|
|
|
"vec4 mColor = vec4( diffuse, opacity );",
|
|
"vec4 mSpecular = vec4( specular, opacity );",
|
|
|
|
"#if MAX_POINT_LIGHTS > 0",
|
|
|
|
"vec4 pointDiffuse = vec4( 0.0 );",
|
|
"vec4 pointSpecular = vec4( 0.0 );",
|
|
|
|
"for( int i = 0; i < MAX_POINT_LIGHTS; i++ ) {",
|
|
|
|
"vec3 pointVector = normalize( vPointLightVector[ i ] );",
|
|
"vec3 pointHalfVector = normalize( vPointLightVector[ i ] + vViewPosition );",
|
|
|
|
"float pointDotNormalHalf = dot( normal, pointHalfVector );",
|
|
"float pointDiffuseWeight = max( dot( normal, pointVector ), 0.0 );",
|
|
|
|
"float pointSpecularWeight = 0.0;",
|
|
"if ( pointDotNormalHalf >= 0.0 )",
|
|
"pointSpecularWeight = pow( pointDotNormalHalf, shininess );",
|
|
|
|
"pointDiffuse += mColor * pointDiffuseWeight;",
|
|
"pointSpecular += mSpecular * pointSpecularWeight;",
|
|
|
|
"}",
|
|
|
|
"#endif",
|
|
|
|
"#if MAX_DIR_LIGHTS > 0",
|
|
|
|
"vec4 dirDiffuse = vec4( 0.0 );",
|
|
"vec4 dirSpecular = vec4( 0.0 );" ,
|
|
|
|
"for( int i = 0; i < MAX_DIR_LIGHTS; i++ ) {",
|
|
|
|
"vec4 lDirection = viewMatrix * vec4( directionalLightDirection[ i ], 0.0 );",
|
|
|
|
"vec3 dirVector = normalize( lDirection.xyz );",
|
|
"vec3 dirHalfVector = normalize( lDirection.xyz + vViewPosition );",
|
|
|
|
"float dirDotNormalHalf = dot( normal, dirHalfVector );",
|
|
|
|
"float dirDiffuseWeight = max( dot( normal, dirVector ), 0.0 );",
|
|
|
|
"float dirSpecularWeight = 0.0;",
|
|
"if ( dirDotNormalHalf >= 0.0 )",
|
|
"dirSpecularWeight = pow( dirDotNormalHalf, shininess );",
|
|
|
|
"dirDiffuse += mColor * dirDiffuseWeight;",
|
|
"dirSpecular += mSpecular * dirSpecularWeight;",
|
|
|
|
"}",
|
|
|
|
"#endif",
|
|
|
|
"vec4 totalLight = vec4( ambient, opacity );",
|
|
|
|
"#if MAX_DIR_LIGHTS > 0",
|
|
"totalLight += dirDiffuse + dirSpecular;",
|
|
"#endif",
|
|
|
|
"#if MAX_POINT_LIGHTS > 0",
|
|
"totalLight += pointDiffuse + pointSpecular;",
|
|
"#endif",
|
|
|
|
"gl_FragColor = gl_FragColor * totalLight;"
|
|
|
|
].join("\n"),
|
|
|
|
// VERTEX COLORS
|
|
|
|
color_pars_fragment: [
|
|
|
|
"#ifdef USE_COLOR",
|
|
|
|
"varying vec3 vColor;",
|
|
|
|
"#endif"
|
|
|
|
].join("\n"),
|
|
|
|
|
|
color_fragment: [
|
|
|
|
"#ifdef USE_COLOR",
|
|
|
|
"gl_FragColor = gl_FragColor * vec4( vColor, opacity );",
|
|
|
|
"#endif"
|
|
|
|
].join("\n"),
|
|
|
|
color_pars_vertex: [
|
|
|
|
"#ifdef USE_COLOR",
|
|
|
|
"varying vec3 vColor;",
|
|
|
|
"#endif"
|
|
|
|
].join("\n"),
|
|
|
|
|
|
color_vertex: [
|
|
|
|
"#ifdef USE_COLOR",
|
|
|
|
"vColor = color;",
|
|
|
|
"#endif"
|
|
|
|
].join("\n"),
|
|
|
|
// skinning
|
|
|
|
skinning_pars_vertex: [
|
|
|
|
"#ifdef USE_SKINNING",
|
|
|
|
"uniform mat4 boneGlobalMatrices[20];",
|
|
|
|
"#endif"
|
|
|
|
].join("\n"),
|
|
|
|
skinning_vertex: [
|
|
|
|
"#ifdef USE_SKINNING",
|
|
|
|
"gl_Position = ( boneGlobalMatrices[ int( skinIndex.x ) ] * skinVertexA ) * skinWeight.x;",
|
|
"gl_Position += ( boneGlobalMatrices[ int( skinIndex.y ) ] * skinVertexB ) * skinWeight.y;",
|
|
|
|
// this doesn't work, no idea why
|
|
//"gl_Position = projectionMatrix * cameraInverseMatrix * objectMatrix * gl_Position;",
|
|
|
|
"gl_Position = projectionMatrix * viewMatrix * objectMatrix * gl_Position;",
|
|
|
|
"#else",
|
|
|
|
"gl_Position = projectionMatrix * mvPosition;",
|
|
|
|
"#endif"
|
|
|
|
].join("\n")
|
|
|
|
};
|
|
|
|
THREE.UniformsLib = {
|
|
|
|
common: {
|
|
|
|
"diffuse" : { type: "c", value: new THREE.Color( 0xeeeeee ) },
|
|
"opacity" : { type: "f", value: 1.0 },
|
|
"map" : { type: "t", value: 0, texture: null },
|
|
|
|
"lightMap" : { type: "t", value: 2, texture: null },
|
|
|
|
"envMap" : { type: "t", value: 1, texture: null },
|
|
"useRefract" : { type: "i", value: 0 },
|
|
"reflectivity" : { type: "f", value: 1.0 },
|
|
"refractionRatio": { type: "f", value: 0.98 },
|
|
"combine" : { type: "i", value: 0 },
|
|
|
|
"fogDensity": { type: "f", value: 0.00025 },
|
|
"fogNear" : { type: "f", value: 1 },
|
|
"fogFar" : { type: "f", value: 2000 },
|
|
"fogColor" : { type: "c", value: new THREE.Color( 0xffffff ) }
|
|
|
|
},
|
|
|
|
lights: {
|
|
|
|
"enableLighting" : { type: "i", value: 1 },
|
|
"ambientLightColor" : { type: "fv", value: [] },
|
|
"directionalLightDirection" : { type: "fv", value: [] },
|
|
"directionalLightColor" : { type: "fv", value: [] },
|
|
"pointLightPosition" : { type: "fv", value: [] },
|
|
"pointLightColor" : { type: "fv", value: [] }
|
|
|
|
},
|
|
|
|
particle: {
|
|
|
|
"psColor" : { type: "c", value: new THREE.Color( 0xeeeeee ) },
|
|
"opacity" : { type: "f", value: 1.0 },
|
|
"size" : { type: "f", value: 1.0 },
|
|
"map" : { type: "t", value: 0, texture: null },
|
|
|
|
"fogDensity": { type: "f", value: 0.00025 },
|
|
"fogNear" : { type: "f", value: 1 },
|
|
"fogFar" : { type: "f", value: 2000 },
|
|
"fogColor" : { type: "c", value: new THREE.Color( 0xffffff ) }
|
|
|
|
}
|
|
|
|
};
|
|
|
|
THREE.ShaderLib = {
|
|
|
|
'depth': {
|
|
|
|
uniforms: { "mNear": { type: "f", value: 1.0 },
|
|
"mFar" : { type: "f", value: 2000.0 },
|
|
"opacity" : { type: "f", value: 1.0 }
|
|
},
|
|
|
|
fragmentShader: [
|
|
|
|
"uniform float mNear;",
|
|
"uniform float mFar;",
|
|
"uniform float opacity;",
|
|
|
|
"void main() {",
|
|
|
|
"float depth = gl_FragCoord.z / gl_FragCoord.w;",
|
|
"float color = 1.0 - smoothstep( mNear, mFar, depth );",
|
|
"gl_FragColor = vec4( vec3( color ), opacity );",
|
|
|
|
"}"
|
|
|
|
].join("\n"),
|
|
|
|
vertexShader: [
|
|
|
|
"void main() {",
|
|
|
|
"gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",
|
|
|
|
"}"
|
|
|
|
].join("\n")
|
|
|
|
},
|
|
|
|
'normal': {
|
|
|
|
uniforms: { "opacity" : { type: "f", value: 1.0 } },
|
|
|
|
fragmentShader: [
|
|
|
|
"uniform float opacity;",
|
|
"varying vec3 vNormal;",
|
|
|
|
"void main() {",
|
|
|
|
"gl_FragColor = vec4( 0.5 * normalize( vNormal ) + 0.5, opacity );",
|
|
|
|
"}"
|
|
|
|
].join("\n"),
|
|
|
|
vertexShader: [
|
|
|
|
"varying vec3 vNormal;",
|
|
|
|
"void main() {",
|
|
|
|
"vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );",
|
|
"vNormal = normalize( normalMatrix * normal );",
|
|
|
|
"gl_Position = projectionMatrix * mvPosition;",
|
|
|
|
"}"
|
|
|
|
].join("\n")
|
|
|
|
},
|
|
|
|
'basic': {
|
|
|
|
uniforms: THREE.UniformsLib[ "common" ],
|
|
|
|
fragmentShader: [
|
|
|
|
"uniform vec3 diffuse;",
|
|
"uniform float opacity;",
|
|
|
|
THREE.Snippets[ "color_pars_fragment" ],
|
|
THREE.Snippets[ "map_pars_fragment" ],
|
|
THREE.Snippets[ "lightmap_pars_fragment" ],
|
|
THREE.Snippets[ "envmap_pars_fragment" ],
|
|
THREE.Snippets[ "fog_pars_fragment" ],
|
|
|
|
"void main() {",
|
|
|
|
"gl_FragColor = vec4( diffuse, opacity );",
|
|
|
|
THREE.Snippets[ "map_fragment" ],
|
|
THREE.Snippets[ "lightmap_fragment" ],
|
|
THREE.Snippets[ "color_fragment" ],
|
|
THREE.Snippets[ "envmap_fragment" ],
|
|
THREE.Snippets[ "fog_fragment" ],
|
|
|
|
"}"
|
|
|
|
].join("\n"),
|
|
|
|
vertexShader: [
|
|
|
|
THREE.Snippets[ "map_pars_vertex" ],
|
|
THREE.Snippets[ "lightmap_pars_vertex" ],
|
|
THREE.Snippets[ "envmap_pars_vertex" ],
|
|
THREE.Snippets[ "color_pars_vertex" ],
|
|
THREE.Snippets[ "skinning_pars_vertex" ],
|
|
|
|
"void main() {",
|
|
|
|
"vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );",
|
|
|
|
THREE.Snippets[ "map_vertex" ],
|
|
THREE.Snippets[ "lightmap_vertex" ],
|
|
THREE.Snippets[ "envmap_vertex" ],
|
|
THREE.Snippets[ "color_vertex" ],
|
|
THREE.Snippets[ "skinning_vertex" ],
|
|
|
|
"}"
|
|
|
|
].join("\n")
|
|
|
|
},
|
|
|
|
'lambert': {
|
|
|
|
uniforms: Uniforms.merge( [ THREE.UniformsLib[ "common" ],
|
|
THREE.UniformsLib[ "lights" ] ] ),
|
|
|
|
fragmentShader: [
|
|
|
|
"uniform vec3 diffuse;",
|
|
"uniform float opacity;",
|
|
|
|
"varying vec3 vLightWeighting;",
|
|
|
|
THREE.Snippets[ "color_pars_fragment" ],
|
|
THREE.Snippets[ "map_pars_fragment" ],
|
|
THREE.Snippets[ "lightmap_pars_fragment" ],
|
|
THREE.Snippets[ "envmap_pars_fragment" ],
|
|
THREE.Snippets[ "fog_pars_fragment" ],
|
|
|
|
"void main() {",
|
|
|
|
"gl_FragColor = vec4( diffuse, opacity );",
|
|
"gl_FragColor = gl_FragColor * vec4( vLightWeighting, 1.0 );",
|
|
|
|
THREE.Snippets[ "map_fragment" ],
|
|
THREE.Snippets[ "lightmap_fragment" ],
|
|
THREE.Snippets[ "color_fragment" ],
|
|
THREE.Snippets[ "envmap_fragment" ],
|
|
THREE.Snippets[ "fog_fragment" ],
|
|
|
|
"}"
|
|
|
|
].join("\n"),
|
|
|
|
vertexShader: [
|
|
|
|
"varying vec3 vLightWeighting;",
|
|
|
|
THREE.Snippets[ "map_pars_vertex" ],
|
|
THREE.Snippets[ "lightmap_pars_vertex" ],
|
|
THREE.Snippets[ "envmap_pars_vertex" ],
|
|
THREE.Snippets[ "lights_pars_vertex" ],
|
|
THREE.Snippets[ "color_pars_vertex" ],
|
|
THREE.Snippets[ "skinning_pars_vertex" ],
|
|
|
|
"void main() {",
|
|
|
|
"vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );",
|
|
|
|
THREE.Snippets[ "map_vertex" ],
|
|
THREE.Snippets[ "lightmap_vertex" ],
|
|
THREE.Snippets[ "envmap_vertex" ],
|
|
THREE.Snippets[ "color_vertex" ],
|
|
|
|
"vec3 transformedNormal = normalize( normalMatrix * normal );",
|
|
|
|
THREE.Snippets[ "lights_vertex" ],
|
|
THREE.Snippets[ "skinning_vertex" ],
|
|
|
|
"}"
|
|
|
|
].join("\n")
|
|
|
|
},
|
|
|
|
'phong': {
|
|
|
|
uniforms: Uniforms.merge( [ THREE.UniformsLib[ "common" ],
|
|
THREE.UniformsLib[ "lights" ],
|
|
|
|
{ "ambient" : { type: "c", value: new THREE.Color( 0x050505 ) },
|
|
"specular" : { type: "c", value: new THREE.Color( 0x111111 ) },
|
|
"shininess": { type: "f", value: 30 }
|
|
}
|
|
|
|
] ),
|
|
|
|
fragmentShader: [
|
|
|
|
"uniform vec3 diffuse;",
|
|
"uniform float opacity;",
|
|
|
|
"uniform vec3 ambient;",
|
|
"uniform vec3 specular;",
|
|
"uniform float shininess;",
|
|
|
|
"varying vec3 vLightWeighting;",
|
|
|
|
THREE.Snippets[ "color_pars_fragment" ],
|
|
THREE.Snippets[ "map_pars_fragment" ],
|
|
THREE.Snippets[ "lightmap_pars_fragment" ],
|
|
THREE.Snippets[ "envmap_pars_fragment" ],
|
|
THREE.Snippets[ "fog_pars_fragment" ],
|
|
THREE.Snippets[ "lights_pars_fragment" ],
|
|
|
|
"void main() {",
|
|
|
|
"gl_FragColor = vec4( vLightWeighting, 1.0 );",
|
|
THREE.Snippets[ "lights_fragment" ],
|
|
|
|
THREE.Snippets[ "map_fragment" ],
|
|
THREE.Snippets[ "lightmap_fragment" ],
|
|
THREE.Snippets[ "color_fragment" ],
|
|
THREE.Snippets[ "envmap_fragment" ],
|
|
THREE.Snippets[ "fog_fragment" ],
|
|
|
|
"}"
|
|
|
|
].join("\n"),
|
|
|
|
vertexShader: [
|
|
|
|
"#define PHONG",
|
|
|
|
"varying vec3 vLightWeighting;",
|
|
"varying vec3 vViewPosition;",
|
|
"varying vec3 vNormal;",
|
|
|
|
THREE.Snippets[ "map_pars_vertex" ],
|
|
THREE.Snippets[ "lightmap_pars_vertex" ],
|
|
THREE.Snippets[ "envmap_pars_vertex" ],
|
|
THREE.Snippets[ "lights_pars_vertex" ],
|
|
THREE.Snippets[ "color_pars_vertex" ],
|
|
THREE.Snippets[ "skinning_pars_vertex" ],
|
|
|
|
"void main() {",
|
|
|
|
"vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );",
|
|
|
|
THREE.Snippets[ "map_vertex" ],
|
|
THREE.Snippets[ "lightmap_vertex" ],
|
|
THREE.Snippets[ "envmap_vertex" ],
|
|
THREE.Snippets[ "color_vertex" ],
|
|
|
|
"#ifndef USE_ENVMAP",
|
|
"vec4 mPosition = objectMatrix * vec4( position, 1.0 );",
|
|
"#endif",
|
|
|
|
"vViewPosition = cameraPosition - mPosition.xyz;",
|
|
|
|
"vec3 transformedNormal = normalize( normalMatrix * normal );",
|
|
"vNormal = transformedNormal;",
|
|
|
|
THREE.Snippets[ "lights_vertex" ],
|
|
THREE.Snippets[ "skinning_vertex" ],
|
|
|
|
"}"
|
|
|
|
].join("\n")
|
|
|
|
},
|
|
|
|
'particle_basic': {
|
|
|
|
uniforms: THREE.UniformsLib[ "particle" ],
|
|
|
|
fragmentShader: [
|
|
|
|
"uniform vec3 psColor;",
|
|
"uniform float opacity;",
|
|
|
|
THREE.Snippets[ "color_pars_fragment" ],
|
|
THREE.Snippets[ "map_particle_pars_fragment" ],
|
|
THREE.Snippets[ "fog_pars_fragment" ],
|
|
|
|
"void main() {",
|
|
|
|
"gl_FragColor = vec4( psColor, opacity );",
|
|
|
|
THREE.Snippets[ "map_particle_fragment" ],
|
|
THREE.Snippets[ "color_fragment" ],
|
|
THREE.Snippets[ "fog_fragment" ],
|
|
|
|
"}"
|
|
|
|
].join("\n"),
|
|
|
|
vertexShader: [
|
|
|
|
"uniform float size;",
|
|
|
|
THREE.Snippets[ "color_pars_vertex" ],
|
|
|
|
"void main() {",
|
|
|
|
THREE.Snippets[ "color_vertex" ],
|
|
|
|
"vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );",
|
|
|
|
"gl_Position = projectionMatrix * mvPosition;",
|
|
"gl_PointSize = size;",
|
|
//"gl_PointSize = 10.0 + 6.0 * mvPosition.z;";
|
|
|
|
"}"
|
|
|
|
].join("\n")
|
|
|
|
}
|
|
|
|
|
|
};
|