Three.js中BufferGeometry自定义法线实现平滑着色异常求助
立方球体LOD法线计算问题
我用LOD制作立方球体时,生成法线遇到了问题。将计算好的this.Normals赋值给BufferGeometry,使用MeshPhongMaterial创建网格后,相邻面之间的法线计算不正确,效果表现为相邻面出现明显明暗断层,过渡不自然。
我的法线生成代码如下:
// VectorVertices is an array of Vector3 let VectorNormals = new Array(this.VectorVertices.length); for (let i = 0; i < VectorNormals.length; i++) { VectorNormals[i] = new THREE.Vector3(); } for (let i = 0; i < this.Triangles.length; i += 3) { let vertexIndexA = this.Triangles[i]; let vertexIndexB = this.Triangles[i + 1]; let vertexIndexC = this.Triangles[i + 2]; let pointA = this.VectorVertices[vertexIndexA]; let pointB = this.VectorVertices[vertexIndexB]; let pointC = this.VectorVertices[vertexIndexC]; pointB.sub(pointA); pointC.sub(pointA); let vertexNormal = new THREE.Vector3().crossVectors(pointB, pointC).normalize(); VectorNormals[vertexIndexA].add(vertexNormal); VectorNormals[vertexIndexB].add(vertexNormal); VectorNormals[vertexIndexC].add(vertexNormal); } for (let i = 0; i < VectorNormals.length; i++) { VectorNormals[i].normalize(); this.Normals.push(VectorNormals[i].x, VectorNormals[i].y, VectorNormals[i].z); }
问题原因
核心问题是直接修改了原始顶点数据:pointB.sub(pointA)和pointC.sub(pointA)会直接改变this.VectorVertices中存储的Vector3对象坐标值。后续处理其他三角形时,用到这些已经被修改的顶点,计算出的面法线必然出错,最终导致顶点法线累加结果异常,出现明暗断层。
修复方案
计算向量时不要修改原始顶点,而是创建顶点的副本进行运算:
// VectorVertices is an array of Vector3 let VectorNormals = new Array(this.VectorVertices.length); for (let i = 0; i < VectorNormals.length; i++) { VectorNormals[i] = new THREE.Vector3(); } for (let i = 0; i < this.Triangles.length; i += 3) { let vertexIndexA = this.Triangles[i]; let vertexIndexB = this.Triangles[i + 1]; let vertexIndexC = this.Triangles[i + 2]; let pointA = this.VectorVertices[vertexIndexA]; let pointB = this.VectorVertices[vertexIndexB]; let pointC = this.VectorVertices[vertexIndexC]; // 创建顶点副本,避免篡改原始数据 const vecAB = pointB.clone().sub(pointA); const vecAC = pointC.clone().sub(pointA); let vertexNormal = new THREE.Vector3().crossVectors(vecAB, vecAC).normalize(); VectorNormals[vertexIndexA].add(vertexNormal); VectorNormals[vertexIndexB].add(vertexNormal); VectorNormals[vertexIndexC].add(vertexNormal); } for (let i = 0; i < VectorNormals.length; i++) { VectorNormals[i].normalize(); this.Normals.push(VectorNormals[i].x, VectorNormals[i].y, VectorNormals[i].z); }
说明
通过clone()方法创建顶点副本后,所有向量运算都在副本上进行,原始顶点数据保持完整。每个三角形都能基于正确的原始坐标计算面法线,累加后的顶点法线能让相邻面的明暗过渡自然,解决断层问题。
内容的提问来源于stack exchange,提问作者Ann Anjell
相关产品推荐
相关产品推荐

