Browse Source

decoupled webgl properties and buffers from renderable objects and attributes. Scenes and objects no longer coupled to renderers and may be used between multiple renderers.

Fordy 10 years ago
parent
commit
4c7239ebcb

+ 6 - 0
examples/index.html

@@ -313,6 +313,12 @@
 				"webgl_multiple_canvases_complex",
 				"webgl_multiple_canvases_complex",
 				"webgl_multiple_canvases_grid",
 				"webgl_multiple_canvases_grid",
 				"webgl_multiple_elements",
 				"webgl_multiple_elements",
+				"webgl_multiple_renderers",
+				"webgl_multiple_renderers_horse",
+				"webgl_multiple_renderers_cubemap",
+				"webgl_multiple_renderers_buffergeometry_custom_attributes_particles",
+				"webgl_multiple_renderers_buffergeometry_instancing_dynamic",
+				"webgl_multiple_renderers_sprites",
 				"webgl_multiple_views",
 				"webgl_multiple_views",
 				"webgl_nearestneighbour",
 				"webgl_nearestneighbour",
 				"webgl_octree",
 				"webgl_octree",

+ 2 - 0
src/renderers/WebGLRenderTarget.js

@@ -5,6 +5,8 @@
 
 
 THREE.WebGLRenderTarget = function ( width, height, options ) {
 THREE.WebGLRenderTarget = function ( width, height, options ) {
 
 
+	this.uuid = THREE.Math.generateUUID();
+
 	this.width = width;
 	this.width = width;
 	this.height = height;
 	this.height = height;
 
 

+ 161 - 83
src/renderers/WebGLRenderer.js

@@ -32,6 +32,12 @@ THREE.WebGLRenderer = function ( parameters ) {
 	_clearColor = new THREE.Color( 0x000000 ),
 	_clearColor = new THREE.Color( 0x000000 ),
 	_clearAlpha = 0;
 	_clearAlpha = 0;
 
 
+	// tracks context specific properties to allow sharing of objects across webgl renderers
+	// each object stores relevant webgl properties that are specific to this renderer
+	// objects are stored by their uuids
+	// attributes are given a uuid in order to store their properties
+	var objectRendererWebGLProps = {};
+
 	var lights = [];
 	var lights = [];
 
 
 	var opaqueObjects = [];
 	var opaqueObjects = [];
@@ -653,24 +659,24 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 
 	var deallocateTexture = function ( texture ) {
 	var deallocateTexture = function ( texture ) {
 
 
-		if ( texture.image && texture.image.__webglTextureCube ) {
+		if ( texture.image && objectRendererWebGLProps[texture.uuid].__image__webglTextureCube ) {
 
 
 			// cube texture
 			// cube texture
 
 
-			_gl.deleteTexture( texture.image.__webglTextureCube );
+			_gl.deleteTexture( objectRendererWebGLProps[texture.uuid].__image__webglTextureCube );
 
 
-			delete texture.image.__webglTextureCube;
+			delete objectRendererWebGLProps[texture.uuid].__image__webglTextureCube;
 
 
 		} else {
 		} else {
 
 
 			// 2D texture
 			// 2D texture
 
 
-			if ( texture.__webglInit === undefined ) return;
+			if ( objectRendererWebGLProps[texture.uuid].__webglInit === undefined ) return;
 
 
-			_gl.deleteTexture( texture.__webglTexture );
+			_gl.deleteTexture( objectRendererWebGLProps[texture.uuid].__webglTexture );
 
 
-			delete texture.__webglTexture;
-			delete texture.__webglInit;
+			delete objectRendererWebGLProps[texture.uuid].__webglTexture;
+			delete objectRendererWebGLProps[texture.uuid].__webglInit;
 
 
 		}
 		}
 
 
@@ -678,40 +684,40 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 
 	var deallocateRenderTarget = function ( renderTarget ) {
 	var deallocateRenderTarget = function ( renderTarget ) {
 
 
-		if ( ! renderTarget || renderTarget.__webglTexture === undefined ) return;
+		if ( ! renderTarget || objectRendererWebGLProps[renderTarget.uuid].__webglTexture === undefined ) return;
 
 
-		_gl.deleteTexture( renderTarget.__webglTexture );
+		_gl.deleteTexture( objectRendererWebGLProps[renderTarget.uuid].__webglTexture );
 
 
-		delete renderTarget.__webglTexture;
+		delete objectRendererWebGLProps[renderTarget.uuid].__webglTexture;
 
 
 		if ( renderTarget instanceof THREE.WebGLRenderTargetCube ) {
 		if ( renderTarget instanceof THREE.WebGLRenderTargetCube ) {
 
 
 			for ( var i = 0; i < 6; i ++ ) {
 			for ( var i = 0; i < 6; i ++ ) {
 
 
-				_gl.deleteFramebuffer( renderTarget.__webglFramebuffer[ i ] );
-				_gl.deleteRenderbuffer( renderTarget.__webglRenderbuffer[ i ] );
+				_gl.deleteFramebuffer( objectRendererWebGLProps[renderTarget.uuid].__webglFramebuffer[ i ] );
+				_gl.deleteRenderbuffer( objectRendererWebGLProps[renderTarget.uuid].__webglRenderbuffer[ i ] );
 
 
 			}
 			}
 
 
 		} else {
 		} else {
 
 
-			_gl.deleteFramebuffer( renderTarget.__webglFramebuffer );
-			_gl.deleteRenderbuffer( renderTarget.__webglRenderbuffer );
+			_gl.deleteFramebuffer( objectRendererWebGLProps[renderTarget.uuid].__webglFramebuffer );
+			_gl.deleteRenderbuffer( objectRendererWebGLProps[renderTarget.uuid].__webglRenderbuffer );
 
 
 		}
 		}
 
 
-		delete renderTarget.__webglFramebuffer;
-		delete renderTarget.__webglRenderbuffer;
+		delete objectRendererWebGLProps[renderTarget.uuid].__webglFramebuffer;
+		delete objectRendererWebGLProps[renderTarget.uuid].__webglRenderbuffer;
 
 
 	};
 	};
 
 
 	var deallocateMaterial = function ( material ) {
 	var deallocateMaterial = function ( material ) {
 
 
-		var program = material.program.program;
+		var program = objectRendererWebGLProps[material.uuid].program.program;
 
 
 		if ( program === undefined ) return;
 		if ( program === undefined ) return;
 
 
-		material.program = undefined;
+		objectRendererWebGLProps[material.uuid].program = undefined;
 
 
 		// only deallocate GL program if this was the last use of shared program
 		// only deallocate GL program if this was the last use of shared program
 		// assumed there is only single copy of any program in the _programs list
 		// assumed there is only single copy of any program in the _programs list
@@ -774,16 +780,22 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 
 		state.initAttributes();
 		state.initAttributes();
 
 
-		if ( object.hasPositions && ! object.__webglVertexBuffer ) object.__webglVertexBuffer = _gl.createBuffer();
-		if ( object.hasNormals && ! object.__webglNormalBuffer ) object.__webglNormalBuffer = _gl.createBuffer();
-		if ( object.hasUvs && ! object.__webglUvBuffer ) object.__webglUvBuffer = _gl.createBuffer();
-		if ( object.hasColors && ! object.__webglColorBuffer ) object.__webglColorBuffer = _gl.createBuffer();
+		if ( ! objectRendererWebGLProps[object.uuid] ) {
+
+			objectRendererWebGLProps[object.uuid] = {};
+
+		}
+
+		if ( object.hasPositions && ! objectRendererWebGLProps[object.uuid].__webglVertexBuffer ) objectRendererWebGLProps[object.uuid].__webglVertexBuffer = _gl.createBuffer();
+		if ( object.hasNormals && ! objectRendererWebGLProps[object.uuid].__webglNormalBuffer ) objectRendererWebGLProps[object.uuid].__webglNormalBuffer = _gl.createBuffer();
+		if ( object.hasUvs && ! objectRendererWebGLProps[object.uuid].__webglUvBuffer ) objectRendererWebGLProps[object.uuid].__webglUvBuffer = _gl.createBuffer();
+		if ( object.hasColors && ! objectRendererWebGLProps[object.uuid].__webglColorBuffer ) objectRendererWebGLProps[object.uuid].__webglColorBuffer = _gl.createBuffer();
 
 
 		var attributes = program.getAttributes();
 		var attributes = program.getAttributes();
 
 
 		if ( object.hasPositions ) {
 		if ( object.hasPositions ) {
 
 
-			_gl.bindBuffer( _gl.ARRAY_BUFFER, object.__webglVertexBuffer );
+			_gl.bindBuffer( _gl.ARRAY_BUFFER, objectRendererWebGLProps[object.uuid].__webglVertexBuffer );
 			_gl.bufferData( _gl.ARRAY_BUFFER, object.positionArray, _gl.DYNAMIC_DRAW );
 			_gl.bufferData( _gl.ARRAY_BUFFER, object.positionArray, _gl.DYNAMIC_DRAW );
 
 
 			state.enableAttribute( attributes.position );
 			state.enableAttribute( attributes.position );
@@ -793,7 +805,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 
 		if ( object.hasNormals ) {
 		if ( object.hasNormals ) {
 
 
-			_gl.bindBuffer( _gl.ARRAY_BUFFER, object.__webglNormalBuffer );
+			_gl.bindBuffer( _gl.ARRAY_BUFFER, objectRendererWebGLProps[object.uuid].__webglNormalBuffer );
 
 
 			if ( material instanceof THREE.MeshPhongMaterial === false && material.shading === THREE.FlatShading ) {
 			if ( material instanceof THREE.MeshPhongMaterial === false && material.shading === THREE.FlatShading ) {
 
 
@@ -848,7 +860,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 
 		if ( object.hasUvs && material.map ) {
 		if ( object.hasUvs && material.map ) {
 
 
-			_gl.bindBuffer( _gl.ARRAY_BUFFER, object.__webglUvBuffer );
+			_gl.bindBuffer( _gl.ARRAY_BUFFER, objectRendererWebGLProps[object.uuid].__webglUvBuffer );
 			_gl.bufferData( _gl.ARRAY_BUFFER, object.uvArray, _gl.DYNAMIC_DRAW );
 			_gl.bufferData( _gl.ARRAY_BUFFER, object.uvArray, _gl.DYNAMIC_DRAW );
 
 
 			state.enableAttribute( attributes.uv );
 			state.enableAttribute( attributes.uv );
@@ -859,7 +871,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 
 		if ( object.hasColors && material.vertexColors !== THREE.NoColors ) {
 		if ( object.hasColors && material.vertexColors !== THREE.NoColors ) {
 
 
-			_gl.bindBuffer( _gl.ARRAY_BUFFER, object.__webglColorBuffer );
+			_gl.bindBuffer( _gl.ARRAY_BUFFER, objectRendererWebGLProps[object.uuid].__webglColorBuffer );
 			_gl.bufferData( _gl.ARRAY_BUFFER, object.colorArray, _gl.DYNAMIC_DRAW );
 			_gl.bufferData( _gl.ARRAY_BUFFER, object.colorArray, _gl.DYNAMIC_DRAW );
 
 
 			state.enableAttribute( attributes.color );
 			state.enableAttribute( attributes.color );
@@ -912,13 +924,15 @@ THREE.WebGLRenderer = function ( parameters ) {
 					var size = geometryAttribute.itemSize;
 					var size = geometryAttribute.itemSize;
 					state.enableAttribute( programAttribute );
 					state.enableAttribute( programAttribute );
 
 
+					var buffer = objects.getAttributeBuffer(geometryAttribute);
+
 					if ( geometryAttribute instanceof THREE.InterleavedBufferAttribute ) {
 					if ( geometryAttribute instanceof THREE.InterleavedBufferAttribute ) {
 
 
 						var data = geometryAttribute.data;
 						var data = geometryAttribute.data;
 						var stride = data.stride;
 						var stride = data.stride;
 						var offset = geometryAttribute.offset;
 						var offset = geometryAttribute.offset;
 
 
-						_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryAttribute.data.buffer );
+						_gl.bindBuffer( _gl.ARRAY_BUFFER, buffer );
 						_gl.vertexAttribPointer( programAttribute, size, _gl.FLOAT, false, stride * data.array.BYTES_PER_ELEMENT, ( startIndex * stride + offset ) * data.array.BYTES_PER_ELEMENT );
 						_gl.vertexAttribPointer( programAttribute, size, _gl.FLOAT, false, stride * data.array.BYTES_PER_ELEMENT, ( startIndex * stride + offset ) * data.array.BYTES_PER_ELEMENT );
 
 
 						if ( data instanceof THREE.InstancedInterleavedBuffer ) {
 						if ( data instanceof THREE.InstancedInterleavedBuffer ) {
@@ -942,7 +956,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 
 					} else {
 					} else {
 
 
-						_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryAttribute.buffer );
+						_gl.bindBuffer( _gl.ARRAY_BUFFER, buffer );
 						_gl.vertexAttribPointer( programAttribute, size, _gl.FLOAT, false, 0, startIndex * size * 4 ); // 4 bytes per Float32
 						_gl.vertexAttribPointer( programAttribute, size, _gl.FLOAT, false, 0, startIndex * size * 4 ); // 4 bytes per Float32
 
 
 						if ( geometryAttribute instanceof THREE.InstancedBufferAttribute ) {
 						if ( geometryAttribute instanceof THREE.InstancedBufferAttribute ) {
@@ -1054,6 +1068,8 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 
 			var type, size;
 			var type, size;
 
 
+			var indexBuffer = objects.getAttributeBuffer(index);
+
 			if ( index.array instanceof Uint32Array && extensions.get( 'OES_element_index_uint' ) ) {
 			if ( index.array instanceof Uint32Array && extensions.get( 'OES_element_index_uint' ) ) {
 
 
 				type = _gl.UNSIGNED_INT;
 				type = _gl.UNSIGNED_INT;
@@ -1073,7 +1089,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 				if ( updateBuffers ) {
 				if ( updateBuffers ) {
 
 
 					setupVertexAttributes( material, program, geometry, 0 );
 					setupVertexAttributes( material, program, geometry, 0 );
-					_gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, index.buffer );
+					_gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, indexBuffer );
 
 
 				}
 				}
 
 
@@ -1114,7 +1130,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 					if ( updateBuffers ) {
 					if ( updateBuffers ) {
 
 
 						setupVertexAttributes( material, program, geometry, startIndex );
 						setupVertexAttributes( material, program, geometry, startIndex );
-						_gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, index.buffer );
+						_gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, indexBuffer );
 
 
 					}
 					}
 
 
@@ -1258,6 +1274,8 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 
 			var type, size;
 			var type, size;
 
 
+			var indexBuffer = objects.getAttributeBuffer(index);
+
 			if ( index.array instanceof Uint32Array && extensions.get( 'OES_element_index_uint' ) ) {
 			if ( index.array instanceof Uint32Array && extensions.get( 'OES_element_index_uint' ) ) {
 
 
 				type = _gl.UNSIGNED_INT;
 				type = _gl.UNSIGNED_INT;
@@ -1277,7 +1295,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 				if ( updateBuffers ) {
 				if ( updateBuffers ) {
 
 
 					setupVertexAttributes( material, program, geometry, 0 );
 					setupVertexAttributes( material, program, geometry, 0 );
-					_gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, index.buffer );
+					_gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, indexBuffer );
 
 
 				}
 				}
 
 
@@ -1301,7 +1319,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 					if ( updateBuffers ) {
 					if ( updateBuffers ) {
 
 
 						setupVertexAttributes( material, program, geometry, startIndex );
 						setupVertexAttributes( material, program, geometry, startIndex );
-						_gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, index.buffer );
+						_gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, indexBuffer );
 
 
 					}
 					}
 
 
@@ -1365,6 +1383,8 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 
 			var type, size;
 			var type, size;
 
 
+			var indexBuffer = objects.getAttributeBuffer(indexBuffer);
+
 			if ( index.array instanceof Uint32Array && extensions.get( 'OES_element_index_uint' ) ) {
 			if ( index.array instanceof Uint32Array && extensions.get( 'OES_element_index_uint' ) ) {
 
 
 				type = _gl.UNSIGNED_INT;
 				type = _gl.UNSIGNED_INT;
@@ -1384,7 +1404,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 				if ( updateBuffers ) {
 				if ( updateBuffers ) {
 
 
 					setupVertexAttributes( material, program, geometry, 0 );
 					setupVertexAttributes( material, program, geometry, 0 );
-					_gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, index.buffer );
+					_gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, indexBuffer );
 
 
 				}
 				}
 
 
@@ -1408,7 +1428,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 					if ( updateBuffers ) {
 					if ( updateBuffers ) {
 
 
 						setupVertexAttributes( material, program, geometry, startIndex );
 						setupVertexAttributes( material, program, geometry, startIndex );
-						_gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, index.buffer );
+						_gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, indexBuffer );
 
 
 					}
 					}
 
 
@@ -1690,6 +1710,12 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 
 						var material = object.material;
 						var material = object.material;
 
 
+						if ( objectRendererWebGLProps[material.uuid] ) {
+
+							material.program = objectRendererWebGLProps[material.uuid].program;
+
+						}
+
 						if ( material.transparent ) {
 						if ( material.transparent ) {
 
 
 							transparentObjects.push( webglObject );
 							transparentObjects.push( webglObject );
@@ -1826,6 +1852,12 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 
 	function initMaterial( material, lights, fog, object ) {
 	function initMaterial( material, lights, fog, object ) {
 
 
+		if ( ! objectRendererWebGLProps[material.uuid] ) {
+
+			objectRendererWebGLProps[material.uuid] = {};
+
+		}
+
 		var shaderID = shaderIDs[ material.type ];
 		var shaderID = shaderIDs[ material.type ];
 
 
 		// heuristics to create shader parameters according to lights in the scene
 		// heuristics to create shader parameters according to lights in the scene
@@ -1925,12 +1957,12 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 
 		var code = chunks.join();
 		var code = chunks.join();
 
 
-		if ( !material.program ) {
+		if ( !objectRendererWebGLProps[material.uuid].program ) {
 
 
 			// new material
 			// new material
 			material.addEventListener( 'dispose', onMaterialDispose );
 			material.addEventListener( 'dispose', onMaterialDispose );
 
 
-		} else if ( material.program.code !== code ) {
+		} else if ( objectRendererWebGLProps[material.uuid].program.code !== code ) {
 
 
 			// changed glsl or parameters
 			// changed glsl or parameters
 			deallocateMaterial( material );
 			deallocateMaterial( material );
@@ -1940,7 +1972,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 			// same glsl
 			// same glsl
 			return;
 			return;
 
 
-		} else if ( material.__webglShader.uniforms === material.uniforms ) {
+		} else if ( objectRendererWebGLProps[material.uuid].__webglShader.uniforms === material.uniforms ) {
 
 
 			// same uniforms (container object)
 			// same uniforms (container object)
 			return;
 			return;
@@ -1951,7 +1983,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 
 			var shader = THREE.ShaderLib[ shaderID ];
 			var shader = THREE.ShaderLib[ shaderID ];
 
 
-			material.__webglShader = {
+			objectRendererWebGLProps[material.uuid].__webglShader = {
 				uniforms: THREE.UniformsUtils.clone( shader.uniforms ),
 				uniforms: THREE.UniformsUtils.clone( shader.uniforms ),
 				vertexShader: shader.vertexShader,
 				vertexShader: shader.vertexShader,
 				fragmentShader: shader.fragmentShader
 				fragmentShader: shader.fragmentShader
@@ -1959,7 +1991,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 
 		} else {
 		} else {
 
 
-			material.__webglShader = {
+			objectRendererWebGLProps[material.uuid].__webglShader = {
 				uniforms: material.uniforms,
 				uniforms: material.uniforms,
 				vertexShader: material.vertexShader,
 				vertexShader: material.vertexShader,
 				fragmentShader: material.fragmentShader
 				fragmentShader: material.fragmentShader
@@ -1988,6 +2020,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 
 		if ( program === undefined ) {
 		if ( program === undefined ) {
 
 
+			material.__webglShader = objectRendererWebGLProps[material.uuid].__webglShader;
 			program = new THREE.WebGLProgram( _this, code, material, parameters );
 			program = new THREE.WebGLProgram( _this, code, material, parameters );
 			_programs.push( program );
 			_programs.push( program );
 
 
@@ -1995,7 +2028,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 
 		}
 		}
 
 
-		material.program = program;
+		objectRendererWebGLProps[material.uuid].program = program;
 
 
 		var attributes = program.getAttributes();
 		var attributes = program.getAttributes();
 
 
@@ -2031,15 +2064,15 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 
 		}
 		}
 
 
-		material.uniformsList = [];
+		objectRendererWebGLProps[material.uuid].uniformsList = [];
 
 
-		var uniformLocations = material.program.getUniforms();
-		for ( var u in material.__webglShader.uniforms ) {
+		var uniformLocations = objectRendererWebGLProps[material.uuid].program.getUniforms();
+		for ( var u in objectRendererWebGLProps[material.uuid].__webglShader.uniforms ) {
 
 
 			var location = uniformLocations[ u ];
 			var location = uniformLocations[ u ];
 
 
 			if ( location ) {
 			if ( location ) {
-				material.uniformsList.push( [ material.__webglShader.uniforms[ u ], location ] );
+				objectRendererWebGLProps[material.uuid].uniformsList.push( [ objectRendererWebGLProps[material.uuid].__webglShader.uniforms[ u ], location ] );
 			}
 			}
 
 
 		}
 		}
@@ -2070,6 +2103,14 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 
 		_usedTextureUnits = 0;
 		_usedTextureUnits = 0;
 
 
+		if ( ! objectRendererWebGLProps[material.uuid] ) {
+
+			objectRendererWebGLProps[material.uuid] = {};
+			// need to reinitialize material for this renderer if from different renderer
+			material.needsUpdate = true;
+
+		}
+
 		if ( material.needsUpdate ) {
 		if ( material.needsUpdate ) {
 
 
 			initMaterial( material, lights, fog, object );
 			initMaterial( material, lights, fog, object );
@@ -2081,9 +2122,9 @@ THREE.WebGLRenderer = function ( parameters ) {
 		var refreshMaterial = false;
 		var refreshMaterial = false;
 		var refreshLights = false;
 		var refreshLights = false;
 
 
-		var program = material.program,
+		var program = objectRendererWebGLProps[material.uuid].program,
 			p_uniforms = program.getUniforms(),
 			p_uniforms = program.getUniforms(),
-			m_uniforms = material.__webglShader.uniforms;
+			m_uniforms = objectRendererWebGLProps[material.uuid].__webglShader.uniforms;
 
 
 		if ( program.id !== _currentProgram ) {
 		if ( program.id !== _currentProgram ) {
 
 
@@ -2288,7 +2329,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 
 			// load common uniforms
 			// load common uniforms
 
 
-			loadUniformsGeneric( material.uniformsList );
+			loadUniformsGeneric( objectRendererWebGLProps[material.uuid].uniformsList );
 
 
 		}
 		}
 
 
@@ -3197,10 +3238,10 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 
 		if ( extension && texture.type !== THREE.FloatType && texture.type !== THREE.HalfFloatType ) {
 		if ( extension && texture.type !== THREE.FloatType && texture.type !== THREE.HalfFloatType ) {
 
 
-			if ( texture.anisotropy > 1 || texture.__currentAnisotropy ) {
+			if ( texture.anisotropy > 1 || objectRendererWebGLProps[texture.uuid].__currentAnisotropy ) {
 
 
 				_gl.texParameterf( textureType, extension.TEXTURE_MAX_ANISOTROPY_EXT, Math.min( texture.anisotropy, _this.getMaxAnisotropy() ) );
 				_gl.texParameterf( textureType, extension.TEXTURE_MAX_ANISOTROPY_EXT, Math.min( texture.anisotropy, _this.getMaxAnisotropy() ) );
-				texture.__currentAnisotropy = texture.anisotropy;
+				objectRendererWebGLProps[texture.uuid].__currentAnisotropy = texture.anisotropy;
 
 
 			}
 			}
 
 
@@ -3210,20 +3251,22 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 
 	this.uploadTexture = function ( texture, slot ) {
 	this.uploadTexture = function ( texture, slot ) {
 
 
-		if ( texture.__webglInit === undefined ) {
+		if ( objectRendererWebGLProps[texture.uuid].__webglInit === undefined ) {
+
+			objectRendererWebGLProps[texture.uuid].__webglInit = true;
 
 
 			texture.__webglInit = true;
 			texture.__webglInit = true;
 
 
 			texture.addEventListener( 'dispose', onTextureDispose );
 			texture.addEventListener( 'dispose', onTextureDispose );
 
 
-			texture.__webglTexture = _gl.createTexture();
+			objectRendererWebGLProps[texture.uuid].__webglTexture = _gl.createTexture();
 
 
 			_this.info.memory.textures ++;
 			_this.info.memory.textures ++;
 
 
 		}
 		}
 
 
 		state.activeTexture( _gl.TEXTURE0 + slot );
 		state.activeTexture( _gl.TEXTURE0 + slot );
-		state.bindTexture( _gl.TEXTURE_2D, texture.__webglTexture );
+		state.bindTexture( _gl.TEXTURE_2D, objectRendererWebGLProps[texture.uuid].__webglTexture );
 
 
 		_gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, texture.flipY );
 		_gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, texture.flipY );
 		_gl.pixelStorei( _gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultiplyAlpha );
 		_gl.pixelStorei( _gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultiplyAlpha );
@@ -3324,6 +3367,19 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 
 	this.setTexture = function ( texture, slot ) {
 	this.setTexture = function ( texture, slot ) {
 
 
+		if ( ! objectRendererWebGLProps[texture.uuid] ) {
+
+			objectRendererWebGLProps[texture.uuid] = {};
+
+		}
+
+		// if the image has been uploaded into a separate renderer, will need to reupload to this renderer
+		if ( ( texture.image && texture.image.complete ) && texture.__webglInit === true && objectRendererWebGLProps[texture.uuid].__webglInit === undefined ) {
+
+			texture.needsUpdate = true;
+
+		}
+
 		if ( texture.needsUpdate === true ) {
 		if ( texture.needsUpdate === true ) {
 
 
 			var image = texture.image;
 			var image = texture.image;
@@ -3348,7 +3404,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 		}
 		}
 
 
 		state.activeTexture( _gl.TEXTURE0 + slot );
 		state.activeTexture( _gl.TEXTURE0 + slot );
-		state.bindTexture( _gl.TEXTURE_2D, texture.__webglTexture );
+		state.bindTexture( _gl.TEXTURE_2D, objectRendererWebGLProps[texture.uuid].__webglTexture );
 
 
 	};
 	};
 
 
@@ -3380,22 +3436,28 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 
 	function setCubeTexture ( texture, slot ) {
 	function setCubeTexture ( texture, slot ) {
 
 
+		if ( ! objectRendererWebGLProps[texture.uuid] ) {
+
+			objectRendererWebGLProps[texture.uuid] = {};
+
+		}
+
 		if ( texture.image.length === 6 ) {
 		if ( texture.image.length === 6 ) {
 
 
 			if ( texture.needsUpdate ) {
 			if ( texture.needsUpdate ) {
 
 
-				if ( ! texture.image.__webglTextureCube ) {
+				if ( ! objectRendererWebGLProps[texture.uuid].__image__webglTextureCube ) {
 
 
 					texture.addEventListener( 'dispose', onTextureDispose );
 					texture.addEventListener( 'dispose', onTextureDispose );
 
 
-					texture.image.__webglTextureCube = _gl.createTexture();
+					objectRendererWebGLProps[texture.uuid].__image__webglTextureCube = _gl.createTexture();
 
 
 					_this.info.memory.textures ++;
 					_this.info.memory.textures ++;
 
 
 				}
 				}
 
 
 				state.activeTexture( _gl.TEXTURE0 + slot );
 				state.activeTexture( _gl.TEXTURE0 + slot );
-				state.bindTexture( _gl.TEXTURE_CUBE_MAP, texture.image.__webglTextureCube );
+				state.bindTexture( _gl.TEXTURE_CUBE_MAP, objectRendererWebGLProps[texture.uuid].__image__webglTextureCube );
 
 
 				_gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, texture.flipY );
 				_gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, texture.flipY );
 
 
@@ -3484,7 +3546,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 			} else {
 			} else {
 
 
 				state.activeTexture( _gl.TEXTURE0 + slot );
 				state.activeTexture( _gl.TEXTURE0 + slot );
-				state.bindTexture( _gl.TEXTURE_CUBE_MAP, texture.image.__webglTextureCube );
+				state.bindTexture( _gl.TEXTURE_CUBE_MAP, objectRendererWebGLProps[texture.uuid].__image__webglTextureCube );
 
 
 			}
 			}
 
 
@@ -3494,8 +3556,14 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 
 	function setCubeTextureDynamic ( texture, slot ) {
 	function setCubeTextureDynamic ( texture, slot ) {
 
 
+		if ( ! objectRendererWebGLProps[texture.uuid] ) {
+
+			objectRendererWebGLProps[texture.uuid] = {};
+
+		}
+
 		state.activeTexture( _gl.TEXTURE0 + slot );
 		state.activeTexture( _gl.TEXTURE0 + slot );
-		state.bindTexture( _gl.TEXTURE_CUBE_MAP, texture.__webglTexture );
+		state.bindTexture( _gl.TEXTURE_CUBE_MAP, objectRendererWebGLProps[texture.uuid].__webglTexture );
 
 
 	}
 	}
 
 
@@ -3503,8 +3571,14 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 
 	function setupFrameBuffer ( framebuffer, renderTarget, textureTarget ) {
 	function setupFrameBuffer ( framebuffer, renderTarget, textureTarget ) {
 
 
+		if ( ! objectRendererWebGLProps[renderTarget.uuid] ) {
+
+			objectRendererWebGLProps[renderTarget.uuid] = {};
+
+		}
+
 		_gl.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );
 		_gl.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );
-		_gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, textureTarget, renderTarget.__webglTexture, 0 );
+		_gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, textureTarget, objectRendererWebGLProps[renderTarget.uuid].__webglTexture, 0 );
 
 
 	}
 	}
 
 
@@ -3538,16 +3612,20 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 
 	this.setRenderTarget = function ( renderTarget ) {
 	this.setRenderTarget = function ( renderTarget ) {
 
 
+		if ( renderTarget && ! objectRendererWebGLProps[renderTarget.uuid] ) {
+			objectRendererWebGLProps[renderTarget.uuid] = {};
+		}
+
 		var isCube = ( renderTarget instanceof THREE.WebGLRenderTargetCube );
 		var isCube = ( renderTarget instanceof THREE.WebGLRenderTargetCube );
 
 
-		if ( renderTarget && renderTarget.__webglFramebuffer === undefined ) {
+		if ( renderTarget && objectRendererWebGLProps[renderTarget.uuid].__webglFramebuffer === undefined ) {
 
 
 			if ( renderTarget.depthBuffer === undefined ) renderTarget.depthBuffer = true;
 			if ( renderTarget.depthBuffer === undefined ) renderTarget.depthBuffer = true;
 			if ( renderTarget.stencilBuffer === undefined ) renderTarget.stencilBuffer = true;
 			if ( renderTarget.stencilBuffer === undefined ) renderTarget.stencilBuffer = true;
 
 
 			renderTarget.addEventListener( 'dispose', onRenderTargetDispose );
 			renderTarget.addEventListener( 'dispose', onRenderTargetDispose );
 
 
-			renderTarget.__webglTexture = _gl.createTexture();
+			objectRendererWebGLProps[renderTarget.uuid].__webglTexture = _gl.createTexture();
 
 
 			_this.info.memory.textures ++;
 			_this.info.memory.textures ++;
 
 
@@ -3559,22 +3637,22 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 
 			if ( isCube ) {
 			if ( isCube ) {
 
 
-				renderTarget.__webglFramebuffer = [];
-				renderTarget.__webglRenderbuffer = [];
+				objectRendererWebGLProps[renderTarget.uuid].__webglFramebuffer = [];
+				objectRendererWebGLProps[renderTarget.uuid].__webglRenderbuffer = [];
 
 
-				state.bindTexture( _gl.TEXTURE_CUBE_MAP, renderTarget.__webglTexture );
+				state.bindTexture( _gl.TEXTURE_CUBE_MAP, objectRendererWebGLProps[renderTarget.uuid].__webglTexture );
 
 
 				setTextureParameters( _gl.TEXTURE_CUBE_MAP, renderTarget, isTargetPowerOfTwo );
 				setTextureParameters( _gl.TEXTURE_CUBE_MAP, renderTarget, isTargetPowerOfTwo );
 
 
 				for ( var i = 0; i < 6; i ++ ) {
 				for ( var i = 0; i < 6; i ++ ) {
 
 
-					renderTarget.__webglFramebuffer[ i ] = _gl.createFramebuffer();
-					renderTarget.__webglRenderbuffer[ i ] = _gl.createRenderbuffer();
+					objectRendererWebGLProps[renderTarget.uuid].__webglFramebuffer[ i ] = _gl.createFramebuffer();
+					objectRendererWebGLProps[renderTarget.uuid].__webglRenderbuffer[ i ] = _gl.createRenderbuffer();
 
 
 					state.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glFormat, renderTarget.width, renderTarget.height, 0, glFormat, glType, null );
 					state.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glFormat, renderTarget.width, renderTarget.height, 0, glFormat, glType, null );
 
 
-					setupFrameBuffer( renderTarget.__webglFramebuffer[ i ], renderTarget, _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i );
-					setupRenderBuffer( renderTarget.__webglRenderbuffer[ i ], renderTarget );
+					setupFrameBuffer( objectRendererWebGLProps[renderTarget.uuid].__webglFramebuffer[ i ], renderTarget, _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i );
+					setupRenderBuffer( objectRendererWebGLProps[renderTarget.uuid].__webglRenderbuffer[ i ], renderTarget );
 
 
 				}
 				}
 
 
@@ -3582,40 +3660,40 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 
 			} else {
 			} else {
 
 
-				renderTarget.__webglFramebuffer = _gl.createFramebuffer();
+				objectRendererWebGLProps[renderTarget.uuid].__webglFramebuffer = _gl.createFramebuffer();
 
 
 				if ( renderTarget.shareDepthFrom ) {
 				if ( renderTarget.shareDepthFrom ) {
 
 
-					renderTarget.__webglRenderbuffer = renderTarget.shareDepthFrom.__webglRenderbuffer;
+					objectRendererWebGLProps[renderTarget.uuid].__webglRenderbuffer = renderTarget.shareDepthFrom.__webglRenderbuffer;
 
 
 				} else {
 				} else {
 
 
-					renderTarget.__webglRenderbuffer = _gl.createRenderbuffer();
+					objectRendererWebGLProps[renderTarget.uuid].__webglRenderbuffer = _gl.createRenderbuffer();
 
 
 				}
 				}
 
 
-				state.bindTexture( _gl.TEXTURE_2D, renderTarget.__webglTexture );
+				state.bindTexture( _gl.TEXTURE_2D, objectRendererWebGLProps[renderTarget.uuid].__webglTexture );
 				setTextureParameters( _gl.TEXTURE_2D, renderTarget, isTargetPowerOfTwo );
 				setTextureParameters( _gl.TEXTURE_2D, renderTarget, isTargetPowerOfTwo );
 
 
 				state.texImage2D( _gl.TEXTURE_2D, 0, glFormat, renderTarget.width, renderTarget.height, 0, glFormat, glType, null );
 				state.texImage2D( _gl.TEXTURE_2D, 0, glFormat, renderTarget.width, renderTarget.height, 0, glFormat, glType, null );
 
 
-				setupFrameBuffer( renderTarget.__webglFramebuffer, renderTarget, _gl.TEXTURE_2D );
+				setupFrameBuffer( objectRendererWebGLProps[renderTarget.uuid].__webglFramebuffer, renderTarget, _gl.TEXTURE_2D );
 
 
 				if ( renderTarget.shareDepthFrom ) {
 				if ( renderTarget.shareDepthFrom ) {
 
 
 					if ( renderTarget.depthBuffer && ! renderTarget.stencilBuffer ) {
 					if ( renderTarget.depthBuffer && ! renderTarget.stencilBuffer ) {
 
 
-						_gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.RENDERBUFFER, renderTarget.__webglRenderbuffer );
+						_gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.RENDERBUFFER, objectRendererWebGLProps[renderTarget.uuid].__webglRenderbuffer );
 
 
 					} else if ( renderTarget.depthBuffer && renderTarget.stencilBuffer ) {
 					} else if ( renderTarget.depthBuffer && renderTarget.stencilBuffer ) {
 
 
-						_gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.RENDERBUFFER, renderTarget.__webglRenderbuffer );
+						_gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.RENDERBUFFER, objectRendererWebGLProps[renderTarget.uuid].__webglRenderbuffer );
 
 
 					}
 					}
 
 
 				} else {
 				} else {
 
 
-					setupRenderBuffer( renderTarget.__webglRenderbuffer, renderTarget );
+					setupRenderBuffer( objectRendererWebGLProps[renderTarget.uuid].__webglRenderbuffer, renderTarget );
 
 
 				}
 				}
 
 
@@ -3646,11 +3724,11 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 
 			if ( isCube ) {
 			if ( isCube ) {
 
 
-				framebuffer = renderTarget.__webglFramebuffer[ renderTarget.activeCubeFace ];
+				framebuffer = objectRendererWebGLProps[renderTarget.uuid].__webglFramebuffer[ renderTarget.activeCubeFace ];
 
 
 			} else {
 			} else {
 
 
-				framebuffer = renderTarget.__webglFramebuffer;
+				framebuffer = objectRendererWebGLProps[renderTarget.uuid].__webglFramebuffer;
 
 
 			}
 			}
 
 
@@ -3695,7 +3773,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 
 		}
 		}
 
 
-		if ( renderTarget.__webglFramebuffer ) {
+		if ( objectRendererWebGLProps[renderTarget.uuid].__webglFramebuffer ) {
 
 
 			if ( renderTarget.format !== THREE.RGBAFormat ) {
 			if ( renderTarget.format !== THREE.RGBAFormat ) {
 
 
@@ -3706,9 +3784,9 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 
 			var restore = false;
 			var restore = false;
 
 
-			if ( renderTarget.__webglFramebuffer !== _currentFramebuffer ) {
+			if ( objectRendererWebGLProps[renderTarget.uuid].__webglFramebuffer !== _currentFramebuffer ) {
 
 
-				_gl.bindFramebuffer( _gl.FRAMEBUFFER, renderTarget.__webglFramebuffer );
+				_gl.bindFramebuffer( _gl.FRAMEBUFFER, objectRendererWebGLProps[renderTarget.uuid].__webglFramebuffer );
 
 
 				restore = true;
 				restore = true;
 
 
@@ -3738,13 +3816,13 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 
 		if ( renderTarget instanceof THREE.WebGLRenderTargetCube ) {
 		if ( renderTarget instanceof THREE.WebGLRenderTargetCube ) {
 
 
-			state.bindTexture( _gl.TEXTURE_CUBE_MAP, renderTarget.__webglTexture );
+			state.bindTexture( _gl.TEXTURE_CUBE_MAP, objectRendererWebGLProps[renderTarget.uuid].__webglTexture );
 			_gl.generateMipmap( _gl.TEXTURE_CUBE_MAP );
 			_gl.generateMipmap( _gl.TEXTURE_CUBE_MAP );
 			state.bindTexture( _gl.TEXTURE_CUBE_MAP, null );
 			state.bindTexture( _gl.TEXTURE_CUBE_MAP, null );
 
 
 		} else {
 		} else {
 
 
-			state.bindTexture( _gl.TEXTURE_2D, renderTarget.__webglTexture );
+			state.bindTexture( _gl.TEXTURE_2D, objectRendererWebGLProps[renderTarget.uuid].__webglTexture );
 			_gl.generateMipmap( _gl.TEXTURE_2D );
 			_gl.generateMipmap( _gl.TEXTURE_2D );
 			state.bindTexture( _gl.TEXTURE_2D, null );
 			state.bindTexture( _gl.TEXTURE_2D, null );
 
 

+ 36 - 10
src/renderers/webgl/WebGLObjects.js

@@ -7,6 +7,9 @@ THREE.WebGLObjects = function ( gl, info ) {
 	var objects = {};
 	var objects = {};
 	var objectsImmediate = [];
 	var objectsImmediate = [];
 
 
+	// stores attributes by uuid in order to decouple buffers from attribute objects
+	var objectWebglProperties = {};
+
 	var morphInfluences = new Float32Array( 8 );
 	var morphInfluences = new Float32Array( 8 );
 
 
 	var geometries = new THREE.WebGLGeometries( gl, info );
 	var geometries = new THREE.WebGLGeometries( gl, info );
@@ -40,11 +43,11 @@ THREE.WebGLObjects = function ( gl, info ) {
 
 
 		}
 		}
 
 
-		delete object.__webglInit;
+		delete objectWebglProperties[object.uuid].__webglInit;
 		delete object._modelViewMatrix;
 		delete object._modelViewMatrix;
 		delete object._normalMatrix;
 		delete object._normalMatrix;
 
 
-		delete object.__webglActive;
+		delete objectWebglProperties[object.uuid].__webglActive;
 
 
 	}
 	}
 
 
@@ -71,9 +74,15 @@ THREE.WebGLObjects = function ( gl, info ) {
 
 
 	this.init = function ( object ) {
 	this.init = function ( object ) {
 
 
-		if ( object.__webglInit === undefined ) {
+		if ( ! objectWebglProperties[object.uuid] ) {
+
+			objectWebglProperties[object.uuid] = {};
+
+		}
+
+		if ( objectWebglProperties[object.uuid].__webglInit === undefined ) {
 
 
-			object.__webglInit = true;
+			objectWebglProperties[object.uuid].__webglInit = true;
 			object._modelViewMatrix = new THREE.Matrix4();
 			object._modelViewMatrix = new THREE.Matrix4();
 			object._normalMatrix = new THREE.Matrix3();
 			object._normalMatrix = new THREE.Matrix3();
 
 
@@ -81,9 +90,9 @@ THREE.WebGLObjects = function ( gl, info ) {
 
 
 		}
 		}
 
 
-		if ( object.__webglActive === undefined ) {
+		if ( objectWebglProperties[object.uuid].__webglActive === undefined ) {
 
 
-			object.__webglActive = true;
+			objectWebglProperties[object.uuid].__webglActive = true;
 
 
 			if ( object instanceof THREE.Mesh || object instanceof THREE.Line || object instanceof THREE.PointCloud ) {
 			if ( object instanceof THREE.Mesh || object instanceof THREE.Line || object instanceof THREE.PointCloud ) {
 
 
@@ -184,14 +193,26 @@ THREE.WebGLObjects = function ( gl, info ) {
 
 
 			var attribute = attributes[ name ];
 			var attribute = attributes[ name ];
 
 
+			if ( ! attribute.uuid ) {
+
+				attribute.uuid = THREE.Math.generateUUID();
+
+			}
+
+			if ( ! objectWebglProperties[attribute.uuid] ) {
+
+				objectWebglProperties[attribute.uuid] = {};
+
+			}
+
 			var bufferType = ( name === 'index' ) ? gl.ELEMENT_ARRAY_BUFFER : gl.ARRAY_BUFFER;
 			var bufferType = ( name === 'index' ) ? gl.ELEMENT_ARRAY_BUFFER : gl.ARRAY_BUFFER;
 
 
 			var data = ( attribute instanceof THREE.InterleavedBufferAttribute ) ? attribute.data : attribute;
 			var data = ( attribute instanceof THREE.InterleavedBufferAttribute ) ? attribute.data : attribute;
 
 
-			if ( data.buffer === undefined ) {
+			if ( objectWebglProperties[attribute.uuid].__webglBuffer === undefined ) {
 
 
-				data.buffer = gl.createBuffer();
-				gl.bindBuffer( bufferType, data.buffer );
+				objectWebglProperties[attribute.uuid].__webglBuffer = gl.createBuffer();
+				gl.bindBuffer( bufferType, objectWebglProperties[attribute.uuid].__webglBuffer );
 
 
 				var usage = gl.STATIC_DRAW;
 				var usage = gl.STATIC_DRAW;
 
 
@@ -209,7 +230,7 @@ THREE.WebGLObjects = function ( gl, info ) {
 
 
 			} else if ( data.needsUpdate === true ) {
 			} else if ( data.needsUpdate === true ) {
 
 
-				gl.bindBuffer( bufferType, data.buffer );
+				gl.bindBuffer( bufferType, objectWebglProperties[attribute.uuid].__webglBuffer );
 
 
 				if ( data.updateRange === undefined || data.updateRange.count === -1 ) { // Not using update ranges
 				if ( data.updateRange === undefined || data.updateRange.count === -1 ) { // Not using update ranges
 
 
@@ -236,6 +257,11 @@ THREE.WebGLObjects = function ( gl, info ) {
 
 
 	};
 	};
 
 
+	// returns the webgl buffer for a specified attribute
+	this.getAttributeBuffer = function (attribute) {
+		return objectWebglProperties[attribute.uuid] ? objectWebglProperties[attribute.uuid].__webglBuffer : undefined;
+	}
+
 	this.update = function ( renderList ) {
 	this.update = function ( renderList ) {
 
 
 		for ( var i = 0, ul = renderList.length; i < ul; i++ ) {
 		for ( var i = 0, ul = renderList.length; i < ul; i++ ) {