WebGL2实例化元素无法渲染问题求助
WebGL2实例化元素渲染无显示问题排查
在WebGL2实现实例化元素渲染时,元素无法正常显示,调用GL.getError()未返回任何报错信息,已确认缓冲区设置正确,相关代码如下:
const Canvas = document.getElementById("game_ui"); Canvas.width = window.innerWidth; Canvas.height = window.innerHeight; const GL = Canvas.getContext("webgl2"); if(!GL) { document.body.innerHTML = "Could not create Webgl2 context."; } class Program { constructor() { this.Identity = GL.createProgram(); this.Shaders = []; } CreateShader(type, glsl_string) { var shader = GL.createShader(type); GL.shaderSource(shader, glsl_string); GL.compileShader(shader); if(!GL.getShaderParameter(shader, GL.COMPILE_STATUS)) { throw new Error(GL.getShaderInfoLog(shader)); } else { this.Shaders.push(shader); } } CreateProgram() { for(var shader of this.Shaders) { GL.attachShader(this.Identity, shader); } GL.linkProgram(this.Identity); if(!GL.getProgramParameter(this.Identity, GL.LINK_STATUS)) { throw new Error(GL.getProgramInfoLog(this.Identity)); } } } class Buffer { constructor(type, buffer, shader_location) { this.Type = type; this.Identity = buffer; this.attributeLocation = shader_location; } } const ADD_COLOR = 0; const TEXTURE = 1; class VertexArrayObject { constructor() { this.Identity = GL.createVertexArray(); this.Buffers = []; this.Uniforms = []; GL.bindVertexArray(this.Identity); } CreateBuffer(type, data, behavior) { var buffer = GL.createBuffer(type); GL.bindBuffer(type, buffer); GL.bufferData(type, new Uint16Array(data), behavior); return buffer; } CreateAttribBuffer(program, variable, type) { var buffer = GL.createBuffer(type); GL.bindBuffer(type, buffer); var attrib = GL.getAttribLocation(program, variable); this.Buffers.push(new Buffer(type, buffer, attrib)); } SetAttribBufferData(buffer_array_index, data, amount_per_vertex, divisor, behavior) { GL.enableVertexAttribArray(this.Buffers[buffer_array_index].attributeLocation); GL.bindBuffer(this.Buffers[buffer_array_index].Type, this.Buffers[buffer_array_index].Identity); GL.bufferData(this.Buffers[buffer_array_index].Type, new Float32Array(data), behavior); GL.vertexAttribPointer(this.Buffers[buffer_array_index].attributeLocation, amount_per_vertex, GL.FLOAT, false, 0, 0); GL.vertexAttribDivisor(this.Buffers[buffer_array_index].attributeLocation, divisor); } CreateUniform(program, variable) { this.Uniforms.push(GL.getUniformLocation(program, variable)); } SetImageUnit(unit) { GL.uniform1i(this.Uniforms[TEXTURE], unit); } SetColorAddition(red, green, blue) { GL.uniform3f(this.Uniforms[ADD_COLOR], red, green, blue); } } var shaderProgram = new Program(); shaderProgram.CreateShader(GL.VERTEX_SHADER, vertexShader); shaderProgram.CreateShader(GL.FRAGMENT_SHADER,fragmentShader); shaderProgram.CreateProgram(); GL.useProgram(shaderProgram.Identity); const DEFAULT_POSITION_SIZE = 0; const TEXTURE_COORDS = 1; const OFFSET = 2; const SCALE = 3; const CROP = 4; const OPACITY = 5; var vertexArrayObject = new VertexArrayObject(); vertexArrayObject.CreateAttribBuffer(shaderProgram.Identity, "defaultPositionSize", GL.ARRAY_BUFFER); vertexArrayObject.CreateAttribBuffer(shaderProgram.Identity, "textureCoord", GL.ARRAY_BUFFER); vertexArrayObject.CreateAttribBuffer(shaderProgram.Identity, "Offset", GL.ARRAY_BUFFER); vertexArrayObject.CreateAttribBuffer(shaderProgram.Identity, "Scale", GL.ARRAY_BUFFER); vertexArrayObject.CreateAttribBuffer(shaderProgram.Identity, "Crop", GL.ARRAY_BUFFER); vertexArrayObject.CreateAttribBuffer(shaderProgram.Identity, "Opacity", GL.ARRAY_BUFFER); vertexArrayObject.CreateUniform(shaderProgram.Identity, "addColor"); vertexArrayObject.CreateUniform(shaderProgram.Identity, "textureSample"); vertexArrayObject.SetColorAddition(0, 0, 0); class UI { constructor() { this.Texture = null; this.Opacity = []; this.Offset = []; this.Scale = []; this.Crop = []; } CreateTexture(image_source) { this.Texture = GL.createTexture(); var image = document.createElement("img"); image.src = "Images/" + image_source + ".png"; image.onload = () => { GL.bindTexture(GL.TEXTURE_2D, this.Texture); GL.texImage2D(GL.TEXTURE_2D, 0, GL.RGBA, GL.RGBA, GL.UNSIGNED_BYTE, image); GL.texParameteri(GL.TEXTURE_2D, GL.TEXTURE_WRAP_S, GL.CLAMP_TO_EDGE); GL.texParameteri(GL.TEXTURE_2D, GL.TEXTURE_WRAP_T, GL.CLAMP_TO_EDGE); GL.texParameteri(GL.TEXTURE_2D, GL.TEXTURE_MIN_FILTER, GL.NEAREST); GL.texParameteri(GL.TEXTURE_2D, GL.TEXTURE_MAG_FILTER, GL.NEAREST); }; GL.bindTexture(GL.TEXTURE_2D, null); } CreateElements(opacity, offset, scale, crop) { this.Opacity = this.Opacity.concat(opacity); this.Offset = this.Offset.concat(offset); this.Scale = this.Scale.concat(scale); this.Crop = this.Crop.concat(crop); } DeleteElements(indices) { for(var index of indices) { this.Opacity.splice(index, 1); this.Offset.splice(index * 2, 2); this.Scale.splice(index * 2, 2); this.Crop.splice(index * 4, 4); } } DeleteUI() { GL.deleteTexture(this.Texture); } } GL.enable(GL.DEPTH_TEST); GL.enable(GL.BLEND); GL.blendFunc(GL.SRC_ALPHA, GL.ONE_MINUS_SRC_ALPHA); GL.activeTexture(GL.TEXTURE0); vertexArrayObject.SetImageUnit(0); var ui = new UI(); ui.CreateTexture("test"); ui.CreateElements([1.0], [0.5, 0.5], [0.5, 0.5], [0, 0, 1, 1]); GL.bindTexture(GL.TEXTURE_2D, ui.Texture); vertexArrayObject.SetAttribBufferData(DEFAULT_POSITION_SIZE, [-1.0, 1.0, 1.0, 1.0, -1.0, -1.0, 1.0, -1.0], 2, 0, GL.STATIC_DRAW); vertexArrayObject.SetAttribBufferData(TEXTURE_COORDS, [0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 1.0, 0.0, 0.0, 1.0, 1.0, 1.0], 2, 0, GL.STATIC_DRAW); vertexArrayObject.SetAttribBufferData(OFFSET, ui.Offset, 2, 1, GL.DYNAMIC_DRAW); vertexArrayObject.SetAttribBufferData(CROP, ui.Crop, 4, 1, GL.DYNAMIC_DRAW); vertexArrayObject.SetAttribBufferData(SCALE, ui.Scale, 2, 1, GL.DYNAMIC_DRAW); vertexArrayObject.SetAttribBufferData(OPACITY, ui.Opacity, 1, 1, GL.DYNAMIC_DRAW); var indicesBuffer = vertexArrayObject.CreateBuffer(GL.ELEMENT_ARRAY_BUFFER, [0, 1, 2, 1, 2, 3], GL.STATIC_DRAW); function Update() { GL.clear(GL.COLOR_BUFFER_BIT | GL.DEPTH_BUFFER_BIT); GL.drawElementsInstanced(GL.TRIANGLES, 6, GL.UNSIGNED_SHORT, 0, ui.Opacity.length); requestAnimationFrame(Update); } requestAnimationFrame(Update);
排查方向
- 纹理加载异步问题:图片加载是异步操作,
Update函数启动时纹理可能还未完成初始化,导致采样无效。需等待图片加载完成后再开始渲染,或初始化一个1x1的默认纹理作为占位。 - VAO未绑定:绘制前未绑定顶点数组对象(VAO),WebGL无法读取顶点和实例化属性数据。需在
GL.drawElementsInstanced前添加GL.bindVertexArray(vertexArrayObject.Identity)。 - 元素缓冲区未关联VAO:创建ELEMENT_ARRAY_BUFFER时,VAO已解绑,导致索引数据未被VAO记录。需在VAO绑定状态下创建并绑定索引缓冲区,可修改
CreateBuffer方法确保在VAO绑定期间执行,或在创建索引缓冲区前重新绑定VAO。 - 视口未设置:Canvas尺寸设置后未调用
GL.viewport(0, 0, Canvas.width, Canvas.height),导致渲染内容与画布尺寸不匹配,可能被偏移或裁剪到不可见区域。 - 着色器属性计算错误:检查顶点着色器中是否正确使用实例化属性(Offset、Scale等)计算最终顶点位置。例如默认顶点坐标为[-1,1],叠加Offset[0.5,0.5]后,需确认最终坐标是否在WebGL的裁剪空间[-1,1]范围内,超出则无法显示。
内容的提问来源于stack exchange,提问作者Youaregreat
相关产品推荐
相关产品推荐

