apply depthBuffer
This commit is contained in:
parent
cc203c40f3
commit
e089619dcf
|
|
@ -1,16 +1,27 @@
|
|||
#include "DepthBuffer.h"
|
||||
#include <cstdint>
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
|
||||
namespace Core
|
||||
{
|
||||
void DepthBuffer::clear(const uint8_t depth)
|
||||
void DepthBuffer::clear(const float depth)
|
||||
{
|
||||
std::fill(buffer.begin(), buffer.end(), depth);
|
||||
}
|
||||
|
||||
float DepthBuffer::get_depth(const int32_t x, const int32_t y) const
|
||||
{
|
||||
if (x < 0 || x >= width || y < 0 || y >= height)
|
||||
{
|
||||
return INFINITY;
|
||||
}
|
||||
// Row-major layout with y = 0 on the first row, matching a top-left screen origin.
|
||||
size_t index = static_cast<size_t>(y) * width + x;
|
||||
return buffer.at(index);
|
||||
}
|
||||
|
||||
void DepthBuffer::set_pixel(const int32_t x, const int32_t y, const uint8_t depth)
|
||||
void DepthBuffer::set_depth(const int32_t x, const int32_t y, const float depth)
|
||||
{
|
||||
if (x < 0 || x >= width || y < 0 || y >= height)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
#pragma once
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
#include "Color.h"
|
||||
#include "Vector2.h"
|
||||
#include <cmath>
|
||||
|
||||
namespace Core
|
||||
{
|
||||
|
|
@ -11,7 +11,7 @@ namespace Core
|
|||
private:
|
||||
int32_t width;
|
||||
int32_t height;
|
||||
std::vector<uint8_t> buffer;
|
||||
std::vector<float> buffer;
|
||||
|
||||
public:
|
||||
int32_t get_width() const { return width; }
|
||||
|
|
@ -22,15 +22,16 @@ namespace Core
|
|||
|
||||
void* get_buffer() const { return (void*)buffer.data(); }
|
||||
|
||||
DepthBuffer(int32_t width, int32_t height) :width(width), height(height), buffer(std::vector<uint8_t>(width* height, 0)) {}
|
||||
DepthBuffer(int32_t width, int32_t height) :width(width), height(height), buffer(std::vector<float>(width* height, INFINITY)) {}
|
||||
|
||||
void clear(const uint8_t depth);
|
||||
void clear(const float depth = INFINITY);
|
||||
|
||||
void set_pixel(const Math::Vector2Int position, const uint8_t depth)
|
||||
{
|
||||
set_pixel(position.x, position.y, depth);
|
||||
}
|
||||
float get_depth(const Math::Vector2Int position) const { return get_depth(position.x, position.y); }
|
||||
|
||||
void set_pixel(const int32_t x, const int32_t y, const uint8_t depth);
|
||||
float get_depth(const int32_t x, const int32_t y) const;
|
||||
|
||||
void set_depth(const Math::Vector2Int position, const float depth) { set_depth(position.x, position.y, depth); }
|
||||
|
||||
void set_depth(const int32_t x, const int32_t y, const float depth);
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
#include "Matrix4x4.h"
|
||||
#include "Vector3.h"
|
||||
#include <cmath>
|
||||
#include "Vector2.h"
|
||||
|
||||
namespace Math
|
||||
{
|
||||
|
|
@ -99,5 +100,10 @@ namespace Math
|
|||
{
|
||||
return vec1.cross(vec2);
|
||||
}
|
||||
|
||||
static Vector3 cross(const Vector2& vec1, const Vector2& vec2)
|
||||
{
|
||||
return vec1.cross(vec2);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,9 +2,13 @@
|
|||
#include <cstdint>
|
||||
#include <utility>
|
||||
#include <cmath>
|
||||
#include "Vector3.h"
|
||||
|
||||
namespace Math
|
||||
{
|
||||
struct Vector2;
|
||||
struct Vector2Int;
|
||||
|
||||
struct Vector2Int
|
||||
{
|
||||
int32_t x = 0;
|
||||
|
|
@ -31,6 +35,7 @@ namespace Math
|
|||
|
||||
Vector2() : x(0), y(0) {}
|
||||
Vector2(float x, float y) : x(x), y(y) {}
|
||||
Vector2(const Vector2Int& other) :x(other.x), y(other.y) {}
|
||||
|
||||
/// <summary>
|
||||
/// 交换当前 Vector2 对象与另一个 Vector2 对象的 x 和 y 的值
|
||||
|
|
@ -46,5 +51,10 @@ namespace Math
|
|||
{
|
||||
return Vector2Int(static_cast<int32_t>(std::lround(x)), static_cast<int32_t>(std::lround(y)));
|
||||
}
|
||||
|
||||
Vector3 cross(const Vector2& other) const
|
||||
{
|
||||
return Vector3(0, 0, this->x * other.y - this->y * other.x);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
@ -30,7 +30,7 @@ namespace Rasterizer
|
|||
int32_t p = 2 * dy - dx;
|
||||
for (int32_t x = start.x; x <= end.x; x++)
|
||||
{
|
||||
frameBuffer.set_pixel(x, y, color.to_rgba());
|
||||
frameBuffer->set_pixel(x, y, color.to_rgba());
|
||||
// 当 p >= 0 时,取上方像素点
|
||||
if (p >= 0)
|
||||
{
|
||||
|
|
@ -63,7 +63,7 @@ namespace Rasterizer
|
|||
int32_t p = 2 * dx - dy;
|
||||
for (int32_t y = start.y; y <= end.y; y++)
|
||||
{
|
||||
frameBuffer.set_pixel(x, y, color.to_rgba());
|
||||
frameBuffer->set_pixel(x, y, color.to_rgba());
|
||||
// 当 p >= 0 时,取上方像素点
|
||||
if (p >= 0)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
#pragma once
|
||||
#include "Color.h"
|
||||
#include "FrameBuffer.h"
|
||||
#include "DepthBuffer.h"
|
||||
#include <Vector2.h>
|
||||
|
||||
namespace Rasterizer
|
||||
|
|
@ -8,13 +9,15 @@ namespace Rasterizer
|
|||
class Rasterizer
|
||||
{
|
||||
private:
|
||||
Core::FrameBuffer& frameBuffer;
|
||||
Core::FrameBuffer* frameBuffer;
|
||||
Core::DepthBuffer* depthBuffer;
|
||||
|
||||
void DrawLineHorizontal(const Math::Vector2Int v0, const Math::Vector2Int v1, const RenderData::Color color);
|
||||
void DrawLineVertical(const Math::Vector2Int v0, const Math::Vector2Int v1, const RenderData::Color color);
|
||||
|
||||
public:
|
||||
explicit Rasterizer(Core::FrameBuffer& frameBuffer) :frameBuffer(frameBuffer) {};
|
||||
explicit Rasterizer(Core::FrameBuffer* frameBuffer) :frameBuffer(frameBuffer), depthBuffer(nullptr) {}
|
||||
explicit Rasterizer(Core::FrameBuffer* frameBuffer, Core::DepthBuffer* depthBuffer) :frameBuffer(frameBuffer), depthBuffer(depthBuffer) {}
|
||||
|
||||
void DrawLine(const Math::Vector2Int v0, const Math::Vector2Int v1, const RenderData::Color color);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -10,20 +10,50 @@ namespace Rasterizer
|
|||
{
|
||||
void TriangleRasterizer::DrawTriangle2D(const RenderData::Triangle& triangle, const RenderData::Color color)
|
||||
{
|
||||
using namespace Math;
|
||||
|
||||
auto boundingBox = triangle.get_boundingBox();
|
||||
|
||||
int32_t minX = std::max(0, boundingBox.min.x);
|
||||
int32_t maxX = std::min(frameBuffer.get_width() - 1, boundingBox.max.x);
|
||||
int32_t maxX = std::min(frameBuffer->get_width() - 1, boundingBox.max.x);
|
||||
int32_t minY = std::max(0, boundingBox.min.y);
|
||||
int32_t maxY = std::min(frameBuffer.get_height() - 1, boundingBox.max.y);
|
||||
int32_t maxY = std::min(frameBuffer->get_height() - 1, boundingBox.max.y);
|
||||
|
||||
for (int x = minX; x <= maxX; x++)
|
||||
{
|
||||
for (int y = minY; y <= maxY; y++)
|
||||
{
|
||||
if (triangle.ContainsPixel(Math::Vector2Int(x, y)))
|
||||
Vector2 samplePoint(x + 0.5f, y + 0.5f);
|
||||
float w0 = 0, w1 = 0, w2 = 0;
|
||||
if (!triangle.get_barycentric(samplePoint, w0, w1, w2))
|
||||
{
|
||||
frameBuffer.set_pixel(Math::Vector2Int(x, y), color.to_rgba());
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((w0 < 0) || (w1 < 0) || (w2 < 0))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
const float depth =
|
||||
w0 * triangle.v0.position.z +
|
||||
w1 * triangle.v1.position.z +
|
||||
w2 * triangle.v2.position.z;
|
||||
|
||||
if (depthBuffer)
|
||||
{
|
||||
// 深度越小离相机越近
|
||||
if (depthBuffer->get_depth(x, y) < depth)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
depthBuffer->set_depth(x, y, depth);
|
||||
frameBuffer->set_pixel(x, y, color.to_rgba());
|
||||
}
|
||||
else
|
||||
{
|
||||
frameBuffer->set_pixel(x, y, color.to_rgba());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,17 +2,20 @@
|
|||
#include "Triangle.h"
|
||||
#include "Color.h"
|
||||
#include "FrameBuffer.h"
|
||||
#include <DepthBuffer.h>
|
||||
|
||||
namespace Rasterizer
|
||||
{
|
||||
class TriangleRasterizer
|
||||
{
|
||||
private:
|
||||
Core::FrameBuffer& frameBuffer;
|
||||
Core::FrameBuffer* frameBuffer;
|
||||
Core::DepthBuffer* depthBuffer;
|
||||
|
||||
|
||||
public:
|
||||
explicit TriangleRasterizer(Core::FrameBuffer& frameBuffer) :frameBuffer(frameBuffer) {};
|
||||
explicit TriangleRasterizer(Core::FrameBuffer* frameBuffer) :frameBuffer(frameBuffer), depthBuffer(nullptr) {};
|
||||
explicit TriangleRasterizer(Core::FrameBuffer* frameBuffer, Core::DepthBuffer* depthBuffer) :frameBuffer(frameBuffer), depthBuffer(depthBuffer) {};
|
||||
|
||||
void DrawTriangle2D(const RenderData::Triangle& triangle, const RenderData::Color color);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <Vector3.h>
|
||||
#include <cstdlib>
|
||||
|
||||
namespace RenderData
|
||||
{
|
||||
|
|
@ -32,28 +33,35 @@ namespace RenderData
|
|||
return BoundingBox2D(min, max);
|
||||
}
|
||||
|
||||
bool ContainsPixel(const Math::Vector2Int point) const
|
||||
/// <summary>
|
||||
/// 给定屏幕像素坐标,输出该点的面积坐标
|
||||
/// </summary>
|
||||
/// <param name="pos">要计算的屏幕像素点</param>
|
||||
/// <param name="w0">面积坐标的 x 分量(引用)</param>
|
||||
/// <param name="w1">面积坐标的 y 分量(引用)</param>
|
||||
/// <param name="w2">面积坐标的 z 分量(引用)</param>
|
||||
/// <returns>是否计算成功</returns>
|
||||
bool get_barycentric(const Math::Vector2& p, float& w0, float& w1, float& w2) const
|
||||
{
|
||||
using namespace Scene;
|
||||
using namespace Math;
|
||||
|
||||
auto cross = [](const Vertex& v1, const Vertex& v2, const Math::Vector2Int& point) -> float
|
||||
{
|
||||
Scene::Vertex v3(Math::Vector3(point.x, point.y, 0));
|
||||
const float x1 = v2.position.x - v1.position.x;
|
||||
const float y1 = v2.position.y - v1.position.y;
|
||||
const float x2 = v3.position.x - v1.position.x;
|
||||
const float y2 = v3.position.y - v1.position.y;
|
||||
return x1 * y2 - y1 * x2;
|
||||
};
|
||||
const float x0 = v0.position.x;
|
||||
const float y0 = v0.position.y;
|
||||
const float x1 = v1.position.x;
|
||||
const float y1 = v1.position.y;
|
||||
const float x2 = v2.position.x;
|
||||
const float y2 = v2.position.y;
|
||||
|
||||
const float c0 = cross(v0, v1, point);
|
||||
const float c1 = cross(v1, v2, point);
|
||||
const float c2 = cross(v2, v0, point);
|
||||
const float square2D = (y1 - y2) * (x0 - x2) + (x2 - x1) * (y0 - y2);
|
||||
if (std::abs(square2D) < 1e-6f)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const bool hasNeg = (c0 < 0) || (c1 < 0) || (c2 < 0);
|
||||
const bool hasPos = (c0 > 0) || (c1 > 0) || (c2 > 0);
|
||||
|
||||
return !(hasNeg && hasPos);
|
||||
w0 = ((y1 - y2) * (p.x - x2) + (x2 - x1) * (p.y - y2)) / square2D;
|
||||
w1 = ((y2 - y0) * (p.x - x2) + (x0 - x2) * (p.y - y2)) / square2D;
|
||||
w2 = 1.0f - w0 - w1;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
@ -23,6 +23,7 @@
|
|||
#include <cstdlib>
|
||||
#include <algorithm>
|
||||
#include "Vertex.h"
|
||||
#include "DepthBuffer.h"
|
||||
|
||||
const uint32_t SDL_INIT_FLAGS = SDL_INIT_VIDEO;
|
||||
const int32_t width = 800;
|
||||
|
|
@ -135,12 +136,6 @@ struct CubeTriangle
|
|||
std::array<int, 3> vertices;
|
||||
};
|
||||
|
||||
struct TriangleDrawCommand
|
||||
{
|
||||
RenderData::Triangle triangle;
|
||||
float averageViewSpaceZ = 0.0f;
|
||||
};
|
||||
|
||||
static ProjectedVertex ProjectToScreen(
|
||||
const Math::Vector3& vertex,
|
||||
const Math::Matrix4x4& mvp,
|
||||
|
|
@ -208,9 +203,10 @@ int main(int argc, char* argv[])
|
|||
|
||||
if (!EnsureTexture()) return -1;
|
||||
|
||||
Core::FrameBuffer frameBuffer(width, height);
|
||||
Rasterizer::Rasterizer rasterizer(frameBuffer);
|
||||
Rasterizer::TriangleRasterizer triangleRasterizer(frameBuffer);
|
||||
Core::FrameBuffer* frameBuffer = new Core::FrameBuffer(width, height);
|
||||
Core::DepthBuffer* depthBuffer = new Core::DepthBuffer(width, height);
|
||||
Rasterizer::Rasterizer rasterizer(frameBuffer, depthBuffer);
|
||||
Rasterizer::TriangleRasterizer triangleRasterizer(frameBuffer, depthBuffer);
|
||||
|
||||
Scene::Camera camera;
|
||||
camera.transform.position = Math::Vector3(0.0f, 0.0f, 3.0f);
|
||||
|
|
@ -265,7 +261,8 @@ int main(int argc, char* argv[])
|
|||
}
|
||||
}
|
||||
|
||||
frameBuffer.clear(clearColor);
|
||||
frameBuffer->clear(clearColor);
|
||||
depthBuffer->clear();
|
||||
|
||||
const float timeSeconds = static_cast<float>(SDL_GetTicks()) * 0.001f;
|
||||
const Math::Matrix4x4 model =
|
||||
|
|
@ -291,7 +288,7 @@ int main(int argc, char* argv[])
|
|||
visibleFaces[faceIndex] = IsFaceVisible(cubeFaces[faceIndex], viewSpaceVertices);
|
||||
}
|
||||
|
||||
std::array<TriangleDrawCommand, 12> drawCommands;
|
||||
std::array<RenderData::Triangle, 12> drawTriangles;
|
||||
size_t drawCommandCount = 0;
|
||||
for (const CubeTriangle& cubeTriangle : cubeTriangles)
|
||||
{
|
||||
|
|
@ -312,27 +309,17 @@ int main(int argc, char* argv[])
|
|||
const Math::Vector3& viewV1 = viewSpaceVertices[cubeTriangle.vertices[1]];
|
||||
const Math::Vector3& viewV2 = viewSpaceVertices[cubeTriangle.vertices[2]];
|
||||
|
||||
drawCommands[drawCommandCount++] = TriangleDrawCommand{
|
||||
drawTriangles[drawCommandCount++] =
|
||||
RenderData::Triangle(
|
||||
Scene::Vertex(v0.screen),
|
||||
Scene::Vertex(v1.screen),
|
||||
Scene::Vertex(v2.screen)
|
||||
),
|
||||
(viewV0.z + viewV1.z + viewV2.z) / 3.0f
|
||||
};
|
||||
);
|
||||
}
|
||||
|
||||
std::sort(
|
||||
drawCommands.begin(),
|
||||
drawCommands.begin() + drawCommandCount,
|
||||
[](const TriangleDrawCommand& a, const TriangleDrawCommand& b)
|
||||
{
|
||||
return a.averageViewSpaceZ < b.averageViewSpaceZ;
|
||||
});
|
||||
|
||||
for (size_t i = 0; i < drawCommandCount; ++i)
|
||||
{
|
||||
triangleRasterizer.DrawTriangle2D(drawCommands[i].triangle, cubeColor);
|
||||
triangleRasterizer.DrawTriangle2D(drawTriangles[i], cubeColor);
|
||||
}
|
||||
|
||||
for (size_t faceIndex = 0; faceIndex < cubeFaces.size(); ++faceIndex)
|
||||
|
|
@ -361,7 +348,7 @@ int main(int argc, char* argv[])
|
|||
}
|
||||
}
|
||||
|
||||
SDL_UpdateTexture(texture, nullptr, frameBuffer.get_buffer(), width * sizeof(uint32_t));
|
||||
SDL_UpdateTexture(texture, nullptr, frameBuffer->get_buffer(), width * sizeof(uint32_t));
|
||||
SDL_RenderClear(renderer);
|
||||
SDL_RenderCopy(renderer, texture, nullptr, nullptr);
|
||||
SDL_RenderPresent(renderer);
|
||||
|
|
|
|||
Loading…
Reference in New Issue