如何在THREE.js着色器中防止顶点颜色插值?

3
我正在尝试编写一个着色器,用于在网格上绘制等高线图。
这是等高线图的一个示例。
我的第一个目标是使用不同的颜色可视化一个三角形面。你可以在这里找到我正在使用的代码。
<html lang="en">
    <head>
        <title>Face Contour Example</title>

    </head>
    <body>

<script src="http://threejs.org/build/three.min.js"></script>
<script src="http://threejs.org/examples/js/controls/OrbitControls.js"></script>



        <script id="vertexShader" type="x-shader/x-vertex">


        varying vec3 vColor;

        void main(){
            vColor = color;
            gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
        }
        </script>

        <script id="fragmentShader" type="x-shader/x-fragment">
            varying vec3 vColor;

            void main(){
                gl_FragColor = vec4( vColor.rgb, 1.0 );
            }
        </script>


        <script type="text/javascript">
            var camera, scene, renderer, mesh, material, controls;
            init();
            animate();

            function init() {
                // Renderer.
                renderer = new THREE.WebGLRenderer();
                //renderer.setPixelRatio(window.devicePixelRatio);
                renderer.setSize(window.innerWidth, window.innerHeight);
                // Add renderer to page
                document.body.appendChild(renderer.domElement);

                // Create camera.
                camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 1, 1000);
                camera.position.z = -400;

                // Create scene.
                scene = new THREE.Scene();

                var colors = {
                  "color1" : {
                    type : "c",
                    value : new THREE.Color(0xff0000) //r
                  },
                  "color2" : {
                    type : "c",
                    value : new THREE.Color(0x00ff00) //b
                  },
                  "color3" : {
                    type : "c",
                    value : new THREE.Color(0x0000ff) //g
                  },
                };

                var fShader = document.getElementById('fragmentShader').text;
                var vShader = document.getElementById('vertexShader').text;

                // Create material
                var material = new THREE.ShaderMaterial({
                  vertexShader: vShader,
                  fragmentShader: fShader,
                  vertexColors: THREE.VertexColors,

                });

                // var material  = new THREE.MeshBasicMaterial( { vertexColors: THREE.VertexColors } );

                // Create cube and add to scene.
                var geometry = new THREE.Geometry();
                geometry.vertices=[
                    new THREE.Vector3(100,0,0),
                    new THREE.Vector3(-100,0,0),
                    new THREE.Vector3(50,100,0)
                ]

                var face=new THREE.Face3();
                face.a=0;
                face.b=1;
                face.c=2;
                face.vertexColors[ 0 ] = colors["color1"].value;
                face.vertexColors[ 1 ] = colors["color2"].value;
                face.vertexColors[ 2 ] = colors["color3"].value;
                geometry.faces=[face]



                mesh = new THREE.Mesh(geometry, material);
                scene.add(mesh);


                function addWireFrame(){
                    //Create wireframe helper for mesh with same geometry
                    var wireframeMesh=new THREE.WireframeGeometry(geometry);
                    var line = new THREE.LineSegments( wireframeMesh );
                    line.material.depthTest = false;
                    line.material.opacity = 0.75;
                    line.material.transparent = true;                            
                    mesh.add( line );
                }
                addWireFrame();

                //Orbit controls
                controls = new THREE.OrbitControls( camera );


                // Create ambient light and add to scene.
                var light = new THREE.AmbientLight(0x404040); // soft white light
                scene.add(light);

                // Create directional light and add to scene.
                var directionalLight = new THREE.DirectionalLight(0xffffff);
                directionalLight.position.set(1, 1, 1).normalize();
                scene.add(directionalLight);

                // Add listener for window resize.
                window.addEventListener('resize', onWindowResize, false);

            }

            function animate() {
                requestAnimationFrame(animate);

                controls.update();
                renderer.render(scene, camera);
            }

            function onWindowResize() {
                camera.aspect = window.innerWidth / window.innerHeight;
                camera.updateProjectionMatrix();
                renderer.setSize(window.innerWidth, window.innerHeight);
            }
        </script>

    </body>
</html>

在代码中,我为每个面的顶点分配了红色、绿色和蓝色。在顶点着色器中,我将这些颜色重定向到片段着色器。在片段着色器中,我计划使用自己的公式来决定该片段实例将使用哪种颜色。(我的公式将取决于面上的位置。)但是,我无法防止顶点颜色的插值。在three.js中,是否有一种直接从数组中选择顶点颜色而不进行插值的方法?此外,我感谢适用于我的问题的替代解决方案。

你能提供一张期望结果的图片吗? - prisoner849
1个回答

8
您不应该禁用插值,而是要将插值坐标用作索引。插值的颜色值告诉您离每个顶点有多近。然后,您可以将这个插值值量化为范围或颜色数组的索引,以产生最终的颜色。
我修改了您的fiddle,使用以下像素着色器显示最近顶点的颜色。
void main(){
    vec3 c = vColor;
    gl_FragColor = vec4(c.r > c.g && c.r > c.b ? 1.0 : 0.0,
      c.g > c.r && c.g > c.b ? 1.0 : 0.0,
      c.b > c.r && c.b > c.g ? 1.0 : 0.0,
      1.0 );
}

结果如下图所示:

triangle

如果您想显示轮廓地图,您需要使用更复杂的量化方法,但我希望这种方法能给您一个良好的起点。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接