简体   繁体   中英

WebGL2 draw multiple textures in one draw call

I am having some trouble finding mistake in the code. I hope you will indicate me the direction where to look for a solution.

I try to use 2+ textures in one draw call. For testing I use 2 textures.

  1. 1-st texture for vertex shader - matricies saved as a texture
  2. 2-nd texture to render as image

When I try to render the scene, the first texture (name: "dataTexture") is empty, the second texture (name: "u_image0") is available and works fine.

Here is a uniform that contains both textures

myUniform = [
...
{
    name: "dataTexture",
    type: "TEXTURE_2D",
    variableLocation: WebGLUniformLocation,
    valueToPass: WebGLTexture
},
{
    name: "u_image0",
    type: "TEXTURE_2D",
    variableLocation: WebGLUniformLocation,
    valueToPass: WebGLTexture
}
];

Then I use a separate function to render these textures It looks like this

// For textures
// Using 2 or more textures
textureID = 0; // textureID = 0, 1, 2, ... (int)
let len = myUniforms.length;
for (i = 0; i < len; i++) {
    ...
    if (type == "TEXTURE_2D") { 
        // Set which texture units to render with
        if (variableLocation != null){
            console.log("Location exist");
            
            gl.uniform1i(variableLocation, textureID); // textureID = 0, 1, 2, ...
    
            textureID++;
        }
        else {console.log("No location");}
    
        // Set each texture unit to use a particular texture
        gl.activeTexture(gl.TEXTURE0 + textureID);
        // Bind texture image
        gl.bindTexture(gl.TEXTURE_2D, valueToPass);
    }
}
...
// Render
gl.drawArrays(primitiveType, offsetArray, count);

Here are the shaders

vertexShaderSource = [
    "#version 300 es",
    // Attributes
    // An attribute is an input (in) to a vertex shader.
    // It will receive data from a buffer
    "in vec2 a_position;",
    // Texture coordinates
    "in vec2 a_texCoord;",
    // Data indices in texture
    "in float a_matrixIndices;",
    
    // Uniforms
    // Data texture
    "uniform sampler2D dataTexture;",
    // Clip space matrix
    "uniform mat3 clipSpaceMatrix;",
    
    // Vareable to pass to fragment shader
    // Color
    "out vec3 color;",
    // Texture coordinates
    "out vec2 v_texCoord;",
    // Texture for use in the current instance
    "out float textureID;",

    // Read data from texture
    "vec4 getValueByIndexFromTexture(sampler2D tex, int index) {",
        "int texWidth = textureSize(tex, 0).x;",
        "int col = index % texWidth;",
        "int row = index / texWidth;",
        "return texelFetch(tex, ivec2(col, row), 0);",
    "}",
    
    "void main() {",
        // Index to read data from texture
        "int index = int(a_matrixIndices);",
        "vec3 data = getValueByIndexFromTexture(dataTexture, index).xyz;",

        // Object type
        "int objectType = int(data.x);",
        // Matrix to convert from object space to world space
        "mat3 matrixWorld = mat3(.0);",
        
        "if (objectType == 0) {",
            // Obect type = RasterImage
            "matrixWorld[0][0] = data.y;",
            "matrixWorld[0][1] = data.z;",

            "data = getValueByIndexFromTexture(dataTexture, index + 1).xyz,",
            "matrixWorld[0][2] = data.x;",
            "matrixWorld[1][0] = data.y;",
            "matrixWorld[1][1] = data.z;",
            "data = getValueByIndexFromTexture(dataTexture, index + 2).xyz,",
            "matrixWorld[1][2] = data.x;",
            "matrixWorld[2][0] = data.y;",
            "matrixWorld[2][1] = data.z;",

            "data = getValueByIndexFromTexture(dataTexture, index + 3).xyz,",
            "matrixWorld[2][2] = data.x;",
            
            // Texture ID
            // Texture for use in the current instance
            "textureID = data.y;",
        "}",
        // Multiply the position by the matrix
        "vec3 position = clipSpaceMatrix * matrixWorld * vec3(a_position.xy, 1);",
        
        "gl_Position = vec4(position, 1);",
        // Send color to fragment shader
        "color = vec3(.1, 0.7, 0.3);",
        // Pass the texCoord to the fragment shader
        "v_texCoord = a_texCoord;",
    "}"
].join("\n");

fragmentShaderSource = [
    // WebGL2 version
    "#version 300 es",
    // Fragment shaders don't have a default precision so we need
    // to pick one. highp is a good default. It means "high precision"
    "precision highp float;",

    // Uniforms
    // Textures
    "uniform sampler2D u_image0;",
    //"uniform sampler2D u_image1;",

    // Passed in from the vertex shader.
    //"uniform vec3 foo;",
    "in vec3 color;",
    // Texture coordinates
    // The GPU will interpolate this value between points
    "in vec2 v_texCoord;",
    // Texture for use in the current instance
    "in float textureID;",

    // We need to declare an output for the fragment shader
    "out vec4 outColor;",

    "void main() {",
        "vec4 fragmentColor = vec4(1.0, 0.0, 1.0, 1.0);",
        "if (textureID == 0.0) {",
            "fragmentColor = texture(u_image0, v_texCoord);",
        "}",
        //"else if (textureID == 1.0) {",
        //  "fragmentColor = texture(u_image1, v_texCoord);",
        //"}",

        // Set color
        "outColor = fragmentColor;",
    "}"
].join("\n");

Thanks to everyone. This code is correct. You can use it however you want. As usual, a SMALL error that spoils everything: invalid data was sent to create a dataTexture. Confused push() with concat() .

For push() method:

dataTexture = dataTexture.push(data0, data1, ...); // This is wrong (returns array length)
dataTexture.push(data0, data1, ...); // Correct (returns changed array)

For conact() method

dataTexture = dataTexture.concat(Array[data0, data1, ...], ...); // Correct way (returns changed array)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM