Как исправить z-бой линии на поверхности сетки в three.js? - PullRequest
1 голос
/ 20 марта 2019

Я пытаюсь нарисовать линии на лице в three.js

Все работает нормально, кроме линий, которые едва заметны - независимо от того, насколько толстыми я их делаю: они выглядят так:

barely visible lines

Код, который рисует линию:

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 -ighting ?)

Есть ли способ решить это?

Я рассматриваю:

  • рисование цилиндров или других фигур вместо линий
  • рисуя линию чуть над поверхностью по нормали

Любой совет или направление двигаться?

1 Ответ

1 голос
/ 20 марта 2019

Это достижимо с помощью комбинации слоев и трафаретных буферов.

Рабочая демонстрация: https://jsfiddle.net/mmalex/dg417kvn/

how to fix z-fighting issues with stencil buffers


Решение:

Для объяснения, пожалуйста, следуйте комментариям в коде ниже:

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);
}
...