From 96359969820441f750a7a36a36688a4f90723fd1 Mon Sep 17 00:00:00 2001 From: AZhan Date: Thu, 30 Mar 2023 17:23:49 +0800 Subject: [PATCH] =?UTF-8?q?Fix=20`Mesh`=20change=20IndexBuffer=E3=80=81Ver?= =?UTF-8?q?texBuffer=E3=80=81VertexElements=20bug(=20need=20to=20update=20?= =?UTF-8?q?VAO)=20(#719)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix:change IndexBuffer、VertexBuffer、VertexElements need to update VAO. --------- Co-authored-by: GuoLei1990 --- packages/core/src/graphic/Mesh.ts | 7 +++ packages/rhi-webgl/src/GLPrimitive.ts | 85 ++++++++++++++------------- 2 files changed, 52 insertions(+), 40 deletions(-) diff --git a/packages/core/src/graphic/Mesh.ts b/packages/core/src/graphic/Mesh.ts index 58b06ba1d9..2874b50dad 100644 --- a/packages/core/src/graphic/Mesh.ts +++ b/packages/core/src/graphic/Mesh.ts @@ -25,6 +25,8 @@ export abstract class Mesh extends RefObject { /** @internal */ _glIndexByteCount: number; /** @internal */ + _bufferStructChanged: boolean; + /** @internal */ _platformPrimitive: IPlatformPrimitive; /** @internal */ @@ -183,6 +185,7 @@ export abstract class Mesh extends RefObject { */ _draw(shaderProgram: ShaderProgram, subMesh: SubMesh): void { this._platformPrimitive.draw(shaderProgram, subMesh); + this._bufferStructChanged = false; } /** @@ -213,16 +216,20 @@ export abstract class Mesh extends RefObject { for (let i = 0, n = elements.length; i < n; i++) { this._addVertexElement(elements[i]); } + this._bufferStructChanged = true; } protected _setIndexBufferBinding(binding: IndexBufferBinding | null): void { + const lastBinding = this._indexBufferBinding; if (binding) { this._indexBufferBinding = binding; this._glIndexType = BufferUtil._getGLIndexType(binding.format); this._glIndexByteCount = BufferUtil._getGLIndexByteCount(binding.format); + (!lastBinding || lastBinding._buffer !== binding._buffer) && (this._bufferStructChanged = true); } else { this._indexBufferBinding = null; this._glIndexType = undefined; + lastBinding && (this._bufferStructChanged = true); } } diff --git a/packages/rhi-webgl/src/GLPrimitive.ts b/packages/rhi-webgl/src/GLPrimitive.ts index ac05345aa7..ee66acdc3b 100644 --- a/packages/rhi-webgl/src/GLPrimitive.ts +++ b/packages/rhi-webgl/src/GLPrimitive.ts @@ -6,7 +6,6 @@ import { WebGLRenderer } from "./WebGLRenderer"; /** * Improvement of VAO: * 1) WebGL2.0 must support VAO, almost all devices support vao extensions in webgl1.0, we can use PollyFill,only keep VAO mode. - * 2) VAO implementation now has bugs, change IndexBuffer、VertexBuffer、VertexElements need to update VAO. */ /** @@ -14,38 +13,42 @@ import { WebGLRenderer } from "./WebGLRenderer"; * GL platform primitive. */ export class GLPrimitive implements IPlatformPrimitive { - protected attribLocArray: number[] = []; - protected readonly _primitive: Mesh; - protected readonly canUseInstancedArrays: boolean; + private _attribLocArray: number[] = []; + private readonly _primitive: Mesh; + private readonly _canUseInstancedArrays: boolean; - private gl: (WebGLRenderingContext & WebGLExtension) | WebGL2RenderingContext; - private vao: Map = new Map(); + private _gl: (WebGLRenderingContext & WebGLExtension) | WebGL2RenderingContext; + private _vaoMap: Map = new Map(); private readonly _useVao: boolean; constructor(rhi: WebGLRenderer, primitive: Mesh) { this._primitive = primitive; - this.canUseInstancedArrays = rhi.canIUse(GLCapabilityType.instancedArrays); + this._canUseInstancedArrays = rhi.canIUse(GLCapabilityType.instancedArrays); this._useVao = rhi.canIUse(GLCapabilityType.vertexArrayObject); - this.gl = rhi.gl; + this._gl = rhi.gl; } /** * Draw the primitive. */ draw(shaderProgram: any, subMesh: SubMesh): void { - const gl = this.gl; + const gl = this._gl; const primitive = this._primitive; // @ts-ignore const useVao = this._useVao && primitive._enableVAO; if (useVao) { - if (!this.vao.has(shaderProgram.id)) { - this.registerVAO(shaderProgram); + // @ts-ignore + if (primitive._bufferStructChanged) { + this._clearVAO(); } - const vao = this.vao.get(shaderProgram.id); + if (!this._vaoMap.has(shaderProgram.id)) { + this._registerVAO(shaderProgram); + } + const vao = this._vaoMap.get(shaderProgram.id); gl.bindVertexArray(vao); } else { - this.bindBufferAndAttrib(shaderProgram); + this._bindBufferAndAttrib(shaderProgram); } // @ts-ignore @@ -66,9 +69,9 @@ export class GLPrimitive implements IPlatformPrimitive { gl.drawArrays(topology, start, count); } } else { - if (this.canUseInstancedArrays) { + if (this._canUseInstancedArrays) { if (_indexBufferBinding) { - if (this._useVao) { + if (useVao) { gl.drawElementsInstanced(topology, count, _glIndexType, start * _glIndexByteCount, _instanceCount); } else { const { _nativeBuffer } = _indexBufferBinding.buffer; @@ -84,34 +87,28 @@ export class GLPrimitive implements IPlatformPrimitive { } } - // unbind - if (this._useVao) { + // Unbind + if (useVao) { gl.bindVertexArray(null); } else { - this.disableAttrib(); + this._disableAttrib(); } } - destroy() { - if (this._useVao) { - const gl = this.gl; - this.vao.forEach((vao) => { - gl.deleteVertexArray(vao); - }); - this.vao.clear(); - } + destroy(): void { + this._useVao && this._clearVAO(); } /** * Bind buffer and attribute. */ - protected bindBufferAndAttrib(shaderProgram: any): void { - const gl = this.gl; + private _bindBufferAndAttrib(shaderProgram: any): void { + const gl = this._gl; const primitive = this._primitive; // @ts-ignore const vertexBufferBindings = primitive._vertexBufferBindings; - this.attribLocArray.length = 0; + this._attribLocArray.length = 0; const attributeLocation = shaderProgram.attributeLocation; // @ts-ignore const attributes = primitive._vertexElementMap; @@ -136,10 +133,10 @@ export class GLPrimitive implements IPlatformPrimitive { gl.enableVertexAttribArray(loc); const elementInfo = element._glElementInfo; gl.vertexAttribPointer(loc, elementInfo.size, elementInfo.type, elementInfo.normalized, stride, element.offset); - if (this.canUseInstancedArrays) { + if (this._canUseInstancedArrays) { gl.vertexAttribDivisor(loc, element.instanceStepRate); } - this.attribLocArray.push(loc); + this._attribLocArray.push(loc); } else { Logger.warn("vertex attribute not found: " + name); } @@ -148,15 +145,15 @@ export class GLPrimitive implements IPlatformPrimitive { gl.bindBuffer(gl.ARRAY_BUFFER, null); } - protected disableAttrib() { - const gl = this.gl; - for (let i = 0, l = this.attribLocArray.length; i < l; i++) { - gl.disableVertexAttribArray(this.attribLocArray[i]); + private _disableAttrib() { + const gl = this._gl; + for (let i = 0, l = this._attribLocArray.length; i < l; i++) { + gl.disableVertexAttribArray(this._attribLocArray[i]); } } - private registerVAO(shaderProgram: any): void { - const gl = this.gl; + private _registerVAO(shaderProgram: any): void { + const gl = this._gl; const vao = gl.createVertexArray(); /** register VAO */ @@ -167,13 +164,21 @@ export class GLPrimitive implements IPlatformPrimitive { if (_indexBufferBinding) { gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, _indexBufferBinding.buffer._nativeBuffer); } - this.bindBufferAndAttrib(shaderProgram); + this._bindBufferAndAttrib(shaderProgram); /** unbind */ gl.bindVertexArray(null); gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null); - this.disableAttrib(); + this._disableAttrib(); + + this._vaoMap.set(shaderProgram.id, vao); + } - this.vao.set(shaderProgram.id, vao); + private _clearVAO(): void { + const gl = this._gl; + this._vaoMap.forEach((vao) => { + gl.deleteVertexArray(vao); + }); + this._vaoMap.clear(); } }