如何使用着色器增加 three.js 边缘几何体中的线条粗细?

How to increase line thickness in three.js edges geometry using shaders?

我正在尝试复制 this Three.js example but instead of showing the wireframe and an opaque box, I'd like to show just the edges without any faces (like what is shown when using the THREE.EdgesGeometry 中显示的效果。)我知道设置 linewidth 属性 不起作用,使用着色器是必要的,但我'我不太确定从哪里开始。作为参考,这些是上述 Three.js 示例中使用的着色器:

顶点着色器:

attribute vec3 center;
varying vec3 vCenter;

void main() {
    vCenter = center;
    gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );

}

片段着色器:

varying vec3 vCenter;

float edgeFactorTri() {
    vec3 d = fwidth( vCenter.xyz );
    vec3 a3 = smoothstep( vec3( 0.0 ), d * 1.5, vCenter.xyz );
    return min( min( a3.x, a3.y ), a3.z );
}

void main() {

    gl_FragColor.rgb = mix( vec3( 1.0 ), vec3( 0.2 ), edgeFactorTri() );
    gl_FragColor.a = 1.0;
}

我已经弄清楚改变 d 乘以(示例中的 1.5)是决定线条粗细的因素,但我完全不知道 vCenter 变量实际上被使用了(它是一个 vec3[1, 0, 0][0, 1, 0][0, 0, 1])或者我可以用来制作 THREE.EdgesGeometry像示例中那样用较粗的线条渲染。

以下是我尝试使用这些着色器渲染边缘几何体时发生的情况:

<script type="x-shader/x-vertex" id="vertexShader">
            attribute vec3 center;
            varying vec3 vCenter;

            void main() {
                vCenter = center;
                gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );

            }
</script>

<script type="x-shader/x-fragment" id="fragmentShader">
            varying vec3 vCenter;
            uniform float lineWidth;

            float edgeFactorTri() {
                float newWidth = lineWidth + 0.5;
                vec3 d = fwidth( vCenter.xyz );
                vec3 a3 = smoothstep( vec3( 0.0 ), d * newWidth, vCenter.xyz );
                return min( min( a3.x, a3.y ), a3.z );
            }

            void main() {

                gl_FragColor.rgb = mix( vec3( 1.0 ), vec3( 0.2 ), edgeFactorTri() );
                gl_FragColor.a = 1.0;
            }
</script>

Javascript:

size = 150
geometry = new THREE.BoxGeometry(size, size, size);
material = new THREE.MeshBasicMaterial({ wireframe: true });

mesh = new THREE.Mesh(geometry, material);
mesh.position.x = -150;
scene.add(mesh);

//

// geometry = new THREE.BufferGeometry().fromGeometry(new THREE.BoxGeometry(size, size, size));
geometry = new THREE.EdgesGeometry(new THREE.BoxGeometry(size, size, size));
setupAttributes(geometry);

material = new THREE.ShaderMaterial({
    uniforms: { lineWidth: { value: 10 } },
    vertexShader: document.getElementById("vertexShader").textContent,
    fragmentShader: document.getElementById("fragmentShader").textContent
});

material.extensions.derivatives = true;
mesh = new THREE.Mesh(geometry, material);
mesh.position.x = 150;
scene.add(mesh);

//

geometry = new THREE.BufferGeometry().fromGeometry(new THREE.SphereGeometry(size / 2, 32, 16));

setupAttributes(geometry);

material = new THREE.ShaderMaterial({
    uniforms: { lineWidth: { value: 1 } },
    vertexShader: document.getElementById("vertexShader").textContent,
    fragmentShader: document.getElementById("fragmentShader").textContent
});

material.extensions.derivatives = true;

mesh = new THREE.Mesh(geometry, material);
mesh.position.x = -150;
scene.add(mesh);

jsFiddle

正如您在 fiddle 中看到的那样,这不是我要找的东西,但我对着色器的工作方式没有足够的了解,不知道哪里出了问题或者这种方法是否适用于我想要的。

我调查了 this answer but I'm not sure how to use it as a ShaderMaterial and I can't use it as a shader pass (here 他用于回答的着色器。)

我也查了THREE.MeshLine and this issue好像没有解决。

任何指导将不胜感激!

您想修改 this three.js 示例,以便将网格渲染为粗线框。

解决方案是修改着色器并丢弃每个面中心部分的片段 -- 即,丢弃不靠近边缘的片段。

你可以这样做:

void main() {

    float factor = edgeFactorTri();
    if ( factor > 0.8 ) discard; // cutoff value is somewhat arbitrary
    gl_FragColor.rgb = mix( vec3( 1.0 ), vec3( 0.2 ), factor );
    gl_FragColor.a = 1.0;
}

如果需要,您也可以设置material.side = THREE.DoubleSide

已更新 fiddle:https://jsfiddle.net/vy0we5wb/4

three.js r.89