提高光线追踪命中功能的性能

2024-06-05

我有一个简单的 python 光线追踪器。渲染 200x200 的图像需要 4 分钟,这对于我的口味来说绝对是太多了。我想改善这种情况。

几点:我为每个像素发射多条光线(以提供抗锯齿功能),每个像素总共发射 16 条光线。 200x200x16 总共有 640000 条光线。必须测试每条光线对场景中多个球体对象的影响。 Ray也是一个相当微不足道的物体

class Ray(object):
    def __init__(self, origin, direction):
        self.origin = numpy.array(origin)
        self.direction = numpy.array(direction)

Sphere 稍微复杂一些,包含命中/不命中的逻辑:

class Sphere(object):
    def __init__(self, center, radius, color):
        self.center = numpy.array(center)
        self.radius = numpy.array(radius)
        self.color = color

    @profile 
    def hit(self, ray):
        temp = ray.origin - self.center
        a = numpy.dot(ray.direction, ray.direction)
        b = 2.0 * numpy.dot(temp, ray.direction)
        c = numpy.dot(temp, temp) - self.radius * self.radius
        disc = b * b - 4.0 * a * c

        if (disc < 0.0):
            return None
        else:
            e = math.sqrt(disc)
            denom = 2.0 * a
            t = (-b - e) / denom 
            if (t > 1.0e-7):
                normal = (temp + t * ray.direction) / self.radius
                hit_point = ray.origin + t * ray.direction
                return ShadeRecord.ShadeRecord(normal=normal, 
                                               hit_point=hit_point, 
                                               parameter=t, 
                                               color=self.color)           

            t = (-b + e) / denom

            if (t > 1.0e-7):
                normal = (temp + t * ray.direction) / self.radius                hit_point = ray.origin + t * ray.direction
                return ShadeRecord.ShadeRecord(normal=normal, 
                                               hit_point=hit_point, 
                                               parameter=t, 
                                               color=self.color)       

        return None    

现在,我运行了一些分析,看来最长的处理时间是在 hit() 函数中

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
  2560000  118.831    0.000  152.701    0.000 raytrace/objects/Sphere.py:12(hit)
  1960020   42.989    0.000   42.989    0.000 {numpy.core.multiarray.array}
        1   34.566   34.566  285.829  285.829 raytrace/World.py:25(render)
  7680000   33.796    0.000   33.796    0.000 {numpy.core._dotblas.dot}
  2560000   11.124    0.000  163.825    0.000 raytrace/World.py:63(f)
   640000   10.132    0.000  189.411    0.000 raytrace/World.py:62(hit_bare_bones_object)
   640023    6.556    0.000  170.388    0.000 {map}

这并不让我感到惊讶,我想尽可能地减少这个值。我传递给线路分析,结果是

Line #      Hits         Time  Per Hit   % Time  Line Contents
==============================================================
    12                                               @profile
    13                                               def hit(self, ray):
    14   2560000     27956358     10.9     19.2          temp = ray.origin - self.center
    15   2560000     17944912      7.0     12.3          a = numpy.dot(ray.direction, ray.direction)
    16   2560000     24132737      9.4     16.5          b = 2.0 * numpy.dot(temp, ray.direction)
    17   2560000     37113811     14.5     25.4          c = numpy.dot(temp, temp) - self.radius * self.radius
    18   2560000     20808930      8.1     14.3          disc = b * b - 4.0 * a * c
    19                                                   
    20   2560000     10963318      4.3      7.5          if (disc < 0.0):
    21   2539908      5403624      2.1      3.7              return None
    22                                                   else:
    23     20092        75076      3.7      0.1              e = math.sqrt(disc)
    24     20092       104950      5.2      0.1              denom = 2.0 * a
    25     20092       115956      5.8      0.1              t = (-b - e) / denom
    26     20092        83382      4.2      0.1              if (t > 1.0e-7):
    27     20092       525272     26.1      0.4                  normal = (temp + t * ray.direction) / self.radius
    28     20092       333879     16.6      0.2                  hit_point = ray.origin + t * ray.direction
    29     20092       299494     14.9      0.2                  return ShadeRecord.ShadeRecord(normal=normal, hit_point=hit_point, parameter=t, color=self.color)

所以,看来大部分时间都花在了这段代码上:

        temp = ray.origin - self.center
        a = numpy.dot(ray.direction, ray.direction)
        b = 2.0 * numpy.dot(temp, ray.direction)
        c = numpy.dot(temp, temp) - self.radius * self.radius
        disc = b * b - 4.0 * a * c

我真的没有看到太多需要优化的地方。您知道如何在不使用 C 的情况下提高此代码的性能吗?


查看您的代码,您的主要问题似乎是您的代码行被调用了 2560000 次。无论您在该代码中执行何种工作,这往往都会花费大量时间。然而,使用numpy https://www.numpy.org/,您可以将大量的工作聚合到少量的 numpy 调用中。

要做的第一件事是将光线组合成大型阵列。不要使用具有 1x3 向量作为原点和方向的 Ray 对象,而是使用具有命中检测所需的所有光线的 Nx3 数组。你的点击函数的顶部最终将如下所示:

temp = rays.origin - self.center
b = 2.0 * numpy.sum(temp * rays.direction,1)
c = numpy.sum(numpy.square(temp), 1) - self.radius * self.radius
disc = b * b - 4.0 * c

对于下一部分,您可以使用

possible_hits = numpy.where(disc >= 0.0)
a = a[possible_hits]
disc = disc[possible_hits]
...

