Browse Source

Added handling of multiple lights to WebGLRenderer.

Limitations:

 - Chrome can handle up to 5 lights in total (directional + point)
 - Firefox seems to handle up to 29 lights

These number are GPU specific (mine is ATI Mobility Radeon 3650).

This turned out to be quite tricky. The number of varying vectors in shaders is limited. Additionally Chrome and Firefox have different limitations (at least on Windows, probably due to Chrome using ANGLE as rendering backend).

Hence WebGLRenderer has hardcoded limit of maximum 5 lights.

WebGLRenderer constructor now takes (optional) scene argument, so that numbers and types of lights present in the scene can be used to generate minimal possible shader.

If no scene is passed, shader allowing 1 directional + 4 point lights will be generated.
alteredq 14 years ago
parent
commit
1c35d90fd7

File diff suppressed because it is too large
+ 0 - 1
build/Three.js


File diff suppressed because it is too large
+ 0 - 1
build/ThreeDebug.js


+ 3 - 3
examples/lights_test.html

@@ -15,7 +15,7 @@
             h1 { }
             a { color:skyblue }
             canvas { pointer-events:none; z-index:10; position:relative; }
-            #log { position:absolute; top:50px; text-align:left; display:block; z-index:100 }
+            #log { position:absolute; top:50px; text-align:left; display:block; z-index:100; }
             #d { text-align:center; margin:1em 0 -15.7em 0; z-index:0; position:relative; display:block }
             .button { background:#000; color:#fff; padding:0.2em 0.5em; cursor:pointer }
             .inactive { background:#999; color:#eee }
@@ -37,7 +37,7 @@
             <p>Canvas renderer is very slow on anything other than Chrome.
         </div>
         
-        <div id="log"></div>
+        <pre id="log"></pre>
 
 		<!--
         <script type="text/javascript" src="../build/Three.js"></script> 
@@ -193,7 +193,7 @@
 
                 if ( render_gl ) {
                     try {
-                        webglRenderer = new THREE.WebGLRenderer();
+                        webglRenderer = new THREE.WebGLRenderer( scene );
                         webglRenderer.setSize( SCREEN_WIDTH, SCREEN_HEIGHT );
                         container.appendChild( webglRenderer.domElement );
                         has_gl = 1;

+ 2 - 2
examples/obj_convert_test.html

@@ -42,10 +42,11 @@
         
         <div id="log"></div>
 
-		<!--
         <script type="text/javascript" src="../build/Three.js"></script> 
+		<!--
         -->
 
+		<!--
 		<script type="text/javascript" src="../src/Three.js"></script>
 		<script type="text/javascript" src="../src/core/Color.js"></script>
 		<script type="text/javascript" src="../src/core/Vector2.js"></script>
@@ -85,7 +86,6 @@
 		<script type="text/javascript" src="../src/renderers/renderables/RenderableFace4.js"></script>
 		<script type="text/javascript" src="../src/renderers/renderables/RenderableParticle.js"></script>
 		<script type="text/javascript" src="../src/renderers/renderables/RenderableLine.js"></script>
-		<!--
         -->
 		
 

+ 2 - 3
examples/shader_test.html

@@ -39,7 +39,7 @@
             <p>Blinn-Phong shader only works in WebGL, canvas has only diffuse materials.
         </div>
         
-        <div id="log"></div>
+        <pre id="log"></pre>
 
 		<!--
         <script type="text/javascript" src="../build/Three.js"></script> 
@@ -177,7 +177,6 @@
                 pointLight.position.z = 0;
 				scene.addLight( pointLight );
 
-
                 // light representation
                 sphere = new Sphere( 100, 16, 8, 1 );
                 lightMesh = new THREE.Mesh( sphere, new THREE.MeshColorFillMaterial( 0xffaa00 ) );
@@ -215,7 +214,7 @@
 
                 if ( render_gl ) {
                     try {
-                        webglRenderer = new THREE.WebGLRenderer();
+                        webglRenderer = new THREE.WebGLRenderer( scene );
                         webglRenderer.setSize( SCREEN_WIDTH, SCREEN_HEIGHT );
                         container.appendChild( webglRenderer.domElement );
                         has_gl = 1;

+ 360 - 136
src/renderers/WebGLRenderer.js

@@ -1,19 +1,78 @@
 /**
  * @author supereggbert / http://www.paulbrunt.co.uk/
  * @author mrdoob / http://mrdoob.com/
+ * @author alteredq / http://alteredqualia.com/
  */
 
-THREE.WebGLRenderer = function () {
-
+THREE.WebGLRenderer = function ( scene ) {
+	
+	// Currently you can use just up to 5 directional / point lights total.
+	// Chrome barfs on shader linking when there are more than 5 lights :(
+		
+	// It seems problem comes from having too many varying vectors.
+	
+	// Weirdly, this is not GPU limitation as the same shader works ok in Firefox.
+	// This difference could come from Chrome using ANGLE on Windows, 
+	// thus going DirectX9 route (while FF uses OpenGL).
+	
 	var _canvas = document.createElement( 'canvas' ), _gl, _program,
 	_modelViewMatrix = new THREE.Matrix4(), _normalMatrix,
-	COLORFILL = 0, COLORSTROKE = 1, BITMAP = 2, PHONG = 3; // material constants used in shader
-
+	
+	COLORFILL = 0, COLORSTROKE = 1, BITMAP = 2, PHONG = 3, // material constants used in shader
+	
+	maxLightCount = allocateLights( scene, 5 );
+	
 	this.domElement = _canvas;
 	this.autoClear = true;
 
 	initGL();
-	initProgram();
+	initProgram( maxLightCount.directional, maxLightCount.point );
+	
+	// Querying via gl.getParameter() reports different values for CH and FF for many max parameters.
+	// On my GPU Chrome reports MAX_VARYING_VECTORS = 8, FF reports 0 yet compiles shaders with many
+	// more varying vectors (up to 29 lights are ok, more start to throw warnings to FF error console
+	// and then crash the browser).
+	
+	//alert( dumpObject( getGLParams() ) );
+	
+	
+	function allocateLights( scene, maxLights ) {
+
+		// heuristics to create shader parameters according to lights in the scene
+		// (not to blow over maxLights budget)
+		
+		if ( scene ) {
+
+			var l, ll, light, dirLights = pointLights = maxDirLights = maxPointLights = 0;
+			
+			for ( l = 0, ll = scene.lights.length; l < ll; l++ ) {
+				
+				light = scene.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 };
+			
+		}
+		
+		return { 'directional' : 1, 'point' : maxLights - 1 };
+		
+	};
 
 	this.setSize = function ( width, height ) {
 
@@ -31,7 +90,9 @@ THREE.WebGLRenderer = function () {
 
 	this.setupLights = function ( scene ) {
 
-	var l, ll, lightColor, lightPosition, lightIntensity, light;
+		var l, ll, light, r, g, b,
+		    ambientLights = [], pointLights = [], directionalLights = [],
+			colors = [], positions = [];
 
 		_gl.uniform1i( _program.enableLighting, scene.lights.length );
 
@@ -41,29 +102,85 @@ THREE.WebGLRenderer = function () {
 
 			if ( light instanceof THREE.AmbientLight ) {
 
-				lightColor = light.color;
-				_gl.uniform3f( _program.ambientLightColor, lightColor.r, lightColor.g, lightColor.b );
+				ambientLights.push( light );
 
 			} else if ( light instanceof THREE.DirectionalLight ) {
 
-				lightColor = light.color;
-				lightPosition = light.position;
-				lightIntensity = light.intensity;
-				_gl.uniform3f( _program.directionalLightDirection, lightPosition.x, lightPosition.y, lightPosition.z );
-				_gl.uniform3f( _program.directionalLightColor, lightColor.r * lightIntensity, lightColor.g * lightIntensity, lightColor.b * lightIntensity );
+				directionalLights.push( light );
 
 			} else if( light instanceof THREE.PointLight ) {
 
-				lightColor = light.color;
-				lightPosition = light.position;
-				lightIntensity = light.intensity;
-				_gl.uniform3f( _program.pointLightPosition, lightPosition.x, lightPosition.y, lightPosition.z );
-				_gl.uniform3f( _program.pointLightColor, lightColor.r * lightIntensity, lightColor.g * lightIntensity, lightColor.b * lightIntensity );
-
+				pointLights.push( light );
+				
 			}
 
 		}
+		
+		// sum all ambient lights
+		r = g = b = 0.0;
+		
+		for ( l = 0, ll = ambientLights.length; l < ll; l++ ) {
+			
+			r += ambientLights[ l ].color.r;
+			g += ambientLights[ l ].color.g;
+			b += ambientLights[ l ].color.b;
+			
+		}
+		
+		_gl.uniform3f( _program.ambientLightColor, r, g, b );
+
+		// pass directional lights as float arrays
+		
+		colors = []; positions = [];
+		
+		for ( l = 0, ll = directionalLights.length; l < ll; l++ ) {
+			
+			light = directionalLights[ l ];
+			
+			colors.push( light.color.r * light.intensity );
+			colors.push( light.color.g * light.intensity );
+			colors.push( light.color.b * light.intensity );
+
+			positions.push( light.position.x );
+			positions.push( light.position.y );
+			positions.push( light.position.z );
+			
+		}
+		
+		if ( directionalLights.length ) {
+
+			_gl.uniform1i(  _program.directionalLightNumber, directionalLights.length );
+			_gl.uniform3fv( _program.directionalLightDirection, positions );
+			_gl.uniform3fv( _program.directionalLightColor, colors );
+			
+		}
 
+		// pass point lights as float arrays
+		
+		colors = []; positions = [];
+		
+		for ( l = 0, ll = pointLights.length; l < ll; l++ ) {
+			
+			light = pointLights[ l ];
+			
+			colors.push( light.color.r * light.intensity );
+			colors.push( light.color.g * light.intensity );
+			colors.push( light.color.b * light.intensity );
+
+			positions.push( light.position.x );
+			positions.push( light.position.y );
+			positions.push( light.position.z );
+			
+		}
+		
+		if ( pointLights.length ) {
+
+			_gl.uniform1i(  _program.pointLightNumber, pointLights.length );
+			_gl.uniform3fv( _program.pointLightPosition, positions );
+			_gl.uniform3fv( _program.pointLightColor, colors );
+		
+		}
+		
 	};
 
 	this.createBuffers = function ( object, mf ) {
@@ -268,17 +385,17 @@ THREE.WebGLRenderer = function () {
 		}
 
 		// vertices
-        
+		
 		_gl.bindBuffer( _gl.ARRAY_BUFFER, materialFaceGroup.__webGLVertexBuffer );
 		_gl.vertexAttribPointer( _program.position, 3, _gl.FLOAT, false, 0, 0 );
 
 		// normals
-        
+		
 		_gl.bindBuffer( _gl.ARRAY_BUFFER, materialFaceGroup.__webGLNormalBuffer );
 		_gl.vertexAttribPointer( _program.normal, 3, _gl.FLOAT, false, 0, 0 );
 
 		// uvs
-        
+		
 		if ( material instanceof THREE.MeshBitmapMaterial ) {
 
 			_gl.bindBuffer( _gl.ARRAY_BUFFER, materialFaceGroup.__webGLUVBuffer );
@@ -293,7 +410,7 @@ THREE.WebGLRenderer = function () {
 		}
 
 		// render triangles
-        
+		
 		if ( material instanceof THREE.MeshBitmapMaterial || 
 
 			material instanceof THREE.MeshColorFillMaterial ||
@@ -303,7 +420,7 @@ THREE.WebGLRenderer = function () {
 			_gl.drawElements( _gl.TRIANGLES, materialFaceGroup.__webGLFaceCount, _gl.UNSIGNED_SHORT, 0 );
 
 		// render lines
-        
+		
 		} else if ( material instanceof THREE.MeshColorStrokeMaterial ) {
 
 			_gl.lineWidth( lineWidth );
@@ -319,13 +436,13 @@ THREE.WebGLRenderer = function () {
 		var i, l, m, ml, mf, material, meshMaterial, materialFaceGroup;
 
 		// create separate VBOs per material
-        
+		
 		for ( mf in object.materialFaceGroup ) {
 
 			materialFaceGroup = object.materialFaceGroup[ mf ];
 
 			// initialise buffers on the first access
-            
+			
 			if( ! materialFaceGroup.__webGLVertexBuffer ) {
 
 				this.createBuffers( object, mf );
@@ -462,21 +579,22 @@ THREE.WebGLRenderer = function () {
 		_gl.blendFunc( _gl.ONE, _gl.ONE_MINUS_SRC_ALPHA );
 		_gl.clearColor( 0, 0, 0, 0 );
 
-	}
-
-	function initProgram() {
-
-		_program = _gl.createProgram();
+	};
 
-		_gl.attachShader( _program, getShader( "fragment", [
+	function generateFragmentShader( maxDirLights, maxPointLights ) {
+	
+		var chunks = [
 
 			"#ifdef GL_ES",
 			"precision highp float;",
 			"#endif",
-        
+		
+			maxDirLights   ? "#define MAX_DIR_LIGHTS " + maxDirLights     : "",
+			maxPointLights ? "#define MAX_POINT_LIGHTS " + maxPointLights : "",
+		
 			"uniform int material;", // 0 - ColorFill, 1 - ColorStroke, 2 - Bitmap, 3 - Phong
 
-            "uniform sampler2D tDiffuse;",
+			"uniform sampler2D tDiffuse;",
 			"uniform vec4 mColor;",
 
 			"uniform vec4 mAmbient;",
@@ -484,99 +602,134 @@ THREE.WebGLRenderer = function () {
 			"uniform vec4 mSpecular;",
 			"uniform float mShininess;",
 
+			"uniform int pointLightNumber;",
+			"uniform int directionalLightNumber;",
+			
+			maxDirLights ? "uniform mat4 viewMatrix;" : "",
+			maxDirLights ? "uniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];" : "",
+			
 			"varying vec3 vNormal;",
-            "varying vec2 vUv;",
-            
+			"varying vec2 vUv;",
+			
 			"varying vec3 vLightWeighting;",
 
-			"varying vec3 vPointLightVector;",
-			"varying vec3 vDirectionalLightVector;",
+			maxPointLights ? "varying vec3 vPointLightVector[ MAX_POINT_LIGHTS ];"     : "",
+			
 			"varying vec3 vViewPosition;",
 
 			"void main() {",
 
 				// Blinn-Phong
 				// based on o3d example
-                
+
 				"if ( material == 3 ) { ", 
 
 					"vec3 normal = normalize( vNormal );",
 					"vec3 viewPosition = normalize( vViewPosition );",
 
-                    // point light
-                    
-					"vec3 pointVector = normalize( vPointLightVector );",
-					"vec3 pointHalfVector = normalize( vPointLightVector + vViewPosition );",
-                    
-					"float pointDotNormalHalf = dot( normal, pointHalfVector );",
-
-					"float pointAmbientWeight = 1.0;",
-					"float pointDiffuseWeight = max( dot( normal, pointVector ), 0.0 );",
-                    
-                    // Ternary conditional is from the original o3d shader. Here it produces abrupt dark cutoff artefacts.
-                    // Using just pow works ok in Chrome, but makes different artefact in Firefox 4.
-                    // Zeroing on negative pointDotNormalHalf seems to work in both.
-                    
+					// point lights
+					
+					maxPointLights ? "vec4 pointDiffuse  = vec4( 0.0, 0.0, 0.0, 0.0 );" : "",
+					maxPointLights ? "vec4 pointSpecular = vec4( 0.0, 0.0, 0.0, 0.0 );" : "",
+
+					maxPointLights ? "for( int i = 0; i < pointLightNumber; i++ ) {" : "",
+					
+					maxPointLights ? 	"vec3 pointVector = normalize( vPointLightVector[ i ] );" : "",
+					maxPointLights ? 	"vec3 pointHalfVector = normalize( vPointLightVector[ i ] + vViewPosition );" : "",
+						
+					maxPointLights ? 	"float pointDotNormalHalf = dot( normal, pointHalfVector );" : "",
+					maxPointLights ? 	"float pointDiffuseWeight = max( dot( normal, pointVector ), 0.0 );" : "",
+
+					// Ternary conditional is from the original o3d shader. Here it produces abrupt dark cutoff artefacts.
+					// Using just pow works ok in Chrome, but makes different artefact in Firefox 4.
+					// Zeroing on negative pointDotNormalHalf seems to work in both.
+					
 					//"float specularCompPoint = dot( normal, pointVector ) < 0.0 || pointDotNormalHalf < 0.0 ? 0.0 : pow( pointDotNormalHalf, mShininess );",
 					//"float specularCompPoint = pow( pointDotNormalHalf, mShininess );",
-					"float pointSpecularWeight = pointDotNormalHalf < 0.0 ? 0.0 : pow( pointDotNormalHalf, mShininess );",
+					//"float pointSpecularWeight = pointDotNormalHalf < 0.0 ? 0.0 : pow( pointDotNormalHalf, mShininess );",
 
-					"vec4 pointAmbient  = mAmbient  * pointAmbientWeight;",
-					"vec4 pointDiffuse  = mDiffuse  * pointDiffuseWeight;",
-					"vec4 pointSpecular = mSpecular * pointSpecularWeight;",
+					// Ternary conditional inside for loop breaks Chrome shader linking.
+					// Must do it with if.
 
-                    // directional light
-                    
-					"vec3 dirVector = normalize( vDirectionalLightVector );",
-					"vec3 dirHalfVector = normalize( vDirectionalLightVector + vViewPosition );",
+					maxPointLights ? 	"float pointSpecularWeight = 0.0;" : "",
+					maxPointLights ? 	"if ( pointDotNormalHalf >= 0.0 )" : "",
+					maxPointLights ? 		"pointSpecularWeight = pow( pointDotNormalHalf, mShininess );" : "",
+						
+					maxPointLights ? 	"pointDiffuse  += mDiffuse  * pointDiffuseWeight;" : "",
+					maxPointLights ? 	"pointSpecular += mSpecular * pointSpecularWeight;" : "",
+						
+					maxPointLights ? "}" : "",
 
-					"float dirDotNormalHalf = dot( normal, dirHalfVector );",
+					// directional lights
+
+					maxDirLights ? "vec4 dirDiffuse  = vec4( 0.0, 0.0, 0.0, 0.0 );" : "",
+					maxDirLights ? "vec4 dirSpecular = vec4( 0.0, 0.0, 0.0, 0.0 );" : "",
+					
+					maxDirLights ? "for( int i = 0; i < directionalLightNumber; i++ ) {" : "",
 
-					"float dirAmbientWeight = 1.0;",
-					"float dirDiffuseWeight = max( dot( normal, dirVector ), 0.0 );",                    
-					"float dirSpecularWeight = dirDotNormalHalf < 0.0 ? 0.0 : pow( dirDotNormalHalf, mShininess );",
+					maxDirLights ?		"vec4 lDirection = viewMatrix * vec4( directionalLightDirection[ i ], 0.0 );" : "",
 
-					"vec4 dirAmbient  = mAmbient  * dirAmbientWeight;",
-					"vec4 dirDiffuse  = mDiffuse  * dirDiffuseWeight;",
-					"vec4 dirSpecular = mSpecular * dirSpecularWeight;",
+					maxDirLights ? 		"vec3 dirVector = normalize( lDirection.xyz );" : "",
+					maxDirLights ? 		"vec3 dirHalfVector = normalize( lDirection.xyz + vViewPosition );" : "",
+						
+					maxDirLights ? 		"float dirDotNormalHalf = dot( normal, dirHalfVector );" : "",
 
-                    // light contribution summation
-                    
-                    "vec4 totalLight = vec4( 0.0, 0.0, 0.0, 1.0 );",
-                    
-					"totalLight += pointAmbient + pointDiffuse + pointSpecular;",
-					"totalLight += dirAmbient + dirDiffuse + dirSpecular;",
+					maxDirLights ? 		"float dirDiffuseWeight = max( dot( normal, dirVector ), 0.0 );" : "",  
+						
+					maxDirLights ? 		"float dirSpecularWeight = 0.0;" : "",
+					maxDirLights ? 		"if ( dirDotNormalHalf >= 0.0 )" : "",
+					maxDirLights ? 			"dirSpecularWeight = pow( dirDotNormalHalf, mShininess );" : "",
 
-                    // looks nicer with weighting
-                    
+					maxDirLights ? 		"dirDiffuse  += mDiffuse  * dirDiffuseWeight;" : "",
+					maxDirLights ? 		"dirSpecular += mSpecular * dirSpecularWeight;" : "",
+
+					maxDirLights ? "}" : "",
+
+					// all lights contribution summation
+					
+					"vec4 totalLight = mAmbient;",
+					maxDirLights   ? "totalLight += dirDiffuse + dirSpecular;" : "",
+					maxPointLights ? "totalLight += pointDiffuse + pointSpecular;" : "",
+
+					// looks nicer with weighting
+					
 					"gl_FragColor = vec4( totalLight.xyz * vLightWeighting, 1.0 );",                    
-                    //"gl_FragColor = vec4( totalLight.xyz, 1.0 );", 
+					//"gl_FragColor = vec4( totalLight.xyz, 1.0 );", 
 
 				// Bitmap: texture
-                
-				"} else if ( material==2 ) {", 
+				
+				"} else if ( material == 2 ) {", 
 
 					"vec4 texelColor = texture2D( tDiffuse, vUv );",
 					"gl_FragColor = vec4( texelColor.rgb * vLightWeighting, texelColor.a );",
 
 				// ColorStroke: wireframe using uniform color
-                
+				
 				"} else if ( material == 1 ) {", 
 
 					"gl_FragColor = vec4( mColor.rgb * vLightWeighting, mColor.a );",
 
 				// ColorFill: triangle using uniform color
-                
+				
 				"} else {", 
 
 					"gl_FragColor = vec4( mColor.rgb * vLightWeighting, mColor.a );",
-					//"gl_FragColor = vec4( vNormal, 1.0 );",
+					
 				"}",
 
-			"}"].join("\n") ) );
-
-		_gl.attachShader( _program, getShader( "vertex", [
-            
+			"}" ];
+			
+		return chunks.join("\n");
+		
+	};
+	
+	function generateVertexShader( maxDirLights, maxPointLights ) {
+		
+		var chunks = [
+			
+			maxDirLights   ? "#define MAX_DIR_LIGHTS " + maxDirLights     : "",
+			maxPointLights ? "#define MAX_POINT_LIGHTS " + maxPointLights : "",
+			
 			"attribute vec3 position;",
 			"attribute vec3 normal;",
 			"attribute vec2 uv;",
@@ -584,13 +737,17 @@ THREE.WebGLRenderer = function () {
 			"uniform vec3 cameraPosition;",
 
 			"uniform bool enableLighting;",
-            
+			
+			"uniform int pointLightNumber;",
+			"uniform int directionalLightNumber;",
+			
 			"uniform vec3 ambientLightColor;",
-			"uniform vec3 directionalLightColor;",
-			"uniform vec3 directionalLightDirection;",
+			
+			maxDirLights ? "uniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];"     : "",
+			maxDirLights ? "uniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];" : "",
 
-			"uniform vec3 pointLightColor;",
-			"uniform vec3 pointLightPosition;",
+			maxPointLights ? "uniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];"    : "",
+			maxPointLights ? "uniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];" : "",
 
 			"uniform mat4 objMatrix;",
 			"uniform mat4 viewMatrix;",
@@ -600,42 +757,50 @@ THREE.WebGLRenderer = function () {
 
 			"varying vec3 vNormal;",
 			"varying vec2 vUv;",
-            
+			
 			"varying vec3 vLightWeighting;",
 
-			"varying vec3 vPointLightVector;",
-			"varying vec3 vDirectionalLightVector;",
+			maxPointLights ? "varying vec3 vPointLightVector[ MAX_POINT_LIGHTS ];"     : "",
+			
 			"varying vec3 vViewPosition;",
 
 			"void main(void) {",
 
-                // eye space
-                
+				// world space
+				
+				"vec4 mPosition = objMatrix * vec4( position, 1.0 );",
+				"vViewPosition = cameraPosition - mPosition.xyz;",
+
+				// eye space
+				
 				"vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );",
 				"vec3 transformedNormal = normalize( normalMatrix * normal );",
 
-				"vec4 lPosition = viewMatrix * vec4( pointLightPosition, 1.0 );",
-				"vec4 lDirection = viewMatrix * vec4( directionalLightDirection, 0.0 );",
-
-				"vPointLightVector = normalize( lPosition.xyz - mvPosition.xyz );",
-				"vDirectionalLightVector = normalize( lDirection.xyz );",
-
-                // world space
-                
-                "vec4 mPosition = objMatrix * vec4( position, 1.0 );",
-				"vViewPosition = cameraPosition - mPosition.xyz;",
-
-				"if( !enableLighting ) {",
+				"if ( !enableLighting ) {",
 
 					"vLightWeighting = vec3( 1.0, 1.0, 1.0 );",
 
 				"} else {",
 
-					"float directionalLightWeighting = max( dot( transformedNormal, normalize(lDirection.xyz ) ), 0.0 );",
-					"float pointLightWeighting = max( dot( transformedNormal, vPointLightVector ), 0.0 );",
+					"vLightWeighting = ambientLightColor;",
+					
+					// directional lights
+					
+					maxDirLights ? "for( int i = 0; i < directionalLightNumber; i++ ) {" : "",
+					maxDirLights ?		"vec4 lDirection = viewMatrix * vec4( directionalLightDirection[ i ], 0.0 );" : "",
+					maxDirLights ?		"float directionalLightWeighting = max( dot( transformedNormal, normalize(lDirection.xyz ) ), 0.0 );" : "",						
+					maxDirLights ?		"vLightWeighting += directionalLightColor[ i ] * directionalLightWeighting;" : "",
+					maxDirLights ? "}" : "",
+					
+					// point lights
+					
+					maxPointLights ? "for( int i = 0; i < pointLightNumber; i++ ) {" : "",
+					maxPointLights ? 	"vec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );" : "",
+					maxPointLights ? 	"vPointLightVector[ i ] = normalize( lPosition.xyz - mvPosition.xyz );" : "",
+					maxPointLights ? 	"float pointLightWeighting = max( dot( transformedNormal, vPointLightVector[ i ] ), 0.0 );" : "",
+					maxPointLights ? 	"vLightWeighting += pointLightColor[ i ] * pointLightWeighting;" : "",
+					maxPointLights ? "}" : "",
 					
-                    "vLightWeighting = ambientLightColor + directionalLightColor * directionalLightWeighting + pointLightColor * pointLightWeighting;",
-
 				"}",
 
 				"vNormal = transformedNormal;",
@@ -643,7 +808,21 @@ THREE.WebGLRenderer = function () {
 
 				"gl_Position = projectionMatrix * mvPosition;",
 
-			"}"].join("\n") ) );
+			"}" ];
+			
+		return chunks.join("\n");
+		
+	};
+		
+	function initProgram( maxDirLights, maxPointLights ) {
+
+		_program = _gl.createProgram();
+		
+		//log ( generateVertexShader( maxDirLights, maxPointLights ) );
+		//log ( generateFragmentShader( maxDirLights, maxPointLights ) );
+		
+		_gl.attachShader( _program, getShader( "fragment", generateFragmentShader( maxDirLights, maxPointLights ) ) );
+		_gl.attachShader( _program, getShader( "vertex",   generateVertexShader( maxDirLights, maxPointLights ) ) );
 
 		_gl.linkProgram( _program );
 
@@ -651,53 +830,67 @@ THREE.WebGLRenderer = function () {
 
 			alert( "Could not initialise shaders" );
 
+			//alert( "VALIDATE_STATUS: " + _gl.getProgramParameter( _program, _gl.VALIDATE_STATUS ) );
+			//alert( _gl.getError() );
 		}
+		
 
 		_gl.useProgram( _program );
 
-        // matrices
-        
+		// matrices
+		
 		_program.viewMatrix = _gl.getUniformLocation( _program, "viewMatrix" );
 		_program.modelViewMatrix = _gl.getUniformLocation( _program, "modelViewMatrix" );
 		_program.projectionMatrix = _gl.getUniformLocation( _program, "projectionMatrix" );
 		_program.normalMatrix = _gl.getUniformLocation( _program, "normalMatrix" );
 		_program.objMatrix = _gl.getUniformLocation( _program, "objMatrix" );
 
-        _program.cameraPosition = _gl.getUniformLocation(_program, 'cameraPosition');
+		_program.cameraPosition = _gl.getUniformLocation(_program, 'cameraPosition');
 
-        // lights
-        
+		// lights
+		
 		_program.enableLighting = _gl.getUniformLocation(_program, 'enableLighting');
-        
+		
 		_program.ambientLightColor = _gl.getUniformLocation(_program, 'ambientLightColor');
-		_program.directionalLightColor = _gl.getUniformLocation(_program, 'directionalLightColor');
-		_program.directionalLightDirection = _gl.getUniformLocation(_program, 'directionalLightDirection');
+		
+		if ( maxDirLights ) {
+			
+			_program.directionalLightNumber = _gl.getUniformLocation(_program, 'directionalLightNumber');
+			_program.directionalLightColor = _gl.getUniformLocation(_program, 'directionalLightColor');
+			_program.directionalLightDirection = _gl.getUniformLocation(_program, 'directionalLightDirection');
+			
+		}
 
-		_program.pointLightColor = _gl.getUniformLocation(_program, 'pointLightColor');
-		_program.pointLightPosition = _gl.getUniformLocation(_program, 'pointLightPosition');
+		if ( maxPointLights ) {
+			
+			_program.pointLightNumber = _gl.getUniformLocation(_program, 'pointLightNumber');
+			_program.pointLightColor = _gl.getUniformLocation(_program, 'pointLightColor');
+			_program.pointLightPosition = _gl.getUniformLocation(_program, 'pointLightPosition');
+			
+		}
 
-        // material
-        
+		// material
+		
 		_program.material = _gl.getUniformLocation(_program, 'material');
-        
-        // material properties (ColorFill / ColorStroke shader)
-        
+		
+		// material properties (ColorFill / ColorStroke shader)
+		
 		_program.mColor = _gl.getUniformLocation(_program, 'mColor');
 
-        // material properties (Blinn-Phong shader)
-        
+		// material properties (Blinn-Phong shader)
+		
 		_program.mAmbient = _gl.getUniformLocation(_program, 'mAmbient');
 		_program.mDiffuse = _gl.getUniformLocation(_program, 'mDiffuse');
 		_program.mSpecular = _gl.getUniformLocation(_program, 'mSpecular');
 		_program.mShininess = _gl.getUniformLocation(_program, 'mShininess');
 
-        // texture (Bitmap shader)
-        
+		// texture (Bitmap shader)
+		
 		_program.tDiffuse = _gl.getUniformLocation( _program, "tDiffuse");
 		_gl.uniform1i( _program.tDiffuse,  0 );
 
-        // vertex arrays
-        
+		// vertex arrays
+		
 		_program.position = _gl.getAttribLocation( _program, "position" );
 		_gl.enableVertexAttribArray( _program.position );
 
@@ -712,7 +905,7 @@ THREE.WebGLRenderer = function () {
 		_program.modelViewMatrixArray = new Float32Array(16);
 		_program.projectionMatrixArray = new Float32Array(16);
 
-	}
+	};
 
 	function getShader( type, string ) {
 
@@ -739,6 +932,37 @@ THREE.WebGLRenderer = function () {
 		}
 
 		return shader;
-	}
+		
+	};
 
+	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;
+	}
+	
 };

+ 1 - 1
utils/REVISION

@@ -1 +1 @@
-25
+26

Some files were not shown because too many files changed in this diff