如何修复 three.js 中网格表面线的 z-fighting?
How to fix z-fighting of the line on mesh surface in three.js?
我正在尝试在 three.js
的脸上画线
一切正常,除了线条几乎看不见 - 无论我把它们做得多厚:它们看起来像这样:
画线的代码是:
var lgeometry = new THREE.Geometry();
var lmaterial = new THREE.LineBasicMaterial( { color: 0xffffff, linewidth: 4 } );
var v1 = p1;
var v2 = p2;
lgeometry.vertices.push(v1);
lgeometry.vertices.push(v2);
console.log(lgeometry);
var line = new THREE.Line( lgeometry, lmaterial );
scene.add( line );
我怀疑 - 由于表面上的线条 完全 ,因此它们不会被渲染(这就是所谓的 z-fighting 吗?)
有办法解决吗?
我正在考虑:
- 绘制圆柱体或其他形状而不是线条
- 沿着法线几乎绘制线
有什么搬进来的建议或方向吗?
这可以通过层和模板缓冲区的组合来实现。
工作演示: https://jsfiddle.net/mmalex/dg417kvn/
解法:
解释请看下面代码中的注释:
document.fixZFighting = function() {
// 1. Get the current WebGL context
const gl = renderer.getContext();
// 2. Set rendering order: mesh before line,
// because we want mesh to initialize stencil buffers before line rendering.
cube.renderOrder = 1;
line.renderOrder = 2;
// 3. Provide render callbacks
cube.onBeforeRender = function() {
// enable stencil buffer test
gl.enable(gl.STENCIL_TEST);
// do it just for all mesh pixels
gl.stencilFunc(gl.ALWAYS, 1, 0xFF);
// ... with no masking
gl.stencilMask(0xFF);
// ... simply increment stencil buffer value for each draw call,
// (important, here we have
gl.stencilOp(gl.KEEP, gl.KEEP, gl.INCR);
}
cube.onAfterRender = function() {
// nothing to do
}
line.onBeforeRender = function() {
// don't rely on z-Buffer for line, disable depth check
gl.disable(gl.DEPTH_TEST);
// enable stencil buffer check instead
gl.enable(gl.STENCIL_TEST)
gl.stencilMask(0x00);
// render line only where stencil buffer was incremented exactly twice
gl.stencilFunc(gl.EQUAL, 2, 0xFF);
}
line.onAfterRender = function() {
// restore flags to initial order
gl.disable(gl.STENCIL_TEST);
gl.enable(gl.DEPTH_TEST);
}
// don't let user click the button twice
document.getElementById("btn").setAttribute("disabled", true);
}
我正在尝试在 three.js
的脸上画线一切正常,除了线条几乎看不见 - 无论我把它们做得多厚:它们看起来像这样:
画线的代码是:
var lgeometry = new THREE.Geometry();
var lmaterial = new THREE.LineBasicMaterial( { color: 0xffffff, linewidth: 4 } );
var v1 = p1;
var v2 = p2;
lgeometry.vertices.push(v1);
lgeometry.vertices.push(v2);
console.log(lgeometry);
var line = new THREE.Line( lgeometry, lmaterial );
scene.add( line );
我怀疑 - 由于表面上的线条 完全 ,因此它们不会被渲染(这就是所谓的 z-fighting 吗?)
有办法解决吗?
我正在考虑:
- 绘制圆柱体或其他形状而不是线条
- 沿着法线几乎绘制线
有什么搬进来的建议或方向吗?
这可以通过层和模板缓冲区的组合来实现。
工作演示: https://jsfiddle.net/mmalex/dg417kvn/
解法:
解释请看下面代码中的注释:
document.fixZFighting = function() {
// 1. Get the current WebGL context
const gl = renderer.getContext();
// 2. Set rendering order: mesh before line,
// because we want mesh to initialize stencil buffers before line rendering.
cube.renderOrder = 1;
line.renderOrder = 2;
// 3. Provide render callbacks
cube.onBeforeRender = function() {
// enable stencil buffer test
gl.enable(gl.STENCIL_TEST);
// do it just for all mesh pixels
gl.stencilFunc(gl.ALWAYS, 1, 0xFF);
// ... with no masking
gl.stencilMask(0xFF);
// ... simply increment stencil buffer value for each draw call,
// (important, here we have
gl.stencilOp(gl.KEEP, gl.KEEP, gl.INCR);
}
cube.onAfterRender = function() {
// nothing to do
}
line.onBeforeRender = function() {
// don't rely on z-Buffer for line, disable depth check
gl.disable(gl.DEPTH_TEST);
// enable stencil buffer check instead
gl.enable(gl.STENCIL_TEST)
gl.stencilMask(0x00);
// render line only where stencil buffer was incremented exactly twice
gl.stencilFunc(gl.EQUAL, 2, 0xFF);
}
line.onAfterRender = function() {
// restore flags to initial order
gl.disable(gl.STENCIL_TEST);
gl.enable(gl.DEPTH_TEST);
}
// don't let user click the button twice
document.getElementById("btn").setAttribute("disabled", true);
}