简单的光线跟踪

昨天搞了本数<<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的代码,直接把电脑搞死机(蓝屏?!)了.

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

posted @ 2012-05-28 10:24  zhuangzhuang1988  阅读(846)  评论(1编辑  收藏  举报