射线追踪与CUDA

射线追踪与CUDA,cuda,raytracing,raycasting,pycuda,Cuda,Raytracing,Raycasting,Pycuda,我有一个光线跟踪模型,我对一个有100k三角形面的网格对象发射20k光线 为了计算交点的坐标,我基于Moller trumbore算法编写了此函数: 我给出光线的原点和方向,以及3个带有三角形顶点坐标v0、v1、v2的向量作为输入 然后我在一个for循环中使用这个函数,该循环有大约100k个三角形重复,另一个for循环有20k个光线重复 由于这段代码非常慢,大约需要2天半的时间来计算所有内容,所以我想与Cuda并行运行它,希望减少这段时间。 因为我在使用Python,所以我使用PyCuda,并尝

我有一个光线跟踪模型,我对一个有100k三角形面的网格对象发射20k光线

为了计算交点的坐标,我基于Moller trumbore算法编写了此函数:

我给出光线的原点和方向,以及3个带有三角形顶点坐标v0、v1、v2的向量作为输入

然后我在一个for循环中使用这个函数,该循环有大约100k个三角形重复,另一个for循环有20k个光线重复

由于这段代码非常慢,大约需要2天半的时间来计算所有内容,所以我想与Cuda并行运行它,希望减少这段时间。 因为我在使用Python,所以我使用PyCuda,并尝试用我的MT_交集函数编写一个C内核:

import pycuda.driver as drv
import pycuda.autoinit
from pycuda.compiler import SourceModule
import numpy as np
from stl import mesh

my_mesh = mesh.Mesh.from_file('sfera1.stl')
n = my_mesh.normals
v0 = my_mesh.v0
v1 = my_mesh.v1
v2 = my_mesh.v2

mod = SourceModule("""
    #include <math.h>
    //#include <vector>
  __global__ void intersect(float *origin,float *dir,float *v0,float *v1,float *v2,float *int_point_real)
  {
    using namespace std;
    //#include <vector>
    //#include <math.h>
    int idx = threadIdx.x;
    //a[idx] *= 2;
    int count = 0;

    //std::vector<double> v0_current(3);
    float v0_current[3];
    float v1_current[3];
    float v2_current[3];
    float dir_current[3] = {dir[idx][0],dir[idx][1],dir[idx][2]}; 
    //std::vector<double> v1_current(3);
    //std::vector<double> v2_current(3);
    float int_point[3];
    //std::vector<float> int_point(3);
    //std::vector<std::vector<float>> int_pointS;
    float int_pointS[2][3];
    //std::vector<std::vector<double>> int_point;
    //std::vector<int> int_faces;
    int int_faces[2];
    float dist[2];
    //std::vector<float> dist;
    int n_tri = 960;

    for(int i = 0; i<n_tri; i++) {
        for (int j = 0; j<3; j++){
            v0_current[j] = v0[i][j];
            v1_current[j] = v1[i][j];
            v2_current[j] = v2[i][j];
        }
        double eps = 0.0000001;
        //std::vector<float> E1(3);
        float E1[3];
        //std::vector<float> E2(3);
        float E2[3];
        //std::vector<float> s(3);
        float s[3];
        for (int j = 0; j < 3; j++) {
            E1[j] = v1_current[j] - v0_current[j];
            E2[j] = v2_current[j] - v0_current[j];
            s[j] = origin[j] - v0_current[j];
        }
        //std::vector<float> h(3);
        float h[3];
        h[0] = dir[1] * E2[2] - dir[2] * E2[1];
        h[1] = -(dir[0] * E2[2] - dir[2] * E2[0]);
        h[2] = dir[0] * E2[1] - dir[1] * E2[0];
        float a;
        a = E1[0] * h[0] + E1[1] * h[1] + E1[2] * h[2];
        if (a > -eps && a < eps) {
            int_point[0] = false;
            //return false;
        }
        else {
            double f = 1 / a;
            float u;
            u = f * (s[0] * h[0] + s[1] * h[1] + s[2] * h[2]);
            if (u < 0 || u > 1) {
                int_point[0] = false;
                //return false;
            }
            else {
                //std::vector<float> q(3);
                float q[3];
                q[0] = s[1] * E1[2] - s[2] * E1[1];
                q[1] = -(s[0] * E1[2] - s[2] * E1[0]);
                q[2] = s[0] * E1[1] - s[1] * E1[0];
                float v;
                v = f * (dir[0] * q[0] + dir[1] * q[1] + dir[2] * q[2]);
                if (v < 0 || (u + v)>1) {
                    int_point[0] = false;
                    //return false;
                }
                else {
                    float t;
                    t = f * (E2[0] * q[0] + E2[1] * q[1] + E2[2] * q[2]);
                    if (t > eps) {
                        for (int j = 0; j < 3; j++) {
                            int_point[j] = origin[j] + dir_current[j] * t;
                        }
                        //return t;
                    }
                }
            }
        }
        if (int_point[0] != false) {
            count = count+1;
            //int_faces.push_back(i);
            int_faces[count-1] = i;
            //dist.push_back(sqrt(pow((origin[0] - int_point[0]), 2) + pow((origin[1] - int_point[1]), 2) + pow((origin[2] - int_point[2]), 2)));
            //dist.push_back(x);
            dist[count-1] = sqrt(pow((origin[0] - int_point[0]), 2) + pow((origin[1] - int_point[1]), 2) + pow((origin[2] - int_point[2]), 2));
            //int_pointS.push_back(int_point);
            for (int j = 0; j<3; j++) {
                int_pointS[count-1][j] = int_point[j];
            }
        } 
    }
    double min = dist[0];
    int ind_min = 0;
    for (int i = 0; i < int_pointS.size(); i++){
        if (min > dist[i]) {
            min = dist[i];
            ind_min = i;
        }
    }
    //dist_real[Idx] = dist[ind_min];
    //int_point_real_x[Idx] = int_pointS[ind_min][0];
    //int_point_real_y[Idx] = int_pointS[ind_min][1];
    //int_point_real_z[Idx] = int_pointS[ind_min][2];
    int_point_real[Idx][0] = int_pointS[ind_min][0];
    int_point_real[Idx][1] = int_pointS[ind_min][1];
    int_point_real[Idx][2] = int_pointS[ind_min][2];
}
  """)

