朱莉娅:基于每个元素的索引的2维数组的广播
我有一个1920 x 1080数组canvas
,每个元素充当像素,默认值rgb(0,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
目前,我通过使用嵌套以循环在所有索引上进行循环来执行此操作。但是,我想使用cuda.jl
来提高性能。我想避免编写GPU内核,并在可能的情况下进行数组编程。但是,在这种情况下,由于必须避免标量索引,因此不可能在数组上进行索引,从我看来,通过数组广播是首选方法。
从我的理解中,广播功能可以根据元素的值返回值(在这种情况下rgb(0,0,0,0)
)而不是索引(这是我需要计算的内容颜色)。
是否有任何方法可以将上述步骤包装到通过广播或任何实现我想要的替代方法的元素索引?
I have a 1920 by 1080 array canvas
with each element acting as a pixel, with default value RGB(0, 0, 0)
, for an image.
What my program (a very simple raytracer) currently does is:
- Use the index of each "pixel" to get the corresponding position on the camera frame
- store the ray from the center of the camera to that position as a three-dimensional vector
- find the closest object that the ray intersects with
- set the value of that pixel to match the color of that object (which again require the indices of that pixel)
The full code is too large to share, but most of the code relevant to the question is as follows:
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
Currently, I do this by using nested for loops to loop over all the indices. However, I wanted to improve performance by using CUDA.jl
. I would like to avoid writing a GPU kernel and make do with Array Programming, if possible. However, in that case, indexing over the array is not possible since scalar indexing has to be avoided, and from what it seems to me, broadcasting over an array is the preferred method.
From my understanding, a broadcasted function can return a value based on the elements' value (in this case RGB(0, 0, 0)
) and not the indices (which is what I require to compute the color).
Is there any way to have a function that wraps the steps mentioned above receive the indices of the element it is acting upon via broadcasting or any alternative method that achieves what I want?
PS: I did look into Computing array values based on their index using Julia Broadcasting in julia but that approach alters only a row (which is a vector by itself), and the expression is quite simple, and I could not get something similar working for a matrix and the large number of statements my program uses.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
让我们首先创建一个矩阵并获取其
cartesianIndices
:现在,让我们定义一个函数,该函数将采用
cartesianIndex
和一个元素:然后,我们可以将我们的新功能应用于
ind
和m
:重要的是
ind
和m
具有完全相同的维度。Let's first create a matrix and get its
CartesianIndices
:Now let's define a function that will take a
CartesianIndex
and an element:We can then apply our new function to
ind
andM
:Importantly
ind
andM
have exactly the same dimensions.