@@ -81,159 +81,6 @@ std::vector<Fragment> Rasterizer::Rasterize(const Vertex& v0, const Vertex& v1,
8181 return fragments;
8282}
8383
84- void Rasterizer::RasterizeTo (const Vertex& v0, const Vertex& v1, const Vertex& v2,
85- int x0, int y0, int x1, int y1,
86- std::vector<Fragment>& out) {
87- // 获取三角形的最小 box(屏幕空间)
88- const Vector4f p0 = v0.GetPosition ();
89- const Vector4f p1 = v1.GetPosition ();
90- const Vector4f p2 = v2.GetPosition ();
91-
92- Vector2f a (p0.x , p0.y );
93- Vector2f b (p1.x , p1.y );
94- Vector2f c (p2.x , p2.y );
95-
96- Vector2f bboxMin = Vector2f{std::min ({a.x , b.x , c.x }), std::min ({a.y , b.y , c.y })};
97- Vector2f bboxMax = Vector2f{std::max ({a.x , b.x , c.x }), std::max ({a.y , b.y , c.y })};
98-
99- // Clamp 到屏幕尺寸
100- float minx = std::max (0 .0f , bboxMin.x );
101- float miny = std::max (0 .0f , bboxMin.y );
102- float maxx = std::min (float (width_ - 1 ), bboxMax.x );
103- float maxy = std::min (float (height_ - 1 ), bboxMax.y );
104-
105- // 与外部提供的裁剪区域相交(半开区间) -> 闭区间扫描
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)));
110- if (sx > ex || sy > ey) return ;
111-
112- for (int x = sx; x <= ex; ++x) {
113- for (int y = sy; y <= ey; ++y) {
114- auto [is_inside, bary] = GetBarycentricCoord (
115- Vector3f (p0.x , p0.y , p0.z ), Vector3f (p1.x , p1.y , p1.z ), Vector3f (p2.x , p2.y , p2.z ),
116- Vector3f (static_cast <float >(x), static_cast <float >(y), 0 ));
117- if (!is_inside) continue ;
118-
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 ;
127-
128- Fragment frag; // material 指针由调用方填写
129- frag.screen_coord = {x, y};
130- frag.normal = Interpolate (v0.GetNormal (), v1.GetNormal (), v2.GetNormal (), corrected_bary);
131- frag.uv = Interpolate (v0.GetTexCoords (), v1.GetTexCoords (), v2.GetTexCoords (), corrected_bary);
132- frag.color = InterpolateColor (v0.GetColor (), v1.GetColor (), v2.GetColor (), corrected_bary);
133- frag.depth = z;
134-
135- out.push_back (frag);
136- }
137- }
138- }
139-
140- void Rasterizer::RasterizeTo (const VertexSoA& soa, size_t i0, size_t i1, size_t i2,
141- int x0, int y0, int x1, int y1,
142- std::vector<Fragment>& out) {
143- // 读取三顶点的屏幕空间位置
144- const Vector4f& p0 = soa.pos_screen [i0];
145- const Vector4f& p1 = soa.pos_screen [i1];
146- const Vector4f& p2 = soa.pos_screen [i2];
147-
148- // 为BarycentricCoord预构造Vec3f,避免循环内重复构造
149- const Vector3f sp0 (p0.x , p0.y , p0.z );
150- const Vector3f sp1 (p1.x , p1.y , p1.z );
151- const Vector3f sp2 (p2.x , p2.y , p2.z );
152-
153- // 计算屏幕空间AABB包围盒
154- const float minx_f = std::max (0 .0f , std::min ({p0.x , p1.x , p2.x }));
155- const float miny_f = std::max (0 .0f , std::min ({p0.y , p1.y , p2.y }));
156- const float maxx_f = std::min (float (width_ - 1 ), std::max ({p0.x , p1.x , p2.x }));
157- const float maxy_f = std::min (float (height_ - 1 ), std::max ({p0.y , p1.y , p2.y }));
158-
159- // 与外部提供的裁剪区域相交(半开区间) -> 闭区间扫描
160- int sx = std::max (x0, static_cast <int >(std::floor (minx_f)));
161- int sy = std::max (y0, static_cast <int >(std::floor (miny_f)));
162- int ex = std::min (x1 - 1 , static_cast <int >(std::floor (maxx_f)));
163- int ey = std::min (y1 - 1 , static_cast <int >(std::floor (maxy_f)));
164- if (sx > ex || sy > ey) return ;
165-
166- // 预计算边函数系数:E(x,y) = A*x + B*y + C
167- // 使用相对坐标的边函数定义,避免大常数项导致的数值不稳定
168- // 如使用绝对形式Ax+By+C会由于常数C的量级过大,造成浮点抵消,有效位丢失不稳定
169- auto cross2 = [](float ax, float ay, float bx, float by) {
170- return ax * by - ay * bx;
171- };
172- // 边向量
173- const float e01x = p1.x - p0.x , e01y = p1.y - p0.y ; // (p0->p1)
174- const float e12x = p2.x - p1.x , e12y = p2.y - p1.y ; // (p1->p2)
175- const float e20x = p0.x - p2.x , e20y = p0.y - p2.y ; // (p2->p0)
176-
177- // 有向面积(两倍),用相对面积定义:area2 = cross(p1 - p0, p2 - p0)
178- float area2 = cross2 (e01x, e01y, p2.x - p0.x , p2.y - p0.y );
179- if (std::abs (area2) < 1e-6f ) return ; // 退化三角形
180- const float inv_area2 = 1 .0f / area2;
181- const bool positive = (area2 > 0 .0f );
182-
183- // 行优先遍历:有利于 cache 与向量化
184- #pragma omp simd
185- for (int y = sy; y <= ey; ++y) {
186- const float yf = static_cast <float >(y);
187-
188- // 注意:此处存在对 out.push_back 的写入,属于有副作用操作,不适合使用
189- // omp simd 进行强制向量化,否则可能导致不符合预期的行为(如周期性伪影)。
190- // 先保持标量内层,后续如切换为“直写像素回调”再考虑安全的 SIMD 化。
191- for (int x = sx; x <= ex; ++x) {
192- const float xf = static_cast <float >(x);
193-
194- // 相对坐标边函数:
195- // E01(p) = cross(p1 - p0, p - p0)
196- // E12(p) = cross(p2 - p1, p - p1)
197- // E20(p) = cross(p0 - p2, p - p2)
198- const float E01 = cross2 (e01x, e01y, xf - p0.x , yf - p0.y );
199- const float E12 = cross2 (e12x, e12y, xf - p1.x , yf - p1.y );
200- const float E20 = cross2 (e20x, e20y, xf - p2.x , yf - p2.y );
201-
202- // 半空间测试(根据朝向选择符号)
203- const bool inside = positive ? (E01 >= 0 .0f && E12 >= 0 .0f && E20 >= 0 .0f )
204- : (E01 <= 0 .0f && E12 <= 0 .0f && E20 <= 0 .0f );
205- if (!inside) continue ;
206-
207- // 重心权重映射:
208- // b0 对应 v0,取与对边 (v1,v2) 的子面积 → E12
209- // b1 对应 v1 → E20
210- // b2 对应 v2 → E01
211- const float b0 = E12 * inv_area2;
212- const float b1 = E20 * inv_area2;
213- const float b2 = E01 * inv_area2;
214- const Vector3f bary (b0, b1, b2);
215-
216- // 透视矫正插值
217- auto perspective_result = PerformPerspectiveCorrection (
218- p0.w , p1.w , p2.w ,
219- p0.z , p1.z , p2.z ,
220- bary);
221-
222- const Vector3f& corrected_bary = perspective_result.corrected_barycentric ;
223- const float z = perspective_result.interpolated_z ;
224-
225- Fragment frag; // Note: material 指针由调用方填写
226- frag.screen_coord = {x, y};
227- frag.normal = Interpolate (soa.normal [i0], soa.normal [i1], soa.normal [i2], corrected_bary);
228- frag.uv = Interpolate (soa.uv [i0], soa.uv [i1], soa.uv [i2], corrected_bary);
229- frag.color = InterpolateColor (soa.color [i0], soa.color [i1], soa.color [i2], corrected_bary);
230- frag.depth = z;
231-
232- out.push_back (frag);
233- }
234- }
235- }
236-
23784std::pair<bool , Vector3f> Rasterizer::GetBarycentricCoord (const Vector3f& p0,
23885 const Vector3f& p1,
23986 const Vector3f& p2,
0 commit comments