Browse Source

Added mesh stroke materials (wireframe) to WebGLRenderer.

Added multipass multimaterials to WebGLRenderer.

Refactored WebGLRenderer shader to become proto-mini-ubershader (untershader :).

Line width is currently not set properly on Chrome in Windows:

http://code.google.com/p/chromium/issues/detail?id=60124
alteredq 15 years ago
parent
commit
ecae266e8a
2 changed files with 398 additions and 273 deletions
  1. 5 2
      examples/materials_test.html
  2. 393 271
      src/renderers/WebGLRenderer.js

+ 5 - 2
examples/materials_test.html

@@ -37,7 +37,7 @@
             <br/>
             <p>Best viewed in Chrome 7/8 or Firefox 4 using WebGL renderer.
             <p>Canvas renderer is very slow on anything other than Chrome.
-            <p>Multi-materials currently work only in canvas renderer.
+            <p><a href="http://code.google.com/p/chromium/issues/detail?id=60124">Line width is not set properly</a> on Chrome in Windows.
         </div>
         
         <div id="log"></div>
@@ -148,7 +148,10 @@
                 
                 sphere = new Sphere( 100, 16, 8, 1 );
                 for (var i=0; i<10; i++) {
-                    mesh = new THREE.Mesh( sphere, [new THREE.MeshColorFillMaterial( 0xffffff ), new THREE.MeshColorStrokeMaterial(0x000000, 1, 1.5)] );
+                    //mesh = new THREE.Mesh( sphere, new THREE.MeshColorFillMaterial( 0xffffff ) );
+                    mesh = new THREE.Mesh( sphere, [ new THREE.MeshColorFillMaterial( 0xffffff ), new THREE.MeshColorStrokeMaterial( 0x000000, 1, 1.5 ) ] );
+                    //mesh = new THREE.Mesh( sphere, new THREE.MeshColorStrokeMaterial( 0x00aa00, 1, 1.5 ) );
+                    //mesh = new THREE.Mesh( sphere, new THREE.MeshFaceColorStrokeMaterial( 2.5 ) );
                     mesh.position.x = 500 * (Math.random() - 0.5);
                     mesh.position.y = 500 * (Math.random() - 0.5);
                     mesh.position.z = 500 * (Math.random() - 0.5);

+ 393 - 271
src/renderers/WebGLRenderer.js

@@ -5,8 +5,9 @@
 
 THREE.WebGLRenderer = function () {
 
-	var _canvas = document.createElement( 'canvas' ), _gl, _program,
-	viewMatrix = new THREE.Matrix4(), normalMatrix;
+	var _canvas = document.createElement( 'canvas' ), 
+    _gl, _program,
+	_viewMatrix = new THREE.Matrix4(), _normalMatrix;
 
 	this.domElement = _canvas;
 	this.autoClear = true;
@@ -14,6 +15,9 @@ THREE.WebGLRenderer = function () {
 	initGL();
 	initProgram();
 
+    // material constants used in shader
+    var COLORFILL = 0, COLORSTROKE = 1, FACECOLORFILL = 2, FACECOLORSTROKE = 3, BITMAP = 4;
+    
 	this.setSize = function ( width, height ) {
 
 		_canvas.width = width;
@@ -28,21 +32,10 @@ THREE.WebGLRenderer = function () {
 
 	};
 
-	this.render = function ( scene, camera ) {
-
-		var face, faceColor, object, material, normal, lightColor, lightPosition, light,
-		vertexArray, faceArray, colorArray, normalArray, vertexIndex,
-		o, ol, f, fl, m, ml, i, v1, v2, v3, v4,
-		l, ll,
-        uv, uvArray;
-
-		if ( this.autoClear ) {
-
-			this.clear();
-
-		}
-
-		//lighting
+    this.setupLights = function ( scene ) {
+        
+        var l, ll, lightColor, lightPosition, light;
+        
 		_gl.uniform1i( _program.enableLighting, scene.lights.length );
 
 		for ( l = 0, ll = scene.lights.length; l < ll; l++ ) {
@@ -54,7 +47,7 @@ THREE.WebGLRenderer = function () {
 				lightColor = light.color;
 				_gl.uniform3f( _program.ambientColor, lightColor.r, lightColor.g, lightColor.b );
 
-			} else if( light instanceof THREE.DirectionalLight ) {
+			} else if ( light instanceof THREE.DirectionalLight ) {
 
 				lightColor = light.color;
 				lightPosition = light.position;
@@ -64,270 +57,384 @@ THREE.WebGLRenderer = function () {
 			}
 
 		}
+    };
+    
+    this.createBuffers = function ( object, materialIndex ) {
+        
+        var materialFace = object.materialFaces[ materialIndex ];
+        var material = object.material[ materialIndex ];
+        
+        var faceArray = [];
+        var lineArray = [];
+        
+        var vertexArray = [];
+        var colorArray = [];
+        var normalArray = [];
+        var uvArray = [];
+        
+        var vertexIndex = 0;
+
+        var f, fl, fi, face, faceColor, vertexNormals, normal, uv, v1, v2, v3, v4;
+        
+        for ( f = 0, fl = materialFace.faces.length; f < fl; f++ ) {
+
+            fi = materialFace.faces[f];
+
+            face = object.geometry.faces[ fi ];
+            faceColor = face.color;
+            vertexNormals = face.vertexNormals;
+            normal = face.normal;
+            uv = object.geometry.uvs[ fi ];
+
+            if ( face instanceof THREE.Face3 ) {
+
+                v1 = object.geometry.vertices[ face.a ].position;
+                v2 = object.geometry.vertices[ face.b ].position;
+                v3 = object.geometry.vertices[ face.c ].position;
+
+                vertexArray.push( v1.x, v1.y, v1.z );
+                vertexArray.push( v2.x, v2.y, v2.z );
+                vertexArray.push( v3.x, v3.y, v3.z );
+
+                if ( vertexNormals.length == 3 ) {
+                    
+                    normalArray.push( vertexNormals[0].x, vertexNormals[0].y, vertexNormals[0].z );
+                    normalArray.push( vertexNormals[1].x, vertexNormals[1].y, vertexNormals[1].z );
+                    normalArray.push( vertexNormals[2].x, vertexNormals[2].y, vertexNormals[2].z );
+                    
+                }
+                else {
+                    
+                    normalArray.push( normal.x, normal.y, normal.z );
+                    normalArray.push( normal.x, normal.y, normal.z );
+                    normalArray.push( normal.x, normal.y, normal.z );
+                    
+                }
 
-		for ( o = 0, ol = scene.objects.length; o < ol; o++ ) {
-
-			object = scene.objects[ o ];
-
-            var materialFace, fi;
-
-			if ( object instanceof THREE.Mesh ) {
-
-				viewMatrix.multiply( camera.matrix, object.matrix );
-
-				_program.viewMatrixArray = new Float32Array( viewMatrix.flatten() );
-				_program.projectionMatrixArray = new Float32Array( camera.projectionMatrix.flatten() );
-
-				normalMatrix =  THREE.Matrix4.makeInvert(viewMatrix).transpose();
-				_program.normalMatrixArray = new Float32Array( normalMatrix.flatten() );
-
-				_gl.uniformMatrix4fv( _program.viewMatrix, false, _program.viewMatrixArray );
-				_gl.uniformMatrix4fv( _program.projectionMatrix, false, _program.projectionMatrixArray );
-				_gl.uniformMatrix4fv( _program.normalMatrix, false, _program.normalMatrixArray );
-
-                // create separate VBOs per material
-                for (var m in object.materialFaces ) {
-
-                    materialFace = object.materialFaces[m];
-                    material = object.material[m];
-                    if( !material ) continue;
-                    //log(material);
-
-                    if( !materialFace.__webGLVertexBuffer ) {
-
-                        vertexArray = [];
-                        faceArray = [];
-                        colorArray = [];
-                        normalArray = [];
-                        uvArray = [];
-                        vertexIndex = 0;
-
-                        //log( "object.geometry.uvs: " + object.geometry.uvs.length + " " + object.geometry.uvs);
-
-                        for ( f = 0, fl = materialFace.faces.length; f < fl; f++ ) {
-
-                            fi = materialFace.faces[f];
-
-                            face = object.geometry.faces[ fi ];
-                            faceColor = face.color;
-                            vertexNormals = face.vertexNormals;
-                            normal = face.normal;
-                            uv = object.geometry.uvs[ fi ];
-
-                            if ( face instanceof THREE.Face3 ) {
-
-                                v1 = object.geometry.vertices[ face.a ].position;
-                                v2 = object.geometry.vertices[ face.b ].position;
-                                v3 = object.geometry.vertices[ face.c ].position;
-
-                                vertexArray.push( v1.x, v1.y, v1.z );
-                                vertexArray.push( v2.x, v2.y, v2.z );
-                                vertexArray.push( v3.x, v3.y, v3.z );
-
-                                if ( vertexNormals.length == 3 ) {
-                                    
-                                    normalArray.push( vertexNormals[0].x, vertexNormals[0].y, vertexNormals[0].z );
-                                    normalArray.push( vertexNormals[1].x, vertexNormals[1].y, vertexNormals[1].z );
-                                    normalArray.push( vertexNormals[2].x, vertexNormals[2].y, vertexNormals[2].z );
-                                    
-                                }
-                                else {
-                                    
-                                    normalArray.push( normal.x, normal.y, normal.z );
-                                    normalArray.push( normal.x, normal.y, normal.z );
-                                    normalArray.push( normal.x, normal.y, normal.z );
-                                    
-                                }
-
-                                colorArray.push( faceColor.r, faceColor.g, faceColor.b, faceColor.a );
-                                colorArray.push( faceColor.r, faceColor.g, faceColor.b, faceColor.a );
-                                colorArray.push( faceColor.r, faceColor.g, faceColor.b, faceColor.a );
-
-                                if ( uv ) {
-                                    
-                                    uvArray.push( uv[0].u, uv[0].v );
-                                    uvArray.push( uv[1].u, uv[1].v );
-                                    uvArray.push( uv[2].u, uv[2].v );
-                                    
-                                }
-
-                                faceArray.push( vertexIndex, vertexIndex + 1, vertexIndex + 2 );
-
-                                vertexIndex += 3;
-
-                            } else if ( face instanceof THREE.Face4 ) {
-
-                                v1 = object.geometry.vertices[ face.a ].position;
-                                v2 = object.geometry.vertices[ face.b ].position;
-                                v3 = object.geometry.vertices[ face.c ].position;
-                                v4 = object.geometry.vertices[ face.d ].position;
-
-                                vertexArray.push( v1.x, v1.y, v1.z );
-                                vertexArray.push( v2.x, v2.y, v2.z );
-                                vertexArray.push( v3.x, v3.y, v3.z );
-                                vertexArray.push( v4.x, v4.y, v4.z );
-
-                                if ( vertexNormals.length == 4 ) {
-                                    
-                                    normalArray.push( vertexNormals[0].x, vertexNormals[0].y, vertexNormals[0].z );
-                                    normalArray.push( vertexNormals[1].x, vertexNormals[1].y, vertexNormals[1].z );
-                                    normalArray.push( vertexNormals[2].x, vertexNormals[2].y, vertexNormals[2].z );
-                                    normalArray.push( vertexNormals[3].x, vertexNormals[3].y, vertexNormals[3].z );
-                                    
-                                }
-                                else {
-                                    
-                                    normalArray.push( normal.x, normal.y, normal.z );
-                                    normalArray.push( normal.x, normal.y, normal.z );
-                                    normalArray.push( normal.x, normal.y, normal.z );
-                                    normalArray.push( normal.x, normal.y, normal.z );
-                                    
-                                }
-
-                                colorArray.push( faceColor.r, faceColor.g, faceColor.b, faceColor.a );
-                                colorArray.push( faceColor.r, faceColor.g, faceColor.b, faceColor.a );
-                                colorArray.push( faceColor.r, faceColor.g, faceColor.b, faceColor.a );
-                                colorArray.push( faceColor.r, faceColor.g, faceColor.b, faceColor.a );
-
-                                if ( uv ) {
-                                    
-                                    uvArray.push( uv[0].u, uv[0].v );
-                                    uvArray.push( uv[1].u, uv[1].v );
-                                    uvArray.push( uv[2].u, uv[2].v );
-                                    uvArray.push( uv[3].u, uv[3].v );
-                                    
-                                }
-                                
-                                faceArray.push( vertexIndex, vertexIndex + 1, vertexIndex + 2 );
-                                faceArray.push( vertexIndex, vertexIndex + 2, vertexIndex + 3 );
-
-                                vertexIndex += 4;
-                            }
-                        }
-
-                        if ( !vertexArray.length ) {
-
-                            continue;
-
-                        }
-
-                        /*
-                        log( "vertices: " + vertexArray.length/3 );
-                        log( "faces: " + faceArray.length/3 );
-                        log( "normals: " + normalArray.length/3 );
-                        log( "colors: " + colorArray.length/4 );
-                        log( "uvs: " + uvArray.length/2 );
-                        */
-                        
+                colorArray.push( faceColor.r, faceColor.g, faceColor.b, faceColor.a );
+                colorArray.push( faceColor.r, faceColor.g, faceColor.b, faceColor.a );
+                colorArray.push( faceColor.r, faceColor.g, faceColor.b, faceColor.a );
 
-                        materialFace.__webGLVertexBuffer = _gl.createBuffer();
-                        _gl.bindBuffer( _gl.ARRAY_BUFFER, materialFace.__webGLVertexBuffer );
-                        _gl.bufferData( _gl.ARRAY_BUFFER, new Float32Array( vertexArray ), _gl.STATIC_DRAW );
+                if ( uv ) {
+                    
+                    uvArray.push( uv[0].u, uv[0].v );
+                    uvArray.push( uv[1].u, uv[1].v );
+                    uvArray.push( uv[2].u, uv[2].v );
+                    
+                }
 
-                        materialFace.__webGLNormalBuffer = _gl.createBuffer();
-                        _gl.bindBuffer( _gl.ARRAY_BUFFER, materialFace.__webGLNormalBuffer );
-                        _gl.bufferData( _gl.ARRAY_BUFFER, new Float32Array( normalArray ), _gl.STATIC_DRAW );
+                faceArray.push( vertexIndex, vertexIndex + 1, vertexIndex + 2 );
+                
+                // TODO: don't add lines that already exist (faces sharing edge)
+                
+                lineArray.push( vertexIndex, vertexIndex + 1 );
+                lineArray.push( vertexIndex, vertexIndex + 2 );
+                lineArray.push( vertexIndex + 1, vertexIndex + 2 );
 
-                        if( material instanceof THREE.MeshFaceColorFillMaterial || material instanceof THREE.MeshBitmapUVMappingMaterial ) {
-                            materialFace.__webGLColorBuffer = _gl.createBuffer();
-                            _gl.bindBuffer( _gl.ARRAY_BUFFER, materialFace.__webGLColorBuffer );
-                            _gl.bufferData( _gl.ARRAY_BUFFER, new Float32Array( colorArray ), _gl.STATIC_DRAW );
-                        }
+                vertexIndex += 3;
 
-                        materialFace.__webGLUVBuffer = _gl.createBuffer();
-                        _gl.bindBuffer( _gl.ARRAY_BUFFER, materialFace.__webGLUVBuffer );
-                        _gl.bufferData( _gl.ARRAY_BUFFER, new Float32Array( uvArray ), _gl.STATIC_DRAW );
+            } else if ( face instanceof THREE.Face4 ) {
 
-                        materialFace.__webGLFaceBuffer = _gl.createBuffer();
-                        _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, materialFace.__webGLFaceBuffer );
-                        _gl.bufferData( _gl.ELEMENT_ARRAY_BUFFER, new Uint16Array( faceArray ), _gl.STATIC_DRAW );
+                v1 = object.geometry.vertices[ face.a ].position;
+                v2 = object.geometry.vertices[ face.b ].position;
+                v3 = object.geometry.vertices[ face.c ].position;
+                v4 = object.geometry.vertices[ face.d ].position;
 
-                        materialFace.__webGLFaceCount = faceArray.length;
+                vertexArray.push( v1.x, v1.y, v1.z );
+                vertexArray.push( v2.x, v2.y, v2.z );
+                vertexArray.push( v3.x, v3.y, v3.z );
+                vertexArray.push( v4.x, v4.y, v4.z );
 
-                    }
+                if ( vertexNormals.length == 4 ) {
                     
-					if ( material instanceof THREE.MeshColorFillMaterial ) {
-
-						if ( !materialFace.__webGLColorBuffer ) {
-
-							colorArray = [];
-
-							for ( i = 0; i < materialFace.__webGLFaceCount; i ++ ) {
-
-								colorArray.push( material.color.r, material.color.g, material.color.b, material.color.a );
-
-							}
+                    normalArray.push( vertexNormals[0].x, vertexNormals[0].y, vertexNormals[0].z );
+                    normalArray.push( vertexNormals[1].x, vertexNormals[1].y, vertexNormals[1].z );
+                    normalArray.push( vertexNormals[2].x, vertexNormals[2].y, vertexNormals[2].z );
+                    normalArray.push( vertexNormals[3].x, vertexNormals[3].y, vertexNormals[3].z );
+                    
+                }
+                else {
+                    
+                    normalArray.push( normal.x, normal.y, normal.z );
+                    normalArray.push( normal.x, normal.y, normal.z );
+                    normalArray.push( normal.x, normal.y, normal.z );
+                    normalArray.push( normal.x, normal.y, normal.z );
+                    
+                }
 
-							materialFace.__webGLColorBuffer = _gl.createBuffer();
-							_gl.bindBuffer( _gl.ARRAY_BUFFER, materialFace.__webGLColorBuffer );
-							_gl.bufferData( _gl.ARRAY_BUFFER, new Float32Array( colorArray ), _gl.STATIC_DRAW );
+                colorArray.push( faceColor.r, faceColor.g, faceColor.b, faceColor.a );
+                colorArray.push( faceColor.r, faceColor.g, faceColor.b, faceColor.a );
+                colorArray.push( faceColor.r, faceColor.g, faceColor.b, faceColor.a );
+                colorArray.push( faceColor.r, faceColor.g, faceColor.b, faceColor.a );
 
-						}
-                            
-                        _gl.uniform1i( _program.enableTexture, 0 );
+                if ( uv ) {
+                    
+                    uvArray.push( uv[0].u, uv[0].v );
+                    uvArray.push( uv[1].u, uv[1].v );
+                    uvArray.push( uv[2].u, uv[2].v );
+                    uvArray.push( uv[3].u, uv[3].v );
+                    
+                }
+                
+                faceArray.push( vertexIndex, vertexIndex + 1, vertexIndex + 2 );
+                faceArray.push( vertexIndex, vertexIndex + 2, vertexIndex + 3 );
+
+                // TODO: don't add lines that already exist (faces sharing edge)
+                
+                lineArray.push( vertexIndex, vertexIndex + 1 );
+                lineArray.push( vertexIndex, vertexIndex + 2 );
+                lineArray.push( vertexIndex, vertexIndex + 3 );
+                lineArray.push( vertexIndex + 1, vertexIndex + 2 );
+                lineArray.push( vertexIndex + 2, vertexIndex + 3 );
+                
+                vertexIndex += 4;
+            }
+        }
+
+        if ( !vertexArray.length ) {
+
+            return;
+
+        }
+
+        /*
+        log( "vertices: " + vertexArray.length/3 );
+        log( "faces: " + faceArray.length/3 );
+        log( "normals: " + normalArray.length/3 );
+        log( "colors: " + colorArray.length/4 );
+        log( "uvs: " + uvArray.length/2 );
+        */
+        
+        materialFace.__webGLVertexBuffer = _gl.createBuffer();
+        _gl.bindBuffer( _gl.ARRAY_BUFFER, materialFace.__webGLVertexBuffer );
+        _gl.bufferData( _gl.ARRAY_BUFFER, new Float32Array( vertexArray ), _gl.STATIC_DRAW );
+
+        materialFace.__webGLNormalBuffer = _gl.createBuffer();
+        _gl.bindBuffer( _gl.ARRAY_BUFFER, materialFace.__webGLNormalBuffer );
+        _gl.bufferData( _gl.ARRAY_BUFFER, new Float32Array( normalArray ), _gl.STATIC_DRAW );
+
+        materialFace.__webGLColorBuffer = _gl.createBuffer();
+        _gl.bindBuffer( _gl.ARRAY_BUFFER, materialFace.__webGLColorBuffer );
+        _gl.bufferData( _gl.ARRAY_BUFFER, new Float32Array( colorArray ), _gl.STATIC_DRAW );
+
+        materialFace.__webGLUVBuffer = _gl.createBuffer();
+        _gl.bindBuffer( _gl.ARRAY_BUFFER, materialFace.__webGLUVBuffer );
+        _gl.bufferData( _gl.ARRAY_BUFFER, new Float32Array( uvArray ), _gl.STATIC_DRAW );
+
+        materialFace.__webGLFaceBuffer = _gl.createBuffer();
+        _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, materialFace.__webGLFaceBuffer );
+        _gl.bufferData( _gl.ELEMENT_ARRAY_BUFFER, new Uint16Array( faceArray ), _gl.STATIC_DRAW );
+
+        materialFace.__webGLLineBuffer = _gl.createBuffer();
+        _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, materialFace.__webGLLineBuffer );
+        _gl.bufferData( _gl.ELEMENT_ARRAY_BUFFER, new Uint16Array( lineArray ), _gl.STATIC_DRAW );
+
+        materialFace.__webGLFaceCount = faceArray.length;
+        materialFace.__webGLLineCount = lineArray.length;
+
+    }
+    
+    this.renderMesh = function ( object, camera ) {
+        
+        var m, ml, mf, material, materialFace, fi, lineWidth;
+
+        // create separate VBOs per material
+        for (var mf in object.materialFaces ) {
+
+            materialFace = object.materialFaces[ mf ];
+            material = object.material[ mf ];
+            if( !material ) continue;
+
+            // initialise on the first access
+            if( !materialFace.__webGLVertexBuffer ) {
+                
+                this.createBuffers( object, mf );
+                
+            }
+            
+            for ( m = 0, ml = object.material.length; m < ml; m++ ) {
+                
+                material = object.material[ m ];
+                
+                if ( material instanceof THREE.MeshBitmapUVMappingMaterial &&
+                     !( m == mf || mf == material.decalIndex ) ) {
+                    
+                    continue;
+                    
+                }
+                
+                //if ( m == element.materialIndex || element.materialIndex == material.decalIndex )
+                
+                if ( material instanceof THREE.MeshColorFillMaterial ) {
 
-                    } else if ( material instanceof THREE.MeshFaceColorFillMaterial ) {
+                    color = material.color;
+                    _gl.uniform4f( _program.uniformColor,  color.r, color.g, color.b, color.a );
+                    
+                    _gl.uniform1i( _program.material, COLORFILL );
+                    
+                } else if ( material instanceof THREE.MeshColorStrokeMaterial ) {
+                    
+                    lineWidth = material.lineWidth;
+                    
+                    color = material.color;
+                    _gl.uniform4f( _program.uniformColor,  color.r, color.g, color.b, color.a );
+                    
+                    _gl.uniform1i( _program.material, COLORSTROKE );
+                    
+                } else if ( material instanceof THREE.MeshFaceColorFillMaterial ) {
+                    
+                    _gl.uniform1i( _program.material, FACECOLORFILL );
+                
+                } else if ( material instanceof THREE.MeshFaceColorStrokeMaterial ) {
 
-                        _gl.uniform1i( _program.enableTexture, 0 );
+                    lineWidth = material.lineWidth;
+                    
+                    _gl.uniform1i( _program.material, FACECOLORSTROKE );
 
-                    } else if ( material instanceof THREE.MeshBitmapUVMappingMaterial ) {
+                } else if ( material instanceof THREE.MeshBitmapUVMappingMaterial ) {
+                    
+                    if ( !material.__webGLTexture && material.loaded ) {
                         
-                        if ( !material.__webGLTexture && material.loaded ) {
-                            
-                            //log(material.bitmap);
-
-                            material.__webGLTexture = _gl.createTexture();
-                            _gl.bindTexture( _gl.TEXTURE_2D, material.__webGLTexture );
-                            _gl.texImage2D( _gl.TEXTURE_2D, 0, _gl.RGBA, _gl.RGBA, _gl.UNSIGNED_BYTE, material.bitmap ) ;
-                            _gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_MAG_FILTER, _gl.LINEAR );
-                            //_gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_MIN_FILTER, _gl.LINEAR_MIPMAP_NEAREST );
-                            _gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_MIN_FILTER, _gl.LINEAR_MIPMAP_LINEAR );
-                            _gl.generateMipmap( _gl.TEXTURE_2D );
-                            _gl.bindTexture( _gl.TEXTURE_2D, null );
-                            
-                        }
-
-                        _gl.uniform1i( _program.enableTexture, 1 );
-                        _gl.activeTexture( _gl.TEXTURE0 );
+                        material.__webGLTexture = _gl.createTexture();
                         _gl.bindTexture( _gl.TEXTURE_2D, material.__webGLTexture );
-                        _gl.uniform1i( _program.diffuse,  0 );
-
+                        _gl.texImage2D( _gl.TEXTURE_2D, 0, _gl.RGBA, _gl.RGBA, _gl.UNSIGNED_BYTE, material.bitmap ) ;
+                        _gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_MAG_FILTER, _gl.LINEAR );
+                        //_gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_MIN_FILTER, _gl.LINEAR_MIPMAP_NEAREST );
+                        _gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_MIN_FILTER, _gl.LINEAR_MIPMAP_LINEAR );
+                        _gl.generateMipmap( _gl.TEXTURE_2D );
+                        _gl.bindTexture( _gl.TEXTURE_2D, null );
+                        
                     }
-
-                    // vertices
-                    _gl.bindBuffer( _gl.ARRAY_BUFFER, materialFace.__webGLVertexBuffer );
-                    _gl.vertexAttribPointer( _program.position, 3, _gl.FLOAT, false, 0, 0 );
-
-                    // normals
-                    _gl.bindBuffer( _gl.ARRAY_BUFFER, materialFace.__webGLNormalBuffer );
-                    _gl.vertexAttribPointer( _program.normal, 3, _gl.FLOAT, false, 0, 0 );
-
-                    // uvs
+                    
+                    _gl.activeTexture( _gl.TEXTURE0 );
+                    _gl.bindTexture( _gl.TEXTURE_2D, material.__webGLTexture );
+                    _gl.uniform1i( _program.diffuse,  0 );
+                    
+                    _gl.uniform1i( _program.material, BITMAP );
+                    
+                }
+                
+
+                // vertices
+                _gl.bindBuffer( _gl.ARRAY_BUFFER, materialFace.__webGLVertexBuffer );
+                _gl.vertexAttribPointer( _program.position, 3, _gl.FLOAT, false, 0, 0 );
+
+                // normals
+                _gl.bindBuffer( _gl.ARRAY_BUFFER, materialFace.__webGLNormalBuffer );
+                _gl.vertexAttribPointer( _program.normal, 3, _gl.FLOAT, false, 0, 0 );
+
+                // colors
+                _gl.bindBuffer( _gl.ARRAY_BUFFER, materialFace.__webGLColorBuffer );
+                _gl.vertexAttribPointer( _program.color, 4, _gl.FLOAT, false, 0, 0 );
+                
+                // uvs
+                
+                if ( material instanceof THREE.MeshBitmapUVMappingMaterial ) {
+                    
                     _gl.bindBuffer( _gl.ARRAY_BUFFER, materialFace.__webGLUVBuffer );
-                    if ( object.geometry.uvs.length ) {
                         
-                        _gl.enableVertexAttribArray( _program.uv );
-                        _gl.vertexAttribPointer( _program.uv, 2, _gl.FLOAT, false, 0, 0 );
+                    _gl.enableVertexAttribArray( _program.uv );
+                    _gl.vertexAttribPointer( _program.uv, 2, _gl.FLOAT, false, 0, 0 );
                         
-                    }
-                    else {
+                }
+                else {
                         
-                        _gl.disableVertexAttribArray( _program.uv );
+                    _gl.disableVertexAttribArray( _program.uv );
                         
-                    }
+                }
 
-                    // colors
-                    _gl.bindBuffer( _gl.ARRAY_BUFFER, materialFace.__webGLColorBuffer );
-                    _gl.enableVertexAttribArray( _program.color );
-                    _gl.vertexAttribPointer( _program.color, 4, _gl.FLOAT, false, 0, 0 );
+                // render triangles
 
-                    // render faces
+                if ( material instanceof THREE.MeshBitmapUVMappingMaterial || 
+                     material instanceof THREE.MeshFaceColorFillMaterial ||
+                     material instanceof THREE.MeshColorFillMaterial ) {
+                    
                     _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, materialFace.__webGLFaceBuffer );
                     _gl.drawElements( _gl.TRIANGLES, materialFace.__webGLFaceCount, _gl.UNSIGNED_SHORT, 0 );
                     
+                } 
+                
+                // render lines
+                
+                else if ( material instanceof THREE.MeshColorStrokeMaterial ||
+                          material instanceof THREE.MeshFaceColorStrokeMaterial ) {
+                    
+                    _gl.lineWidth( lineWidth );
+                    _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, materialFace.__webGLLineBuffer );
+                    _gl.drawElements( _gl.LINES, materialFace.__webGLLineCount, _gl.UNSIGNED_SHORT, 0 );
+                    
                 }
+                
             }
 
+        }
+    };
+    
+    this.setupMatrices = function ( object, camera ) {
+        
+        _viewMatrix.multiply( camera.matrix, object.matrix );
+
+        _program.viewMatrixArray = new Float32Array( _viewMatrix.flatten() );
+        _program.projectionMatrixArray = new Float32Array( camera.projectionMatrix.flatten() );
+
+        _normalMatrix =  THREE.Matrix4.makeInvert( _viewMatrix ).transpose();
+        _program.normalMatrixArray = new Float32Array( _normalMatrix.flatten() );
+
+        _gl.uniformMatrix4fv( _program.viewMatrix, false, _program.viewMatrixArray );
+        _gl.uniformMatrix4fv( _program.projectionMatrix, false, _program.projectionMatrixArray );
+        _gl.uniformMatrix4fv( _program.normalMatrix, false, _program.normalMatrixArray );
+        
+    };
+    
+	this.render = function ( scene, camera ) {
+        
+        var o, ol, object;
+
+		if ( this.autoClear ) {
+
+			this.clear();
+
+		}
+
+        this.setupLights( scene );
+
+		for ( o = 0, ol = scene.objects.length; o < ol; o++ ) {
+
+			object = scene.objects[ o ];
+
+            this.setupMatrices( object, camera );
+
+			if ( object instanceof THREE.Mesh ) {
+
+                this.renderMesh( object, camera );
+                
+            } else if ( object instanceof THREE.Line ) {
+                
+                // TODO
+
+                // It would be very inefficient to do lines one-by-one.
+                
+                // This will need a complete redesign from how CanvasRenderer does it.
+                
+                // Though it could be brute forced, if only used for lightweight
+                // stuff (as CanvasRenderer can only handle small number of elements 
+                // anyways). 
+                
+                // Heavy-duty wireframe lines are handled efficiently in mesh renderer.
+
+            } else if ( object instanceof THREE.Particle ) {
+                
+                // TODO
+                
+                // The same as with lines, particles shouldn't be handled one-by-one.
+                
+                // Again, heavy duty particle system would require different approach,
+                // like one VBO per particle system and then update attribute arrays, 
+                // though the best would be to move also behavior computation
+                // into the shader (ala http://spidergl.org/example.php?id=11)
+                
+            }
+            
 		}
 
 	};
@@ -370,19 +477,32 @@ THREE.WebGLRenderer = function () {
 			"precision highp float;",
 			"#endif",
 
-            "uniform bool enableTexture;",
             "uniform sampler2D diffuse;",
-			"varying vec2 vuv;",
 
-			"varying vec4 vcolor;",
+			"uniform vec4 uniformColor;",
+        
+            "varying vec2 vertexUv;",
+			"varying vec4 vertexColor;",
 			"varying vec3 lightWeighting;",
 
+            "uniform int material;", // 0 - ColorFill, 1 - ColorStroke, 2 - FaceColorFill, 3 - FaceColorStroke, 4 - Bitmap
+
 			"void main(){",
-                "if(enableTexture) {",
-                    "vec4 texelColor = texture2D(diffuse, vuv);",
+                "if(material==4) {", // texture
+                    "vec4 texelColor = texture2D(diffuse, vertexUv);",
                     "gl_FragColor = vec4(texelColor.rgb * lightWeighting, texelColor.a);",
-                "} else {",
-                    "gl_FragColor = vec4(vcolor.rgb * lightWeighting, vcolor.a);",
+                
+                "} else if(material==3) {", // wireframe using vertex color 
+                    "gl_FragColor = vec4(vertexColor.rgb * lightWeighting, vertexColor.a);",
+                
+                "} else if(material==2) {", // triangle using vertex color
+                    "gl_FragColor = vec4(vertexColor.rgb * lightWeighting, vertexColor.a);",
+                
+                "} else if(material==1) {", // wireframe using uniform color
+                    "gl_FragColor = vec4(uniformColor.rgb * lightWeighting, uniformColor.a);",
+                
+                "} else {", // triangle using uniform color
+                    "gl_FragColor = vec4(uniformColor.rgb * lightWeighting, uniformColor.a);",
                 "}",
 			"}"
 			].join("\n") ) );