origin = np.asarray([1, 1, 1]).astype(np.float32)
direction = np.ones((100, 3)).astype(np.float32)
int_point_real = np.zeros((100, 3)).astype(np.float32)

intersect = mod.get_function("intersect")
intersect(drv.In(origin), drv.In(direction), drv.In(v0), drv.In(v1), drv.In(v2), drv.Out(int_point_real), block=(512,1,1), grid=(64,1,1))
我的想法是并行运行20k光线。 此Python脚本给了我不同的错误:

kernel.cu18:错误:表达式必须具有指向对象类型的指针

kernel.cu18:错误:表达式必须具有指向对象类型的指针

kernel.cu18:错误:表达式必须具有指向对象类型的指针

kernel.cu34:错误:表达式必须具有指向对象类型的指针

kernel.cu35:错误:表达式必须具有指向对象类型的指针

kernel.cu36:错误:表达式必须具有指向对象类型的指针

kernel.cu108:错误:表达式必须具有类类型

kernel.cu118:错误:表达式必须具有指向对象类型的指针

kernel.cu119:错误:表达式必须具有指向对象类型的指针

kernel.cu120:错误:表达式必须具有指向对象类型的指针

kernel.cu27:警告:设置了变量int_faces,但从未使用过

在汇编过程中检测到10个错误 C:/Users/20180781/AppData/Local/Temp/tmpxft_0000d44_00000000-10_kernel.cpp1.ii。 ]

知道为什么吗


当我有很多光线和很多面时,有人知道一种更聪明、更有效的方法来计算交点吗?

似乎所有的错误都是针对那些试图对事物进行双重索引的直线报告的。行编号有点不正确,但来自警告内核。cu27:警告:设置了变量int_faces,但从未使用。可以推断,前几条错误消息涉及以下行:

float dir_current[3] = {dir[idx][0],dir[idx][1],dir[idx][2]}; 
[……]

这是有意义的,因为dir、v0、v1和v2都定义为float*。这只是一个浮点指针。您可以像dir[idx]一样对它进行一次索引,生成一个浮点值,但是像dir[idx][0]那样将它仅仅作为浮点值进行索引是没有意义的

在此点之后,行号再次关闭,但接受我的假设,可以假设这是最后3条有问题的行号:

int_point_real[Idx][0] = int_pointS[ind_min][0];
int_point_real[Idx][1] = int_pointS[ind_min][1];
int_point_real[Idx][2] = int_pointS[ind_min][2];
事实上,int_point_real也只是一个指向浮点的指针。 另外,请注意,尽管int_点在其他几行中被引用,但它们没有错误报告,因为该变量被正确声明为二维数组,可以被索引两次

v0_current[j] = v0[i][j];
v1_current[j] = v1[i][j];
v2_current[j] = v2[i][j];
int_point_real[Idx][0] = int_pointS[ind_min][0];
int_point_real[Idx][1] = int_pointS[ind_min][1];
int_point_real[Idx][2] = int_pointS[ind_min][2];