Skip to content

Commit ffe0d75

Browse files
committed
Optimize perspective correction, add helper func, simplify code
Signed-off-by: ZhouFANG <indevn@outlook.com>
1 parent 258607a commit ffe0d75

7 files changed

Lines changed: 188 additions & 184 deletions

File tree

src/include/rasterizer.hpp

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
#include "config.h"
55
#include "shader.hpp"
6-
#include "vertex_soa.hpp"
6+
#include "vertex.hpp"
77

88
namespace simple_renderer {
99

@@ -36,13 +36,25 @@ class Rasterizer {
3636
private:
3737
size_t width_, height_;
3838

39+
// 透视矫正结果
40+
struct PerspectiveCorrectionResult {
41+
Vector3f corrected_barycentric;
42+
float interpolated_z;
43+
};
44+
45+
// 透视矫正helper函数
46+
PerspectiveCorrectionResult PerformPerspectiveCorrection(
47+
float w0, float w1, float w2,
48+
float z0, float z1, float z2,
49+
const Vector3f& original_barycentric) const;
50+
3951
template <typename T>
4052
T Interpolate(const T& v0, const T& v1, const T& v2,
41-
const Vector3f& barycentric_coord);
53+
const Vector3f& barycentric_coord) const;
4254

4355
Color InterpolateColor(const Color& color0, const Color& color1,
4456
const Color& color2,
45-
const Vector3f& barycentric_coord);
57+
const Vector3f& barycentric_coord) const;
4658