@@ -401,22 +521,23 @@ THREE.WebGLRenderer = function () {
 			"uniform mat4 viewMatrix;",
 			"uniform mat4 projectionMatrix;",
 			"uniform mat4 normalMatrix;",
-			"varying vec4 vcolor;",
+			
+            "varying vec4 vertexColor;",
+            "varying vec2 vertexUv;",
 			"varying vec3 lightWeighting;",
-            "varying vec2 vuv;",
 
 			"void main(void) {",
 
-						"if(!enableLighting) {",
-							"lightWeighting = vec3(1.0, 1.0, 1.0);",
-						"} else {",
-							"vec4 transformedNormal = normalMatrix * vec4(normal, 1.0);",
-							"float directionalLightWeighting = max(dot(normalize(transformedNormal.xyz), lightingDirection), 0.0);",
-							"lightWeighting = ambientColor + directionalColor * directionalLightWeighting;",
-						"}",
+                "if(!enableLighting) {",
+                    "lightWeighting = vec3(1.0, 1.0, 1.0);",
+                "} else {",
+                    "vec4 transformedNormal = normalMatrix * vec4(normal, 1.0);",
+                    "float directionalLightWeighting = max(dot(normalize(transformedNormal.xyz), lightingDirection), 0.0);",
+                    "lightWeighting = ambientColor + directionalColor * directionalLightWeighting;",
+                "}",
 
-				"vcolor = color;",
-				"vuv = uv;",
+				"vertexColor = color;",
+				"vertexUv = uv;",
 				"gl_Position = projectionMatrix * viewMatrix * vec4( position, 1.0 );",
 
 			"}"].join("\n") ) );
@@ -440,7 +561,8 @@ THREE.WebGLRenderer = function () {
 		_program.directionalColor = _gl.getUniformLocation(_program, 'directionalColor');
 		_program.lightingDirection = _gl.getUniformLocation(_program, 'lightingDirection');
 
-        _program.enableTexture = _gl.getUniformLocation(_program, 'enableTexture');
+        _program.material = _gl.getUniformLocation(_program, 'material');
+        _program.uniformColor = _gl.getUniformLocation(_program, 'uniformColor');
 
 		_program.color = _gl.getAttribLocation( _program, "color" );
 		_gl.enableVertexAttribArray( _program.color );