@@ -1036,36 +1036,24 @@ class Bitmap
1036
1036
// 着色器定义
1037
1037
// ---------------------------------------------------------------------
1038
1038
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 {
1054
1041
std::map<int , float > varying_float; // 浮点数 varying 列表
1055
1042
std::map<int , Vec2f> varying_vec2f; // 二维矢量 varying 列表
1056
1043
std::map<int , Vec3f> varying_vec3f; // 三维矢量 varying 列表
1057
1044
std::map<int , Vec4f> varying_vec4f; // 四维矢量 varying 列表
1058
1045
};
1059
1046
1060
1047
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;
1064
1052
1065
1053
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;
1069
1057
1070
1058
1071
1059
// ---------------------------------------------------------------------
@@ -1108,7 +1096,6 @@ class RenderHelp
1108
1096
delete [] _depth_buffer;
1109
1097
_depth_buffer= NULL ;
1110
1098
}
1111
- ClearVertex ();
1112
1099
_color_fg = 0xffffffff ;
1113
1100
_color_bg = 0xff191970 ;
1114
1101
}
@@ -1139,35 +1126,10 @@ class RenderHelp
1139
1126
}
1140
1127
}
1141
1128
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
-
1157
1129
// 设置 VS/PS 着色器函数
1158
1130
inline void SetVertexShader (VertexShader vs) { _vertex_shader = vs; }
1159
1131
inline void SetPixelShader (PixelShader ps) { _pixel_shader = ps; }
1160
1132
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
-
1171
1133
// 保存 FrameBuffer 到 BMP 文件
1172
1134
inline void SaveFile (const char *filename) { if (_frame_buffer) _frame_buffer->SaveFile (filename); }
1173
1135
@@ -1200,49 +1162,46 @@ class RenderHelp
1200
1162
1201
1163
// 绘制一个三角形,必须先 SetVertex/SetAttrib 设定好三个点坐标和属性
1202
1164
inline bool DrawPrimitive () {
1203
- if (_frame_buffer == NULL )
1165
+ if (_frame_buffer == NULL || _vertex_shader == NULL )
1204
1166
return false ;
1205
1167
1206
1168
// 顶点初始化
1207
1169
for (int k = 0 ; k < 3 ; k++) {
1208
1170
Vertex& vertex = _vertex[k];
1209
1171
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 ();
1212
1177
1213
- // 运行顶点着色程序
1214
- if (_vertex_shader) {
1215
- _vertex_shader (vertex.vs_input , vertex.ps_input );
1216
- }
1178
+ // 运行顶点着色程序,返回顶点坐标
1179
+ vertex.pos = _vertex_shader (k, vertex.context );
1217
1180
1218
1181
// 简单裁剪,任何一个顶点超过 CVV 就剔除
1219
- Vec4f& pos = vertex.ps_input .pos ;
1220
- float w = pos.w ;
1182
+ float w = vertex.pos .w ;
1221
1183
1222
1184
// 这里图简单,当一个点越界,立马放弃整个三角形,更精细的做法是
1223
1185
// 如果越界了就在齐次空间内进行裁剪,拆分为 0-2 个三角形然后继续
1224
1186
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;
1228
1193
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 ;
1235
1196
1236
1197
// 计算屏幕坐标
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 ;
1239
1200
1240
1201
// 整数屏幕坐标:加 0.5 的偏移取屏幕像素方格中心对齐
1241
1202
vertex.spi .x = (int )(vertex.spf .x + 0 .5f );
1242
1203
vertex.spi .y = (int )(vertex.spf .y + 0 .5f );
1243
1204
1244
- // printf("%d: (%d, %d)\n", k, vertex.spi.x, vertex.spi.y);
1245
-
1246
1205
// 更新外接矩形范围
1247
1206
if (k == 0 ) {
1248
1207
_min_x = _max_x = Between (0 , _fb_width - 1 , vertex.spi .x );
@@ -1254,16 +1213,6 @@ class RenderHelp
1254
1213
_min_y = Between (0 , _fb_height - 1 , Min (_min_y, vertex.spi .y ));
1255
1214
_max_y = Between (0 , _fb_height - 1 , Max (_max_y, vertex.spi .y ));
1256
1215
}
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;
1267
1216
}
1268
1217
1269
1218
// 绘制线框
@@ -1277,8 +1226,8 @@ class RenderHelp
1277
1226
if (_render_pixel == false ) return false ;
1278
1227
1279
1228
// 判断三角形朝向
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 ;
1282
1231
Vec4f normal = vector_cross (v01, v02);
1283
1232
1284
1233
// 使用 vtx 访问三个顶点,而不直接用 _vertex 访问,因为可能会调整顺序
@@ -1342,58 +1291,60 @@ class RenderHelp
1342
1291
b = b * (1 .0f / s);
1343
1292
c = c * (1 .0f / s);
1344
1293
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;
1351
1296
1352
1297
// 进行深度测试
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;
1355
1309
1356
- // 更新 w
1357
- float w = 1 . 0f / rw ;
1310
+ // 准备为当前像素的各项 varying 进行插值
1311
+ ShaderContext input ;
1358
1312
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 ;
1365
1316
1366
1317
// 插值各项 varying
1367
1318
for (auto const &it: i0.varying_float ) {
1368
1319
int key = it.first ;
1369
1320
float f0 = i0.varying_float [key];
1370
1321
float f1 = i1.varying_float [key];
1371
1322
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;
1373
1324
}
1374
1325
1375
1326
for (auto const &it: i0.varying_vec2f ) {
1376
1327
int key = it.first ;
1377
1328
const Vec2f& f0 = i0.varying_vec2f [key];
1378
1329
const Vec2f& f1 = i1.varying_vec2f [key];
1379
1330
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;
1381
1332
}
1382
1333
1383
1334
for (auto const &it: i0.varying_vec3f ) {
1384
1335
int key = it.first ;
1385
1336
const Vec3f& f0 = i0.varying_vec3f [key];
1386
1337
const Vec3f& f1 = i1.varying_vec3f [key];
1387
1338
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;
1389
1340
}
1390
1341
1391
1342
for (auto const &it: i0.varying_vec4f ) {
1392
1343
int key = it.first ;
1393
1344
const Vec4f& f0 = i0.varying_vec4f [key];
1394
1345
const Vec4f& f1 = i1.varying_vec4f [key];
1395
1346
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;
1397
1348
}
1398
1349
1399
1350
// 执行像素着色器
@@ -1422,10 +1373,11 @@ class RenderHelp
1422
1373
1423
1374
// 顶点结构体
1424
1375
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; // 整数屏幕坐标
1429
1381
};
1430
1382
1431
1383
protected:
0 commit comments