这一节为2D图形处理,展示如何去渲染基本几何(点,线,三角形),按 TAB可以切换图元显示
渲染器新增接口:
void SoftRenderer::Render(const Vertex * varray, int vertexCount, const int * iarray, int primCount, int primType)
{
// 顶点处理
mRasterizerVertexBuffer.resize(vertexCount);
for (int i = 0; i < vertexCount; ++i)
{
_vertex_shader(&mRasterizerVertexBuffer[i], &varray[i]);
}
// 图元处理
RasterizerVertex A, B, C, D;
for (int i = 0; i < primCount; ++i)
{
if (primType == ePrimType::TRI_LIST)
{
if (iarray != NULL)
{
// 使用索引列表
A = mRasterizerVertexBuffer[iarray[i * 3 + 0]];
B = mRasterizerVertexBuffer[iarray[i * 3 + 1]];
C = mRasterizerVertexBuffer[iarray[i * 3 + 2]];
}
else
{
// 使用顶点列表
A = mRasterizerVertexBuffer[i * 3 + 0];
B = mRasterizerVertexBuffer[i * 3 + 1];
C = mRasterizerVertexBuffer[i * 3 + 2];
}
// 背面裁剪
// 裁剪
// 视口变换
A.position.x /= A.position.w;
A.position.y /= A.position.w;
B.position.x /= B.position.w;
B.position.y /= B.position.w;
C.position.x /= C.position.w;
C.position.y /= C.position.w;
A.position.x = (A.position.x + 1) / 2 * mWidth;
A.position.y = (1 - A.position.y) / 2 * mHeight;
B.position.x = (B.position.x + 1) / 2 * mWidth;
B.position.y = (1 - B.position.y) / 2 * mHeight;
C.position.x = (C.position.x + 1) / 2 * mWidth;
C.position.y = (1 - C.position.y) / 2 * mHeight;
// 光栅化
_rasterizeTri(&A, &B, &C);
}
else if (primType == ePrimType::LINE_LIST)
{
if (iarray != NULL)
{
// 使用索引列表
A = mRasterizerVertexBuffer[iarray[i * 2 + 0]];
B = mRasterizerVertexBuffer[iarray[i * 2 + 1]];
}
else
{
// 使用顶点列表
A = mRasterizerVertexBuffer[i * 2 + 0];
B = mRasterizerVertexBuffer[i * 2 + 1];
}
// 背面裁剪
// 裁剪
// 视口变换
A.position.x /= A.position.w;
A.position.y /= A.position.w;
B.position.x /= B.position.w;
B.position.y /= B.position.w;
A.position.x = (A.position.x + 1) / 2 * mWidth;
A.position.y = (1 - A.position.y) / 2 * mHeight;
B.position.x = (B.position.x + 1) / 2 * mWidth;
B.position.y = (1 - B.position.y) / 2 * mHeight;
// 光栅化
_rasterizeLine(&A, &B);
}
else if (primType == ePrimType::POINT_LIST)
{
if (iarray != NULL)
{
// 使用索引列表
A = mRasterizerVertexBuffer[iarray[i]];
}
else
{
// 使用顶点列表
A = mRasterizerVertexBuffer[i];
}
// 背面裁剪
// 裁剪
// 视口变换
A.position.x /= A.position.w;
A.position.y /= A.position.w;
A.position.x = (A.position.x + 1) / 2 * mWidth;
A.position.y = (1 - A.position.y) / 2 * mHeight;
// 光栅化
_rasterizePoint(&A);
}
}
}
渲染点:
void SoftRenderer::_rasterizePoint(const RasterizerVertex * PA)
{
RasterizerVertex v = *PA;
int x = (int)v.position.x, y = (int)v.position.y;
if (x >= 0 && x < mWidth && y >= 0 && y <= mHeight)
{
_pixel_shader(&v);
_output(x, y, &v);
}
}
渲染线段(中心点算法):
void SoftRenderer::_rasterizeLine(const RasterizerVertex * PA, const RasterizerVertex * PB)
{
if (PA->position.x > PB->position.x)
std::swap(PA, PB);
RasterizerVertex v;
Int2 A = Int2((int)PA->position.x, (int)PA->position.y);
Int2 B = Int2((int)PB->position.x, (int)PB->position.y);
Int2 AB = B - A;
if (AB.x > abs(AB.y))
{
float k = (float)AB.y / AB.x;
int x = A.x, y = A.y;
if (k > 0)
{
float e = -0.5f;
for (int i = 0; i < AB.x; ++i)
{
x = x + 1;
e = e + k;
if (e > 0)
{
y = y + 1;
e = e - 1.0f;
}
if (x >= 0 && x < mWidth && y >= 0 && y <= mHeight)
{
float d = AB.x > 0 ? (float)i / AB.x : 1;
RasterizerVertex::Lerp(v, *PA, *PB, d);
_pixel_shader(&v);
_output(x, y, &v);
}
}
}
else if (k == 0)
{
for (int i = 0; i < AB.x; ++i)
{
x = x + 1;
if (x >= 0 && x < mWidth && y >= 0 && y <= mHeight)
{
float d = AB.x > 0 ? (float)i / AB.x : 1;
RasterizerVertex::Lerp(v, *PA, *PB, d);
_pixel_shader(&v);
_output(x, y, &v);
}
}
}
else
{
float e = -0.5f;
for (int i = 0; i < AB.x; ++i)
{
x = x + 1;
e = e - k;
if (e > 0)
{
y = y - 1;
e = e - 1.0f;
}
if (x >= 0 && x < mWidth && y >= 0 && y <= mHeight)
{
float d = AB.x > 0 ? (float)i / AB.x : 1;
RasterizerVertex::Lerp(v, *PA, *PB, d);
_pixel_shader(&v);
_output(x, y, &v);
}
}
}
}
else
{
float k = (float)AB.x / AB.y;
int x = A.x, y = A.y;
if (k > 0)
{
float e = -0.5f;
for (int i = 0; i < AB.y; ++i)
{
y = y + 1;
e = e + k;
if (e > 0)
{
x = x + 1;
e = e - 1.0f;
}
if (x >= 0 && x < mWidth && y >= 0 && y <= mHeight)
{
float d = AB.y > 0 ? (float)i / AB.y : 1;
RasterizerVertex::Lerp(v, *PA, *PB, d);
_pixel_shader(&v);
_output(x, y, &v);
}
}
}
else if (k == 0)
{
if (AB.y > 0)
{
for (int i = 0; i < AB.y; ++i)
{
y = y + 1;
if (x >= 0 && x < mWidth && y >= 0 && y <= mHeight)
{
float d = AB.y > 0 ? (float)i / AB.y : 1;
RasterizerVertex::Lerp(v, *PA, *PB, d);
_pixel_shader(&v);
_output(x, y, &v);
}
}
}
else
{
for (int i = 0; i < -AB.y; ++i)
{
y = y - 1;
if (x >= 0 && x < mWidth && y >= 0 && y <= mHeight)
{
float d = -AB.y > 0 ? (float)i / -AB.y : 1;
RasterizerVertex::Lerp(v, *PA, *PB, d);
_pixel_shader(&v);
_output(x, y, &v);
}
}
}
}
else
{
float e = -0.5f;
for (int i = 0; i < -AB.y; ++i)
{
y = y - 1;
e = e - k;
if (e > 0)
{
x = x + 1;
e = e - 1.0f;
}
if (x >= 0 && x < mWidth && y >= 0 && y <= mHeight)
{
float d = -AB.y > 0 ? (float)i / -AB.y : 1;
RasterizerVertex::Lerp(v, *PA, *PB, d);
_pixel_shader(&v);
_output(x, y, &v);
}
}
}
}
}
渲染三角形(扫描线算法):
void SoftRenderer::_rasterizeTri(const RasterizerVertex * PA, const RasterizerVertex * PB, const RasterizerVertex * PC)
{
int _width = mWidth, _height = mHeight;
// 确保点A是最上面的点
if (PA->position.y > PB->position.y)
std::swap(PA, PB);
if (PA->position.y > PC->position.y)
std::swap(PA, PC);
// 确保B在C的左边
if (PB->position.x > PC->position.x)
std::swap(PB, PC);
Int2 A = Int2((int)PA->position.x, (int)PA->position.y);
Int2 B = Int2((int)PB->position.x, (int)PB->position.y);
Int2 C = Int2((int)PC->position.x, (int)PC->position.y);
Int2 AB = B - A, AC = C - A;
RasterizerVertex v1, v2, v;
if (B.y > C.y)
{
// 三角形类型1 (B.y < C.y)
// A*
//
// *C
// B*
//
// 画上半部分
int cy = A.y, ey = C.y;
cy = std::max(cy, 0);
ey = std::min(ey, _height);
while (cy < ey)
{
float kab = AB.y > 0 ? (float)(cy - A.y) / (float)AB.y : 1;
float kac = AC.y > 0 ? (float)(cy - A.y) / (float)AC.y : 1;
int x1 = (int)(A.x + AB.x * kab);
int x2 = (int)(A.x + AC.x * kac);
RasterizerVertex::Lerp(v1, *PA, *PB, kab);
RasterizerVertex::Lerp(v2, *PA, *PC, kac);
if (x1 > x2)
{
std::swap(x1, x2);
std::swap(v1, v2);
}
int sx = std::max(x1, 0);
int ex = std::min(x2, _width);
for (int x = sx; x < ex; x += 1)
{
float k = (x2 - x1) > 0 ? (float)(x - x1) / (float)(x2 - x1) : 1;
RasterizerVertex::Lerp(v, v1, v2, k);
_pixel_shader(&v);
_output(x, cy, &v);
}
cy += 1;
}
// 画下半部分
Int2 CB = Int2(B.x - C.x, B.y - C.y);
ey = std::min(B.y, _height);
while (cy < ey)
{
float kab = AB.y > 0 ? (float)(cy - A.y) / (float)AB.y : 1;
float kcb = CB.y > 0 ? (float)(cy - C.y) / (float)CB.y : 1;
int x1 = (int)(A.x + AB.x * kab);
int x2 = (int)(C.x + CB.x * kcb);
RasterizerVertex::Lerp(v1, *PA, *PB, kab);
RasterizerVertex::Lerp(v2, *PC, *PB, kcb);
if (x1 > x2)
{
std::swap(x1, x2);
std::swap(v1, v2);
}
int sx = std::max(x1, 0);
int ex = std::min(x2, _width);
for (int x = sx; x < ex; x += 1)
{
float k = (x2 - x1) > 0 ? (float)(x - x1) / (float)(x2 - x1) : 1;
RasterizerVertex::Lerp(v, v1, v2, k);
_pixel_shader(&v);
_output(x, cy, &v);
}
cy += 1;
}
}
else
{
// 三角形类型2 (B在C上面)
// A*
//
// B*
// *C
//
// 画上半部分
int cy = A.y, ey = B.y;
cy = std::max(cy, 0);
ey = std::min(ey, _height);
while (cy < ey)
{
float kab = AB.y > 0 ? (float)(cy - A.y) / (float)AB.y : 1;
float kac = AC.y > 0 ? (float)(cy - A.y) / (float)AC.y : 1;
int x1 = (int)(A.x + AB.x * kab);
int x2 = (int)(A.x + AC.x * kac);
RasterizerVertex::Lerp(v1, *PA, *PB, kab);
RasterizerVertex::Lerp(v2, *PA, *PC, kac);
if (x1 > x2)
{
std::swap(x1, x2);
std::swap(v1, v2);
}
int sx = std::max(x1, 0);
int ex = std::min(x2, _width);
for (int x = sx; x < ex; x += 1)
{
float k = (x2 - x1) > 0 ? (float)(x - x1) / (float)(x2 - x1) : 1;
RasterizerVertex::Lerp(v, v1, v2, k);
_pixel_shader(&v);
_output(x, cy, &v);
}
cy += 1;
}
// 画下半部分
Int2 BC = Int2(C.x - B.x, C.y - B.y);
ey = std::min(C.y, _height);
while (cy < ey)
{
float kbc = BC.y > 0 ? (float)(cy - B.y) / (float)BC.y : 1;
float kac = AC.y > 0 ? (float)(cy - A.y) / (float)AC.y : 1;
int x1 = (int)(B.x + BC.x * kbc);
int x2 = (int)(A.x + AC.x * kac);
RasterizerVertex::Lerp(v1, *PB, *PC, kbc);
RasterizerVertex::Lerp(v2, *PA, *PC, kac);
if (x1 > x2)
{
std::swap(x1, x2);
std::swap(v1, v2);
}
int sx = std::max(x1, 0);
int ex = std::min(x2, _width);
for (int x = sx; x < ex; x += 1)
{
float k = (x2 - x1) > 0 ? (float)(x - x1) / (float)(x2 - x1) : 1;
RasterizerVertex::Lerp(v, v1, v2, k);
_pixel_shader(&v);
_output(x, cy, &v);
}
cy += 1;
}
}
}
程序逻辑:
virtual void OnInit(int w, int h)
{
mRenderer = new SoftRenderer(mWnd, w, h);
// 创建正方形
Vertex * vb = mQuad;
vb[0].position = Float3(-1, +1, 0) * 0.5f;
vb[1].position = Float3(+1, +1, 0) * 0.5f;
vb[2].position = Float3(-1, -1, 0) * 0.5f;
vb[3].position = Float3(+1, -1, 0) * 0.5f;
vb[0].color = Float4(1, 0, 0, 1);
vb[1].color = Float4(1, 0, 0, 1);
vb[2].color = Float4(0, 1, 0, 1);
vb[3].color = Float4(0, 1, 0, 1);
// 三角形列表
int * ib = mTriList;
{
*ib++ = 0, *ib++ = 1, *ib++ = 2;
*ib++ = 2, *ib++ = 1, *ib++ = 3;
}
// 线列表
ib = mLineList;
{
*ib++ = 0, *ib++ = 1;
*ib++ = 1, *ib++ = 3;
*ib++ = 3, *ib++ = 2;
*ib++ = 2, *ib++ = 0;
}
// 点列表直接使用顶点的列表,不用额外定义
//
mPrimType = ePrimType::TRI_LIST;
}
virtual void OnUpdate()
{
mRenderer->Begin();
// 清屏
mRenderer->Clear(Float3(0, 0, 0), 1);
// 随着时间旋转
Mat4 form;
form.MakeRotation(Float3(0, 0, 1), PI * mTime * 0.3f);
Vertex * vb = mQuad;
vb[0].position = Float3(-1, +1, 0) * 0.5f;
vb[1].position = Float3(+1, +1, 0) * 0.5f;
vb[2].position = Float3(-1, -1, 0) * 0.5f;
vb[3].position = Float3(+1, -1, 0) * 0.5f;
mQuad[0].position.TransformA(form);
mQuad[1].position.TransformA(form);
mQuad[2].position.TransformA(form);
mQuad[3].position.TransformA(form);
// 保持纵横比
float aspect = (float)mHeight / mWidth;
vb[0].position *= Float3(aspect, 1, 0);
vb[1].position *= Float3(aspect, 1, 0);
vb[2].position *= Float3(aspect, 1, 0);
vb[3].position *= Float3(aspect, 1, 0);
// 渲染图元
switch (mPrimType)
{
case ePrimType::TRI_LIST:
mRenderer->Render(vb, 4, mTriList, 2, ePrimType::TRI_LIST);
break;
case ePrimType::LINE_LIST:
mRenderer->Render(vb, 4, mLineList, 4, ePrimType::LINE_LIST);
break;
case ePrimType::POINT_LIST:
mRenderer->Render(vb, 4, NULL, 4, ePrimType::POINT_LIST);
break;
}
mRenderer->End();
// 提交
mRenderer->Present();
}
总结:
例程最重要部分是渲染流程(Render函数的处理流程)和三种图元的渲染算法(3个_rasterizeX函数),对于跟深入的了解可以看下基础计算机图形书籍。