日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

简单的光线追踪教程(一)

發(fā)布時(shí)間:2023/12/31 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 简单的光线追踪教程(一) 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

簡(jiǎn)單的光線追蹤教程(一)

1. 概述

最近閑來(lái)無(wú)事,想學(xué)習(xí)一下java,并且了解一下C++。網(wǎng)上搜索了很多得相關(guān)教程,學(xué)了一段時(shí)間之后發(fā)現(xiàn),還是得自己親自動(dòng)手寫一點(diǎn)東西。所以學(xué)了一點(diǎn)簡(jiǎn)單的光線追蹤,與大家一起分享

里面涉及一點(diǎn)矩陣的操作,以及簡(jiǎn)單的C++/Java

2. 如何輸出圖象

我采用的就是最簡(jiǎn)單的方法,就是從純文本ppm文件開始,不了解ppm文件的可以從下面的鏈接中簡(jiǎn)單了解一下,這里也不需要更深入的了解。總之,PPM是一種簡(jiǎn)單的圖片格式,我們可以通過(guò)PPM進(jìn)行圖像相關(guān)的學(xué)習(xí)。

https://blog.csdn.net/kinghzkingkkk/article/details/70226214

讓我們寫一個(gè)最簡(jiǎn)單的C++/Java來(lái)輸入一個(gè)簡(jiǎn)單的PPM文件

C++ :

#include <iostream>int main() {// Imageconst int image_width = 256;const int image_height = 256;// Renderstd::cout << "P3\n" << image_width << ' ' << image_height << "\n255\n";for (int j = image_height-1; j >= 0; --j) {for (int i = 0; i < image_width; ++i) {auto r = double(i) / (image_width-1);auto g = double(j) / (image_height-1);auto b = 0.25;int ir = static_cast<int>(255.999 * r);int ig = static_cast<int>(255.999 * g);int ib = static_cast<int>(255.999 * b);std::cout << ir << ' ' << ig << ' ' << ib << '\n';}} }

對(duì)于這個(gè)簡(jiǎn)單的文件需要注意

1. 圖片中的像素按從左到右打的像素按行寫出
2.行從上到下寫出

之后我們會(huì)將這段代碼重定向/寫入到圖像文件

在C++中我們使用重定向符來(lái)完成,在java中我們可以創(chuàng)建一個(gè)類來(lái)完成這個(gè)功能

