如何使用着色器增加three.js边几何中的线宽?

时间:2018-02-13 18:20:40

标签: three.js webgl

我试图复制this Three.js示例中显示的效果,但我不想显示线框和不透明的框,而是只显示没有任何面的边(就像使用THREE.EdgesGeometry时显示的内容一样。)我知道设置linewidth属性并不起作用,并且使用着色器是必要的,但我不确定从哪里开始。作为参考,这些是在上面的Three.js示例中使用的着色器:

顶点着色器:

attribute vec3 center;
varying vec3 vCenter;

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

}

Fragment Shader:

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]的{​​{1}}或我可以使用的变量THREE.EdgesGeometry使用较粗的线条渲染,如示例所示。

当我尝试使用这些着色器渲染边几何时会发生什么:

[0, 0, 1]

使用Javascript:

<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>

jsFiddle

正如你可以在小提琴中看到的那样,这不是我想要的,但我不能很好地掌握着色器如何工作以了解我哪里出错了或者这种方法是否符合我的要求。

我已查看this answer,但我不确定如何将其用作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); ,我无法将其用作着色器传递({{ 3}}是他用来回答的着色器。)

我也调查了hereTHREE.MeshLine似乎没有得到解决。

非常感谢任何指导!

1 个答案:

答案 0 :(得分:2)

您想要修改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

更新了小提琴:https://jsfiddle.net/vy0we5wb/4

three.js r.89