DrawLine 消除 set_pixel
This commit is contained in:
parent
08088c8413
commit
16d961e9f3
|
|
@ -100,7 +100,8 @@
|
||||||
这意味着:
|
这意味着:
|
||||||
|
|
||||||
- 当前 demo 还没有实现完整的视锥裁剪
|
- 当前 demo 还没有实现完整的视锥裁剪
|
||||||
- 如果一条线段只有一部分还在屏幕内,但端点已经越出 NDC,整条线仍可能被直接丢弃
|
- **2D 屏幕空间线段裁剪已实现**:`Rasterizer::DrawLine` 使用 Cohen-Sutherland 算法对屏幕边界做裁剪,部分在屏幕内的线段可以正确绘制,不再整条丢弃
|
||||||
|
- 3D 视锥裁剪(齐次裁剪空间)仍未实现
|
||||||
|
|
||||||
## 8. 屏幕与像素坐标
|
## 8. 屏幕与像素坐标
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -91,6 +91,7 @@
|
||||||
- 像素写入路径应尽量减少分支和函数调用层级。
|
- 像素写入路径应尽量减少分支和函数调用层级。
|
||||||
- 像素级写入的 Release 快路径不要使用带额外边界检查的容器访问(例如 `std::vector::at()`);边界检查应在外层完成。
|
- 像素级写入的 Release 快路径不要使用带额外边界检查的容器访问(例如 `std::vector::at()`);边界检查应在外层完成。
|
||||||
- 裁剪、剔除、包围盒收缩要尽早执行,避免把不可见数据送入像素级循环。
|
- 裁剪、剔除、包围盒收缩要尽早执行,避免把不可见数据送入像素级循环。
|
||||||
|
- `Rasterizer::DrawLine` 已采用此策略:入口做快速全屏可见性检查,屏幕内直接走 `set_pixel_unsafe` 快路径;屏幕外走 Cohen-Sutherland 裁剪后再走快路径。
|
||||||
- 三角形属性插值、深度测试、纹理采样等未来功能必须先定义定点/整数方案,再接入热路径。
|
- 三角形属性插值、深度测试、纹理采样等未来功能必须先定义定点/整数方案,再接入热路径。
|
||||||
- PC 调试版可以保留更易读的检查与可视化代码,但 ARM release 路径必须能关闭这些额外成本。
|
- PC 调试版可以保留更易读的检查与可视化代码,但 ARM release 路径必须能关闭这些额外成本。
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,102 +1,199 @@
|
||||||
#include "Rasterizer.h"
|
#include "Rasterizer.h"
|
||||||
#include <Vector2.h>
|
#include <Vector2.h>
|
||||||
#include "Color.h"
|
#include "Color.h"
|
||||||
#include <cmath>
|
#include <cstdint>
|
||||||
#include <cstdint>
|
|
||||||
|
namespace Rasterizer
|
||||||
namespace Rasterizer
|
{
|
||||||
{
|
using namespace Math;
|
||||||
using namespace Math;
|
using namespace RenderData;
|
||||||
using namespace RenderData;
|
|
||||||
|
namespace
|
||||||
void Rasterizer::DrawLineHorizontal(const Vector2Int v0, const Vector2Int v1, const Color color)
|
{
|
||||||
{
|
// Cohen-Sutherland 线段裁剪常量
|
||||||
Vector2Int start = v0, end = v1;
|
const int32_t CS_INSIDE = 0;
|
||||||
if (v0.x > v1.x)
|
const int32_t CS_LEFT = 1;
|
||||||
{
|
const int32_t CS_RIGHT = 2;
|
||||||
start = v1;
|
const int32_t CS_BOTTOM = 4;
|
||||||
end = v0;
|
const int32_t CS_TOP = 8;
|
||||||
}
|
|
||||||
|
inline int32_t cs_compute_outcode(int32_t x, int32_t y, int32_t w, int32_t h)
|
||||||
int32_t dx = end.x - start.x;
|
{
|
||||||
int32_t dy = end.y - start.y;
|
int32_t code = CS_INSIDE;
|
||||||
|
if (x < 0) code |= CS_LEFT;
|
||||||
int32_t dir = dy < 0 ? -1 : 1;
|
else if (x >= w) code |= CS_RIGHT;
|
||||||
dy *= dir;
|
if (y < 0) code |= CS_TOP;
|
||||||
|
else if (y >= h) code |= CS_BOTTOM;
|
||||||
if (dx == 0) return;
|
return code;
|
||||||
|
}
|
||||||
int32_t y = start.y;
|
|
||||||
int32_t p = 2 * dy - dx;
|
bool cs_clip_line(int32_t& x0, int32_t& y0, int32_t& x1, int32_t& y1,
|
||||||
for (int32_t x = start.x; x <= end.x; x++)
|
int32_t w, int32_t h)
|
||||||
{
|
{
|
||||||
frameBuffer->set_pixel(x, y, color.to_rgba());
|
int32_t outcode0 = cs_compute_outcode(x0, y0, w, h);
|
||||||
// 当 p >= 0 时,取上方像素点
|
int32_t outcode1 = cs_compute_outcode(x1, y1, w, h);
|
||||||
if (p >= 0)
|
|
||||||
{
|
while (true)
|
||||||
y += dir;
|
{
|
||||||
p -= 2 * dx;
|
if (!(outcode0 | outcode1))
|
||||||
}
|
{
|
||||||
// 当 p < 0 时,取下方像素点
|
return true;
|
||||||
p += 2 * dy;
|
}
|
||||||
}
|
if (outcode0 & outcode1)
|
||||||
}
|
{
|
||||||
|
return false;
|
||||||
void Rasterizer::DrawLineVertical(const Vector2Int v0, const Vector2Int v1, const Color color)
|
}
|
||||||
{
|
|
||||||
Vector2Int start = v0, end = v1;
|
const int32_t outcode_out = outcode0 ? outcode0 : outcode1;
|
||||||
if (v0.y > v1.y)
|
int32_t x, y;
|
||||||
{
|
|
||||||
start = v1;
|
if (outcode_out & CS_TOP)
|
||||||
end = v0;
|
{
|
||||||
}
|
x = x0 + (x1 - x0) * (0 - y0) / (y1 - y0);
|
||||||
|
y = 0;
|
||||||
int32_t dx = end.x - start.x;
|
}
|
||||||
int32_t dy = end.y - start.y;
|
else if (outcode_out & CS_BOTTOM)
|
||||||
|
{
|
||||||
int32_t dir = dx < 0 ? -1 : 1;
|
x = x0 + (x1 - x0) * (h - 1 - y0) / (y1 - y0);
|
||||||
dx *= dir;
|
y = h - 1;
|
||||||
|
}
|
||||||
if (dy == 0) return;
|
else if (outcode_out & CS_RIGHT)
|
||||||
|
{
|
||||||
int32_t x = start.x;
|
y = y0 + (y1 - y0) * (w - 1 - x0) / (x1 - x0);
|
||||||
int32_t p = 2 * dx - dy;
|
x = w - 1;
|
||||||
for (int32_t y = start.y; y <= end.y; y++)
|
}
|
||||||
{
|
else
|
||||||
frameBuffer->set_pixel(x, y, color.to_rgba());
|
{
|
||||||
// 当 p >= 0 时,取上方像素点
|
y = y0 + (y1 - y0) * (0 - x0) / (x1 - x0);
|
||||||
if (p >= 0)
|
x = 0;
|
||||||
{
|
}
|
||||||
x += dir;
|
|
||||||
p -= 2 * dy;
|
if (outcode_out == outcode0)
|
||||||
}
|
{
|
||||||
// 当 p < 0 时,取下方像素点
|
x0 = x; y0 = y;
|
||||||
p += 2 * dx;
|
outcode0 = cs_compute_outcode(x0, y0, w, h);
|
||||||
}
|
}
|
||||||
}
|
else
|
||||||
|
{
|
||||||
/// <summary>
|
x1 = x; y1 = y;
|
||||||
/// 在给定的起始点和结束点之间绘制一条线段,并使用指定的颜色填充
|
outcode1 = cs_compute_outcode(x1, y1, w, h);
|
||||||
/// </summary>
|
}
|
||||||
/// <param name="v0">直线顶点 1</param>
|
}
|
||||||
/// <param name="v1">直线顶点 2</param>
|
}
|
||||||
/// <param name="color">绘制的颜色</param>
|
}
|
||||||
/// <remarks>
|
|
||||||
/// bresenham 画线算法
|
void Rasterizer::DrawLineHorizontal(Vector2Int v0, Vector2Int v1, uint32_t rgba)
|
||||||
/// </remarks>
|
{
|
||||||
void Rasterizer::DrawLine(const Vector2Int v0, const Vector2Int v1, const Color color)
|
if (v0.x > v1.x)
|
||||||
{
|
{
|
||||||
int32_t x0 = v0.x, y0 = v0.y;
|
Vector2Int tmp = v0;
|
||||||
int32_t x1 = v1.x, y1 = v1.y;
|
v0 = v1;
|
||||||
|
v1 = tmp;
|
||||||
if (std::abs(x1 - x0) > std::abs(y1 - y0))
|
}
|
||||||
{
|
|
||||||
DrawLineHorizontal(v0, v1, color);
|
const int32_t dx = v1.x - v0.x;
|
||||||
}
|
int32_t dy = v1.y - v0.y;
|
||||||
else
|
if (dx == 0) return;
|
||||||
{
|
|
||||||
DrawLineVertical(v0, v1, color);
|
const int32_t dir = dy < 0 ? -1 : 1;
|
||||||
}
|
dy *= dir;
|
||||||
}
|
|
||||||
}
|
const int32_t fb_w = frameBuffer->get_width();
|
||||||
|
int32_t y = v0.y;
|
||||||
|
int32_t p = 2 * dy - dx;
|
||||||
|
|
||||||
|
for (int32_t x = v0.x; x <= v1.x; ++x)
|
||||||
|
{
|
||||||
|
frameBuffer->set_pixel_unsafe(x, y, rgba);
|
||||||
|
if (p >= 0)
|
||||||
|
{
|
||||||
|
y += dir;
|
||||||
|
p -= 2 * dx;
|
||||||
|
}
|
||||||
|
p += 2 * dy;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Rasterizer::DrawLineVertical(Vector2Int v0, Vector2Int v1, uint32_t rgba)
|
||||||
|
{
|
||||||
|
if (v0.y > v1.y)
|
||||||
|
{
|
||||||
|
Vector2Int tmp = v0;
|
||||||
|
v0 = v1;
|
||||||
|
v1 = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t dx = v1.x - v0.x;
|
||||||
|
const int32_t dy = v1.y - v0.y;
|
||||||
|
if (dy == 0) return;
|
||||||
|
|
||||||
|
const int32_t dir = dx < 0 ? -1 : 1;
|
||||||
|
dx *= dir;
|
||||||
|
|
||||||
|
int32_t x = v0.x;
|
||||||
|
int32_t p = 2 * dx - dy;
|
||||||
|
|
||||||
|
for (int32_t y = v0.y; y <= v1.y; ++y)
|
||||||
|
{
|
||||||
|
frameBuffer->set_pixel_unsafe(x, y, rgba);
|
||||||
|
if (p >= 0)
|
||||||
|
{
|
||||||
|
x += dir;
|
||||||
|
p -= 2 * dy;
|
||||||
|
}
|
||||||
|
p += 2 * dx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Rasterizer::DrawLineClipped(Vector2Int v0, Vector2Int v1, uint32_t rgba)
|
||||||
|
{
|
||||||
|
if (!cs_clip_line(v0.x, v0.y, v1.x, v1.y,
|
||||||
|
frameBuffer->get_width(), frameBuffer->get_height()))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const int32_t dx = v1.x - v0.x;
|
||||||
|
const int32_t dy = v1.y - v0.y;
|
||||||
|
const int32_t adx = dx < 0 ? -dx : dx;
|
||||||
|
const int32_t ady = dy < 0 ? -dy : dy;
|
||||||
|
|
||||||
|
if (adx > ady)
|
||||||
|
{
|
||||||
|
DrawLineHorizontal(v0, v1, rgba);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DrawLineVertical(v0, v1, rgba);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Rasterizer::DrawLine(const Vector2Int v0, const Vector2Int v1, const Color color)
|
||||||
|
{
|
||||||
|
const int32_t w = frameBuffer->get_width();
|
||||||
|
const int32_t h = frameBuffer->get_height();
|
||||||
|
|
||||||
|
// 快速全屏可见性检查:两点都在屏幕内则跳过裁剪
|
||||||
|
if (v0.x >= 0 && v0.x < w && v0.y >= 0 && v0.y < h &&
|
||||||
|
v1.x >= 0 && v1.x < w && v1.y >= 0 && v1.y < h)
|
||||||
|
{
|
||||||
|
const uint32_t rgba = color.to_rgba();
|
||||||
|
const int32_t dx = v1.x - v0.x;
|
||||||
|
const int32_t dy = v1.y - v0.y;
|
||||||
|
const int32_t adx = dx < 0 ? -dx : dx;
|
||||||
|
const int32_t ady = dy < 0 ? -dy : dy;
|
||||||
|
|
||||||
|
if (adx > ady)
|
||||||
|
{
|
||||||
|
DrawLineHorizontal(v0, v1, rgba);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DrawLineVertical(v0, v1, rgba);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
DrawLineClipped(v0, v1, color.to_rgba());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,8 +12,9 @@ namespace Rasterizer
|
||||||
Core::FrameBuffer* frameBuffer;
|
Core::FrameBuffer* frameBuffer;
|
||||||
Core::DepthBuffer* depthBuffer;
|
Core::DepthBuffer* depthBuffer;
|
||||||
|
|
||||||
void DrawLineHorizontal(const Math::Vector2Int v0, const Math::Vector2Int v1, const RenderData::Color color);
|
void DrawLineHorizontal(Math::Vector2Int v0, Math::Vector2Int v1, uint32_t rgba);
|
||||||
void DrawLineVertical(const Math::Vector2Int v0, const Math::Vector2Int v1, const RenderData::Color color);
|
void DrawLineVertical(Math::Vector2Int v0, Math::Vector2Int v1, uint32_t rgba);
|
||||||
|
void DrawLineClipped(Math::Vector2Int v0, Math::Vector2Int v1, uint32_t rgba);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit Rasterizer(Core::FrameBuffer* frameBuffer) :frameBuffer(frameBuffer), depthBuffer(nullptr) {}
|
explicit Rasterizer(Core::FrameBuffer* frameBuffer) :frameBuffer(frameBuffer), depthBuffer(nullptr) {}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue