Javascript 在WebGL中绘制多个二维图像

Javascript 在WebGL中绘制多个二维图像,javascript,html,canvas,webgl,Javascript,Html,Canvas,Webgl,我一直在学习一些关于html5rocks的教程,我成功地制作了一个javascript程序,使用webGL在画布上显示一幅图像。我已经在下面发布了我的代码 问题是,似乎没有人向您展示如何在webGL中绘制多个对象。我以前从未直接使用过webGL,所以对我来说不是很直观 如何修改此代码以绘制imageObjectArray中的每个对象?(请注意,现在我正在绘制imageObjectArray[0] function render(canvas, contextGL, imageObject

我一直在学习一些关于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精灵游戏。没有图书馆的舒适。(除了glMatrix.js)


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

以下代码执行以下操作:

  • 编译顶点着色器和片段着色器
  • 将它们链接到一个着色器程序中
  • 创建顶点缓冲区以保存纹理坐标并填充它(texCoordBuffer)
  • 创建纹理(createTexture)
  • 配置纹理的采样方式(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);
    
    其余代码必须针对要绘制的每个图像执行,并执行以下操作:

  • 将图像上载到纹理(texImage2D)
  • 创建顶点缓冲区以保留位置并填充它(缓冲区)
  • 调用数组
  • contextGL.texImage2D(contextGL.TEXTURE_2D,0,contextGL.RGBA,contextGL.RGBA,contextGL.UNSIGNED_字节,imageObjectArray[0]。displayObject.data); var resolutionLocation=contextGL.getUniformLocation(程序,“u_resolution”); contextGL.uniform2f(分辨率位置,canvas.width,canvas.height); var buffer=contextGL.createBuffer(); contextGL.bindBuffer(contextGL.ARRAY_BUFFER,BUFFER); contextGL.EnableVertexAttributeArray(位置位置); contextGL.VertexAttribute指针(位置位置,2,contextGL.FLOAT,false,0,0); setRectangle(contextGL,imageObjectArray[0]。x,imageObjectArray[0]。y,imageObjectArray[0]。宽度,imageObjectArray[0]。高度); //画 contextGL.DrawArray(contextGL.TRIANGLES,0,6); 您需要将步骤2拆分为单独的步骤。第一步,为posistions创建顶点缓冲区,只应执行一次。第二步,填充图像的位置,需要为要绘制的每个图像执行

    我应该说我的建议不会给出最佳的实施方案,但它会让你画出超过1张的图像。
    • 实现纹理贴图(将所有图像打包到单个纹理上)
    • 只上传一次纹理和位置坐标
    • 使用更好的顶点和片段着色器来选择要绘制的图像(纹理坐标偏移)、绘制位置(位置偏移)以及应该多大(宽度和高度缩放)

    感谢您的精彩解释!但是,您说“您需要将步骤2拆分为单独的步骤。第一步,为posistions创建顶点缓冲区,应该只执行一次”-您说的一次是什么意思?我不是应该为每个图像执行整个步骤2吗?您想移动
    var buffer=contextGL.createBuffer()
    在循环之外,剩下的部分仍然存在。不要让它变得更混乱,但另一种方法是在步骤2中创建一个单位矩形,并添加一些制服(如矩阵)要将单位矩阵转换、缩放和旋转到您想要绘制图像的大小和位置,我不知道是更快还是更好,更新每个图像的缓冲区还是为每个图像计算不同的矩阵。谢谢,伙计们,这很有意义。我会在这之后马上讨论效率部分。 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);