⚡ Implémentation de pipeline de rendu programmable, annotation chinoise complète, aidant les débutants à apprendre les principes de rendu.
mkdir build
cmake -S . -B ./build
cmake --build ./build --config ReleaseNotez que Copiez le dossier Res sur le chemin où se trouve le fichier exécutable.
Il suffit de trouver un exemple de fichier commençant par sample_ et de le compiler directement avec le fichier unique GCC:
gcc -O2 sample_07_specular.cpp -o sample_07_specular -lstdc++ Il semble que je dois ajouter -std=c++17 à mon Mac. Vous devrez peut-être ajouter un -lm pour afficher et déclarer la bibliothèque mathématique de lien.
courir:
./sample_07_specular Obtenez ensuite un fichier d'image output.bmp :
Le modèle de ce projet utilise le modèle open source dans Tinyrender.
Il utilise principalement une structure ShaderContext, qui est utilisée pour transmettre des paramètres entre vs-> ps, et il est plein de différents types de variations.
// 着色器上下文,由 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 列表
}; La couche externe doit fournir le pointeur de fonction vers le rendu vs, et appeler les trois sommets du triangle en séquence lorsque la fonction DrawPrimitive du rendu est initialisée:
// 顶点着色器:因为是 C++ 编写,无需传递 attribute,传个 0-2 的顶点序号
// 着色器函数直接在外层根据序号读取响应数据即可,最后需要返回一个坐标 pos
// 各项 varying 设置到 output 里,由渲染器插值后传递给 PS
typedef std::function<Vec4f( int index, ShaderContext &output)> VertexShader; Chaque fois que l'appel est appelé, le rendu passera les numéros 0 , 1 index 2 des trois sommets au programme VS à tour de rôle pour faciliter la lecture des données de sommet de l'extérieur.
Le rendu appelle le pixel shader pour chaque point qui doit être rempli dans le triangle:
// 像素着色器:输入 ShaderContext,需要返回 Vec4f 类型的颜色
// 三角形内每个点的 input 具体值会根据前面三个顶点的 output 插值得到
typedef std::function<Vec4f(ShaderContext &input)> PixelShader;La couleur renvoyée par le programme d'ombrage Pixel sera attirée sur la position correspondante du tampon de trame.
Appeler l'interface suivante peut dessiner un triangle:
bool RenderHelp::DrawPrimitive ()Cette fonction est le cœur du rendu.
Ensuite, deux couches de la boucle ditérent sur chaque point du triangle reliant le rectangle à l'écran, puis déterminez que dans la plage de triangle, appelez le programme VS pour calculer la couleur du point.
Maintenant, vous voulez écrire un dessin triangle de D3d 12. Vous ne pouvez pas le gérer sans mille lignes, mais maintenant nous n'avons besoin que des lignes suivantes:
# 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 ;
}Résultats en cours:
| nom de fichier | illustrer |
|---|---|
| Renderhelp.h | Le fichier d'implémentation de rendu, lorsqu'il est utilisé, il suffit de |
| Model.h | Chargement du modèle |
| sample_01_triangle.cpp | Exemple de dessin de triangles |
| sample_02_texture.cpp | Comment utiliser les textures, comment régler la matrice de la caméra, etc. |
| sample_03_box.cpp | Comment dessiner une boîte |
| sample_04_gouraud.cpp | Coloriage de galaude simple de la boîte |
| sample_05_model.cpp | Comment charger et dessiner un modèle |
| sample_06_normal.cpp | Améliorer les détails du modèle avec une carte normale |
| samptample_07_specular.cpp | Dessiner des points forts |
Il y a plus de dix ans, j'ai écrit un tutoriel de rendu doux MINI3D, qui a clairement expliqué les principes de base des rendus logiciels.
La méthode de mise en œuvre de ce projet est modélisée sur la méthode d'implémentation de l'équation des bords du GPU. La méthode de mise en œuvre de ce projet simule le GPU est relativement simple et intuitive, mais le calcul est très important et ne convient pas au CPU en temps réel, mais il convient au traitement parallèle brut du GPU.
Il y a de nombreux tutoriels pour mettre en œuvre des pipelines de rendu programmables sur Internet, mais beaucoup d'entre eux ont des problèmes. Par exemple, lorsque l'échantillonnage de texture, la conversion des coordonnées entières doit être arrondie, sinon la position de plusieurs sommets de la texture n'est pas suffisamment stable, et il y aura des signes de légèreté; . . .
Il existe de nombreux aspects très détaillés de la mise en œuvre du rendu.
Un autre est la lisibilité.
Le fichier principal RenderHelp.h de ce projet a plus de mille lignes au total, dont un tiers sont des annotations chinoises.
Les principes de base, j'ai expliqué dans l'article suivant:
Lors de la lecture, le code est essentiellement quelques bibliothèques d'outils devant elle, qui peuvent être lues à partir des 200 dernières lignes.
Si vous ne comprenez pas le code, vous pouvez poser une question dans le problème.