11

假设您的眼睛位于对象 A 上的表面点 P1 上,并且有一个目标对象 B,并且对象 B 后面有一个点光源。

问题:如果我看着光源并说“我在阴影中”,如果我因为物体 B 而看不到光,我是对的吗?然后我将对象 A 的那个点标记为“A 上 B 的阴影点之一”。

在此处输入图像描述

如果这是真的,那么我们是否可以在 A 的表面上构建一个“阴影几何”(黑色)对象,然后由于光、B、A 等的实时运动而不断改变它?假设一个球体(A)有 1000 个顶点,而其他球体(B)也有 1000 个顶点,那么这是否意味着 100 万个比较?(是阴影,O(N ^ 2)(时间)复杂度?)。我不确定复杂性,因为改变 P1(眼睛)也会改变 B 的可见点(在 P1 和光源点之间)。二阶或更高级别的阴影(例如灯光在两个物体之间多次反射)呢?

我现在正在使用 java-3D,但它没有影子功能,所以我想转移到其他与 java 兼容的库。

谢谢。

编辑:移动相机以构建阴影时,我需要禁用“相机”。我怎样才能做到这一点?这会严重降低性能吗?

新想法: java3D 有内置的碰撞检测。我将创建从光到目标多边形顶点的线(不可见),然后检查来自另一个对象的碰撞。如果发生碰撞,请添加该顶点corrd。到阴影列表,但这仅适用于点灯:(。

任何为 java3d 提供真正的阴影库的人都会很有帮助。

java3D 中非常小的样本 Geomlib 阴影/光线跟踪可能是最好的 光线跟踪示例?

我知道这有点难,但至少有一百人尝试过。

谢谢。

4

4 回答 4

3

阴影可能是 3D 图形编程中最复杂的主题,并且有很多方法,但应根据任务要求确定最佳选项。您正在谈论的算法是实现从点光源到平面的阴影的最简单方法。它不应该在 CPU 上完成,因为您已经使用 GPU 进行 3D 渲染。

基本上,该方法是两次渲染同一个对象:一次从相机视点,一次从光源点。您需要准备模型视图矩阵以在这两个视图之间进行转换。从光点渲染对象后,您将获得深度图,其中每个点最靠近光源。然后,对于正常渲染的每个像素,您应该将其 3D 坐标转换为前一个视图,并检查相应的深度值。这实质上为您提供了一种方法来判断哪些像素被阴影覆盖。

性能影响来自两次渲染同一个对象。如果您的任务不假设阴影投射解决方案的高可扩展性,那么它可能是一种可行的方法。

一些相关的问题:

如何在 OpenGL 中创建廉价的阴影?

有没有一种简单的方法可以在 OpenGL 中获得阴影?

在 OpenGL 的场景中渲染阴影的最简单方法是什么?

于 2012-10-05T20:04:57.813 回答
2

您的方法可以总结如下:

foreach (point p to be shaded) {
    foreach (light) {
        if (light is visible from p)
            // p is lit by that light
        else
            // p is in shadow
    }
}

有趣的事实是,这就是今天在 GPU 上实时阴影的处理方式

但是,要有效地工作并非易事。渲染场景是一个逐个三角形的简化过程。如果对于每个三角形中的每个点(像素、片段)都需要考虑其他所有其他三角形来检查光线相交,那将非常麻烦。

那么如何有效地做到这一点呢?答:颠倒过程。

通常,场景中的灯光比像素少得多。让我们利用这一事实并进行一些预处理:

// preprocess
foreach (light) {
    // find all pixels p on the scene reachable from the light
}
// then render the whole scene...
foreach (point p to be shaded) {
    foreach (light) {
        // simply look up into what was calculated before...
        if (p is visible by the light)
            // p is lit
        else
            // p is in shadow
    }
 }

这似乎快了很多......但仍然存在两个问题:

  1. 如何找到光线可见的所有像素?
  2. 如何使它们在渲染过程中快速访问以进行查找?

有一个棘手的部分:

  • 为了找到灯光可见的所有点,将相机放置在那里并渲染整个场景!深度测试将拒绝不可见的点。
  • 为了让这个结果以后可以访问,请将其保存为纹理并在实际渲染阶段使用该纹理进行查找。

这种技术称为阴影贴图,具有从灯光可见的像素的纹理称为阴影贴图。有关更详细的解释,请参见例如Wikipedia 文章

于 2012-10-10T14:11:00.877 回答
1

基本上是的,你的方法会产生阴影。但是逐点执行(对于实时)在性能方面是不可行的,除非它是在 GPU 上完成的。我不熟悉 API 今天提供的内容,但我确信任何最近的引擎都会提供一些开箱即用的影子。

您的“新想法”是在仍然使用 CPU 完成渲染的日子里,阴影是如何实现的如果多边形的数量不是太大(或者你可以通过对体积进行分组等来有效地拒绝整个束),它可以用相当少的 CPU 能力来完成。

于 2012-10-09T15:26:24.543 回答
1

vanilla Java 上的 3D 阴影渲染永远不会高效。您最好使用为利用图形卡的全部功能而编写的图形库,例如 OpenGL 或 DirectX。当您使用 Canvas(来自您提供的屏幕截图)时,您甚至可以使用 JNI 从本机代码绘制该 Canvas。因此,您可以使用图形库中的所有技术,只需稍作改动,直接从本机代码绘制您的 Canvas。与编写您自己的 3D 引擎相比,使其工作所需的工作量很少。

关于 AWT 本地访问的 Wiki 链接:http ://en.wikipedia.org/wiki/Java_AWT_Native_Interface 文档:http ://docs.oracle.com/javase/7/docs/technotes/guides/awt/AWT_Native_Interface.html

于 2012-10-10T13:53:50.850 回答