Skip to content

Commit

Permalink
Fix Mesh change IndexBuffer、VertexBuffer、VertexElements bug( need t…
Browse files Browse the repository at this point in the history
…o update VAO) (#719)

* fix:change IndexBuffer、VertexBuffer、VertexElements need to update VAO.
---------
Co-authored-by: GuoLei1990 <gl3336563@163.com>
  • Loading branch information
cptbtptpbcptdtptp authored Mar 30, 2023
1 parent 9c922b3 commit 9635996
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 40 deletions.
7 changes: 7 additions & 0 deletions packages/core/src/graphic/Mesh.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ export abstract class Mesh extends RefObject {
/** @internal */
_glIndexByteCount: number;
/** @internal */
_bufferStructChanged: boolean;
/** @internal */
_platformPrimitive: IPlatformPrimitive;

/** @internal */
Expand Down Expand Up @@ -183,6 +185,7 @@ export abstract class Mesh extends RefObject {
*/
_draw(shaderProgram: ShaderProgram, subMesh: SubMesh): void {
this._platformPrimitive.draw(shaderProgram, subMesh);
this._bufferStructChanged = false;
}

/**
Expand Down Expand Up @@ -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);
}
}

Expand Down
85 changes: 45 additions & 40 deletions packages/rhi-webgl/src/GLPrimitive.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,46 +6,49 @@ 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.
*/

/**
* @internal
* 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<number, WebGLVertexArrayObject> = new Map();
private _gl: (WebGLRenderingContext & WebGLExtension) | WebGL2RenderingContext;
private _vaoMap: Map<number, WebGLVertexArrayObject> = 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
Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -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);
}
Expand All @@ -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 */
Expand All @@ -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();
}
}

0 comments on commit 9635996

Please sign in to comment.