Mixing multiple objects

For depth testing reasons, draw two translucent Windows, the former window will completely block the latter window, that is to say, the latter window overlap was abandoned

The solution

1. Draw all opaque objects first.

2. Sort all transparent objects.

3. Draw all transparent objects in order

One way to sort transparent objects is to get their distance from the observer’s point of view. This can be obtained by calculating the distance between the camera position vector and the object position vector. Next we store the distance and its corresponding position vector in the MAP data structure of an STL library. The map automatically sorts its value by Key, so as soon as we add all the positions and use their distance as the Key, they will automatically sort by distance.

std::map<float, glm::vec3> sorted;
for (unsigned int i = 0; i < windows.size(a); i++) {float distance = glm::length(camera.Position - windows[i]);
    sorted[distance] = windows[i];
}
Copy the code

\

  • Vertex shader
export let vs_blending =
`#version 300 es layout (location = 0) in vec3 aPos; layout (location = 1) in vec2 aTexCoords; out vec2 TexCoords; uniform mat4 model; uniform mat4 view; uniform mat4 projection; void main() { TexCoords = aTexCoords; Gl_Position = projection * view * model * VEC4 (aPos, 1.0); } `
Copy the code
  • Chip shader
export let fs_blending =
`#version 300 es precision mediump float; out vec4 FragColor; in vec2 TexCoords; uniform sampler2D texture1; void main() { FragColor = texture(texture1, TexCoords); } `
Copy the code
  • Rendering pipeline
    camera = new Camera(vec3.fromValues(0.0.0.0.10.0), vec3.fromValues(0.0.1.0.0.0));
    / / the three
    gl.enable(gl.DEPTH_TEST);
    gl.enable(gl.BLEND);
    gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
    shader = new Shader(gl, vs_blending, fs_blending);
    cubeTexture = loadTexture(".. /.. /textures/marble.jpg".4.false);
    floorTexture = loadTexture(".. /.. /textures/metal.png".4.false);
    transparentTexture = loadTexture(".. /.. /textures/window.png".4.false);

    function loadTexture(url, nrComponents, gammaCorrection) {
        const textureID = gl.createTexture();
        gl.bindTexture(gl.TEXTURE_2D, textureID);
        const level = 0;
        const srcType = gl.UNSIGNED_BYTE;
        const pixel = new Uint8Array([0.0.255.255]);
        gl.texImage2D(gl.TEXTURE_2D, level, gl.RGBA, 1.1.0, gl.RGBA, srcType, pixel);
        const image = new Image();
        image.onload = function () {
            let internalFormat;
            let dataFormat;
            if (nrComponents == 1) {
                dataFormat = gl.RED;
                internalFormat = gl.R8;
            }
            else if (nrComponents == 3) {
                internalFormat = gammaCorrection ? gl.SRGB : gl.RGB;
                dataFormat = gl.RGB;
            }
            else if (nrComponents == 4) {
                internalFormat = gammaCorrection ? gl.SRGB8_ALPHA8 : gl.RGBA;
                dataFormat = gl.RGBA;
            }
            gl.bindTexture(gl.TEXTURE_2D, textureID);
            gl.texImage2D(gl.TEXTURE_2D, 0, internalFormat, image.naturalWidth, image.naturalHeight, 0, dataFormat, gl.UNSIGNED_BYTE, image);
            gl.generateMipmap(gl.TEXTURE_2D);
            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT);
            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT);
            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR);
            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
        };
        image.src = url;
        return textureID;
    }
Copy the code
    plane = new Quad();
    planeVao = CreateVAO(plane, { POSITION: 0.TEXCOORD_0: 1 });
    cube = new Cube();
    cubeVao = CreateVAO(cube, { POSITION: 0.TEXCOORD_0: 1 });
    transparent = new Quad();
    transparentVao = CreateVAO(transparent, { POSITION: 0.TEXCOORD_0: 1 });

    shader.use(gl);
    shader.setInt(gl, "texture1".0);
    requestAnimationFrame(render);
    //
    function CreateVAO(geo, layout) {
        let VAO = gl.createVertexArray();
        gl.bindVertexArray(VAO);
        const vbo = gl.createBuffer();
        const ebo = gl.createBuffer();
        gl.bindBuffer(gl.ARRAY_BUFFER, vbo);
        gl.bufferData(gl.ARRAY_BUFFER, geo.vertices, gl.STATIC_DRAW);
        gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, ebo);
        gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, geo.indices, gl.STATIC_DRAW);
        let acc = geo.accessors[geo.attributes.POSITION];
        gl.vertexAttribPointer(layout.POSITION, acc.countComponent, gl.FLOAT, false, acc.stride, acc.byteOffset);
        gl.enableVertexAttribArray(layout.POSITION);
        if (layout.TEXCOORD_0) {
            acc = geo.accessors[geo.attributes.TEXCOORD_0];
            gl.vertexAttribPointer(layout.TEXCOORD_0, acc.countComponent, gl.FLOAT, false, acc.stride, acc.byteOffset);
            gl.enableVertexAttribArray(layout.TEXCOORD_0);
        }
        if (layout.NORMAL) {
            acc = geo.accessors[geo.attributes.NORMAL];
            gl.vertexAttribPointer(layout.NORMAL, acc.countComponent, gl.FLOAT, false, acc.stride, acc.byteOffset);
            gl.enableVertexAttribArray(layout.NORMAL);
        }
        return VAO;
    }
