增加扫描线光栅算法

This commit is contained in:
2025-06-29 09:38:39 +08:00
parent 8388f448f3
commit 2fe2ef5d74
3 changed files with 57 additions and 34 deletions
+1
View File
@@ -415,6 +415,7 @@ struct iFloat2
iFloat2() : x(0), y(0) {} iFloat2() : x(0), y(0) {}
iFloat2(const iFloat2& other) : x(other.x), y(other.y) {} iFloat2(const iFloat2& other) : x(other.x), y(other.y) {}
iFloat2(float32_t _x, float32_t _y) : x(_x), y(_y) {} iFloat2(float32_t _x, float32_t _y) : x(_x), y(_y) {}
iFloat2(iFloat _x, iFloat _y) : x(_x), y(_y) {}
}; };
struct iFloat3 struct iFloat3
+2 -2
View File
@@ -42,8 +42,8 @@ public:
//Scaleline algorithm //Scaleline algorithm
static void drawTriangleScanline(int32_t canvasWidth, int32_t canvasHeight, static void drawTriangleScanline(int32_t canvasWidth, int32_t canvasHeight,
const fVector3& v0, const fVector3& v1, const fVector3& v2, const fVector2& v0, const fVector2& v1, const fVector2& v2,
DrawTriangleCallback callback); DrawTriangleCallback callback, bool ccw = true);
}; };
DV_CORE_END_NAMESPACE DV_CORE_END_NAMESPACE
@@ -544,58 +544,80 @@ void Rasterizer::drawTriangleLarrabee(int32_t canvasWidth, int32_t canvasHeight,
} }
//------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------
void Rasterizer::drawTriangleScanline(int32_t canvasWidth, int32_t canvasHeight, const fVector3& v0, const fVector3& v1, const fVector3& v2, DrawTriangleCallback callback) void Rasterizer::drawTriangleScanline(int32_t canvasWidth, int32_t canvasHeight,
const fVector2& _v0, const fVector2& _v1, const fVector2& _v2,
DrawTriangleCallback callback, bool ccw)
{ {
#if 0 //Whether the three input vertices are in the agreed clockwise order or not,
//back cull // it indicates that the triangle is invisible
fVector3 edge0 = v2 - v1; bool isCCW = (_v1 - _v0).crossProduct(_v2 - _v1) > 0;
fVector3 edge1 = v0 - v2; if (isCCW != ccw) return;
fVector3 vnormal = edge0.crossProduct(edge1);
if (vnormal.z > 0) return;
fVector3 edge2 = v1 - v0; fVector2 v[3];
v[0] = _v0;
v[1] = ccw ? _v1 : _v2;
v[2] = ccw ? _v2 : _v1;
float xmin = MathUtil::min3(v0.x, v1.x, v2.x); float32_t xmin = MathUtil::min3(v[0].x, v[1].x, v[2].x);
float ymin = MathUtil::min3(v0.y, v1.y, v2.y); float32_t ymin = MathUtil::min3(v[0].y, v[1].y, v[2].y);
float xmax = MathUtil::max3(v0.x, v1.x, v2.x); float32_t xmax = MathUtil::max3(v[0].x, v[1].x, v[2].x);
float ymax = MathUtil::max3(v0.y, v1.y, v2.y); float32_t ymax = MathUtil::max3(v[0].y, v[1].y, v[2].y);
float area = _edge(v0, v1, v2);
int32_t x0 = MathUtil::max2(0, (int32_t)std::floor(xmin)); int32_t x0 = MathUtil::max2(0, (int32_t)std::floor(xmin));
int32_t x1 = MathUtil::min2(canvasWidth - 1, (int32_t)std::floor(xmax)); int32_t x1 = MathUtil::min2(canvasWidth - 1, (int32_t)std::floor(xmax));
int32_t y0 = MathUtil::max2(0, (int32_t)std::floor(ymin)); int32_t y0 = MathUtil::max2(0, (int32_t)std::floor(ymin));
int32_t y1 = MathUtil::min2(canvasHeight - 1, (int32_t)std::floor(ymax)); int32_t y1 = MathUtil::min2(canvasHeight - 1, (int32_t)std::floor(ymax));
float32_t area = (v[1] - v[0]).crossProduct(v[2] - v[1]);
//edge function
// e(x,y)=(x1-x0)(y-y0)-(y1-y0))(x-x0)=ax+by+c
// a=y0-y1, b=x1-x0, c=(y1-y0)x0-(x1-x0)y0
iFloat edge_a[3], edge_b[3], edge_c[3];
bool edge_tl[3]; //is top-left edge?
for (int32_t i = 0; i < 3; i++) {
int32_t next = (i + 1) % 3;
iFloat2 v0 = iFloat2(v[i].x, v[i].y);
iFloat2 v1 = iFloat2(v[next].x, v[next].y);
edge_a[i] = v0.y - v1.y;
edge_b[i] = v1.x - v0.x;
edge_c[i] = (v1.y - v0.y) * v0.x - (v1.x - v0.x) * v0.y;
edge_tl[i] = (edge_a[i] != 0) ? (edge_a[i] > 0) : (edge_b[i] < 0);
}
for (int32_t y = y0; y <= y1; y++) { for (int32_t y = y0; y <= y1; y++) {
for (int32_t x = x0; x <= x1; x++) { for (int32_t x = x0; x <= x1; x++) {
fVector3 pixel(x + 0.5f, y + 0.5f, 0.f); iFloat2 iPixel(iFloat(x) + iFloat::kHalf, iFloat(y) + iFloat::kHalf);
bool overlaps = true; bool outsideTriangle = false;
for (int32_t i = 0; i < 3; i++)
{
iFloat edge = edge_a[i] * iPixel.x + edge_b[i] * iPixel.y + edge_c[i];
bool insideEdge = edge.s3132 > 0 || (edge.s3132 == 0 && edge_tl[i]);
float w0 = _edge(v1, v2, pixel); if (!insideEdge) {
overlaps &= (w0 == 0 ? ((edge0.y == 0 && edge0.x > 0) || edge0.y > 0) : (w0 > 0)); outsideTriangle = true;
if (!overlaps) continue; break;
}
}
if (outsideTriangle) {
continue;
}
float w1 = _edge(v2, v0, pixel); fVector2 pixel(x + 0.5f, y + 0.5f);
overlaps &= (w1 == 0 ? ((edge1.y == 0 && edge1.x > 0) || edge1.y > 0) : (w1 > 0)); float32_t w0 = (v[2] - v[1]).crossProduct(pixel - v[2]);
if (!overlaps) continue; float32_t w1 = (v[0] - v[2]).crossProduct(pixel - v[0]);
float32_t w2 = (v[1] - v[0]).crossProduct(pixel - v[1]);
float w2 = _edge(v0, v1, pixel); fVector3 t = fVector3(w0 / area, (ccw ? w1 : w2) / area, (ccw ? w2 : w1) / area);
overlaps &= (w2 == 0 ? ((edge2.y == 0 && edge2.x > 0) || edge2.y > 0) : (w2 > 0));
if (!overlaps) continue;
fVector3 t = fVector3(w0 / area, w1 / area, w2 / area);
float invZ = MathUtil::lerp3(v0.z, v1.z, v2.z, t);
t *= fVector3(v0.z / invZ, v1.z / invZ, v2.z / invZ);
callback(std::make_pair(x, y), t); callback(std::make_pair(x, y), t);
} }
} }
#endif
} }
DV_CORE_END_NAMESPACE DV_CORE_END_NAMESPACE