使用光线跟踪在球体上翻转2D纹理

时间:2012-08-02 14:52:37

标签: c++ graphics texture-mapping raytracing

我正在研究我的光线追踪器,我想我已经取得了一些重大成就。我目前正在尝试将纹理图像放在对象上。然而,它们并不是很好。它们出现在球体上。以下是我当前代码的最终图像:Look at how North and South America appears

以下是相关代码:

- 用于打开图像的图像类

class Image
{
public:
    Image() {}

    void read_bmp_file(char* filename)
    {
        int i;
        FILE* f = fopen(filename, "rb");
        unsigned char info[54];
        fread(info, sizeof(unsigned char), 54, f); // read the 54-byte header

        // extract image height and width from header
        width = *(int*)&info[18];
        height = *(int*)&info[22];

        int size = 3 * width * height;
        data = new unsigned char[size]; // allocate 3 bytes per pixel
        fread(data, sizeof(unsigned char), size, f); // read the rest of the data at once
        fclose(f);

        for(i = 0; i < size; i += 3)
        {
            unsigned char tmp = data[i];
            data[i] = data[i+2];
            data[i+2] = tmp;
        }
        /*Now data should contain the (R, G, B) values of the pixels. The color of pixel (i, j) is stored at 
        data[j * 3* width + 3 * i], data[j * 3 * width + 3 * i + 1] and data[j * 3 * width + 3*i + 2].

        In the last part, the swap between every first and third pixel is done because windows stores the 
        color values as (B, G, R) triples, not (R, G, B).*/
    }

public:
    int width;
    int height;
    unsigned char* data;
};

-Texture class

class Texture: public Material
{
public:
    Texture(char* filename): Material() {
        image_ptr = new Image;
        image_ptr->read_bmp_file(filename);
    }
    virtual ~Texture() {}

    virtual void set_mapping(Mapping* mapping)
    {   mapping_ptr = mapping;}

    virtual Vec get_color(const ShadeRec& sr)   {
        int row, col;

        if(mapping_ptr)
            mapping_ptr->get_texel_coordinates(sr.local_hit_point, image_ptr->width, image_ptr->height, row, col);

        return Vec (image_ptr->data[row * 3 * image_ptr->width + 3*col  ]/255.0, 
                    image_ptr->data[row * 3 * image_ptr->width + 3*col+1]/255.0,
                    image_ptr->data[row * 3 * image_ptr->width + 3*col+2]/255.0);
    }
public:
    Image* image_ptr;
    Mapping* mapping_ptr;
};

-Mapping class

class SphericalMap: public Mapping
{
public:
    SphericalMap(): Mapping()   {}
    virtual ~SphericalMap() {}

    virtual void get_texel_coordinates (const Vec& local_hit_point, 
                                        const int hres,
                                        const int vres,
                                        int& row,
                                        int& column) const  
    {
        float theta = acos(local_hit_point.y);
        float phi   = atan2(local_hit_point.z, local_hit_point.x);

        if(phi < 0.0)
            phi += 2*PI;

        float u = phi/(2*PI);
        float v = (PI - theta)/PI;

        column = (int)((hres - 1) * u); 
        row = (int)((vres - 1) * v); 
    }
};

- 本地生命值:

virtual void Sphere::set_local_hit_point(ShadeRec& sr)
    {
        sr.local_hit_point.x = sr.hit_point.x - c.x;
        sr.local_hit_point.y = (sr.hit_point.y - c.y)/R;
        sr.local_hit_point.z = sr.hit_point.z -c.z;
    }

- 这就是我在main中构建球体的方式:

Texture* t1 = new Texture("Texture\\earthmap2.bmp");
SphericalMap* sm = new SphericalMap();
t1->set_mapping(sm);
t1->set_ka(0.55);
t1->set_ks(0.0);
Sphere *s1 = new Sphere(Vec(-60,0,50), 149);
s1->set_material(t1);
w.add_object(s1);

很抱歉长代码,但如果我知道可能出现问题的地方,我会发布那个部分。最后,这是我从get_color()

调用main函数的方式
xShaded +=  sr.material_ptr->get_color(sr).x * in.x * max(0.0, sr.normal.dot(l)) + 
        sr.material_ptr->ks * in.x * pow((max(0.0,sr.normal.dot(h))),1);
yShaded +=  sr.material_ptr->get_color(sr).y * in.y * max(0.0, sr.normal.dot(l)) + 
        sr.material_ptr->ks * in.y * pow((max(0.0,sr.normal.dot(h))),1);
zShaded +=  sr.material_ptr->get_color(sr).z * in.z * max(0.0, sr.normal.dot(l)) + 
        sr.material_ptr->ks * in.z * pow((max(0.0,sr.normal.dot(h))),1);

2 个答案:

答案 0 :(得分:0)

在黑暗中拍摄:如果内存服务,BMP从下往上存储,而许多其他图像格式是自上而下。这可能是问题吗?也许您的文件阅读器只需要反转行?

答案 1 :(得分:0)

float phi = atan2(local_hit_point.z, local_hit_point.x);更改为float phi = atan2(local_hit_point.x, local_hit_point.z);解决了这个问题。