diff --git a/examples/jsm/renderers/webgl/WebGLBackend.js b/examples/jsm/renderers/webgl/WebGLBackend.js index 71a995fc08c440..080a54a1c1ef2a 100644 --- a/examples/jsm/renderers/webgl/WebGLBackend.js +++ b/examples/jsm/renderers/webgl/WebGLBackend.js @@ -114,9 +114,24 @@ class WebGLBackend extends Backend { } - clear( /*renderContext, color, depth, stencil*/ ) { + clear( renderContext, color, depth, stencil ) { - console.warn( 'Abstract class.' ); + const { gl } = this; + + // + + let clear = 0; + + if ( color ) clear |= gl.COLOR_BUFFER_BIT; + if ( depth ) clear |= gl.DEPTH_BUFFER_BIT; + if ( stencil ) clear |= gl.STENCIL_BUFFER_BIT; + + const clearColor = renderContext.clearColorValue; + + if ( clear === 0 ) return; + + gl.clearColor( clearColor.x, clearColor.y, clearColor.z, clearColor.a ); + gl.clear( clear ); } @@ -185,21 +200,30 @@ class WebGLBackend extends Backend { let mode; if ( object.isPoints ) mode = gl.POINTS; - else if ( object.isLine ) mode = gl.LINES; + else if ( object.isLine ) mode = gl.LINE_STRIP; else if ( object.isLineLoop ) mode = gl.LINE_LOOP; else if ( object.isLineSegments ) mode = gl.LINES; else mode = gl.TRIANGLES; // + const instanceCount = this.getInstanceCount( renderObject ); if ( index !== null ) { const indexData = this.get( index ); - const indexCount = ( drawRange.count !== Infinity ) ? drawRange.count : index.count; - gl.drawElements( mode, index.count, indexData.type, firstVertex ); + if ( instanceCount > 1 ) { + + gl.drawElementsInstanced( mode, index.count, indexData.type, firstVertex, instanceCount ); + + } else { + + gl.drawElements( mode, index.count, indexData.type, firstVertex ); + + } + info.update( object, indexCount, 1 ); @@ -208,8 +232,16 @@ class WebGLBackend extends Backend { const positionAttribute = geometry.attributes.position; const vertexCount = ( drawRange.count !== Infinity ) ? drawRange.count : positionAttribute.count; + if ( instanceCount > 1 ) { + + gl.drawArraysInstanced( mode, 0, vertexCount, instanceCount ); + + } else { + + gl.drawArrays( mode, 0, vertexCount ); + + } - gl.drawArrays( mode, 0, vertexCount ); //gl.drawArrays( mode, vertexCount, gl.UNSIGNED_SHORT, firstVertex ); info.update( object, vertexCount, 1 ); @@ -482,7 +514,7 @@ class WebGLBackend extends Backend { const vaoGPU = gl.createVertexArray(); const index = renderObject.getIndex(); - const vertexBuffers = renderObject.getVertexBuffers(); + const attributes = renderObject.getAttributes(); gl.bindVertexArray( vaoGPU ); @@ -494,14 +526,39 @@ class WebGLBackend extends Backend { } - for ( let i = 0; i < vertexBuffers.length; i ++ ) { + for ( let i = 0; i < attributes.length; i ++ ) { - const attribute = vertexBuffers[ i ]; + const attribute = attributes[ i ]; const attributeData = this.get( attribute ); gl.bindBuffer( gl.ARRAY_BUFFER, attributeData.bufferGPU ); gl.enableVertexAttribArray( i ); - gl.vertexAttribPointer( i, attribute.itemSize, attributeData.type, false, 0, 0 ); + + let stride, offset; + + if ( attribute.isInterleavedBufferAttribute === true ) { + + stride = attribute.data.stride * attributeData.bytesPerElement; + offset = attribute.offset * attributeData.bytesPerElement; + + } else { + + stride = 0; + offset = 0; + + } + + gl.vertexAttribPointer( i, attribute.itemSize, attributeData.type, false, stride, offset ); + + if ( attribute.isInstancedBufferAttribute && ! attribute.isInterleavedBufferAttribute ) { + + gl.vertexAttribDivisor( i, attribute.meshPerAttribute ); + + } else if ( attribute.isInterleavedBufferAttribute && attribute.data.isInstancedInterleavedBuffer ) { + + gl.vertexAttribDivisor( i, attribute.data.meshPerAttribute ); + + } } @@ -608,9 +665,9 @@ class WebGLBackend extends Backend { } - updateAttribute( /*attribute*/ ) { + updateAttribute( attribute ) { - console.warn( 'Abstract class.' ); + this.attributeUtils.updateAttribute( attribute ); } diff --git a/examples/jsm/renderers/webgl/nodes/GLSLNodeBuilder.js b/examples/jsm/renderers/webgl/nodes/GLSLNodeBuilder.js index e800caa02166ba..24b082a50c02b6 100644 --- a/examples/jsm/renderers/webgl/nodes/GLSLNodeBuilder.js +++ b/examples/jsm/renderers/webgl/nodes/GLSLNodeBuilder.js @@ -14,6 +14,10 @@ const precisionLib = { high: 'highp' }; +const supports = { + instance: true +}; + class GLSLNodeBuilder extends NodeBuilder { constructor( object, renderer, scene = null ) { @@ -176,7 +180,7 @@ class GLSLNodeBuilder extends NodeBuilder { if ( shaderStage === 'vertex' ) { - const attributes = this.attributes; + const attributes = this.getAttributesArray(); let location = 0; @@ -285,6 +289,13 @@ class GLSLNodeBuilder extends NodeBuilder { } + isAvailable( name ) { + + return supports[ name ] === true; + + } + + isFlipY() { return true; diff --git a/examples/jsm/renderers/webgl/utils/WebGLAttributeUtils.js b/examples/jsm/renderers/webgl/utils/WebGLAttributeUtils.js index 8e7f219dd1107f..d4946bd2bdd8d0 100644 --- a/examples/jsm/renderers/webgl/utils/WebGLAttributeUtils.js +++ b/examples/jsm/renderers/webgl/utils/WebGLAttributeUtils.js @@ -14,11 +14,24 @@ class WebGLAttributeUtils { const array = attribute.array; const usage = attribute.usage || gl.STATIC_DRAW; - const bufferGPU = gl.createBuffer(); + const bufferAttribute = attribute.isInterleavedBufferAttribute ? attribute.data : attribute; + const bufferData = backend.get( bufferAttribute ); - gl.bindBuffer( bufferType, bufferGPU ); - gl.bufferData( bufferType, array, usage ); - gl.bindBuffer( bufferType, null ); + let bufferGPU = bufferData.bufferGPU; + + if ( bufferGPU === undefined ) { + + bufferGPU = gl.createBuffer(); + + gl.bindBuffer( bufferType, bufferGPU ); + gl.bufferData( bufferType, array, usage ); + gl.bindBuffer( bufferType, null ); + + bufferData.bufferGPU = bufferGPU; + bufferData.bufferType = bufferType; + bufferData.version = bufferAttribute.version; + + } //attribute.onUploadCallback(); @@ -73,12 +86,29 @@ class WebGLAttributeUtils { backend.set( attribute, { bufferGPU, type, - bytesPerElement: array.BYTES_PER_ELEMENT, - version: attribute.version + bytesPerElement: array.BYTES_PER_ELEMENT } ); } + updateAttribute( attribute ) { + + const backend = this.backend; + const { gl } = backend; + + const array = attribute.array; + const bufferAttribute = attribute.isInterleavedBufferAttribute ? attribute.data : attribute; + const bufferData = backend.get( bufferAttribute ); + const bufferType = bufferData.bufferType; + + gl.bindBuffer( bufferType, bufferData.bufferGPU ); + gl.bufferSubData( bufferType, 0, array ); + gl.bindBuffer( bufferType, null ); + + bufferData.version = bufferAttribute.version; + + } + } export default WebGLAttributeUtils; diff --git a/examples/screenshots/webgpu_lines_fat.jpg b/examples/screenshots/webgpu_lines_fat.jpg index 001fe203e0b94e..d8df6c93aa25b3 100644 Binary files a/examples/screenshots/webgpu_lines_fat.jpg and b/examples/screenshots/webgpu_lines_fat.jpg differ diff --git a/examples/webgpu_lines_fat.html b/examples/webgpu_lines_fat.html index d0c32f59c28519..0632935a5ed664 100644 --- a/examples/webgpu_lines_fat.html +++ b/examples/webgpu_lines_fat.html @@ -28,6 +28,8 @@ import * as THREE from 'three'; import WebGPU from 'three/addons/capabilities/WebGPU.js'; + import WebGL from 'three/addons/capabilities/WebGL.js'; + import WebGPURenderer from 'three/addons/renderers/webgpu/WebGPURenderer.js'; import Stats from 'three/addons/libs/stats.module.js'; @@ -54,11 +56,11 @@ function init() { - if ( WebGPU.isAvailable() === false ) { + if ( WebGPU.isAvailable() === false && WebGL.isWebGL2Available() === false ) { document.body.appendChild( WebGPU.getErrorMessage() ); - throw new Error( 'No WebGPU support' ); + throw new Error( 'No WebGPU or WebGL2 support' ); } diff --git a/test/e2e/puppeteer.js b/test/e2e/puppeteer.js index 413b0a607d7629..d9f59827c0a85b 100644 --- a/test/e2e/puppeteer.js +++ b/test/e2e/puppeteer.js @@ -117,7 +117,6 @@ const exceptionList = [ 'webgpu_compute_texture_pingpong', 'webgpu_cubemap_dynamic', 'webgpu_instance_mesh', - 'webgpu_lines_fat', 'webgpu_loader_gltf', 'webgpu_loader_gltf_compressed', 'webgpu_loader_gltf_iridescence',