增加扫描线光栅算法
This commit is contained in:
@@ -415,6 +415,7 @@ struct iFloat2
|
||||
iFloat2() : x(0), y(0) {}
|
||||
iFloat2(const iFloat2& other) : x(other.x), y(other.y) {}
|
||||
iFloat2(float32_t _x, float32_t _y) : x(_x), y(_y) {}
|
||||
iFloat2(iFloat _x, iFloat _y) : x(_x), y(_y) {}
|
||||
};
|
||||
|
||||
struct iFloat3
|
||||
|
||||
@@ -42,8 +42,8 @@ public:
|
||||
|
||||
//Scaleline algorithm
|
||||
static void drawTriangleScanline(int32_t canvasWidth, int32_t canvasHeight,
|
||||
const fVector3& v0, const fVector3& v1, const fVector3& v2,
|
||||
DrawTriangleCallback callback);
|
||||
const fVector2& v0, const fVector2& v1, const fVector2& v2,
|
||||
DrawTriangleCallback callback, bool ccw = true);
|
||||
};
|
||||
|
||||
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
|
||||
//back cull
|
||||
fVector3 edge0 = v2 - v1;
|
||||
fVector3 edge1 = v0 - v2;
|
||||
fVector3 vnormal = edge0.crossProduct(edge1);
|
||||
if (vnormal.z > 0) return;
|
||||
//Whether the three input vertices are in the agreed clockwise order or not,
|
||||
// it indicates that the triangle is invisible
|
||||
bool isCCW = (_v1 - _v0).crossProduct(_v2 - _v1) > 0;
|
||||
if (isCCW != ccw) 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);
|
||||
float ymin = MathUtil::min3(v0.y, v1.y, v2.y);
|
||||
float xmax = MathUtil::max3(v0.x, v1.x, v2.x);
|
||||
float ymax = MathUtil::max3(v0.y, v1.y, v2.y);
|
||||
|
||||
float area = _edge(v0, v1, v2);
|
||||
float32_t xmin = MathUtil::min3(v[0].x, v[1].x, v[2].x);
|
||||
float32_t ymin = MathUtil::min3(v[0].y, v[1].y, v[2].y);
|
||||
float32_t xmax = MathUtil::max3(v[0].x, v[1].x, v[2].x);
|
||||
float32_t ymax = MathUtil::max3(v[0].y, v[1].y, v[2].y);
|
||||
|
||||
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 y0 = MathUtil::max2(0, (int32_t)std::floor(ymin));
|
||||
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 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);
|
||||
overlaps &= (w0 == 0 ? ((edge0.y == 0 && edge0.x > 0) || edge0.y > 0) : (w0 > 0));
|
||||
if (!overlaps) continue;
|
||||
if (!insideEdge) {
|
||||
outsideTriangle = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (outsideTriangle) {
|
||||
continue;
|
||||
}
|
||||
|
||||
float w1 = _edge(v2, v0, pixel);
|
||||
overlaps &= (w1 == 0 ? ((edge1.y == 0 && edge1.x > 0) || edge1.y > 0) : (w1 > 0));
|
||||
if (!overlaps) continue;
|
||||
fVector2 pixel(x + 0.5f, y + 0.5f);
|
||||
float32_t w0 = (v[2] - v[1]).crossProduct(pixel - v[2]);
|
||||
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);
|
||||
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);
|
||||
fVector3 t = fVector3(w0 / area, (ccw ? w1 : w2) / area, (ccw ? w2 : w1) / area);
|
||||
|
||||
callback(std::make_pair(x, y), t);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
DV_CORE_END_NAMESPACE
|
||||
|
||||
Reference in New Issue
Block a user