【发布时间】:2021-09-18 18:33:52
【问题描述】:
我正在尝试使用以下方法在一些 3D 网格上创建轮廓效果:
- 绘制原始的初始着色网格
- 平滑网格法线
- 按照法线向外推vertives
- 仅使用纯色轮廓颜色绘制背面
除了平滑部分之外,我得到了所有的工作。需要平滑网格以创建良好的连续外部轮廓(否则角度会出现不规则)。 I've allready asked how to smooth a mesh normals。平滑过程是这样的:
let geometry = new THREE.BoxGeometry();
geometry.deleteAttribute('normal');
geometry.deleteAttribute('uv');
geometry = THREE.BufferGeometryUtils.mergeVertices(geometry);
geometry.computeVertexNormals();
虽然这对于定义明确的简单几何图形效果很好,但它会在更复杂的模型上产生伪影。我相信这是由于丢弃了原始法线。 computeVertexNormals() 然后从里到外解释一些面孔。
知道如何解决这个问题吗?
平滑法线之前
平滑法线后
旁注: 1/ 我无法修改原始网格拓扑,因为它们是在运行时使用 jscad 生成的。
2/ 我试图编写一个算法来解决这个问题,但没有取得很大成功。我的推理如下:
假设computeVertexNormals() 根据组成它的顶点的顺序将三角形解释为面朝上或面朝下。我要找到法线反转的顶点的三角形,并交换两个三角形顶点来翻转它。如果在computeVertexNormals() 和computeVertexNormals() 之前的法线的点积为负,则顶点法线被反转。
下面是代码:
const fixNormals: (bufferGeometry: THREE.BufferGeometry) => THREE.BufferGeometry
= (bufferGeometry) => {
// this function is only made for non indexed buffer geometry
if (bufferGeometry.index)
return bufferGeometry;
const positionAttribute = bufferGeometry.getAttribute('position');
if (positionAttribute == undefined)
return bufferGeometry;
let oldNormalAttribute = bufferGeometry.getAttribute('normal').clone();
if (oldNormalAttribute === undefined)
return bufferGeometry;
bufferGeometry.deleteAttribute('normal');
bufferGeometry.deleteAttribute('uv');
bufferGeometry.computeVertexNormals();
let normalAttribute = bufferGeometry.getAttribute('normal');
if (normalAttribute === undefined) {
console.error("bufferGeometry.computeVertexNormals() resulted in empty normals")
return bufferGeometry;
}
const pA = new THREE.Vector3(),
pB = new THREE.Vector3(),
pC = new THREE.Vector3();
const onA = new THREE.Vector3(),
onB = new THREE.Vector3(),
onC = new THREE.Vector3();
const nA = new THREE.Vector3(),
nB = new THREE.Vector3(),
nC = new THREE.Vector3();
for (let i = 0, il = positionAttribute.count; i < il; i += 3) {
pA.fromBufferAttribute(positionAttribute, i + 0);
pB.fromBufferAttribute(positionAttribute, i + 1);
pC.fromBufferAttribute(positionAttribute, i + 2);
onA.fromBufferAttribute(oldNormalAttribute, i + 0);
onB.fromBufferAttribute(oldNormalAttribute, i + 1);
onC.fromBufferAttribute(oldNormalAttribute, i + 2);
nA.fromBufferAttribute(normalAttribute, i + 0);
nB.fromBufferAttribute(normalAttribute, i + 1);
nC.fromBufferAttribute(normalAttribute, i + 2);
// new normals for this triangle are inverted,
// need to switch 2 vertices order to keep right face up
if (onA.dot(nA) < 0 && onB.dot(nB) < 0 && onC.dot(nC) < 0) {
positionAttribute.setXYZ(i + 0, pB.x, pB.y, pB.z)
positionAttribute.setXYZ(i + 1, pA.x, pA.y, pA.z)
}
}
bufferGeometry.deleteAttribute('normal');
bufferGeometry.deleteAttribute('uv');
bufferGeometry.computeVertexNormals();
return bufferGeometry;
}
【问题讨论】:
标签: javascript three.js mesh normals topology