美文网首页
从零实现光线追踪器(0)- 将数据保存为图片

从零实现光线追踪器(0)- 将数据保存为图片

作者: 不吃折耳根 | 来源:发表于2018-10-22 20:31 被阅读0次

    前言


    本人一直对图形学感兴趣。之前一直在scratchapixel.com学习图形学的知识。这个网站对相关的数学基础以及图形学入门概念讲解十分详细,推荐有一定英语能力的人阅读。但是读了那么多理论知识,总想着去自己动手实现一把。可是万事开头难啊,到底需要编写哪些类,设计哪些算法,让人头大。这时我去油管找到了一个2013年的教程使用C++实现了一个简易的光线追踪器,效果还挺好。在这里写下自己的学习过程供大家参考和交流。

    这是该作者的教程地址共9节Raytracer from Scratch in C++,有兴趣的同学可以科学上网浏览一下。该作者的编码水平并不高,其中有很多可以优化的地方,但是他所展示的实现光线追踪器的一套流程还是十分值得学习。

    下面我们正式开始。

    1.保存bmp图片


    第一步我们需要编写一个函数saveBmp()将图像数据保存为bmp图片。此处也可以去查阅相关的博客来编写该函数。而一个简单的bmp的格式为bmpFileHeader+bmpInfoHeader+data。创建一个头文件命名为func.h,在其中进行如下编写。

    首先我们定义字长。此处第一行#pragma pack(2)是必不可少的。否则无法字节对齐,bmp格式相关参数会设置错误。

    #pragma pack(2)
    typedef unsigned char BYTE;
    typedef unsigned short WORD;
    typedef unsigned long DWORD;
    typedef long LONG;
    

    接下来我们定义一个bmpFileHeaderbmpInfoHeader结构体。

    struct BmpFileHeader
    {
        WORD    bfType;
        DWORD   bfSize;
        WORD    bfReserved1;
        WORD    bfReserved2;
        DWORD   bfOffBits;
    };
    struct BmpInfoHeader
    {
        DWORD   biSize;             
        LONG    biWidth;            
        LONG    biHeight;           
        WORD    biPlanes;           
        WORD    biBitCount;        
        DWORD   biCompression;      
        DWORD   biSizeImage;        
        LONG    biXPelsPerMeter;    
        LONG    biYPelsPerMeter;    
        DWORD   biClrUsed;          
        DWORD   biClrImportant; 
    };
    

    此处各项变量的意义可以去查阅讲解bitmap位图格式的相关博客

    接下来我们定义一个结构体用于保存RGB数据

    struct RGBType
    {
        unsigned char r;
        unsigned char g;
        unsigned char b;
    
        void set(unsigned char r1, unsigned char g1, unsigned char b1)
        {
            r = r1;
            g = g1;
            b = b1;
        }
    };
    

    这样我们就可以来编写saveBmp()函数了。

    void saveBmp(const char *fileName, int w, int h, RGBType *data)
    {
        int size = 4 * w * h;
    
        //设置bmpfileheader的各种数值
        BmpFileHeader fileHeader;
        fileHeader.bfType = 0x4D42;//0x4d42即字母 'B''M'
        fileHeader.bfReserved1 = 0;//保留位1
        fileHeader.bfReserved2 = 0;//保留位2
        fileHeader.bfSize = 54 + size;//文件总长度 文件头(54字节) + 图像数据(size)
        fileHeader.bfOffBits = 54;//文件头长度
    
        //设置infoheader的值
        BmpInfoHeader infoHeader = {0};
        infoHeader.biSize = 40;//infoheader的长度
        infoHeader.biHeight = -h;//高度
        infoHeader.biWidth = w;//宽度
        infoHeader.biPlanes = 1;
        infoHeader.biBitCount = 24;//颜色位数。一般为24
        infoHeader.biSizeImage = 0;//默认为0
        infoHeader.biCompression = 0;//压缩率 ,默认为0
    
    
        //将传入的RGB数值写入文件中
        FILE *output = fopen(fileName, "wb");
        if (output)
        {
            fwrite(&fileHeader, 14, 1, output);
            fwrite(&infoHeader, 40, 1, output);
            for (int i = 0; i < w * h; ++i)
            {
                RGBType rgb = data[i];
                unsigned char color[3] = {rgb.r, rgb.g, rgb.b};
                fwrite(color, 3, 1, output);
            }
            fclose(output);
        }
    }
    

    接下来我们进行简单的测试。

    #include "func.h"
    #include <iostream>
    #include <cmath>
    #include <fstream>
    using namespace std;
    
    int main(int argc, char *argv[])
    {
        cout << "rendering";
        
        int width = 640;
        int height = 480;
        int n = width * height;
    
        RGBType *pixels = new RGBType[n];
        for (int x = 0; x < width; ++x)
        {
            for (int y = 0; y < height; ++y)
            {
                int i = y * width + x;
                //设置一个矩形
                if((x>100 && x<300)&&(y>200 && y<400)){
                     pixels[i].set(200,100,200);
                }else{
                     pixels[i].set(255,255,255);
                }
            }
        }
        //将RGB数据保存到bmp图片中
        saveBmp("pic.bmp",width,height,pixels);
    }
    

    编译运行一下。打开pic.bmp如下。可以使用windows自带图片查看器或者windows上的画图直接查看。

    pic.png

    那么这就是第一步。已经初见成果(可以看到一个矩形了哈哈)。那么离后面的成功就不远了~~

    相关文章

      网友评论

          本文标题:从零实现光线追踪器(0)- 将数据保存为图片

          本文链接:https://www.haomeiwen.com/subject/xrknzftx.html