Copy the code
  • Get the nearest distance
windows =
    [
        vec3.fromValues(-2.0.0.0, -0.48),
        vec3.fromValues(3.0.0.0.0.51),
        vec3.fromValues(0.0.0.0.2.7),
        vec3.fromValues(-0.6.0.0, -2.3),
        vec3.fromValues(1.0.0.0, -0.6)];let currentFrame = performance.now() / 1000;
    deltaTime = (currentFrame - lastFrame) * 1000;
    lastFrame = currentFrame;
    processInput();
    let sortArray = [];
    let sub = vec3.create();
    for (let i = 0; i < windows.length; i++) {
        let distance = vec3.len(vec3.subtract(sub, camera.Position, windows[i]));
        sortArray.push([distance, windows[i]]);
    }
    sortArray.sort(function (a, b) {
        return b[0] - a[0];
    });
    gl.clearColor(0.1.0.1.0.1.1.0);
    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
Copy the code
  • drawcall cube
   shader.use(gl);
   let projection = mat4.create();
   mat4.perspective(projection, (camera.Zoom) * Math.PI / 180, canvas.width / canvas.height, 0.1.100.0);
   gl.uniformMatrix4fv(gl.getUniformLocation(shader.programId, "projection"), false, projection);
   let view = camera.GetViewMatrix();
   gl.uniformMatrix4fv(gl.getUniformLocation(shader.programId, "view"), false, view);
   let model = mat4.create();
   mat4.identity(model);
   gl.bindVertexArray(cubeVao);
   gl.activeTexture(gl.TEXTURE0);
   gl.bindTexture(gl.TEXTURE_2D, cubeTexture);
   mat4.translate(model, model, vec3.fromValues(-2.0.0.0, -1.0));
   gl.uniformMatrix4fv(gl.getUniformLocation(shader.programId, "model"), false, model);
   gl.drawElements(gl.TRIANGLES, cube.indices.length, gl.UNSIGNED_SHORT, 0);
   mat4.identity(model);
   mat4.translate(model, model, vec3.fromValues(3.0.0.0.0.0));
   gl.uniformMatrix4fv(gl.getUniformLocation(shader.programId, "model"), false, model);
   gl.drawElements(gl.TRIANGLES, cube.indices.length, gl.UNSIGNED_SHORT, 0);
Copy the code
  • drawcall plane
    gl.bindVertexArray(planeVao);
    gl.bindTexture(gl.TEXTURE_2D, floorTexture);
    mat4.identity(model);
    mat4.fromXRotation(model, Math.PI / 2);
    mat4.scale(model, model, [5.0.5.0.1.0]);
    gl.uniformMatrix4fv(gl.getUniformLocation(shader.programId, "model"), false, model);
    gl.drawElements(gl.TRIANGLES, plane.indices.length, gl.UNSIGNED_SHORT, 0);
Copy the code
  • Drawcall Opaque object from far to near draw
    gl.bindVertexArray(transparentVao);
    gl.bindTexture(gl.TEXTURE_2D, transparentTexture);
    for (let i = 0, iLen = sortArray.length; i < iLen; i++) {
        model = mat4.identity(model);
        mat4.translate(model, model, sortArray[i][1]);
        gl.uniformMatrix4fv(gl.getUniformLocation(shader.programId, "model"), false, model);
        gl.drawElements(gl.TRIANGLES, transparent.indices.length, gl.UNSIGNED_SHORT, 0); } requestAnimationFrame(render); };//# sourceMappingURL=blending_sorted.js.map
Copy the code