在 ThreeJS 中获取阴影像素的 3D 位置

Get 3D Position of shadow pixels in ThreeJS

我在下面使用 ThreeJS 创建了以下项目。你会注意到金色物体在球体后面创建了一个阴影,我只渲染背面以便我们可以看到里面的物体。我在眼睛模型的正中央使用点光源在各个方向均匀地创建阴影。这就是影子弯曲的原因。

我需要知道如何获取创建的此阴影的每个像素的 3D 坐标 (x,y,z)。此处供参考的是创建阴影的代码,为了简单起见,删除了很多内容。

renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.BasicShadowMap//THREE.PCFSoftShadowMap;

const light = new THREE.PointLight( 0xffffff, 20, 0 );
light.position.set( 0, 0, 0 );
light.castShadow = true;
light.shadow.mapSize.width = 512;
light.shadow.camera.near = 0.5;
light.shadow.camera.far = 500;
scene.add( light );

const sphereGeometry = new THREE.SphereGeometry( 25, 32, 32 );
const sphereMaterial = new THREE.MeshStandardMaterial( { color: 0xffffff } );
sphereMaterial.side=THREE.BackSide;

const sphere = new THREE.Mesh( sphereGeometry, sphereMaterial );
sphere.castShadow = false;
sphere.receiveShadow = true;
scene.add( sphere );

我对此进行了一些研究,我认为它可能将阴影信息存储在模型的矩阵 属性 中,但这在任何文档中都不确定,所以我不确定在哪里查看以获取此信息。感谢您的帮助!

--- 额外的不重要信息 ---

此外,如果您好奇的话,我需要阴影坐标的原因是因为我将使用它们将光线投射回眼睛并在右侧的方位角等距项目上创建不同类型的阴影(这很复杂...),但只要知道如果我有阴影像素的 3D 坐标,我就可以这样做:)。例如,我已经在为眼部肌肉做这件事了。

您无法将阴影提取到新的几何体中,因为这都是在渲染时在 GPU 着色器中计算的,因此 JavaScript 实际上无法访问 shadowMap 位置。不过,还是有解决办法的。

假设您的点光源位于 (0, 0, 0),并且它位于球体的中心,您可以遍历黄金对象的顶点并将这些位置投影到球体上:

// Sphere radius
const radius = 25;

const vec3 = new THREE.Vector3();

// Get the vertex position array
const vertices = goldObject.geometry.getAttribute("position").array;

// Loop that iterates through all vertex positions
for (let i3 = 0; i3 < vertices.length; i3 += 3) {
    // Set this vertex into our vec3
    vec3.set(
        vertices[i3 + 0], // x
        vertices[i3 + 1], // y
        vertices[i3 + 2]  // z
    );

    // Set vector magnitude to 1
    vec3.normalize();

    // Set vector magnitude to radius of sphere
    vec3.multiplyScalar(sphereRadius);

    // Now you have the spherical projection of this vertex!
    console.log(vec3);
}

由于光源恰好是球体的中心,您可以获取金色物体每个顶点的位置,对其进行归一化,然后将其乘以球体的半径。现在你在每次迭代中都有 vec3,你可以将它添加到你自己的数组中以构建你自己的 THREE.BufferGeometry,它被推向球体。

当然,如果您平移或旋转了黄金对象,那么这将影响顶点位置,因此您必须在遍历所有顶点时撤消这些平移、旋转等操作。