4759
std::pair<bool, Vector3f> GetBarycentricCoord(const Vector3f& p0,
4860
const Vector3f& p1,

src/include/renderer.h

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include <cstdint>
2121
#include <functional>
2222
#include <span>
23+
#include <string>
2324

2425
#include "buffer.hpp"
2526
#include "light.h"
@@ -38,6 +39,10 @@ enum class RenderingMode {
3839
DEFERRED // 延迟渲染模式 - 经典GPU管线教学模拟
3940
};
4041

42+
// RenderingMode辅助函数声明
43+
std::string RenderingModeToString(RenderingMode mode);
44+
std::string RenderingModeToDetailedString(RenderingMode mode);
45+
4146

4247
// SoA 版 tile 列表中的三角形引用(仅存索引与材质指针)
4348
struct TriangleRef {
@@ -94,11 +99,15 @@ class SimpleRenderer {
9499
const size_t width_;
95100
LogSystem log_system_;
96101
RenderingMode current_mode_; // 当前渲染模式
97-
bool early_z_enabled_; // Early-Z优化开关
102+
bool is_early_z_enabled_; // Early-Z优化开关
98103

99104
std::shared_ptr<Shader> shader_;
100105
std::shared_ptr<Rasterizer> rasterizer_;
101106

107+
// Rendering constants
108+
static constexpr float kMinWValue = 1e-6f; // W分量检查阈值(避免除零)
109+
static constexpr size_t kDefaultTileSize = 64; // 默认Tile大小(64x64像素)
110+
102111
/**
103112
* 执行绘制管线
104113
* @param model 模型
@@ -125,13 +134,6 @@ class SimpleRenderer {
125134
const std::vector<Vertex> &processedVertices,
126135
uint32_t *buffer);
127136

128-
/**
129-
* Tile-based光栅化渲染
130-
* @param model 模型
131-
* @param processedVertices 已处理的顶点
132-
* @param buffer 输出缓冲区
133-
* @return 渲染统计信息
134-
*/
135137
struct TileRenderStats {
136138
double setup_ms;
137139
double binning_ms;
@@ -167,10 +169,8 @@ class SimpleRenderer {
167169
const std::vector<Vertex> &processedVertices,
168170
uint32_t *buffer);
169171

170-
171172
private:
172173

173-
174174
// SoA 版本的 Triangle-Tile binning(两遍计数 + reserve)
175175
void TriangleTileBinning(
176176
const Model &model,
@@ -191,7 +191,6 @@ class SimpleRenderer {
191191
bool use_early_z = false,
192192
std::vector<Fragment>* scratch_fragments = nullptr);
193193

194-
195194
/**
196195
* 透视除法 - 将裁剪空间坐标转换为归一化设备坐标(NDC)
197196
* @param vertex 裁剪空间坐标的顶点
@@ -206,6 +205,21 @@ class SimpleRenderer {
206205
*/
207206
Vertex ViewportTransformation(const Vertex &vertex);
208207

208+
/**
209+
* 打印传统渲染性能统计信息
210+
*/
211+
void PrintTraditionalStats(double vertex_ms, const RenderStats& stats) const;
212+
213+
/**
214+
* 打印基于Tile渲染性能统计信息
215+
*/
216+
void PrintTileBasedStats(double vertex_ms, const TileRenderStats& stats) const;
217+
218+
/**
219+
* 打印延迟渲染性能统计信息
220+
*/
221+
void PrintDeferredStats(double vertex_ms, const DeferredRenderStats& stats) const;
222+
209223
};
210224
} // namespace simple_renderer
211225

src/include/vertex.hpp

Lines changed: 30 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
#ifndef SIMPLERENDER_SRC_INCLUDE_VERTEX_HPP_
22
#define SIMPLERENDER_SRC_INCLUDE_VERTEX_HPP_
33

4+
#include <vector>
5+
#include <optional>
6+
47
#include <math.hpp>
58

69
#include "color.h"
@@ -31,18 +34,13 @@ class Vertex {
3134
// 析构函数
3235
~Vertex() = default;
3336

34-
// Constructor with parameters 带参数的构造函数
35-
explicit Vertex(const Vector4f& pos, const Vector3f& norm,
36-
const Vector2f& tex, const Color& color_)
37-
: position_(pos), normal_(norm), texCoords_(tex), color_(color_),
38-
clip_position_(pos), has_clip_position_(false) {}
39-
40-
// 扩展构造函数:包含裁剪空间坐标
37+
// Constructor with parameters: optional clip space coordinate
38+
// 带参数的构造函数:可选的裁剪空间坐标
4139
explicit Vertex(const Vector4f& pos, const Vector3f& norm,
4240
const Vector2f& tex, const Color& color_,
43-
const Vector4f& clip_pos)
41+
std::optional<Vector4f> clip_pos = std::nullopt)
4442
: position_(pos), normal_(norm), texCoords_(tex), color_(color_),
45-
clip_position_(clip_pos), has_clip_position_(true) {}
43+
clip_position_(clip_pos) {}
4644

4745
// Transform the vertex with a matrix 使用矩阵变换顶点
4846
void transform(const Matrix4f& matrix) { position_ = matrix * position_; }
@@ -55,8 +53,8 @@ class Vertex {
5553
[[nodiscard]] inline Color GetColor() const { return color_; }
5654

5755
// 扩展坐标访问
58-
[[nodiscard]] inline Vector4f GetClipPosition() const { return clip_position_; }
59-
[[nodiscard]] inline bool HasClipPosition() const { return has_clip_position_; }
56+
[[nodiscard]] inline std::optional<Vector4f> GetClipPosition() const { return clip_position_; }
57+
[[nodiscard]] inline bool HasClipPosition() const { return clip_position_.has_value(); }
6058

6159
private:
6260
Vector4f position_; // 3D position, 3D顶点坐标
@@ -65,8 +63,7 @@ class Vertex {
6563
Color color_;
6664

6765
// 扩展坐标用于裁剪优化
68-
Vector4f clip_position_; // 裁剪空间坐标 (用于视锥体裁剪)
69-
bool has_clip_position_; // 是否包含裁剪坐标
66+
std::optional<Vector4f> clip_position_; // 裁剪空间坐标 (用于视锥体裁剪)
7067
};
7168

7269
inline Vertex operator*(const Matrix4f& matrix, const Vertex& vertex) {
@@ -75,6 +72,26 @@ inline Vertex operator*(const Matrix4f& matrix, const Vertex& vertex) {
7572
vertex.GetColor());
7673
}
7774

75+
// Minimal SoA layout for TBR pipeline
76+
struct VertexSoA {
77+
// 屏幕空间坐标(视口变换后)
78+
std::vector<Vector4f> pos_screen; // screen space position (x,y,z,w)
79+
// 裁剪空间坐标(用于视锥体剔除):clip = MVP * pos
80+
std::vector<Vector4f> pos_clip;
81+
std::vector<Vector3f> normal;
82+
std::vector<Vector2f> uv;
83+
std::vector<Color> color;
84+
85+
inline size_t size() const { return pos_screen.size(); }
86+
inline void resize(size_t n) {
87+
pos_screen.resize(n);
88+
pos_clip.resize(n);
89+
normal.resize(n);
90+
uv.resize(n);
91+
color.resize(n);
92+
}
93+
};
94+
7895
} // namespace simple_renderer
7996

8097
#endif

src/include/vertex_soa.hpp

Lines changed: 0 additions & 33 deletions
This file was deleted.

src/rasterizer.cpp

Lines changed: 49 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -50,24 +50,13 @@ std::vector<Fragment> Rasterizer::Rasterize(const Vertex& v0, const Vertex& v1,
5050
}
5151

5252
// 透视矫正插值
53-
// 1. 获取三个顶点的1/w值
54-
float w0_inv = v0.GetPosition().w;
55-
float w1_inv = v1.GetPosition().w;
56-
float w2_inv = v2.GetPosition().w;
53+
auto perspective_result = PerformPerspectiveCorrection(
54+
v0.GetPosition().w, v1.GetPosition().w, v2.GetPosition().w,
55+
v0.GetPosition().z, v1.GetPosition().z, v2.GetPosition().z,
56+
barycentric_coord);
5757

58-
// 2. 插值1/w
59-
float w_inv_interpolated = Interpolate(w0_inv, w1_inv, w2_inv, barycentric_coord);
60-
61-
// 3. 计算透视矫正的重心坐标
62-
Vector3f corrected_bary(
63-
barycentric_coord.x * w0_inv / w_inv_interpolated,
64-
barycentric_coord.y * w1_inv / w_inv_interpolated,
65-
barycentric_coord.z * w2_inv / w_inv_interpolated
66-
);
67-
68-
// 4. 使用矫正的重心坐标进行插值
69-
auto z = Interpolate(v0.GetPosition().z, v1.GetPosition().z,
70-
v2.GetPosition().z, corrected_bary);
58+
const Vector3f& corrected_bary = perspective_result.corrected_barycentric;
59+
float z = perspective_result.interpolated_z;
7160

7261

7362
Fragment fragment;
@@ -114,39 +103,34 @@ void Rasterizer::RasterizeTo(const VertexSoA& soa, size_t i0, size_t i1, size_t
114103
float maxy = std::min(float(height_ - 1), bboxMax.y);
115104

116105
// 与外部提供的裁剪区域相交(半开区间) -> 闭区间扫描
117-
int sx = std::max(x0, int(std::floor(minx)));
118-
int sy = std::max(y0, int(std::floor(miny)));
119-
int ex = std::min(x1 - 1, int(std::floor(maxx)));
120-
int ey = std::min(y1 - 1, int(std::floor(maxy)));
106+
int sx = std::max(x0, static_cast<int>(std::floor(minx)));
107+
int sy = std::max(y0, static_cast<int>(std::floor(miny)));
108+
int ex = std::min(x1 - 1, static_cast<int>(std::floor(maxx)));
109+
int ey = std::min(y1 - 1, static_cast<int>(std::floor(maxy)));
121110
if (sx > ex || sy > ey) return;
122111

123-
// 透视矫正插值依赖 w
124-
float w0_inv = p0.w;
125-
float w1_inv = p1.w;
126-
float w2_inv = p2.w;
127-
128112
for (int x = sx; x <= ex; ++x) {
129113
for (int y = sy; y <= ey; ++y) {
130114
auto [is_inside, bary] = GetBarycentricCoord(
131115
Vector3f(p0.x, p0.y, p0.z), Vector3f(p1.x, p1.y, p1.z), Vector3f(p2.x, p2.y, p2.z),
132116
Vector3f(static_cast<float>(x), static_cast<float>(y), 0));
133117
if (!is_inside) continue;
134118

135-
float w_inv_interp = Interpolate(w0_inv, w1_inv, w2_inv, bary);
136-
Vector3f cb(
137-
bary.x * w0_inv / w_inv_interp,
138-
bary.y * w1_inv / w_inv_interp,
139-
bary.z * w2_inv / w_inv_interp);
119+
// 透视矫正插值
120+
auto perspective_result = PerformPerspectiveCorrection(
121+
p0.w, p1.w, p2.w,
122+
p0.z, p1.z, p2.z,
123+
bary);
124+
125+
const Vector3f& corrected_bary = perspective_result.corrected_barycentric;
126+
float z = perspective_result.interpolated_z;
140127

141-
float z = Interpolate(p0.z, p1.z, p2.z, cb);
142-
143-
Fragment frag;
128+
Fragment frag; // Note: material 指针由调用方填写
144129
frag.screen_coord = {x, y};
145-
frag.normal = Interpolate(soa.normal[i0], soa.normal[i1], soa.normal[i2], cb);
146-
frag.uv = Interpolate(soa.uv[i0], soa.uv[i1], soa.uv[i2], cb);
147-
frag.color = InterpolateColor(soa.color[i0], soa.color[i1], soa.color[i2], cb);
130+
frag.normal = Interpolate(soa.normal[i0], soa.normal[i1], soa.normal[i2], corrected_bary);
131+
frag.uv = Interpolate(soa.uv[i0], soa.uv[i1], soa.uv[i2], corrected_bary);
132+
frag.color = InterpolateColor(soa.color[i0], soa.color[i1], soa.color[i2], corrected_bary);
148133
frag.depth = z;
149-
// material 指针由调用方填写
150134

151135
out.push_back(frag);
152136
}
@@ -182,14 +166,14 @@ std::pair<bool, Vector3f> Rasterizer::GetBarycentricCoord(const Vector3f& p0,
182166

183167
template <typename T>
184168
T Rasterizer::Interpolate(const T& v0, const T& v1, const T& v2,
185-
const Vector3f& barycentric_coord) {
169+
const Vector3f& barycentric_coord) const {
186170
return v0 * barycentric_coord.x + v1 * barycentric_coord.y +
187171
v2 * barycentric_coord.z;
188172
}
189173

190174
Color Rasterizer::InterpolateColor(const Color& color0, const Color& color1,
191175
const Color& color2,
192-
const Vector3f& barycentric_coord) {
176+
const Vector3f& barycentric_coord) const {
193177
auto color_r = FloatToUint8_t(
194178
static_cast<float>(color0[Color::kColorIndexRed]) * barycentric_coord.x +
195179
static_cast<float>(color1[Color::kColorIndexRed]) * barycentric_coord.y +
@@ -208,6 +192,31 @@ Color Rasterizer::InterpolateColor(const Color& color0, const Color& color1,
208192
return Color(color_r, color_g, color_b);
209193
}
210194

195+
// 透视矫正helper函数:在透视投影下,1/w 在屏幕空间中是线性的// 因此需要先对 1/w 进行插值,再用结果矫正其他属性
196+
Rasterizer::PerspectiveCorrectionResult Rasterizer::PerformPerspectiveCorrection(
197+
float w0, float w1, float w2,
198+
float z0, float z1, float z2,
199+
const Vector3f& original_barycentric) const {
200+
201+
// 1. 插值 1/w (注意:这里传入的w0,w1,w2是原始的w值,需要先求倒数)
202+
float w0_inv = 1.0f / w0;
203+
float w1_inv = 1.0f / w1;
204+
float w2_inv = 1.0f / w2;
205+
float w_inv_interpolated = Interpolate(w0_inv, w1_inv, w2_inv, original_barycentric);
206+
207+
// 2. 计算透视矫正的重心坐标
208+
Vector3f corrected_barycentric(
209+
original_barycentric.x * w0_inv / w_inv_interpolated,
210+
original_barycentric.y * w1_inv / w_inv_interpolated,
211+
original_barycentric.z * w2_inv / w_inv_interpolated
212+
);
213+
214+
// 3. 使用矫正的重心坐标插值深度值
215+
float interpolated_z = Interpolate(z0, z1, z2, corrected_barycentric);
216+
217+
return {corrected_barycentric, interpolated_z};
218+
}
219+
211220
// Calculate the normal vector based on the vertices
212221
// 根据顶点计算法向量
213222
Vector3f Rasterizer::CalculateNormal(const Vector3f& v0, const Vector3f& v1,

0 commit comments

Comments
 (0)