@@ -145,41 +145,82 @@ void Rasterizer::RasterizeTo(const VertexSoA& soa, size_t i0, size_t i1, size_t
145145 const Vector4f& p1 = soa.pos_screen [i1];
146146 const Vector4f& p2 = soa.pos_screen [i2];
147147
148- Vector2f a = Vector2f (p0.x , p0.y );
149- Vector2f b = Vector2f (p1.x , p1.y );
150- Vector2f c = Vector2f (p2.x , p2.y );
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 );
151152
152- Vector2f bboxMin = Vector2f{std::min ({a.x , b.x , c.x }), std::min ({a.y , b.y , c.y })};
153- Vector2f bboxMax = Vector2f{std::max ({a.x , b.x , c.x }), std::max ({a.y , b.y , c.y })};
154-
155- // Clamp 到屏幕尺寸
156- float minx = std::max (0 .0f , bboxMin.x );
157- float miny = std::max (0 .0f , bboxMin.y );
158- float maxx = std::min (float (width_ - 1 ), bboxMax.x );
159- float maxy = std::min (float (height_ - 1 ), bboxMax.y );
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 }));
160158
161159 // 与外部提供的裁剪区域相交(半开区间) -> 闭区间扫描
162- int sx = std::max (x0, static_cast <int >(std::floor (minx )));
163- int sy = std::max (y0, static_cast <int >(std::floor (miny )));
164- int ex = std::min (x1 - 1 , static_cast <int >(std::floor (maxx )));
165- int ey = std::min (y1 - 1 , static_cast <int >(std::floor (maxy )));
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 )));
166164 if (sx > ex || sy > ey) return ;
167165
168- for (int x = sx; x <= ex; ++x) {
169- for (int y = sy; y <= ey; ++y) {
170- auto [is_inside, bary] = GetBarycentricCoord (
171- Vector3f (p0.x , p0.y , p0.z ), Vector3f (p1.x , p1.y , p1.z ), Vector3f (p2.x , p2.y , p2.z ),
172- Vector3f (static_cast <float >(x), static_cast <float >(y), 0 ));
173- if (!is_inside) continue ;
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);
174215
175216 // 透视矫正插值
176217 auto perspective_result = PerformPerspectiveCorrection (
177218 p0.w , p1.w , p2.w ,
178219 p0.z , p1.z , p2.z ,
179220 bary);
180-
221+
181222 const Vector3f& corrected_bary = perspective_result.corrected_barycentric ;
182- float z = perspective_result.interpolated_z ;
223+ const float z = perspective_result.interpolated_z ;
183224
184225 Fragment frag; // Note: material 指针由调用方填写
185226 frag.screen_coord = {x, y};
0 commit comments