@@ -1036,36 +1036,24 @@ class Bitmap
10361036// 着色器定义
10371037// ---------------------------------------------------------------------
10381038
1039- // VertexShader 输入
1040- // 不同属性使用整数 key 进行访问
1041- struct VS_Input {
1042- Vec4f pos; // 顶点坐标
1043- std::map<int , float > attrib_float; // 浮点数属性列表
1044- std::map<int , Vec2f> attrib_vec2f; // 二维矢量属性列表
1045- std::map<int , Vec3f> attrib_vec3f; // 三维矢量属性列表
1046- std::map<int , Vec4f> attrib_vec4f; // 四维矢量属性列表
1047- };
1048-
1049-
1050- // PixelShader 输入,同时也是 VertexShader 的输出
1051- // 前面 VS 设置好 pos 和 varying 后,每次调用 PS 前会根据像素坐标进行插值
1052- struct PS_Input {
1053- Vec4f pos; // VS 输出的新坐标
1039+ // 着色器上下文,由 VS 设置,再由渲染器按像素逐点插值后,供 PS 读取
1040+ struct ShaderContext {
10541041 std::map<int , float > varying_float; // 浮点数 varying 列表
10551042 std::map<int , Vec2f> varying_vec2f; // 二维矢量 varying 列表
10561043 std::map<int , Vec3f> varying_vec3f; // 三维矢量 varying 列表
10571044 std::map<int , Vec4f> varying_vec4f; // 四维矢量 varying 列表
10581045};
10591046
10601047
1061- // 顶点着色器:输入 VS_Input,需要填充 PS_Input
1062- // 顶点着色器需要根据 VS_Input 的内容,设置好 PS_Input 的 pos
1063- typedef std::function<void (VS_Input &, PS_Input &)> VertexShader;
1048+ // 顶点着色器:因为是 C++ 编写,无需传递 attribute,传个 0-2 的顶点序号
1049+ // 着色器函数直接在外层根据序号读取响应数据即可,最后需要返回一个坐标 pos
1050+ // 各项 varying 设置到 output 里,由渲染器插值后传递给 PS
1051+ typedef std::function<Vec4f(int index, ShaderContext &output)> VertexShader;
10641052
10651053
1066- // 像素着色器:输入 PS_Input ,需要返回 Vec4f 类型的颜色
1067- // 三角形内每个点的 PS_Input 具体值会根据前面三个顶点的 PS_Input 插值得到
1068- typedef std::function<Vec4f(PS_Input & )> PixelShader;
1054+ // 像素着色器:输入 ShaderContext ,需要返回 Vec4f 类型的颜色
1055+ // 三角形内每个点的 input 具体值会根据前面三个顶点的 output 插值得到
1056+ typedef std::function<Vec4f(ShaderContext &input )> PixelShader;
10691057
10701058
10711059// ---------------------------------------------------------------------
@@ -1108,7 +1096,6 @@ class RenderHelp
11081096 delete [] _depth_buffer;
11091097 _depth_buffer= NULL ;
11101098 }
1111- ClearVertex ();
11121099 _color_fg = 0xffffffff ;
11131100 _color_bg = 0xff191970 ;
11141101 }
@@ -1139,35 +1126,10 @@ class RenderHelp
11391126 }
11401127 }
11411128
1142- // 清空顶点的 attrib/varying
1143- inline void ClearVertex () {
1144- for (int i = 0 ; i < 3 ; i++) {
1145- Vertex &vertex = _vertex[i];
1146- vertex.vs_input .attrib_float .clear ();
1147- vertex.vs_input .attrib_vec4f .clear ();
1148- vertex.vs_input .attrib_vec3f .clear ();
1149- vertex.vs_input .attrib_vec2f .clear ();
1150- vertex.ps_input .varying_float .clear ();
1151- vertex.ps_input .varying_vec4f .clear ();
1152- vertex.ps_input .varying_vec3f .clear ();
1153- vertex.ps_input .varying_vec2f .clear ();
1154- }
1155- }
1156-
11571129 // 设置 VS/PS 着色器函数
11581130 inline void SetVertexShader (VertexShader vs) { _vertex_shader = vs; }
11591131 inline void SetPixelShader (PixelShader ps) { _pixel_shader = ps; }
11601132
1161- // 设置顶点坐标,id 是顶点下标,范围是 [0, 2]
1162- inline void SetVertex (int id, const Vec4f& pos) { _vertex[id].vs_input .pos = pos; }
1163- inline void SetVertex (int id, const Vec3f& pos) { SetVertex (id, pos.xyz1 ()); }
1164-
1165- // 设置顶点属性,id 是顶点下表,name 为属性列表的 key
1166- inline void SetAttrib (int id, int name, float x) { _vertex[id].vs_input .attrib_float [name] = x; }
1167- inline void SetAttrib (int id, int name, const Vec2f& v) { _vertex[id].vs_input .attrib_vec2f [name] = v; }
1168- inline void SetAttrib (int id, int name, const Vec3f& v) { _vertex[id].vs_input .attrib_vec3f [name] = v; }
1169- inline void SetAttrib (int id, int name, const Vec4f& v) { _vertex[id].vs_input .attrib_vec4f [name] = v; }
1170-
11711133 // 保存 FrameBuffer 到 BMP 文件
11721134 inline void SaveFile (const char *filename) { if (_frame_buffer) _frame_buffer->SaveFile (filename); }
11731135
@@ -1200,49 +1162,46 @@ class RenderHelp
12001162
12011163 // 绘制一个三角形,必须先 SetVertex/SetAttrib 设定好三个点坐标和属性
12021164 inline bool DrawPrimitive () {
1203- if (_frame_buffer == NULL )
1165+ if (_frame_buffer == NULL || _vertex_shader == NULL )
12041166 return false ;
12051167
12061168 // 顶点初始化
12071169 for (int k = 0 ; k < 3 ; k++) {
12081170 Vertex& vertex = _vertex[k];
12091171
1210- // 先复制一遍坐标,vertex shader 不设置的话,就用这个默认值
1211- vertex.ps_input .pos = vertex.vs_input .pos ;
1172+ // 清空上下文 varying 列表
1173+ vertex.context .varying_float .clear ();
1174+ vertex.context .varying_vec2f .clear ();
1175+ vertex.context .varying_vec3f .clear ();
1176+ vertex.context .varying_vec4f .clear ();
12121177
1213- // 运行顶点着色程序
1214- if (_vertex_shader) {
1215- _vertex_shader (vertex.vs_input , vertex.ps_input );
1216- }
1178+ // 运行顶点着色程序,返回顶点坐标
1179+ vertex.pos = _vertex_shader (k, vertex.context );
12171180
12181181 // 简单裁剪,任何一个顶点超过 CVV 就剔除
1219- Vec4f& pos = vertex.ps_input .pos ;
1220- float w = pos.w ;
1182+ float w = vertex.pos .w ;
12211183
12221184 // 这里图简单,当一个点越界,立马放弃整个三角形,更精细的做法是
12231185 // 如果越界了就在齐次空间内进行裁剪,拆分为 0-2 个三角形然后继续
12241186 if (w == 0 .0f ) return false ;
1225- if (pos.z < 0 .0f || pos.z > w) return false ;
1226- if (pos.x < -w || pos.x > w) return false ;
1227- if (pos.y < -w || pos.y > w) return false ;
1187+ if (vertex.pos .z < 0 .0f || vertex.pos .z > w) return false ;
1188+ if (vertex.pos .x < -w || vertex.pos .x > w) return false ;
1189+ if (vertex.pos .y < -w || vertex.pos .y > w) return false ;
1190+
1191+ // 计算 w 的倒数:Reciprocal of the Homogeneous W
1192+ vertex.rhw = 1 .0f / w;
12281193
1229- // 顶点所坐标除以 w
1230- float reciprocal_w = 1 .0f / w;
1231- pos.w = reciprocal_w; // pos.w 保存 w 的倒数
1232- pos.x *= reciprocal_w;
1233- pos.y *= reciprocal_w;
1234- pos.z *= reciprocal_w;
1194+ // 齐次坐标空间 /w 归一化到单位体积 cvv
1195+ vertex.pos *= vertex.rhw ;
12351196
12361197 // 计算屏幕坐标
1237- vertex.spf .x = (pos.x + 1 .0f ) * _fb_width * 0 .5f ;
1238- vertex.spf .y = (1 .0f - pos.y ) * _fb_height * 0 .5f ;
1198+ vertex.spf .x = (vertex. pos .x + 1 .0f ) * _fb_width * 0 .5f ;
1199+ vertex.spf .y = (1 .0f - vertex. pos .y ) * _fb_height * 0 .5f ;
12391200
12401201 // 整数屏幕坐标:加 0.5 的偏移取屏幕像素方格中心对齐
12411202 vertex.spi .x = (int )(vertex.spf .x + 0 .5f );
12421203 vertex.spi .y = (int )(vertex.spf .y + 0 .5f );
12431204
1244- // printf("%d: (%d, %d)\n", k, vertex.spi.x, vertex.spi.y);
1245-
12461205 // 更新外接矩形范围
12471206 if (k == 0 ) {
12481207 _min_x = _max_x = Between (0 , _fb_width - 1 , vertex.spi .x );
@@ -1254,16 +1213,6 @@ class RenderHelp
12541213 _min_y = Between (0 , _fb_height - 1 , Min (_min_y, vertex.spi .y ));
12551214 _max_y = Between (0 , _fb_height - 1 , Max (_max_y, vertex.spi .y ));
12561215 }
1257-
1258- // 所有 varying 提前除以 w,为线性插值做准备
1259- for (auto &it: vertex.ps_input .varying_float )
1260- it.second = it.second * reciprocal_w;
1261- for (auto &it: vertex.ps_input .varying_vec2f )
1262- it.second = it.second * reciprocal_w;
1263- for (auto &it: vertex.ps_input .varying_vec3f )
1264- it.second = it.second * reciprocal_w;
1265- for (auto &it: vertex.ps_input .varying_vec4f )
1266- it.second = it.second * reciprocal_w;
12671216 }
12681217
12691218 // 绘制线框
@@ -1277,8 +1226,8 @@ class RenderHelp
12771226 if (_render_pixel == false ) return false ;
12781227
12791228 // 判断三角形朝向
1280- Vec4f v01 = _vertex[1 ].ps_input . pos - _vertex[0 ]. ps_input .pos ;
1281- Vec4f v02 = _vertex[2 ].ps_input . pos - _vertex[0 ]. ps_input .pos ;
1229+ Vec4f v01 = _vertex[1 ].pos - _vertex[0 ].pos ;
1230+ Vec4f v02 = _vertex[2 ].pos - _vertex[0 ].pos ;
12821231 Vec4f normal = vector_cross (v01, v02);
12831232
12841233 // 使用 vtx 访问三个顶点,而不直接用 _vertex 访问,因为可能会调整顺序
@@ -1342,58 +1291,60 @@ class RenderHelp
13421291 b = b * (1 .0f / s);
13431292 c = c * (1 .0f / s);
13441293
1345- PS_Input& i0 = vtx[0 ]->ps_input ;
1346- PS_Input& i1 = vtx[1 ]->ps_input ;
1347- PS_Input& i2 = vtx[2 ]->ps_input ;
1348-
1349- // 插值得到当前点的 1/w,先前保存的 pos.w 已经是 w 的倒数了
1350- float rw = a * i0.pos .w + b * i1.pos .w + c * i2.pos .w ;
1294+ // 计算当前点的 1/w,因 1/w 和屏幕空间呈线性关系,故直接重心插值
1295+ float rhw = vtx[0 ]->rhw * a + vtx[1 ]->rhw * b + vtx[2 ]->rhw * c;
13511296
13521297 // 进行深度测试
1353- if (rw < _depth_buffer[cy][cx]) continue ;
1354- _depth_buffer[cy][cx] = rw;
1298+ if (rhw < _depth_buffer[cy][cx]) continue ;
1299+ _depth_buffer[cy][cx] = rhw;
1300+
1301+ // 还原当前像素的 w
1302+ float w = 1 .0f / ((rhw != 0 .0f )? rhw : 1 .0f );
1303+
1304+ // 计算三个顶点插值 varying 的系数
1305+ // 先除以各自顶点的 w 然后进行屏幕空间插值然后再乘以当前 w
1306+ float k0 = vtx[0 ]->rhw * a * w;
1307+ float k1 = vtx[1 ]->rhw * b * w;
1308+ float k2 = vtx[2 ]->rhw * c * w;
13551309
1356- // 更新 w
1357- float w = 1 . 0f / rw ;
1310+ // 准备为当前像素的各项 varying 进行插值
1311+ ShaderContext input ;
13581312
1359- // 初始化像素着色器输入
1360- PS_Input input;
1361- input.pos .w = w;
1362- input.pos .x = (a * i0.pos .x + b * i1.pos .x + c * i2.pos .x ) * w;
1363- input.pos .y = (a * i0.pos .y + b * i1.pos .y + c * i2.pos .y ) * w;
1364- input.pos .z = (a * i0.pos .z + b * i1.pos .z + c * i2.pos .z ) * w;
1313+ ShaderContext& i0 = vtx[0 ]->context ;
1314+ ShaderContext& i1 = vtx[1 ]->context ;
1315+ ShaderContext& i2 = vtx[2 ]->context ;
13651316
13661317 // 插值各项 varying
13671318 for (auto const &it: i0.varying_float ) {
13681319 int key = it.first ;
13691320 float f0 = i0.varying_float [key];
13701321 float f1 = i1.varying_float [key];
13711322 float f2 = i2.varying_float [key];
1372- input.varying_float [key] = (a * f0 + b * f1 + c * f2) * w ;
1323+ input.varying_float [key] = k0 * f0 + k1 * f1 + k2 * f2;
13731324 }
13741325
13751326 for (auto const &it: i0.varying_vec2f ) {
13761327 int key = it.first ;
13771328 const Vec2f& f0 = i0.varying_vec2f [key];
13781329 const Vec2f& f1 = i1.varying_vec2f [key];
13791330 const Vec2f& f2 = i2.varying_vec2f [key];
1380- input.varying_vec2f [key] = (a * f0 + b * f1 + c * f2) * w ;
1331+ input.varying_vec2f [key] = k0 * f0 + k1 * f1 + k2 * f2;
13811332 }
13821333
13831334 for (auto const &it: i0.varying_vec3f ) {
13841335 int key = it.first ;
13851336 const Vec3f& f0 = i0.varying_vec3f [key];
13861337 const Vec3f& f1 = i1.varying_vec3f [key];
13871338 const Vec3f& f2 = i2.varying_vec3f [key];
1388- input.varying_vec3f [key] = (a * f0 + b * f1 + c * f2) * w ;
1339+ input.varying_vec3f [key] = k0 * f0 + k1 * f1 + k2 * f2;
13891340 }
13901341
13911342 for (auto const &it: i0.varying_vec4f ) {
13921343 int key = it.first ;
13931344 const Vec4f& f0 = i0.varying_vec4f [key];
13941345 const Vec4f& f1 = i1.varying_vec4f [key];
13951346 const Vec4f& f2 = i2.varying_vec4f [key];
1396- input.varying_vec4f [key] = (a * f0 + b * f1 + c * f2) * w ;
1347+ input.varying_vec4f [key] = k0 * f0 + k1 * f1 + k2 * f2;
13971348 }
13981349
13991350 // 执行像素着色器
@@ -1422,10 +1373,11 @@ class RenderHelp
14221373
14231374 // 顶点结构体
14241375 struct Vertex {
1425- VS_Input vs_input; // VS 输入
1426- PS_Input ps_input; // PS 输入,同时也是 VS 输出
1427- Vec2f spf; // 浮点数屏幕坐标
1428- Vec2i spi; // 整数屏幕坐标
1376+ ShaderContext context; // 上下文
1377+ float rhw; // w 的倒数
1378+ Vec4f pos; // 坐标
1379+ Vec2f spf; // 浮点数屏幕坐标
1380+ Vec2i spi; // 整数屏幕坐标
14291381 };
14301382
14311383protected:
0 commit comments