mirror of
https://github.com/wahyd4/three.js.git
synced 2026-08-14 15:35:57 +10:00
Renamed: setClearColor( hex, opacity ) => setClearColorHex( hex, opacity ) New: setClearColor( color, opacity ) In this way it's a bit cheaper to animate clear color. Hope I didn't break examples - I searched for "setClearColor" and changed it in one place where it was used.
814 lines
20 KiB
JavaScript
814 lines
20 KiB
JavaScript
/**
|
|
* @author mrdoob / http://mrdoob.com/
|
|
*
|
|
* Based on code by:
|
|
* @author alteredq / http://alteredqualia.com/
|
|
* @author supereggbert / http://www.paulbrunt.co.uk/
|
|
*/
|
|
|
|
THREE.WebGLRenderer2 = function ( antialias ) {
|
|
|
|
var _renderList = null,
|
|
_projector = new THREE.Projector(),
|
|
|
|
_canvas = document.createElement( 'canvas' ),
|
|
|
|
_clearColor = new THREE.Color( 0x000000 ),
|
|
_clearOpacity = 0,
|
|
|
|
_gl, _currentProgram,
|
|
|
|
_modelViewMatrix = new THREE.Matrix4(),
|
|
_normalMatrix = new THREE.Matrix4(),
|
|
_viewMatrixArray = new Float32Array( 16 ),
|
|
_modelViewMatrixArray = new Float32Array( 16 ),
|
|
_projectionMatrixArray = new Float32Array( 16 ),
|
|
_normalMatrixArray = new Float32Array( 9 ),
|
|
_objectMatrixArray = new Float32Array( 16 );
|
|
|
|
try {
|
|
|
|
antialias = antialias !== undefined ? antialias : true;
|
|
_gl = _canvas.getContext( 'experimental-webgl', { antialias: antialias } );
|
|
|
|
} catch(e) { }
|
|
|
|
if ( !_gl ) {
|
|
|
|
alert("WebGL not supported");
|
|
throw "cannot create webgl context";
|
|
|
|
}
|
|
|
|
_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, _clearOpacity );
|
|
|
|
this.domElement = _canvas;
|
|
|
|
this.autoClear = true;
|
|
this.sortObjects = true;
|
|
|
|
this.setSize = function ( width, height ) {
|
|
|
|
_canvas.width = width;
|
|
_canvas.height = height;
|
|
_gl.viewport( 0, 0, _canvas.width, _canvas.height );
|
|
|
|
};
|
|
|
|
this.setClearColor = function( color, opacity ) {
|
|
|
|
_clearColor = color;
|
|
_clearOpacity = opacity;
|
|
|
|
_gl.clearColor( _clearColor.r, _clearColor.g, _clearColor.b, _clearOpacity );
|
|
|
|
};
|
|
|
|
this.setClearColorHex = function( hex, opacity ) {
|
|
|
|
_clearColor.setHex( hex );
|
|
_clearOpacity = opacity;
|
|
|
|
_gl.clearColor( _clearColor.r, _clearColor.g, _clearColor.b, _clearOpacity );
|
|
|
|
};
|
|
|
|
this.clear = function () {
|
|
|
|
_gl.clear( _gl.COLOR_BUFFER_BIT | _gl.DEPTH_BUFFER_BIT );
|
|
|
|
};
|
|
|
|
this.render = function( scene, camera ) {
|
|
|
|
var o, ol;
|
|
|
|
this.autoClear && this.clear();
|
|
|
|
camera.autoUpdateMatrix && camera.updateMatrix();
|
|
|
|
// Setup camera matrices
|
|
|
|
_viewMatrixArray.set( camera.matrix.flatten() );
|
|
_projectionMatrixArray.set( camera.projectionMatrix.flatten() );
|
|
|
|
_currentProgram = null;
|
|
|
|
/*
|
|
for ( o = 0, ol = scene.objects.length; o < ol; o++ ) {
|
|
|
|
renderObject( scene.objects[ o ] );
|
|
|
|
}
|
|
*/
|
|
|
|
_renderList = _projector.projectObjects( scene, camera, this.sortObjects );
|
|
|
|
for ( o = 0, ol = _renderList.length; o < ol; o++ ) {
|
|
|
|
renderObject( _renderList[ o ].object );
|
|
|
|
}
|
|
|
|
function renderObject( object ) {
|
|
|
|
var geometry, material, m, ml,
|
|
program, uniforms, attributes;
|
|
|
|
object.autoUpdateMatrix && object.updateMatrix();
|
|
|
|
// Setup object matrices
|
|
|
|
_objectMatrixArray.set( object.matrix.flatten() );
|
|
|
|
_modelViewMatrix.multiply( camera.matrix, object.matrix );
|
|
_modelViewMatrixArray.set( _modelViewMatrix.flatten() );
|
|
|
|
_normalMatrix = THREE.Matrix4.makeInvert3x3( _modelViewMatrix ).transpose();
|
|
_normalMatrixArray.set( _normalMatrix.m );
|
|
|
|
if ( object instanceof THREE.Mesh ) {
|
|
|
|
geometry = object.geometry;
|
|
|
|
if ( geometry.__webglBuffers == undefined ) {
|
|
|
|
if ( buildBuffers( geometry ) == false ) return;
|
|
|
|
}
|
|
|
|
for ( m = 0, ml = object.materials.length; m < ml; m ++ ) {
|
|
|
|
material = object.materials[ m ];
|
|
|
|
if ( material.__webglProgram == undefined ) {
|
|
|
|
if ( createProgram( material ) == false ) continue;
|
|
|
|
}
|
|
|
|
program = material.__webglProgram;
|
|
uniforms = program.uniforms;
|
|
attributes = program.attributes;
|
|
|
|
if( program != _currentProgram ) {
|
|
|
|
_currentProgram = program;
|
|
|
|
_gl.useProgram( program );
|
|
|
|
// scene
|
|
|
|
if ( scene.fog ) {
|
|
|
|
_gl.uniform1f( uniforms.fog, 1 );
|
|
_gl.uniform1f( uniforms.fogNear, scene.fog.near );
|
|
_gl.uniform1f( uniforms.fogFar, scene.fog.far );
|
|
_gl.uniform3f( uniforms.fogColor, scene.fog.color.r, scene.fog.color.g, scene.fog.color.b );
|
|
|
|
} else {
|
|
|
|
_gl.uniform1f( uniforms.fog, 0 );
|
|
|
|
}
|
|
|
|
// material
|
|
|
|
if ( material instanceof THREE.MeshBasicMaterial ||
|
|
material instanceof THREE.MeshLambertMaterial ||
|
|
material instanceof THREE.MeshPhongMaterial ) {
|
|
|
|
_gl.uniform3f( uniforms.mColor, material.color.r, material.color.g, material.color.b );
|
|
_gl.uniform1f( uniforms.mOpacity, material.opacity );
|
|
|
|
if ( material.map ) {
|
|
|
|
setTexture( material.map, 0 );
|
|
_gl.uniform1i( uniforms.tMap, 0 );
|
|
|
|
}
|
|
|
|
if ( material.env_map ) {
|
|
|
|
setTexture( material.env_map, 1 );
|
|
_gl.uniform1i( uniforms.tSpherical, 1 );
|
|
|
|
}
|
|
|
|
} else if ( material instanceof THREE.MeshNormalMaterial ) {
|
|
|
|
_gl.uniform1f( uniforms.mOpacity, material.opacity );
|
|
|
|
} else if ( material instanceof THREE.MeshDepthMaterial ) {
|
|
|
|
_gl.uniform1f( uniforms.mNear, camera.near );
|
|
_gl.uniform1f( uniforms.mFar, camera.far );
|
|
_gl.uniform1f( uniforms.mOpacity, material.opacity );
|
|
|
|
}
|
|
|
|
_gl.uniform3f( uniforms.cameraPosition, camera.position.x, camera.position.y, camera.position.z );
|
|
_gl.uniformMatrix4fv( uniforms.viewMatrix, false, _viewMatrixArray );
|
|
_gl.uniformMatrix4fv( uniforms.projectionMatrix, false, _projectionMatrixArray );
|
|
|
|
}
|
|
|
|
_gl.uniformMatrix4fv( uniforms.objectMatrix, false, _objectMatrixArray );
|
|
_gl.uniformMatrix4fv( uniforms.modelViewMatrix, false, _modelViewMatrixArray );
|
|
_gl.uniformMatrix3fv( uniforms.normalMatrix, false, _normalMatrixArray );
|
|
|
|
var buffer, buffers = geometry.__webglBuffers;
|
|
|
|
for ( var i = 0, l = buffers.length; i < l; i ++ ) {
|
|
|
|
buffer = buffers[ i ];
|
|
|
|
// vertices
|
|
|
|
_gl.bindBuffer( _gl.ARRAY_BUFFER, buffer.vertices );
|
|
_gl.vertexAttribPointer( attributes.position, 3, _gl.FLOAT, false, 0, 0 );
|
|
_gl.enableVertexAttribArray( attributes.position );
|
|
|
|
// normals
|
|
|
|
if ( attributes.normal >= 0 ) {
|
|
|
|
_gl.bindBuffer( _gl.ARRAY_BUFFER, buffer.normals );
|
|
_gl.vertexAttribPointer( attributes.normal, 3, _gl.FLOAT, false, 0, 0 );
|
|
_gl.enableVertexAttribArray( attributes.normal );
|
|
|
|
}
|
|
|
|
// uvs
|
|
|
|
if ( attributes.uv >= 0 ) {
|
|
|
|
if ( buffer.uvs ) {
|
|
|
|
_gl.bindBuffer( _gl.ARRAY_BUFFER, buffer.uvs );
|
|
_gl.vertexAttribPointer( attributes.uv, 2, _gl.FLOAT, false, 0, 0 );
|
|
_gl.enableVertexAttribArray( attributes.uv );
|
|
|
|
} else {
|
|
|
|
_gl.disableVertexAttribArray( attributes.uv );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// render triangles
|
|
|
|
if ( ! material.wireframe ) {
|
|
|
|
_gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, buffer.faces );
|
|
_gl.drawElements( _gl.TRIANGLES, buffer.faceCount, _gl.UNSIGNED_SHORT, 0 );
|
|
|
|
// render lines
|
|
|
|
} else {
|
|
|
|
_gl.lineWidth( material.wireframe_linewidth );
|
|
_gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, buffer.lines );
|
|
_gl.drawElements( _gl.LINES, buffer.lineCount, _gl.UNSIGNED_SHORT, 0 );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if ( object instanceof THREE.Line ) {
|
|
|
|
|
|
|
|
} else if ( object instanceof THREE.Particle ) {
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Buffers
|
|
|
|
function buildBuffers( geometry ) {
|
|
|
|
var itemCount = 0, vertexIndex, group,
|
|
f, fl, face, v1, v2, v3, v4, vertexNormals, faceNormal, normal, uv,
|
|
vertexGroups = [], faceGroups = [], lineGroups = [], normalGroups = [], uvGroups = [],
|
|
vertices, faces, lines, normals, uvs;
|
|
|
|
for ( f = 0, fl = geometry.faces.length; f < fl; f++ ) {
|
|
|
|
face = geometry.faces[ f ];
|
|
uv = geometry.uvs[ f ];
|
|
vertexNormals = face.vertexNormals;
|
|
faceNormal = face.normal;
|
|
|
|
if ( face instanceof THREE.Face3 ) {
|
|
|
|
itemCount += 3;
|
|
group = Math.floor( itemCount / 65535 );
|
|
|
|
if ( !vertexGroups[ group ] ) {
|
|
|
|
vertexIndex = 0;
|
|
vertices = vertexGroups[ group ] = [];
|
|
normals = normalGroups[ group ] = [];
|
|
uvs = uvGroups[ group ] = [];
|
|
faces = faceGroups[ group ] = [];
|
|
lines = lineGroups[ group ] = [];
|
|
|
|
}
|
|
|
|
v1 = geometry.vertices[ face.a ].position;
|
|
v2 = geometry.vertices[ face.b ].position;
|
|
v3 = geometry.vertices[ face.c ].position;
|
|
|
|
vertices.push( v1.x, v1.y, v1.z );
|
|
vertices.push( v2.x, v2.y, v2.z );
|
|
vertices.push( v3.x, v3.y, v3.z );
|
|
|
|
if ( vertexNormals.length == 3 ) {
|
|
|
|
for ( i = 0; i < 3; i ++ ) {
|
|
|
|
normals.push( vertexNormals[ i ].x, vertexNormals[ i ].y, vertexNormals[ i ].z );
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
for ( i = 0; i < 3; i ++ ) {
|
|
|
|
normals.push( faceNormal.x, faceNormal.y, faceNormal.z );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ( uv ) {
|
|
|
|
for ( i = 0; i < 3; i ++ ) {
|
|
|
|
uvs.push( uv[ i ].u, uv[ i ].v );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
faces.push( vertexIndex, vertexIndex + 1, vertexIndex + 2 );
|
|
|
|
// TODO: don't add lines that already exist (faces sharing edge)
|
|
|
|
lines.push( vertexIndex, vertexIndex + 1 );
|
|
lines.push( vertexIndex, vertexIndex + 2 );
|
|
lines.push( vertexIndex + 1, vertexIndex + 2 );
|
|
|
|
vertexIndex += 3;
|
|
|
|
} else if ( face instanceof THREE.Face4 ) {
|
|
|
|
itemCount += 4;
|
|
group = Math.floor( itemCount / 65535 );
|
|
|
|
if ( !vertexGroups[ group ] ) {
|
|
|
|
vertexIndex = 0;
|
|
vertices = vertexGroups[ group ] = [];
|
|
normals = normalGroups[ group ] = [];
|
|
uvs = uvGroups[ group ] = [];
|
|
faces = faceGroups[ group ] = [];
|
|
lines = lineGroups[ group ] = [];
|
|
|
|
}
|
|
|
|
v1 = geometry.vertices[ face.a ].position;
|
|
v2 = geometry.vertices[ face.b ].position;
|
|
v3 = geometry.vertices[ face.c ].position;
|
|
v4 = geometry.vertices[ face.d ].position;
|
|
|
|
vertices.push( v1.x, v1.y, v1.z );
|
|
vertices.push( v2.x, v2.y, v2.z );
|
|
vertices.push( v3.x, v3.y, v3.z );
|
|
vertices.push( v4.x, v4.y, v4.z );
|
|
|
|
if ( vertexNormals.length == 4 ) {
|
|
|
|
for ( i = 0; i < 4; i ++ ) {
|
|
|
|
normals.push( vertexNormals[ i ].x, vertexNormals[ i ].y, vertexNormals[ i ].z );
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
for ( i = 0; i < 4; i ++ ) {
|
|
|
|
normals.push( faceNormal.x, faceNormal.y, faceNormal.z );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ( uv ) {
|
|
|
|
for ( i = 0; i < 4; i ++ ) {
|
|
|
|
uvs.push( uv[ i ].u, uv[ i ].v );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
faces.push( vertexIndex, vertexIndex + 1, vertexIndex + 2 );
|
|
faces.push( vertexIndex, vertexIndex + 2, vertexIndex + 3 );
|
|
|
|
// TODO: don't add lines that already exist (faces sharing edge)
|
|
|
|
lines.push( vertexIndex, vertexIndex + 1 );
|
|
lines.push( vertexIndex, vertexIndex + 3 );
|
|
lines.push( vertexIndex + 1, vertexIndex + 2 );
|
|
lines.push( vertexIndex + 2, vertexIndex + 3 );
|
|
|
|
vertexIndex += 4;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ( !vertices.length ) return false;
|
|
|
|
var buffer, buffers = [];
|
|
|
|
for ( var i = 0, l = group; i <= l; i ++ ) {
|
|
|
|
buffer = {
|
|
|
|
vertices: null,
|
|
faces: null,
|
|
faceCount: faceGroups[ i ].length,
|
|
normals: null,
|
|
lines: null,
|
|
lineCount: lineGroups[ i ].length,
|
|
uvs: null
|
|
|
|
};
|
|
|
|
buffer.vertices = _gl.createBuffer();
|
|
_gl.bindBuffer( _gl.ARRAY_BUFFER, buffer.vertices );
|
|
_gl.bufferData( _gl.ARRAY_BUFFER, new Float32Array( vertexGroups[ i ] ), _gl.STATIC_DRAW );
|
|
|
|
buffer.normals = _gl.createBuffer();
|
|
_gl.bindBuffer( _gl.ARRAY_BUFFER, buffer.normals );
|
|
_gl.bufferData( _gl.ARRAY_BUFFER, new Float32Array( normalGroups[ i ] ), _gl.STATIC_DRAW );
|
|
|
|
if ( uvs.length > 0 ) {
|
|
|
|
buffer.uvs = _gl.createBuffer();
|
|
_gl.bindBuffer( _gl.ARRAY_BUFFER, buffer.uvs );
|
|
_gl.bufferData( _gl.ARRAY_BUFFER, new Float32Array( uvGroups[ i ] ), _gl.STATIC_DRAW );
|
|
|
|
}
|
|
|
|
buffer.faces = _gl.createBuffer();
|
|
_gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, buffer.faces );
|
|
_gl.bufferData( _gl.ELEMENT_ARRAY_BUFFER, new Uint16Array( faceGroups[ i ] ), _gl.STATIC_DRAW );
|
|
|
|
buffer.lines = _gl.createBuffer();
|
|
_gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, buffer.lines );
|
|
_gl.bufferData( _gl.ELEMENT_ARRAY_BUFFER, new Uint16Array( lineGroups[ i ] ), _gl.STATIC_DRAW );
|
|
|
|
buffers.push( buffer );
|
|
|
|
}
|
|
|
|
geometry.__webglBuffers = buffers;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
// Shaders
|
|
|
|
function createProgram( material ) {
|
|
|
|
var vs, fs, identifiers = [ 'viewMatrix', 'modelViewMatrix', 'projectionMatrix', 'normalMatrix', 'objectMatrix', 'cameraPosition' ];
|
|
|
|
if ( material instanceof THREE.MeshBasicMaterial ||
|
|
material instanceof THREE.MeshLambertMaterial ||
|
|
material instanceof THREE.MeshPhongMaterial ) {
|
|
|
|
vs = [
|
|
material.map ? 'varying vec2 vUv;' : null,
|
|
material.env_map ? 'varying vec2 vSpherical;' : null,
|
|
|
|
'void main() {',
|
|
'gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );',
|
|
|
|
material.map ? 'vUv = uv;' : null,
|
|
|
|
material.env_map ? 'vec3 u = normalize( modelViewMatrix * vec4( position, 1.0 ) ).xyz;' : null,
|
|
material.env_map ? 'vec3 n = normalize( normalMatrix * normal );' : null,
|
|
material.env_map ? 'vec3 r = reflect( u, n );' : null,
|
|
material.env_map ? 'float m = 2.0 * sqrt( r.x * r.x + r.y * r.y + ( r.z + 1.0 ) * ( r.z + 1.0 ) );' : null,
|
|
material.env_map ? 'vSpherical.x = r.x / m + 0.5;' : null,
|
|
material.env_map ? 'vSpherical.y = - r.y / m + 0.5;' : null,
|
|
|
|
'}'
|
|
].filter( removeNull ).join( '\n' );
|
|
|
|
fs = [
|
|
'uniform vec3 mColor;',
|
|
'uniform float mOpacity;',
|
|
|
|
material.map ? 'uniform sampler2D tMap;' : null,
|
|
material.map ? 'varying vec2 vUv;' : null,
|
|
|
|
material.env_map ? 'uniform sampler2D tSpherical;' : null,
|
|
material.env_map ? 'varying vec2 vSpherical;' : null,
|
|
|
|
material.fog ? 'uniform float fog;' : null,
|
|
material.fog ? 'uniform float fogNear;' : null,
|
|
material.fog ? 'uniform float fogFar;' : null,
|
|
material.fog ? 'uniform vec3 fogColor;' : null,
|
|
|
|
'void main() {',
|
|
'gl_FragColor = vec4( mColor.xyz, mOpacity );',
|
|
|
|
/* Premultiply alpha
|
|
material.map ? 'vec4 mapColor = texture2D( tMap, vUv );' : null,
|
|
material.map ? 'mapColor.xyz *= mapColor.w;' : null,
|
|
*/
|
|
|
|
material.map ? 'gl_FragColor *= texture2D( tMap, vUv );' : null,
|
|
|
|
material.env_map ? 'gl_FragColor += texture2D( tSpherical, vSpherical );' : null,
|
|
|
|
material.fog ? 'float depth = gl_FragCoord.z / gl_FragCoord.w;' : null,
|
|
material.fog ? 'float fogFactor = fog * smoothstep( fogNear, fogFar, depth );' : null,
|
|
material.fog ? 'gl_FragColor = mix( gl_FragColor, vec4( fogColor, 1.0 ), fogFactor );' : null,
|
|
'}'
|
|
].filter( removeNull ).join( '\n' );
|
|
|
|
identifiers.push( 'mColor', 'mOpacity' );
|
|
|
|
if ( material.map ) identifiers.push( 'tMap' );
|
|
if ( material.env_map ) identifiers.push( 'tSpherical' );
|
|
if ( material.fog ) identifiers.push( 'fog', 'fogColor', 'fogNear', 'fogFar' );
|
|
|
|
|
|
} else if ( material instanceof THREE.MeshNormalMaterial ) {
|
|
|
|
vs = [
|
|
'varying vec3 vNormal;',
|
|
|
|
'void main() {',
|
|
'gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );',
|
|
'vNormal = normalize( normalMatrix * normal );',
|
|
'}'
|
|
].join( '\n' );
|
|
|
|
fs = [
|
|
'uniform float mOpacity;',
|
|
'varying vec3 vNormal;',
|
|
|
|
'void main() {',
|
|
'gl_FragColor = vec4( ( normalize( vNormal ) + 1.0 ) * 0.5, mOpacity );',
|
|
'}'
|
|
].join( '\n' );
|
|
|
|
identifiers.push( 'mOpacity' );
|
|
|
|
} else if ( material instanceof THREE.MeshDepthMaterial ) {
|
|
|
|
vs = [
|
|
'void main() {',
|
|
'gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );',
|
|
'}'
|
|
|
|
].join( '\n' );
|
|
|
|
fs = [
|
|
'uniform float mNear;',
|
|
'uniform float mFar;',
|
|
'uniform float mOpacity;',
|
|
|
|
'void main() {',
|
|
'float depth = gl_FragCoord.z / gl_FragCoord.w;',
|
|
'float color = 1.0 - smoothstep( mNear, mFar, depth );',
|
|
'gl_FragColor = vec4( vec3( color ), 1.0 );',
|
|
'}'
|
|
].join( '\n' );
|
|
|
|
identifiers.push( 'mNear', 'mFar', 'mOpacity' );
|
|
|
|
} else if ( material instanceof THREE.MeshShaderMaterial ) {
|
|
|
|
vs = material.vertex_shader;
|
|
fs = material.fragment_shader;
|
|
|
|
for( uniform in material.uniforms ) {
|
|
|
|
identifiers.push( uniform );
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
material.__webglProgram = compileProgram( vs, fs );
|
|
|
|
cacheUniformLocations( material.__webglProgram, identifiers );
|
|
cacheAttributeLocations( material.__webglProgram, [ "position", "normal", "uv"/*, "tangent"*/ ] );
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
function compileProgram( vertex_shader, fragment_shader ) {
|
|
|
|
var program = _gl.createProgram(), shader, prefix_vertex, prefix_fragment;
|
|
|
|
prefix_vertex = [
|
|
maxVertexTextures() > 0 ? "#define VERTEX_TEXTURES" : "",
|
|
|
|
"uniform mat4 objectMatrix;",
|
|
"uniform mat4 modelViewMatrix;",
|
|
"uniform mat4 projectionMatrix;",
|
|
//"uniform mat4 viewMatrix;",
|
|
"uniform mat3 normalMatrix;",
|
|
"uniform vec3 cameraPosition;",
|
|
"attribute vec3 position;",
|
|
"attribute vec3 normal;",
|
|
"attribute vec2 uv;",
|
|
""
|
|
].join("\n"),
|
|
|
|
prefix_fragment = [
|
|
"#ifdef GL_ES",
|
|
"precision highp float;",
|
|
"#endif",
|
|
//"uniform mat4 viewMatrix;",
|
|
""
|
|
].join("\n");
|
|
|
|
// Vertex shader
|
|
|
|
shader = _gl.createShader( _gl.VERTEX_SHADER );
|
|
_gl.shaderSource( shader, prefix_vertex + vertex_shader );
|
|
_gl.compileShader( shader );
|
|
_gl.attachShader( program, shader );
|
|
|
|
if ( !_gl.getShaderParameter( shader, _gl.COMPILE_STATUS ) ) {
|
|
|
|
alert( _gl.getShaderInfoLog( shader ) );
|
|
return null;
|
|
|
|
}
|
|
|
|
// Fragment Shader
|
|
|
|
shader = _gl.createShader( _gl.FRAGMENT_SHADER );
|
|
_gl.shaderSource( shader, prefix_fragment + fragment_shader );
|
|
_gl.compileShader( shader );
|
|
_gl.attachShader( program, shader );
|
|
|
|
if ( !_gl.getShaderParameter( shader, _gl.COMPILE_STATUS ) ) {
|
|
|
|
alert( _gl.getShaderInfoLog( shader ) );
|
|
return null;
|
|
|
|
}
|
|
|
|
_gl.linkProgram( program );
|
|
|
|
if ( !_gl.getProgramParameter( program, _gl.LINK_STATUS ) ) {
|
|
|
|
alert( "Could not initialise shaders.\n" +
|
|
"VALIDATE_STATUS: " + _gl.getProgramParameter( program, _gl.VALIDATE_STATUS ) + "\n" +
|
|
"ERROR: " + _gl.getError() + "\n\n" +
|
|
"- Vertex Shader -\n" + prefix_vertex + vertex_shader + "\n\n" +
|
|
"- Fragment Shader -\n" + prefix_fragment + fragment_shader );
|
|
|
|
}
|
|
|
|
program.uniforms = {};
|
|
program.attributes = {};
|
|
|
|
return program;
|
|
|
|
}
|
|
|
|
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 );
|
|
|
|
if ( program.attributes[ id ] >= 0 ) {
|
|
|
|
_gl.enableVertexAttribArray( program.attributes[ id ] );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Textures
|
|
|
|
function setTexture( texture, slot ) {
|
|
|
|
if ( !texture.__webglTexture && texture.image.loaded ) {
|
|
|
|
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 );
|
|
|
|
_gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_WRAP_S, paramThreeToGL( texture.wrap_s ) );
|
|
_gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_WRAP_T, paramThreeToGL( texture.wrap_t ) );
|
|
|
|
_gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_MAG_FILTER, paramThreeToGL( texture.mag_filter ) );
|
|
_gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_MIN_FILTER, paramThreeToGL( texture.min_filter ) );
|
|
_gl.generateMipmap( _gl.TEXTURE_2D );
|
|
_gl.bindTexture( _gl.TEXTURE_2D, null );
|
|
|
|
}
|
|
|
|
_gl.activeTexture( _gl.TEXTURE0 + slot );
|
|
_gl.bindTexture( _gl.TEXTURE_2D, texture.__webglTexture );
|
|
|
|
}
|
|
|
|
function maxVertexTextures() {
|
|
|
|
return _gl.getParameter( _gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS );
|
|
|
|
};
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
function removeNull( element ) {
|
|
|
|
return element !== null;
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
};
|