简单的光线跟踪

昨天搞了本数<<GPU高性能编程CUDA实战>>感觉不错花了一个下午+晚上才看了100页,其中有个超简单光线跟踪算法,试了下感觉不错。

原理如下图(是那本数上的):

其中没有考虑到摄像机模型,基本就是平面上一一个像素点发送平行与Z轴光线看能与哪些点球碰撞,并计算出像素值,计算过程中我重新使用了TBB来加速,CUDA还是很郁闷的,只能用在NVIDIA的显卡特定上.图像部分直接使用的是OpenCV的接口,封装成CPUBitmap,虽然自己重新写下也没有太多的代码(http://www.thecodeway.com/blog/?p=409),可是谁让咱懒呢.

代码如下:

#include <tbb/tbb.h>

#include <math.h>

#include <stdlib.h>

#include <highgui.h>

#include <time.h>

#pragma comment(lib,"opencv_core231.lib")

#pragma comment(lib,"opencv_highgui231.lib")



#define INF 2e10f

#define SPHERES 20

#define rnd(x) (x*rand()/RAND_MAX)

#define DIM 640



struct Sphere

{

    float r,b,g;

    float radius;

    float x,y,z;

    float hit(float ox,float oy,float *n)

    {

        float dx = ox - x;

        float dy = oy - y;

        if(dx * dx + dy*dy < radius*radius){

            float dz = sqrtf(radius*radius - dx*dx - dy*dy);

            *n = dz / sqrtf(radius*radius);

            return dz + z;

        }

        return -INF;

    }

};



class CPUBitmap

{

public:

    CPUBitmap(int dimx,int dimy)

    {

        img = cvCreateImage(cvSize(dimx,dimy),8,3);        

    }

    ~CPUBitmap()

    {

        if(img)

            cvReleaseImage(&img);

    }

    unsigned char *get_ptr()

    {

        return (unsigned char *)img->imageDataOrigin;

    }

    

    void display_and_exit()

    {

        cvShowImage("CPUBitmap",img);

        cvWaitKey(0);

    }

private:

    IplImage *img;

};





struct ray_kernel

{    

    ray_kernel(Sphere* s,int num,unsigned char* ptr,int dimx):

                            sp(s),number(num),

                            ptr(ptr),dimx(dimx)

    {

        

    }



    void operator()(const tbb::blocked_range2d<int,int>& r)const

    {        

        for(int y = r.rows().begin();y<r.rows().end();y++)

        {

            for(int x = r.cols().begin();x < r.cols().end();x ++)

            {

                int offset = x + y*dimx;

                float ox = (x - dimx/2);

                float oy = (y - dimx/2);

                float r= 0,g = 0,b = 0;

                float maxz  = -INF;

                for(int i = 0;i<number;i++)

                {

                    float n;

                    float t = sp[i].hit(ox,oy,&n);

                    if(t > maxz)

                    {

                        float fscale = n;

                        r = sp[i].r  * fscale;

                        g = sp[i].g  * fscale;

                        b = sp[i].b  * fscale;

                    }

                }

                ptr[offset*3 + 0] = (int)(b*255);

                ptr[offset*3 + 1] = (int)(g*255);

                ptr[offset*3 + 2] = (int)(r*255);

            }

        }

    }

    int number;

    int dimx;

    Sphere *sp;

    unsigned char *ptr;

};



int main()

{

    Sphere *s;

    tbb::task_scheduler_init init;

    srand(time(NULL));



    CPUBitmap bitmap(DIM,DIM);

    s = new Sphere[SPHERES];    

    for(int i = 0;i<SPHERES;i++){

        s[i].r = rnd(1.0f);

        s[i].g = rnd(1.0f);

        s[i].b = rnd(1.0f);

        

        s[i].x = rnd(1000.0f) - 500;

        s[i].y = rnd(1000.0f) - 500;

        s[i].z = rnd(1000.0f) - 500;



        s[i].radius = rnd(100.0f) + 20;

    }

    

    tbb::blocked_range2d<int,int> range2d(0,DIM,0,DIM);

    tbb::parallel_for(range2d,ray_kernel(s,SPHERES,bitmap.get_ptr(),DIM));

    bitmap.display_and_exit();



    delete[] s;

    return 0;

}

代码基本是直译的书上的代码,不过它用的是CUDA,我用的是TBB而已.

效果如下:

简单的光线跟踪

简单的光线跟踪

ps:1.不知道怎么回事,CUDA3.2的开发包可用使用,但是CUDA4.0的有问题(新版本的可以使用nvidia的thrust库<-官方说某些情况下比tbb快200倍)

   2.CUDA的代码带我的电脑上编译不是一般的慢,而是特慢.

   3.早上敲了个CUDA的代码,直接把电脑搞死机(蓝屏?!)了.

不知道哪个高手能够解答下.....

你可能感兴趣的:(简单)