我有一个1920 × 1080的数组canvas
,每个元素作为一个像素,默认值RGB(0, 0, 0)
,用于图像。
我的程序(一个非常简单的光线追踪器)目前做的是:
- 使用每个"像素"的索引以获得相机帧上的相应位置
- 将从相机中心到该位置的光线存储为三维矢量
- 查找光线与 相交的最近的物体
- 设置该像素的值以匹配该对象的颜色(这再次需要该像素的索引)
完整的代码太大而无法共享,但与问题相关的大部分代码如下:
world = World(RGB(0, 0, 0), 5e-6, objects, lights, 0.2, 4)
camera = Camera((0, -5000, -5000), 1000, (0, 0, 0), 1920, 1080)
canvas = CUDA.fill(world.background, camera.height, camera.width)
for i in 1:camera.width
for j in 1:camera.height
ray = [([i, j] - [camera.width / 2, camera.height / 2])..., camera.depth]
(ray[2], ray[3]) = (cos(camera.rotation[1] + atan(ray[3], ray[2])), sin(camera.rotation[1] + atan(ray[3], ray[2]))) .* sqrt(ray[2]^2 + ray[3]^2)
(ray[1], ray[3]) = (cos(camera.rotation[2] + atan(ray[3], ray[1])), sin(camera.rotation[2] + atan(ray[3], ray[1]))) .* sqrt(ray[1]^2 + ray[3]^2)
(ray[1], ray[2]) = (cos(camera.rotation[3] + atan(ray[2], ray[1])), sin(camera.rotation[3] + atan(ray[2], ray[1]))) .* sqrt(ray[2]^2 + ray[1]^2)
v = (Inf, nothing, nothing)
for object in world.objects
# traceray returns a tuple containing the distance of the point of intersection, and the normal to the surface at that point if the ray intersects the object, or nothing otherwise
t = traceray(ray, camera.position, object, mindistance=camera.depth)
t !== nothing && t[1] < v[1] && (v = (t[1], t[2], object))
end
# computecolor gets the color of the object based on lighting etc.
v[1] != Inf && (canvas[j, i] = computecolor(v[3].material, ray, v[1], v[2], world, camera.position .+ v[1] * ray, v[3]))
end
end
目前,我通过使用嵌套的for循环来遍历所有索引来实现这一点。然而,我想通过使用CUDA.jl
来提高性能。如果可能的话,我想避免编写GPU内核并使用数组编程。然而,在这种情况下,对数组进行索引是不可能的,因为必须避免标量索引,在我看来,对数组进行广播是首选方法。
根据我的理解,广播函数可以根据元素的值(在本例中为RGB(0, 0, 0)
)返回值,而不是索引(这是我需要计算颜色的)。
是否有任何方法可以让一个函数包装上面提到的步骤,通过广播或任何替代方法来接收它所作用的元素的索引,以实现我想要的?
PS:我确实研究了计算数组值基于他们的索引使用朱莉娅广播在朱莉娅,但这种方法只改变一行(这是一个向量本身),表达式是相当简单的,我不能得到类似的东西为矩阵工作和大量的语句我的程序使用。
让我们首先创建一个矩阵并获得它的CartesianIndices
:
julia> M = rand(10, 10)
10×10 Matrix{Float64}:
0.343127 0.0461174 0.000208743 0.739489 0.0881014 … 0.744987 0.150881 0.769042 0.951578
0.415609 0.919787 0.917708 0.31243 0.659583 0.579605 0.428906 0.880912 0.0689765
0.887541 0.308289 0.306524 0.10873 0.0731005 0.0678841 0.560323 0.684129 0.601884
0.614483 0.817356 0.196868 0.863195 0.364332 0.0697723 0.599979 0.709638 0.598244
0.856793 0.37702 0.357844 0.65256 0.254954 0.0564696 0.49687 0.704261 0.488966
0.233914 0.0196481 0.201217 0.560289 0.327611 … 0.957368 0.41253 0.0796238 0.774057
0.905422 0.227343 0.048688 0.374488 0.145598 0.0120923 0.959117 0.83804 0.413381
0.518771 0.298739 0.0497088 0.947807 0.511978 0.0194308 0.0520221 0.40886 0.316115
0.150333 0.3123 0.564887 0.869185 0.406472 0.822917 0.611867 0.396063 0.255475
0.628552 0.634305 0.484303 0.452939 0.0510651 0.207345 0.143286 0.869137 0.626775
julia> ind = CartesianIndices(M)
10×10 CartesianIndices{2, Tuple{Base.OneTo{Int64}, Base.OneTo{Int64}}}:
CartesianIndex(1, 1) CartesianIndex(1, 2) … CartesianIndex(1, 9) CartesianIndex(1, 10)
CartesianIndex(2, 1) CartesianIndex(2, 2) CartesianIndex(2, 9) CartesianIndex(2, 10)
CartesianIndex(3, 1) CartesianIndex(3, 2) CartesianIndex(3, 9) CartesianIndex(3, 10)
CartesianIndex(4, 1) CartesianIndex(4, 2) CartesianIndex(4, 9) CartesianIndex(4, 10)
CartesianIndex(5, 1) CartesianIndex(5, 2) CartesianIndex(5, 9) CartesianIndex(5, 10)
CartesianIndex(6, 1) CartesianIndex(6, 2) … CartesianIndex(6, 9) CartesianIndex(6, 10)
CartesianIndex(7, 1) CartesianIndex(7, 2) CartesianIndex(7, 9) CartesianIndex(7, 10)
CartesianIndex(8, 1) CartesianIndex(8, 2) CartesianIndex(8, 9) CartesianIndex(8, 10)
CartesianIndex(9, 1) CartesianIndex(9, 2) CartesianIndex(9, 9) CartesianIndex(9, 10)
CartesianIndex(10, 1) CartesianIndex(10, 2) CartesianIndex(10, 9) CartesianIndex(10, 10)
现在让我们定义一个函数,它将接受一个CartesianIndex
和一个元素:
f(I::CartesianIndex, m::Float64) = I[1] + I[2] + m
我们可以将我们的新函数应用于ind
和M
:
julia> f.(ind, M)
10×10 Matrix{Float64}:
2.34313 3.04612 4.00021 5.73949 6.0881 7.75464 8.74499 9.15088 10.769 11.9516
3.41561 4.91979 5.91771 6.31243 7.65958 8.04954 9.57961 10.4289 11.8809 12.069
4.88754 5.30829 6.30652 7.10873 8.0731 9.79731 10.0679 11.5603 12.6841 13.6019
5.61448 6.81736 7.19687 8.86319 9.36433 10.7867 11.0698 12.6 13.7096 14.5982
6.85679 7.37702 8.35784 9.65256 10.255 11.3884 12.0565 13.4969 14.7043 15.489
7.23391 8.01965 9.20122 10.5603 11.3276 12.7932 13.9574 14.4125 15.0796 16.7741
8.90542 9.22734 10.0487 11.3745 12.1456 13.8769 14.0121 15.9591 16.838 17.4134
9.51877 10.2987 11.0497 12.9478 13.512 14.9054 15.0194 16.052 17.4089 18.3161
10.1503 11.3123 12.5649 13.8692 14.4065 15.5465 16.8229 17.6119 18.3961 19.2555
11.6286 12.6343 13.4843 14.4529 15.0511 16.0112 17.2073 18.1433 19.8691 20.6268
重要的是ind
和M
有完全相同的尺寸。