public void writeToFile(String path) throws IOException {FileWriter fw = new FileWriter(path);BufferedWriter bw = new BufferedWriter(fw);double scale = 1.0 / samplesPerPixel;bw.write("P3\n" + imageWidth + " " + imageHeight + "\n255\n");for (int j = imageHeight - 1; j >= 0; j--) {System.out.println(j);for (int i = 0; i < imageWidth; i++) {double r = pixelColor[j][i].getX() * scale;double g = pixelColor[j][i].getY() * scale;double b = pixelColor[j][i].getZ() * scale;bw.write( String.valueOf((int)(255.999 * r + ' ' +String.valueOf((int)255.999 * g)) + ' ' +String.valueOf((int)(255.999 * b)) + ' ');bw.write("\n");}}}

最終我們可以看到我們寫的圖像為

[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來(lái)直接上傳(img-JePhTtOm-1623992609952)(https://raytracing.github.io/images/img-1.01-first-ppm-image.png)]

一個(gè)漸變的色塊,這樣,我們的第一個(gè)ppm圖象生成成功了!

由于以后的寫入工作會(huì)變得很緩慢,有時(shí)我們會(huì)懷疑它是否在正常工作,我們?yōu)槲覀兊膶懭牒瘮?shù)/寫入方法加上一個(gè)簡(jiǎn)單的進(jìn)度條,注意要寫入錯(cuò)誤輸出流。

for (int j = image_height-1; j >= 0; --j) {std::cerr << "\rScanlines remaining: " << j << ' ' << std::flush;for (int i = 0; i < image_width; ++i) {auto r = double(i) / (image_width-1);auto g = double(j) / (image_height-1);auto b = 0.25;int ir = static_cast<int>(255.999 * r);int ig = static_cast<int>(255.999 * g);int ib = static_cast<int>(255.999 * b);std::cout << ir << ' ' << ig << ' ' << ib << '\n';}}std::cerr << "\nDone.\n";

3. vec3 類

說(shuō)明一下,vec3其實(shí)就是每個(gè)像素的顏色類以及其他的性質(zhì)(例如反射),其中包含著r,g,b。我們把這三個(gè)元素分別視為三個(gè)向量,用向量操作來(lái)完成圖像的操作,以及我們光線追蹤的要求。

3.1. vec3類的變量與方法

代碼如下,使用了C++中運(yùn)算符重載的特性

#ifndef VEC3_H #define VEC3_H#include <cmath> #include <iostream>using std::sqrt;class vec3 {public:vec3() : e{0,0,0} {}vec3(double e0, double e1, double e2) : e{e0, e1, e2} {}double x() const { return e[0]; }double y() const { return e[1]; }double z() const { return e[2]; }vec3 operator-() const { return vec3(-e[0], -e[1], -e[2]); }double operator[](int i) const { return e[i]; }double& operator[](int i) { return e[i]; }vec3& operator+=(const vec3 &v) {e[0] += v.e[0];e[1] += v.e[1];e[2] += v.e[2];return *this;}vec3& operator*=(const double t) {e[0] *= t;e[1] *= t;e[2] *= t;return *this;}vec3& operator/=(const double t) {return *this *= 1/t;}double length() const {return sqrt(length_squared());}double length_squared() const {return e[0]*e[0] + e[1]*e[1] + e[2]*e[2];}public:double e[3]; };// Type aliases for vec3 using point3 = vec3; // 3D point using color = vec3; // RGB color#endif
3.2. 對(duì)于vec3類的簡(jiǎn)單操作
// vec3 Utility Functionsinline std::ostream& operator<<(std::ostream &out, const vec3 &v) {return out << v.e[0] << ' ' << v.e[1] << ' ' << v.e[2]; }inline vec3 operator+(const vec3 &u, const vec3 &v) {return vec3(u.e[0] + v.e[0], u.e[1] + v.e[1], u.e[2] + v.e[2]); }inline vec3 operator-(const vec3 &u, const vec3 &v) {return vec3(u.e[0] - v.e[0], u.e[1] - v.e[1], u.e[2] - v.e[2]); }inline vec3 operator*(const vec3 &u, const vec3 &v) {return vec3(u.e[0] * v.e[0], u.e[1] * v.e[1], u.e[2] * v.e[2]); }inline vec3 operator*(double t, const vec3 &v) {return vec3(t*v.e[0], t*v.e[1], t*v.e[2]); }inline vec3 operator*(const vec3 &v, double t) {return t * v; }inline vec3 operator/(vec3 v, double t) {return (1/t) * v; }inline double dot(const vec3 &u, const vec3 &v) {return u.e[0] * v.e[0]+ u.e[1] * v.e[1]+ u.e[2] * v.e[2]; }inline vec3 cross(const vec3 &u, const vec3 &v) {return vec3(u.e[1] * v.e[2] - u.e[2] * v.e[1],u.e[2] * v.e[0] - u.e[0] * v.e[2],u.e[0] * v.e[1] - u.e[1] * v.e[0]); }inline vec3 unit_vector(vec3 v) {return v / v.length(); }

對(duì)于C++,你可以寫道頭文件中,或者java寫在工具類中

3.3. 簡(jiǎn)單封裝

使用我們vec3類,我們簡(jiǎn)單封裝一下我們寫入ppm文件的過(guò)程

#ifndef COLOR_H #define COLOR_H#include "vec3.h"#include <iostream>void write_color(std::ostream &out, color pixel_color) {// Write the translated [0,255] value of each color component.out << static_cast<int>(255.999 * pixel_color.x()) << ' '<< static_cast<int>(255.999 * pixel_color.y()) << ' '<< static_cast<int>(255.999 * pixel_color.z()) << '\n'; }#endif

因此,我們只需要在主函數(shù)中進(jìn)行調(diào)用即可

#include "color.h" #include "vec3.h"#include <iostream>int main() {// Imageconst int image_width = 256;const int image_height = 256;// Renderstd::cout << "P3\n" << image_width << ' ' << image_height << "\n255\n";for (int j = image_height-1; j >= 0; --j) {std::cerr << "\rScanlines remaining: " << j << ' ' << std::flush;for (int i = 0; i < image_width; ++i) {color pixel_color(double(i)/(image_width-1), double(j)/(image_height-1), 0.25);write_color(std::cout, pixel_color);}}std::cerr << "\nDone.\n"; }

這樣,我們就實(shí)現(xiàn)了對(duì)我們最初寫的ppm圖象生成的簡(jiǎn)單封裝

這次先說(shuō)這些,以后會(huì)持續(xù)更新,感興趣的可以關(guān)注一下
這樣,我們就實(shí)現(xiàn)了對(duì)我們最初寫的ppm圖象生成的簡(jiǎn)單封裝。
這次先說(shuō)這些,以后會(huì)持續(xù)更新,感興趣的可以關(guān)注一下

總結(jié)

以上是生活随笔為你收集整理的简单的光线追踪教程(一)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。