我有一个由 WebGL 中的立方体组成的 3D 网格。每个立方体都由三角形基元组成。一些立方体需要是透明的,以便背景中的立方体能够显示出来。
我当前的解决方案允许使用透明的立方体,但渲染画布背景——透明的颜色(我认为)——而不是后面的立方体。附图显示了我混乱的 WebGL 代码中某个地方的问题。如果您有任何想法请告诉我。
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)
}
这里是经过必要修改的代码,以确保透明元素在 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
函数中提供正确的相机位置,并在绘制之前为每个透明对象设置适当的制服和缓冲区。
排序过程只是使用冒泡排序的一个示例。可以使用更高效的排序算法(例如合并排序或快速排序)来获得更好的性能。