Three.js raycaster 相交对象 returns 奇怪的面法线

Three.js raycaster intersection object returns strange face normals

我有一个模型 与我的 raycaster 相交。 raycaster returns 正确的点,但面部法线向量不是我正在等待的。 Three.js 内置了 VertexNormalsHelper,当我使用它时它会显示正确的法线,但是当我创建两个立方体时,一个将位于交点位置,另一个将位于法向量处,就像这个:

红色立方体是raycaster交点,蓝色立方体是面法线

我的代码很简单,只是一个简单的光线投射器,我将点的位置复制到立方体。当我加载我的模型时,我会更新几何上的所有内容。我使用 Orbitcontrols 进行相机移动。

var intersects = this.checkIntersection(this.surfaceModel);

for (var i = 0; i < intersects.length; i++) {

    var p = intersects[ 0 ].point;

    var normal = intersects[ 0 ].face.normal.clone();

    //Red & Blue cube position update
    this.pointHelper_A.position.copy(p);
    this.pointHelper_B.position.copy(normal);

这是打开 VertexNormalsHelper 时的图像,因此您可以看到此处的法线正常:

我已经阅读了 VertexNormalsHelper 的源代码,并从中创建了一个函数,它可以为您提供面的法向量。所以它可以告诉你这一点,但我认为这不是主要问题的真正解决方案,而且它有很多操作。

代码如下:

(对象: THREE.Mesh, 脸:THREE.Face3)

this.getFaceNormalPosition = function (object, face) {

    var v1 = new THREE.Vector3();

    var keys = ['a', 'b', 'c', 'd'];

    object.updateMatrixWorld(true);

    var size = (size !== undefined) ? size : 1;

    var normalMatrix = new THREE.Matrix3();

    normalMatrix.getNormalMatrix(object.matrixWorld);

    var vertices = new THREE.Vector3();

    var verts = object.geometry.vertices;

    var faces = object.geometry.faces;

    var worldMatrix = object.matrixWorld;


    for (var j = 0, jl = face.vertexNormals.length; j < jl; j++) {

        var vertexId = face[ keys[ j ] ];
        var vertex = verts[ vertexId ];

        var normal = face.vertexNormals[ j ];

        vertices.copy(vertex).applyMatrix4(worldMatrix);

        v1.copy(normal).applyMatrix3(normalMatrix).normalize().multiplyScalar(size);

        v1.add(vertices);
    }

    return v1;
};

我学过一些向量数学,所以法向量在正确的位置。当你需要在垂直于相交面的光线交点处的一个点时,你需要将 faceNormalVector 乘以一个标量,这将是面和新点之间的距离,然后将这个新向量添加到交点。

我有同样的问题,就是不理解我得到的正常面孔。我的解决方案是将法线与对象的法线矩阵相乘(不知道那是一回事)。这是一个用 typescript 编写的简单助手 class,将其移植到 javascript 应该不会太难:

import { Vector3, Object3D, Matrix3, Face3 } from 'three';

export class Face3Utils {
    private static _matrix3: Matrix3;

    private static get matrix3(): Matrix3 {
        if(this._matrix3 === undefined) {
            this._matrix3 = new Matrix3();
        }
        return this._matrix3;
    }

    public static getWorldNormal(face: Face3, object: Object3D, normalVector?: Vector3): Vector3 {
        if(normalVector === null || normalVector === undefined) {
            normalVector = new Vector3();
        }

        object.updateMatrixWorld( true );
        Face3Utils.matrix3.getNormalMatrix( object.matrixWorld );

        normalVector.copy(face.normal).applyMatrix3( Face3Utils.matrix3 ).normalize();
        return normalVector;
    }
}