继续仅使用通过判别测试的值。通过这种方式,您可以轻松获得数量级的性能提升。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

提高光线追踪命中功能的性能 的相关文章

  • 为什么带有子进程的 Python 线程无法按预期工作?

    我有以下微妙的问题 Python 代码启动两个线程 每个线程创建一个对可执行文件 实际上是用 C 编写的 的子进程调用 第一个可执行文件传递参数 10000 这意味着在退出之前延迟 10 秒 第二个可执行文件类似 但延迟了 20 秒 我观察
  • 如何将 python 中的 wav 转换为 flac?

    我刚刚开始使用 Python 并且正在使用PyAudio and Wave模块从我的麦克风获取声音并将其转换为 wav file 我现在想做的就是转换它 wav to a flac 我已经看到了几种方法来做到这一点 所有这些都涉及安装转换器
  • Python 中的 ZeroMQ 和多个订阅过滤器

    我想使用一个套接字使用 Python 中的 ZeroMQ 订阅多个过滤器 sock setsockopt zmq SUBSCRIBE first filter sock setsockopt zmq SUBSCRIBE second fil
  • pandas 中任意列表的笛卡尔积[重复]

    这个问题在这里已经有答案了 给定任意数量的列表 我想生成一个 pandasDataFrame作为笛卡尔积 例如 给定 a 1 2 3 b val1 val2 c 100 101 我想最终得到一个DataFrame有柱子a b and c 以
  • 在 Python 中使用 LaTeX 表示法格式化数字

    在Python中使用格式字符串我可以轻松地以 科学记数法 打印数字 例如 gt gt print g 1e9 1e 09 将数字格式化为 LaTeX 格式 即 1 times10 09 的最简单方法是什么 The siunitx http
  • 按受欢迎程度列出 PyPI 包 [关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 是否可以获得按受欢迎程度 总下载数 排序的 PyPI 软件包列表 我无法找到在 PyPI 上执行此操作
  • 如何计算CPU核心频率

    我正在尝试使用 RDTSC 但似乎我的方法获取核心速度可能是错误的 include stdafx h include
  • Python 和 SQLite:插入表

    具有以下表架构 tablename name varchar 100 age int sex char 1 有一个list有 3 行 每行代表一个表行 row1 laks 444 M row2 kam 445 M row3 kam 445
  • 仅使用 Python 生成示例 SOAP 请求和响应模板。没有 Zeep、SOAPUI 或任何其他工具

    我对 python 很陌生 对网络服务也很陌生 我最近开始了一个我非常热衷的项目 这是一个很好的学习机会 然而 经过几周的研究 我陷入了困境 需要一些帮助 我想做的是制作我自己的 WSDL 界面 其工作方式类似于 SOAPUI 我的程序将解
  • 如何使用 python 将 OpenCV 输出发送到浏览器?

    我有一个带有 open cv 的简单 python 脚本 它接收视频并使用 YOLO 对其进行对象检测 我的问题是 如何将输出作为实时流显示到我的网站 这是Python代码 保存到output avi import cv2 from dar
  • 部署到 Heroku 时找不到“site”模块

    我正在尝试将 django 应用程序部署到 Heroku 但我不断收到错误 ImportError no module named site 我正在使用来自的自定义构建包https github com jiaaro heroku buil
  • 无法在 Windows 中安装 mysql-python(较新版本)

    I have mysql pythonv1 2 4 在我的机器 Windows 8 上安装得很好 我正在使用Python 2 7 每次尝试升级到 v1 2 5 时 我总是遇到以下错误 从 v1 3 7 开始仍然发生 C Users User
  • 升级pip有什么用?

    虽然 pip 用于从 PyPI 安装和升级其他 Python 包 但您能帮我理解为什么需要升级 pip 本身吗 我正在开发一个新的 python 项目 并将使用 pip 来安装依赖项 但是 我不确定在安装其他软件包之前是否需要将 pip 升
  • 使用 Numpy 或 Scipy 的累积乘积

    我有一个一维 numpy 数组 我希望将其转换为其累积乘积 一个幼稚的实现是这样的 import numpy as np arr 1 2 3 4 5 6 7 8 9 10 c sum np prod arr i for i in range
  • pytest 在参数化中使用固定装置作为参数

    我想使用固定装置作为参数pytest mark parametrize或者会产 生相同结果的东西 例如 import pytest import my package pytest fixture def dir1 fixture retu
  • 为什么反斜杠出现两次?

    当我创建包含反斜杠的字符串时 它们会重复 gt gt gt my string why does it happen gt gt gt my string why does it happen Why 你所看到的是表示 of my stri
  • UTF-16-LE 文件的 Python 字符串替换

    Python 2 6 使用 Python string replace 似乎不适用于 UTF 16 LE 文件 我想到了2种方法 找到一个可以处理 Unicode 字符串操作的 Python 模块 将目标 Unicode 文件转换为 ASC
  • Azure Cosmos DB,删除 IDS(肯定存在)

    这可能是一个非常简单和愚蠢的错误 但我不确定这是如何失败的 我已经用过https github com Azure azure cosmos python insert data https github com Azure azure c
  • Numpy 矩阵到 tkinter 画布

    如何将 Numpy 矩阵作为位图显示到 Tkinter 画布中 更准确地说 如何填写PhotoImage来自矩阵的内容 photo ImageTk PhotoImage self canvas create image 0 0 image
  • 装饰器更改返回类型时键入函数

    如何正确编写返回类型被装饰器修改的函数的类型 简单的例子 def example decorator fn def wrapper data res fn data return join res return wrapper exampl

随机推荐