如何在THREE.js着色器中防止顶点颜色插值?用于网格等高线绘制
如何在Three.js着色器中防止顶点颜色插值,实现三角面纯色显示
嘿,我完全懂你想要的效果——让每个三角面呈现单一纯色,而不是顶点颜色插值出来的平滑过渡对吧?下面给你几个实用的方案,结合Three.js的特性来实现:
方案1:用内置FlatShading快速实现(最简单)
如果你用的是Three.js自带的材质(比如MeshBasicMaterial、MeshLambertMaterial),直接开启flatShading就能禁用顶点颜色插值,让每个面显示统一颜色:
const material = new THREE.MeshLambertMaterial({ vertexColors: THREE.VertexColors, flatShading: true // 关键:开启后面级纯色生效 });
注意:这种方式需要给每个面的三个顶点设置完全相同的颜色,开启flatShading后整个面就会锁定这个颜色。
方案2:自定义着色器实现面纯色(更灵活)
如果需要用自定义着色器,核心思路是给每个面的所有顶点传递同一个标识/颜色值,这样片元着色器拿到的值不会因为插值而变化:
步骤1:给BufferGeometry添加面颜色属性
先给几何体的每个顶点绑定所属面的颜色(同一个面的三个顶点用同一种颜色):
// 先创建基础几何体,比如立方体 const geometry = new THREE.BoxGeometry(1, 1, 1); const bufferGeometry = new THREE.BufferGeometry().fromGeometry(geometry); // 准备面颜色数据:每个面对应一个颜色,每个面的3个顶点重复该颜色 const faceColors = []; for (let i = 0; i < geometry.faces.length; i++) { // 随机生成面颜色,你也可以自定义固定色值 const color = new THREE.Color(); color.setHSL(Math.random(), 0.7, 0.5); // 给当前面的3个顶点都赋值这个颜色 faceColors.push(color.r, color.g, color.b); faceColors.push(color.r, color.g, color.b); faceColors.push(color.r, color.g, color.b); } // 将颜色数据作为自定义属性添加到几何体 bufferGeometry.setAttribute('faceColor', new THREE.Float32BufferAttribute(faceColors, 3));
步骤2:编写自定义着色器
顶点着色器直接传递面颜色,片元着色器直接使用该值(因为同一面的顶点颜色完全一致,插值后不会改变):
// 顶点着色器 varying vec3 vFaceColor; void main() { vFaceColor = faceColor; // 直接传递面颜色属性 gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); }
// 片元着色器 varying vec3 vFaceColor; void main() { gl_FragColor = vec4(vFaceColor, 1.0); // 直接使用面颜色,无插值 }
步骤3:创建ShaderMaterial并使用
const shaderMaterial = new THREE.ShaderMaterial({ vertexShader: `// 粘贴上面的顶点着色器代码`, fragmentShader: `// 粘贴上面的片元着色器代码`, vertexColors: true }); const mesh = new THREE.Mesh(bufferGeometry, shaderMaterial); scene.add(mesh);
方案3:针对旧版Geometry的Face3颜色设置
如果你还在使用Three.js的Geometry(非BufferGeometry),可以直接给每个Face3设置颜色:
const geometry = new THREE.BoxGeometry(1, 1, 1); for (let i = 0; i < geometry.faces.length; i++) { geometry.faces[i].color.setHSL(Math.random(), 0.7, 0.5); } const material = new THREE.MeshBasicMaterial({ vertexColors: THREE.FaceColors, flatShading: true });
这样每个面就会显示你设置的纯色,不会有顶点插值效果。
内容的提问来源于stack exchange,提问作者Three Percent Games
相关产品推荐
相关产品推荐

