WebGL中如何让透明元素渲染其后面的元素?

问题描述 投票:0回答:1

我有一个由 WebGL 中的立方体组成的 3D 网格。每个立方体都由三角形基元组成。一些立方体需要是透明的,以便背景中的立方体能够显示出来。

我当前的解决方案允许使用透明的立方体,但渲染画布背景——透明的颜色(我认为)——而不是后面的立方体。附图显示了我混乱的 WebGL 代码中某个地方的问题。如果您有任何想法请告诉我。

Mesh image

function draw() {

        let colorData = [];

        // Loops through all cubes making each colored or transparent
        for (let i = 0; i < (N + extra) * N**2; i++){
            colorData = flu.dyeIdx(i, colorData);
        }

        // routine to output xyz coordinates from buffer into vertex shader
        const positionBuffer = gl.createBuffer();
        gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer); // bind to current array buffer
        gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(meshVertices), gl.STATIC_DRAW); // load vertex data into buffer and choose draw mode

        const vertexShader = gl.createShader(gl.VERTEX_SHADER);
        gl.shaderSource(vertexShader, `
        precision mediump float;

        attribute vec4 position;
        attribute vec4 color;
        varying vec4 vColor;

        uniform mat4 matrix;

        void main() {
            vColor = color;
            gl_Position = matrix * position;
        }
        `);
        gl.compileShader(vertexShader)


        //routine to assign color shader
        const colorBuffer = gl.createBuffer();
        gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer); // bind to current array buffer
        gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colorData), gl.STATIC_DRAW); // load color data into buffer and choose draw mode

        const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
        gl.shaderSource(fragmentShader, `
        precision mediump float;

        varying vec4 vColor;

        void main() {
            gl_FragColor = vColor;
        }
        `);
        gl.compileShader(fragmentShader);


        
        // "link" vertex and color shaders
        const program = gl.createProgram();
        gl.attachShader(program, vertexShader);
        gl.attachShader(program, fragmentShader);
        gl.linkProgram(program);

        // assign position, color, and uniform locations
        const positionLocation = gl.getAttribLocation(program, 'position'); // attribute index
        gl.enableVertexAttribArray(positionLocation);
        gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
        gl.vertexAttribPointer(positionLocation, 3, gl.FLOAT, false, 0, 0);

        const colorLocation = gl.getAttribLocation(program, 'color'); // attribute index
        gl.enableVertexAttribArray(colorLocation);
        gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
        gl.vertexAttribPointer(colorLocation, 4, gl.FLOAT, false, 0, 0);


        //TRANSPARENCY
        gl.clearColor(0.0, 0.0, 0.0, 0.0);
        gl.enable(gl.BLEND);
        gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
        gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

        //DRAW OPAQUE OBJECTS HERE

        gl.disable(gl.DEPTH_TEST);

        //DRAW SEMI-TRANSPARENT OBJECTS HERE
        //gl.drawElements(gl.TRIANGLES, N, gl.UNSIGNED_BYTE, 0);


        const uniformLocation = {
            matrix : gl.getUniformLocation(program, `matrix`)
        };

        gl.useProgram(program);
        gl.enable(gl.DEPTH_TEST);



        let matrix = mat4.create();


        // change to 0, 0, 2.5 for redone origin
        mat4.translate(matrix, matrix, [0, .75, -4]);

        let projectionMatrix = mat4.create();
        mat4.perspective(projectionMatrix,
            50 * Math.PI / 180,   // vertical fov
            canvas.width / canvas.height, // aspect ratio
            1e-4,   // near cull distance
            1e4 // far cull distance
        );

        let outMatrix = mat4.create();
        
        mat4.rotateX(matrix, matrix, Math.PI/5);
        //mat4.rotateX(matrix, matrix, Math.PI/200);
        // comment for redone origin
        mat4.rotateY(matrix, matrix, Math.PI);
        //mat4.rotateZ(matrix, matrix, Math.PI/200);

        mat4.multiply(outMatrix, projectionMatrix, matrix);
        gl.uniformMatrix4fv(uniformLocation.matrix, false, outMatrix);
        gl.drawArrays(gl.TRIANGLES, 0, meshVertices.length / 3); // triangle, first vertex, draw all three
        // divide length of vertices array by 3 to get the number of vertices. vertices = coordinateComponents/componentsPerCoordinate(x,y,z)

    }
glsl webgl
1个回答
0
投票

这里是经过必要修改的代码,以确保透明元素在 WebGL 中渲染其后面的元素:

function draw() {
    // ... (previous code)

    // TRANSPARENCY
    gl.enable(gl.BLEND);
    gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

    // DRAW OPAQUE OBJECTS HERE

    // Enable depth test for proper rendering
    gl.enable(gl.DEPTH_TEST);

    // DRAW SEMI-TRANSPARENT OBJECTS HERE
    // Sort transparent objects by distance from camera and then draw
    // Example sorting function using bubble sort:
    for (let i = 0; i < transparentObjects.length - 1; i++) {
        for (let j = 0; j < transparentObjects.length - i - 1; j++) {
            const distanceA = computeDistanceFromCamera(transparentObjects[j]);
            const distanceB = computeDistanceFromCamera(transparentObjects[j + 1]);
            if (distanceA < distanceB) {
                // Swap transparentObjects[j] and transparentObjects[j + 1]
                const temp = transparentObjects[j];
                transparentObjects[j] = transparentObjects[j + 1];
                transparentObjects[j + 1] = temp;
            }
        }
    }

    // Now draw the sorted transparent objects
    for (const obj of transparentObjects) {
        // Set model-view-projection matrix and other uniforms
        // Bind buffers and draw transparent object
    }
}

// Calculate the distance from camera for sorting
function computeDistanceFromCamera(object) {
    const cameraPosition = [0, 0, 0]; // Update with your camera position
    const objectPosition = object.position; // Update with the object's position
    const dx = objectPosition[0] - cameraPosition[0];
    const dy = objectPosition[1] - cameraPosition[1];
    const dz = objectPosition[2] - cameraPosition[2];
    return Math.sqrt(dx * dx + dy * dy + dz * dz);
}

注意:您需要创建一个数组

transparentObjects
来保存有关每个透明对象的位置和其他必要数据的信息。排序过程对于实现适当的透明度渲染至关重要。

此外,请确保在

computeDistanceFromCamera
函数中提供正确的相机位置,并在绘制之前为每个透明对象设置适当的制服和缓冲区。

排序过程只是使用冒泡排序的一个示例。可以使用更高效的排序算法(例如合并排序或快速排序)来获得更好的性能。

© www.soinside.com 2019 - 2024. All rights reserved.