⚡ Implementasi pipa rendering yang dapat diprogram, anotasi Cina penuh, membantu pemula belajar prinsip rendering.
mkdir build
cmake -S . -B ./build
cmake --build ./build --config ReleasePerhatikan bahwa menyalin folder res ke jalur di mana file yang dapat dieksekusi berada.
Cukup temukan file contoh yang dimulai dengan sample_ dan secara langsung mengkompilasinya dengan file tunggal GCC:
gcc -O2 sample_07_specular.cpp -o sample_07_specular -lstdc++ Tampaknya saya perlu menambahkan -std=c++17 ke mac saya. Anda mungkin perlu menambahkan -lm untuk menampilkan dan mendeklarasikan tautan Perpustakaan Matematika.
berlari:
./sample_07_specular Kemudian dapatkan output.bmp file gambar.bmp:
Model proyek ini menggunakan model open source di Tinyrender.
Ini terutama menggunakan struktur shaderContext, yang digunakan untuk melewati parameter antara vs-> ps, dan penuh dengan berbagai jenis variasi.
// 着色器上下文,由 VS 设置,再由渲染器按像素逐点插值后,供 PS 读取
struct ShaderContext {
std::map< int , float > varying_float; // 浮点数 varying 列表
std::map< int , Vec2f> varying_vec2f; // 二维矢量 varying 列表
std::map< int , Vec3f> varying_vec3f; // 三维矢量 varying 列表
std::map< int , Vec4f> varying_vec4f; // 四维矢量 varying 列表
}; Lapisan luar perlu memberikan penunjuk fungsi ke renderer vs, dan memanggil tiga simpul segitiga secara berurutan ketika fungsi DrawPrimitive renderer diinisialisasi:
// 顶点着色器:因为是 C++ 编写,无需传递 attribute,传个 0-2 的顶点序号
// 着色器函数直接在外层根据序号读取响应数据即可,最后需要返回一个坐标 pos
// 各项 varying 设置到 output 里,由渲染器插值后传递给 PS
typedef std::function<Vec4f( int index, ShaderContext &output)> VertexShader; Setiap kali panggilan dipanggil, renderer akan melewati angka 0 , 1 , index 2 dari tiga simpul ke program VS pada gilirannya untuk memfasilitasi pembacaan data verteks dari luar.
Renderer memanggil piksel shader untuk setiap titik yang perlu diisi dalam segitiga:
// 像素着色器:输入 ShaderContext,需要返回 Vec4f 类型的颜色
// 三角形内每个点的 input 具体值会根据前面三个顶点的 output 插值得到
typedef std::function<Vec4f(ShaderContext &input)> PixelShader;Warna yang dikembalikan oleh program naungan piksel akan ditarik ke posisi yang sesuai dari buffer bingkai.
Memanggil antarmuka berikut dapat menggambar segitiga:
bool RenderHelp::DrawPrimitive ()Fungsi ini adalah inti dari renderer. Pertama, panggilan vs untuk menginisialisasi simpul pada gilirannya, dapatkan koordinat titik, dan kemudian lakukan pemangkasan ruang homogen, dan dapatkan koordinat layar segitiga setelah normalisasi.
Kemudian, dua lapisan untuk mengulangi loop di setiap titik segitiga yang menghubungkan persegi panjang pada layar, dan kemudian menentukan bahwa dalam rentang segitiga, panggil program VS untuk menghitung warna titik titik itu.
Sekarang Anda ingin menulis gambar segitiga D3D 12. Anda tidak dapat menanganinya tanpa seribu baris, tetapi sekarang kami hanya membutuhkan baris berikut:
# include " RenderHelp.h "
int main ( void )
{
// 初始化渲染器和帧缓存大小
RenderHelp rh ( 800 , 600 );
const int VARYING_COLOR = 0 ; // 定义一个 varying 的 key
// 顶点数据,由 VS 读取,如有多个三角形,可每次更新 vs_input 再绘制
struct { Vec4f pos; Vec4f color; } vs_input[ 3 ] = {
{ { 0.0 , 0.7 , 0.90 , 1 }, { 1 , 0 , 0 , 1 } },
{ { - 0.6 , - 0.2 , 0.01 , 1 }, { 0 , 1 , 0 , 1 } },
{ { + 0.6 , - 0.2 , 0.01 , 1 }, { 0 , 0 , 1 , 1 } },
};
// 顶点着色器,初始化 varying 并返回坐标,
// 参数 index 是渲染器传入的顶点序号,范围 [0, 2] 用于读取顶点数据
rh. SetVertexShader ([&] ( int index , ShaderContext& output) -> Vec4f {
output. varying_vec4f [VARYING_COLOR] = vs_input[ index ]. color ;
return vs_input[ index ]. pos ; // 直接返回坐标
});
// 像素着色器,返回颜色
rh. SetPixelShader ([&] (ShaderContext& input) -> Vec4f {
return input. varying_vec4f [VARYING_COLOR];
});
// 渲染并保存
rh. DrawPrimitive ();
rh. SaveFile ( " output.bmp " );
return 0 ;
}Hasil Menjalankan:
| Nama file | menjelaskan |
|---|---|
| Renderhelp.h | File implementasi renderer, bila digunakan termasuk itu sudah cukup |
| Model.h | Memuat model |
| sample_01_triangle.cpp | Contoh menggambar segitiga |
| sample_02_texture.cpp | Cara menggunakan tekstur, cara mengatur matriks kamera, dll. |
| sample_03_box.cpp | Cara menggambar kotak |
| sample_04_gouraud.cpp | Pewarnaan galaude sederhana dari kotak |
| sample_05_model.cpp | Cara memuat dan menggambar model |
| sampel_06_normal.cpp | Tingkatkan detail model dengan peta normal |
| sample_07_specular.cpp | Menggambar sorotan |
Lebih dari sepuluh tahun yang lalu, saya menulis mini3D tutorial renderer yang lembut, yang dengan jelas menjelaskan prinsip -prinsip inti dari rendering perangkat lunak.
Metode implementasi proyek ini dimodelkan pada metode implementasi persamaan tepi GPU. Metode implementasi proyek ini mensimulasikan GPU relatif sederhana dan intuitif, tetapi perhitungannya sangat besar dan tidak cocok untuk CPU real-time, tetapi cocok untuk pemrosesan paralel GPU yang kasar.
Ada banyak tutorial untuk mengimplementasikan pipa rendering yang dapat diprogram di internet, tetapi banyak dari mereka memiliki masalah Pengambilan sampel tekstur, konversi koordinat integer harus dibulatkan, jika tidak posisi beberapa simpul tekstur tidak cukup stabil, dan akan ada tanda -tanda sedikit bergerak; . . .
Ada banyak aspek yang sangat terperinci dari implementasi renderer.
Yang lain adalah keterbacaan.
File utama RenderHelp.h dari proyek ini memiliki lebih dari seribu baris, sepertiga di antaranya adalah anotasi Cina.
Prinsip -prinsip dasar, saya telah menjelaskan dalam artikel berikut:
Saat membaca, kode ini pada dasarnya adalah beberapa pustaka alat di depannya, yang dapat dibaca dari 200 baris terakhir.
Jika Anda tidak memahami kode tersebut, Anda dapat mengajukan pertanyaan dalam masalah ini.