【问题标题】:Get 3D Position of shadow pixels in ThreeJS在 ThreeJS 中获取阴影像素的 3D 位置
【发布时间】:2022-02-01 10:31:46
【问题描述】:

我在下面使用 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 坐标,我就可以做到这一点:)。例如,我已经在为眼睛的肌肉做这件事了。

【问题讨论】:

  • 你需要知道阴影覆盖的每个点,还是边缘就足够了?你可以做一些机械的事情来找到阴影的边缘:从光源通过每个顶点的光线投射到阴影投射形状的边缘,并与球体相交。但是,同样,如果您需要阴影区域内的点,这将无济于事。
  • 我对此很感兴趣,你能给我举个例子说明如何做到这一点吗?

标签: javascript three.js shadow


【解决方案1】:

您无法将阴影提取到新几何体中,因为这一切都是在渲染时在 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,该THREE.BufferGeometry 被推向球体。

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

【讨论】:

  • 如果我只关心阴影的周长点,我该怎么做?对于我如何使用它,因为有数千个顶点,出于速度原因,我试图只使用周边形状,这是阴影最初的目的。
  • @JosephAstrahan 我不认为你可以选择周边点。但是如果你要对球面阴影应用一个新的投影,你不想要那个深度数据吗?如果没有所有中间点,您可能会得到一个平面,并且您的附加投影不会有那个球形轮廓。
  • @JosephAstrahan 这种方法比投射顶点的光线投射要快得多。关于边,如果您已经知道哪些顶点构成了形状边,那会容易得多。否则,根据它们与投影中心沿球体弧的距离以及它们在投影形状范围内的包含情况来计算它们会在计算上很昂贵(尽管并非不可能)。
猜你喜欢
  • 1970-01-01
  • 2021-09-09
  • 2014-08-05
  • 1970-01-01
  • 1970-01-01
  • 2013-07-06
  • 1970-01-01
  • 1970-01-01
  • 2021-04-08
相关资源
最近更新 更多