【问题标题】:Drawing multiple 2D images in WebGL在 WebGL 中绘制多个 2D 图像
【发布时间】:2013-02-04 05:40:06
【问题描述】:

我一直在关注一些关于 html5rocks 的教程,并且我设法制作了一个 javascript 程序,该程序使用 webGL 在画布上显示一个图像。我已经在下面发布了我的代码。

问题是,似乎没有人向您展示如何在 webGL 中绘制多个对象。我以前从未直接使用过 webGL,所以它对我来说不是很直观。

如何修改此代码以绘制imageObjectArray 中的每个对象? (请注意,现在我只是在画imageObjectArray[0]

    function render(canvas, contextGL, imageObjectArray) { 
        vertexShader = createShaderFromScriptElement(contextGL, "2d-vertex-shader");
        fragmentShader = createShaderFromScriptElement(contextGL, "2d-fragment-shader");

        program = createProgram(contextGL, [vertexShader, fragmentShader]);
        contextGL.useProgram(program);

        var positionLocation = contextGL.getAttribLocation(program, "a_position");

        var texCoordLocation = contextGL.getAttribLocation(program, "a_texCoord");

        var texCoordBuffer = contextGL.createBuffer();
        contextGL.bindBuffer(contextGL.ARRAY_BUFFER, texCoordBuffer);

        contextGL.enableVertexAttribArray(texCoordLocation);
        contextGL.vertexAttribPointer(texCoordLocation, 2, contextGL.FLOAT, false, 0, 0);

        setRectangle(contextGL, 0.0, 0.0, 1.0, 1.0);

        var texture = contextGL.createTexture();
        contextGL.bindTexture(contextGL.TEXTURE_2D, texture);

        contextGL.texParameteri(contextGL.TEXTURE_2D, contextGL.TEXTURE_WRAP_S, contextGL.CLAMP_TO_EDGE);
        contextGL.texParameteri(contextGL.TEXTURE_2D, contextGL.TEXTURE_WRAP_T, contextGL.CLAMP_TO_EDGE);
        contextGL.texParameteri(contextGL.TEXTURE_2D, contextGL.TEXTURE_MIN_FILTER, contextGL.NEAREST);
        contextGL.texParameteri(contextGL.TEXTURE_2D, contextGL.TEXTURE_MAG_FILTER, contextGL.NEAREST);

        contextGL.texImage2D(contextGL.TEXTURE_2D, 0, contextGL.RGBA, contextGL.RGBA, contextGL.UNSIGNED_BYTE, imageObjectArray[0].displayObject.data);

        var resolutionLocation = contextGL.getUniformLocation(program, "u_resolution");
        contextGL.uniform2f(resolutionLocation, canvas.width, canvas.height);

        var buffer = contextGL.createBuffer();
        contextGL.bindBuffer(contextGL.ARRAY_BUFFER, buffer);
        contextGL.enableVertexAttribArray(positionLocation);
        contextGL.vertexAttribPointer(positionLocation, 2, contextGL.FLOAT, false, 0, 0);

        setRectangle(contextGL, imageObjectArray[0].x, imageObjectArray[0].y, imageObjectArray[0].width, imageObjectArray[0].height);

        // draw
        contextGL.drawArrays(contextGL.TRIANGLES, 0, 6);
    }

function setRectangle(gl, x, y, width, height) {
    var x2 = x + width;
    var y2 = y + height;
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(
                                        [x, y,
                                         x2, y,
                                         x, y2,
                                         x, y2,
                                         x2, y,
                                         x2, y2
                                        ]), gl.STATIC_DRAW);
}

我的目标是开发一个(非常基本的)2d sprite 游戏。没有图书馆的舒适。 (可能 glMatrix.js 除外)

[编辑] 我的渲染函数有错误,已修复。

【问题讨论】:

    标签: javascript html canvas webgl


    【解决方案1】:

    以下代码执行以下操作:

    1. 编译顶点和片段着色器
    2. 将它们链接到一个着色器程序中
    3. 创建一个顶点缓冲区来保存纹理坐标并填充它 (texCoordBuffer)
    4. 创建纹理 (createTexture)
    5. 配置纹理的采样方式 (texParameteri)

    以上5个步骤只需运行一次。

        vertexShader = createShaderFromScriptElement(contextGL, "2d-vertex-shader");
        fragmentShader = createShaderFromScriptElement(contextGL, "2d-fragment-shader");
    
        program = createProgram(contextGL, [vertexShader, fragmentShader]);
        contextGL.useProgram(program);
    
        var positionLocation = contextGL.getAttribLocation(program, "a_position");
    
        var texCoordLocation = contextGL.getAttribLocation(program, "a_texCoord");
    
        var texCoordBuffer = contextGL.createBuffer();
        contextGL.bindBuffer(contextGL.ARRAY_BUFFER, texCoordBuffer);
    
        contextGL.enableVertexAttribArray(texCoordLocation);
        contextGL.vertexAttribPointer(texCoordLocation, 2, contextGL.FLOAT, false, 0, 0);
    
        var texture = contextGL.createTexture();
        contextGL.bindTexture(contextGL.TEXTURE_2D, texture);
    
        contextGL.texParameteri(contextGL.TEXTURE_2D, contextGL.TEXTURE_WRAP_S, contextGL.CLAMP_TO_EDGE);
        contextGL.texParameteri(contextGL.TEXTURE_2D, contextGL.TEXTURE_WRAP_T, contextGL.CLAMP_TO_EDGE);
        contextGL.texParameteri(contextGL.TEXTURE_2D, contextGL.TEXTURE_MIN_FILTER, contextGL.NEAREST);
        contextGL.texParameteri(contextGL.TEXTURE_2D, contextGL.TEXTURE_MAG_FILTER, contextGL.NEAREST);
    
        setRectangle(contextGL, 0.0, 0.0, 1.0, 1.0);
    

    必须为您要绘制的每个图像执行其余代码,它执行以下操作:

    1. 将图像上传到纹理 (texImage2D)
    2. 创建一个顶点缓冲区来保存位置并填充它(缓冲区)
    3. 调用drawArrays
    contextGL.texImage2D(contextGL.TEXTURE_2D, 0, contextGL.RGBA, contextGL.RGBA,contextGL.UNSIGNED_BYTE, imageObjectArray[0].displayObject.data); var resolutionLocation = contextGL.getUniformLocation(program, "u_resolution"); contextGL.uniform2f(resolutionLocation, canvas.width, canvas.height); var buffer = contextGL.createBuffer(); contextGL.bindBuffer(contextGL.ARRAY_BUFFER, 缓冲区); contextGL.enableVertexAttribArray(positionLocation); contextGL.vertexAttribPointer(positionLocation, 2, contextGL.FLOAT, false, 0, 0); setRectangle(contextGL, imageObjectArray[0].x, imageObjectArray[0].y, imageObjectArray[0].width, imageObjectArray[0].height); // 画 contextGL.drawArrays(contextGL.TRIANGLES, 0, 6);

    您需要将第 2 步拆分为单独的步骤。第一步,为位置创建顶点缓冲区,应该只执行一次。第二步,填充图片的位置,需要对每张要绘制的图片执行。

    我应该说我的建议不会提供 最佳 实现,但它会让您绘制超过 1 个图像。为了达到最佳效果,您应该考虑这样做:

    • 实现纹理图集(将所有图像打包到一个纹理中)。
    • 只上传一次纹理和位置坐标。
    • 使用更好的顶点和片段着色器来选择正在绘制的图像(纹理坐标偏移)、绘制位置(位置偏移)以及应该有多大(宽度和高度缩放)

    【讨论】:

    • 感谢您的精彩解释!但是,您说“您需要将第 2 步拆分为单独的步骤。第一步,为位置创建顶点缓冲区,应该只执行一次” - 一次是什么意思?我不应该为每张图片执行整个步骤 2 吗?
    • 您想将var buffer = contextGL.createBuffer(); 移出循环,其余部分保留。
    • 不要让它更混乱,但另一种方法是在第 2 步中创建一个单位矩形并添加一些统一(如矩阵)以将该单位矩阵平移、缩放和旋转到大小和您要绘制图像的位置。哪个更快或更好,更新每个图像的缓冲区或为每个图像计算不同的矩阵,我不知道。
    • 谢谢大家,这是有道理的。我会在这之后马上进入效率部分。
    猜你喜欢
    • 1970-01-01
    • 2016-10-21
    • 1970-01-01
    • 2017-11-06
    • 2013-10-05
    • 2019-08-04
    • 2021-12-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多