重构项目,为后续开发铺路

This commit is contained in:
SepComet 2026-03-15 16:20:36 +08:00
parent bd2f846a34
commit 7bd5d7c13d
38 changed files with 791 additions and 516 deletions

View File

@ -3,5 +3,7 @@
<Platform Name="x64" /> <Platform Name="x64" />
<Platform Name="x86" /> <Platform Name="x86" />
</Configurations> </Configurations>
<Project Path="CPU-Software-Renderer/CPU-Software-Renderer.vcxproj" Id="937b923d-dd0c-41ae-81eb-af978170b0ca" /> <Project Path="CPU-Software-Renderer/CPU-Software-Renderer.vcxproj" Id="937b923d-dd0c-41ae-81eb-af978170b0ca">
<Platform Solution="Debug|x86" Project="x64" />
</Project>
</Solution> </Solution>

View File

@ -0,0 +1,7 @@
#pragma once
namespace Asset
{
class ObjLoader
{};
}

View File

@ -77,10 +77,13 @@
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode> <ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp20</LanguageStandard> <LanguageStandard>stdcpp20</LanguageStandard>
<AdditionalIncludeDirectories>D:\source\CPU-Software-Renderer\CPU-Software-Renderer\Asset;D:\source\CPU-Software-Renderer\CPU-Software-Renderer\Core;D:\source\CPU-Software-Renderer\CPU-Software-Renderer\Math;D:\source\CPU-Software-Renderer\CPU-Software-Renderer\Rasterizer;D:\source\CPU-Software-Renderer\CPU-Software-Renderer\RenderData;D:\source\CPU-Software-Renderer\CPU-Software-Renderer\Scene;D:\source\CPU-Software-Renderer\CPU-Software-Renderer\Shading;D:\source\CPU-Software-Renderer\CPU-Software-Renderer\libs\SDL2\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile> </ClCompile>
<Link> <Link>
<SubSystem>Console</SubSystem> <SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>SDL2.lib;SDL2main.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>D:\source\CPU-Software-Renderer\CPU-Software-Renderer\libs\SDL2\lib\x86;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
@ -92,10 +95,13 @@
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode> <ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp20</LanguageStandard> <LanguageStandard>stdcpp20</LanguageStandard>
<AdditionalIncludeDirectories>D:\source\CPU-Software-Renderer\CPU-Software-Renderer\Asset;D:\source\CPU-Software-Renderer\CPU-Software-Renderer\Core;D:\source\CPU-Software-Renderer\CPU-Software-Renderer\Math;D:\source\CPU-Software-Renderer\CPU-Software-Renderer\Rasterizer;D:\source\CPU-Software-Renderer\CPU-Software-Renderer\RenderData;D:\source\CPU-Software-Renderer\CPU-Software-Renderer\Scene;D:\source\CPU-Software-Renderer\CPU-Software-Renderer\Shading;D:\source\CPU-Software-Renderer\CPU-Software-Renderer\libs\SDL2\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile> </ClCompile>
<Link> <Link>
<SubSystem>Console</SubSystem> <SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>SDL2.lib;SDL2main.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>D:\source\CPU-Software-Renderer\CPU-Software-Renderer\libs\SDL2\lib\x86;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
@ -105,7 +111,7 @@
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode> <ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp20</LanguageStandard> <LanguageStandard>stdcpp20</LanguageStandard>
<AdditionalIncludeDirectories>D:\source\CPU-Software-Renderer\CPU-Software-Renderer\libs\SDL2\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>D:\source\CPU-Software-Renderer\CPU-Software-Renderer\Asset;D:\source\CPU-Software-Renderer\CPU-Software-Renderer\Core;D:\source\CPU-Software-Renderer\CPU-Software-Renderer\Math;D:\source\CPU-Software-Renderer\CPU-Software-Renderer\Rasterizer;D:\source\CPU-Software-Renderer\CPU-Software-Renderer\RenderData;D:\source\CPU-Software-Renderer\CPU-Software-Renderer\Scene;D:\source\CPU-Software-Renderer\CPU-Software-Renderer\Shading;D:\source\CPU-Software-Renderer\CPU-Software-Renderer\libs\SDL2\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile> </ClCompile>
<Link> <Link>
<SubSystem>Console</SubSystem> <SubSystem>Console</SubSystem>
@ -123,24 +129,50 @@
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode> <ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp20</LanguageStandard> <LanguageStandard>stdcpp20</LanguageStandard>
<AdditionalIncludeDirectories>D:\source\CPU-Software-Renderer\CPU-Software-Renderer\Asset;D:\source\CPU-Software-Renderer\CPU-Software-Renderer\Core;D:\source\CPU-Software-Renderer\CPU-Software-Renderer\Math;D:\source\CPU-Software-Renderer\CPU-Software-Renderer\Rasterizer;D:\source\CPU-Software-Renderer\CPU-Software-Renderer\RenderData;D:\source\CPU-Software-Renderer\CPU-Software-Renderer\Scene;D:\source\CPU-Software-Renderer\CPU-Software-Renderer\Shading;D:\source\CPU-Software-Renderer\CPU-Software-Renderer\libs\SDL2\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile> </ClCompile>
<Link> <Link>
<SubSystem>Console</SubSystem> <SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>SDL2.lib;SDL2main.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>D:\source\CPU-Software-Renderer\CPU-Software-Renderer\libs\SDL2\lib\x64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="Color.cpp" /> <ClCompile Include="Asset\ObjLoader.cpp" />
<ClCompile Include="Core\DepthBuffer.cpp" />
<ClCompile Include="Core\FrameBuffer.cpp" />
<ClCompile Include="Core\Renderer.cpp" />
<ClCompile Include="main.cpp" /> <ClCompile Include="main.cpp" />
<ClCompile Include="Rasterization.cpp" /> <ClCompile Include="Rasterizer\Rasterizer.cpp" />
<ClCompile Include="Rasterizer\TriangleRasterizer.cpp" />
<ClCompile Include="Shading\BlinnPhongShader.cpp" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="TODO.md" /> <None Include="TODO.md" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="Color.h" /> <ClInclude Include="Asset\ObjLoader.h" />
<ClInclude Include="Rasterization.h" /> <ClInclude Include="Core\DepthBuffer.h" />
<ClInclude Include="StructType.h" /> <ClInclude Include="Core\FrameBuffer.h" />
<ClInclude Include="Core\Renderer.h" />
<ClInclude Include="Math\MathUtil.h" />
<ClInclude Include="Math\Matrix4x4.h" />
<ClInclude Include="Math\Vector2.h" />
<ClInclude Include="Math\Vector3.h" />
<ClInclude Include="Math\Vector4.h" />
<ClInclude Include="Rasterizer\Rasterizer.h" />
<ClInclude Include="Rasterizer\TriangleRasterizer.h" />
<ClInclude Include="RenderData\BoundingBox.h" />
<ClInclude Include="RenderData\Color.h" />
<ClInclude Include="RenderData\Triangle.h" />
<ClInclude Include="Scene\Camera.h" />
<ClInclude Include="Scene\Mesh.h" />
<ClInclude Include="Scene\Model.h" />
<ClInclude Include="Scene\Transform.h" />
<ClInclude Include="Scene\Vertex.h" />
<ClInclude Include="Shading\BlinnPhongShader.h" />
<ClInclude Include="Shading\ShaderTypes.h" />
</ItemGroup> </ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets"> <ImportGroup Label="ExtensionTargets">

View File

@ -13,16 +13,64 @@
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier> <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions> <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter> </Filter>
<Filter Include="头文件\Core">
<UniqueIdentifier>{e546c002-17ba-4911-9a70-a1cf7ce337fd}</UniqueIdentifier>
</Filter>
<Filter Include="头文件\Math">
<UniqueIdentifier>{b92096d9-3d39-4064-b9a2-efa279ad0775}</UniqueIdentifier>
</Filter>
<Filter Include="头文件\Scene">
<UniqueIdentifier>{7b6f5c6b-60bb-46f2-925b-65346e4d8c4b}</UniqueIdentifier>
</Filter>
<Filter Include="头文件\Shading">
<UniqueIdentifier>{1aa3c6ac-a580-480c-a2fe-2d57c98693ff}</UniqueIdentifier>
</Filter>
<Filter Include="头文件\Rasterizer">
<UniqueIdentifier>{a7d67eb7-b4bc-4b5a-86f2-e80bcd1518d5}</UniqueIdentifier>
</Filter>
<Filter Include="头文件\Asset">
<UniqueIdentifier>{55224e49-7917-4fee-9a61-f1c14ebf8d5e}</UniqueIdentifier>
</Filter>
<Filter Include="源文件\Core">
<UniqueIdentifier>{6eda961b-ec6a-4670-b093-be46b27fdeb7}</UniqueIdentifier>
</Filter>
<Filter Include="源文件\Asset">
<UniqueIdentifier>{4345cc0e-3d61-4dd9-b37f-4b42c30aa8d3}</UniqueIdentifier>
</Filter>
<Filter Include="源文件\Rasterizer">
<UniqueIdentifier>{4b52509e-dde8-45e0-aeb3-d18131b94265}</UniqueIdentifier>
</Filter>
<Filter Include="源文件\Shading">
<UniqueIdentifier>{1644176d-c2fe-404b-9f42-45eb0bc85222}</UniqueIdentifier>
</Filter>
<Filter Include="头文件\RenderData">
<UniqueIdentifier>{c77ae566-281a-4d76-80bd-41496deb0aeb}</UniqueIdentifier>
</Filter>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="main.cpp"> <ClCompile Include="main.cpp">
<Filter>源文件</Filter> <Filter>源文件</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="Color.cpp"> <ClCompile Include="Core\DepthBuffer.cpp">
<Filter>源文件</Filter> <Filter>源文件\Core</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="Rasterization.cpp"> <ClCompile Include="Core\FrameBuffer.cpp">
<Filter>源文件</Filter> <Filter>源文件\Core</Filter>
</ClCompile>
<ClCompile Include="Core\Renderer.cpp">
<Filter>源文件\Core</Filter>
</ClCompile>
<ClCompile Include="Asset\ObjLoader.cpp">
<Filter>源文件\Asset</Filter>
</ClCompile>
<ClCompile Include="Shading\BlinnPhongShader.cpp">
<Filter>源文件\Shading</Filter>
</ClCompile>
<ClCompile Include="Rasterizer\Rasterizer.cpp">
<Filter>源文件\Rasterizer</Filter>
</ClCompile>
<ClCompile Include="Rasterizer\TriangleRasterizer.cpp">
<Filter>源文件\Rasterizer</Filter>
</ClCompile> </ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
@ -31,14 +79,68 @@
</None> </None>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="Color.h"> <ClInclude Include="Core\DepthBuffer.h">
<Filter>头文件</Filter> <Filter>头文件\Core</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="StructType.h"> <ClInclude Include="Core\FrameBuffer.h">
<Filter>头文件</Filter> <Filter>头文件\Core</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="Rasterization.h"> <ClInclude Include="Core\Renderer.h">
<Filter>头文件</Filter> <Filter>头文件\Core</Filter>
</ClInclude>
<ClInclude Include="Math\MathUtil.h">
<Filter>头文件\Math</Filter>
</ClInclude>
<ClInclude Include="Math\Matrix4x4.h">
<Filter>头文件\Math</Filter>
</ClInclude>
<ClInclude Include="Math\Vector2.h">
<Filter>头文件\Math</Filter>
</ClInclude>
<ClInclude Include="Math\Vector3.h">
<Filter>头文件\Math</Filter>
</ClInclude>
<ClInclude Include="Math\Vector4.h">
<Filter>头文件\Math</Filter>
</ClInclude>
<ClInclude Include="Scene\Camera.h">
<Filter>头文件\Scene</Filter>
</ClInclude>
<ClInclude Include="Scene\Mesh.h">
<Filter>头文件\Scene</Filter>
</ClInclude>
<ClInclude Include="Scene\Model.h">
<Filter>头文件\Scene</Filter>
</ClInclude>
<ClInclude Include="Scene\Transform.h">
<Filter>头文件\Scene</Filter>
</ClInclude>
<ClInclude Include="Scene\Vertex.h">
<Filter>头文件\Scene</Filter>
</ClInclude>
<ClInclude Include="Shading\BlinnPhongShader.h">
<Filter>头文件\Shading</Filter>
</ClInclude>
<ClInclude Include="Shading\ShaderTypes.h">
<Filter>头文件\Shading</Filter>
</ClInclude>
<ClInclude Include="Rasterizer\Rasterizer.h">
<Filter>头文件\Rasterizer</Filter>
</ClInclude>
<ClInclude Include="Rasterizer\TriangleRasterizer.h">
<Filter>头文件\Rasterizer</Filter>
</ClInclude>
<ClInclude Include="Asset\ObjLoader.h">
<Filter>头文件\Asset</Filter>
</ClInclude>
<ClInclude Include="RenderData\Triangle.h">
<Filter>头文件\RenderData</Filter>
</ClInclude>
<ClInclude Include="RenderData\Color.h">
<Filter>头文件\RenderData</Filter>
</ClInclude>
<ClInclude Include="RenderData\BoundingBox.h">
<Filter>头文件\RenderData</Filter>
</ClInclude> </ClInclude>
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -1,22 +0,0 @@
#include "Color.h"
Color::Color(uint8_t r, uint8_t g, uint8_t b, uint8_t a)
{
this->r = r;
this->g = g;
this->b = b;
this->a = a;
}
Color::Color(uint8_t r, uint8_t g, uint8_t b)
{
Color(r, g, b, 255);
}
Color::Color(Color& other)
{
this->r = other.r;
this->g = other.g;
this->b = other.b;
this->a = other.a;
}

View File

@ -1,34 +0,0 @@
#pragma once
#include<cstdint>
class Color
{
uint8_t r;
uint8_t g;
uint8_t b;
uint8_t a;
public:
Color(uint8_t r, uint8_t g, uint8_t b, uint8_t a);
Color(uint8_t r, uint8_t g, uint8_t b);
Color(Color& other);
uint8_t GetR() const { return r; }
void SetR(const uint8_t r) { this->r = r; }
uint8_t GetG() const { return g; }
void SetG(const uint8_t g) { this->g = g; }
uint8_t GetB() const { return b; }
void SetB(const uint8_t b) { this->b = b; }
uint8_t GetA() const { return a; }
void SetA(const uint8_t a) { this->a = a; }
operator uint32_t() const
{
return (r << 24) | (g << 16) | (b << 8) | a;
}
};

View File

@ -0,0 +1,7 @@
#pragma once
namespace Core
{
class DepthBuffer
{};
}

View File

@ -0,0 +1,25 @@
#include "FrameBuffer.h"
#include <cstdint>
#include <iostream>
#include <algorithm>
using namespace Math;
namespace Core
{
void FrameBuffer::clear(const uint32_t color)
{
std::fill(buffer.begin(), buffer.end(), color);
}
void FrameBuffer::set_pixel(const int32_t x, const int32_t y, const uint32_t color)
{
if (x < 0 || x >= width || y < 0 || y >= height)
{
std::cerr << "Error: Attempting to set pixel at (" << x << ", " << y << ") which is out of bounds." << std::endl;
return;
}
size_t index = static_cast<size_t>(y) * width + x;
buffer.at(index) = color;
}
}

View File

@ -0,0 +1,42 @@
#pragma once
#include "Color.h"
#include "Vector2.h"
#include <cstdint>
#include <vector>
namespace Core
{
class FrameBuffer
{
private:
int32_t width;
int32_t height;
std::vector<uint32_t> buffer;
public:
size_t total_pixels() const { return buffer.size(); }
void* get_buffer() const { return (void*)buffer.data(); }
FrameBuffer(int32_t width, int32_t height) :width(width), height(height), buffer(std::vector<uint32_t>(width * height, 0)) {}
void clear(const RenderData::Color& color)
{
clear(color.to_rgba());
}
void clear(const uint32_t color);
void set_pixel(const int32_t x, const int32_t y, const RenderData::Color& color)
{
set_pixel(Math::Vector2Int(x, y), color.to_rgba());
}
void set_pixel(const Math::Vector2Int position, const uint32_t color)
{
set_pixel(position.x, position.y, color);
}
void set_pixel(const int32_t x, const int32_t y, const uint32_t color);
};
}

View File

View File

@ -0,0 +1,7 @@
#pragma once
namespace Core
{
class Renderer
{};
}

View File

@ -0,0 +1,7 @@
#pragma once
namespace Math
{
class MathUtil
{};
}

View File

@ -0,0 +1,7 @@
#pragma once
namespace Math
{
class Matrix4x4
{};
}

View File

@ -0,0 +1,50 @@
#pragma once
#include <cstdint>
#include <utility>
#include <cmath>
namespace Math
{
struct Vector2Int
{
int32_t x = 0;
int32_t y = 0;
Vector2Int() : x(0), y(0) {}
Vector2Int(int32_t x, int32_t y) : x(x), y(y) {}
/// <summary>
/// 交换当前 Vector2Int 对象与另一个 Vector2Int 对象的 x 和 y 的值
/// </summary>
/// <param name="other">要交换的对象</param>
static void swap(Vector2Int& vec1, Vector2Int& vec2)
{
std::swap(vec1.x, vec2.x);
std::swap(vec1.y, vec2.y);
}
};
struct Vector2
{
float x = 0.0f;
float y = 0.0f;
Vector2() : x(0), y(0) {}
Vector2(float x, float y) : x(x), y(y) {}
/// <summary>
/// 交换当前 Vector2 对象与另一个 Vector2 对象的 x 和 y 的值
/// </summary>
/// <param name="other">要交换的对象</param>
static void swap(Vector2& vec1, Vector2& vec2)
{
std::swap(vec1.x, vec2.x);
std::swap(vec1.y, vec2.y);
}
Vector2Int to_vector2Int() const
{
return Vector2Int(static_cast<int32_t>(std::lround(x)), static_cast<int32_t>(std::lround(y)));
}
};
}

View File

@ -0,0 +1,20 @@
#pragma once
#include <cmath>
namespace Math
{
struct Vector3
{
float x = 0.0f;
float y = 0.0f;
float z = 0.0f;
Vector3() : x(0), y(0), z(0) {}
Vector3(float x, float y, float z) : x(x), y(y), z(z) {}
float magnitude() const
{
return std::sqrt(x * x + y * y + z * z);
}
};
}

View File

@ -0,0 +1,7 @@
#pragma once
namespace Math
{
class Vector4
{};
}

View File

@ -1,129 +0,0 @@
#include "Rasterization.h"
#include "StructType.h"
#include <vector>
#include <algorithm>
#include <cstdint>
#include <cmath>
using namespace CustomStructs;
void Rasterization::DrawLineHorizontal(Vector2Int v0, Vector2Int v1, Color color)
{
if (v0.x > v1.x) Vector2Int::swap(v0, v1);
int32_t dx = v1.x - v0.x;
int32_t dy = v1.y - v0.y;
int32_t dir = dy < 0 ? -1 : 1;
dy *= dir;
if (dx == 0) return;
int32_t y = v0.y;
int32_t p = 2 * dy - dx;
for (int32_t x = v0.x; x <= v1.x; x++)
{
SetPixel(Vector2Int(x, y), color);
// 当 p >= 0 时,取上方像素点
if (p >= 0)
{
y += dir;
p -= 2 * dx;
}
// 当 p < 0 时,取下方像素点
p += 2 * dy;
}
}
void Rasterization::DrawLineVertical(Vector2Int v0, Vector2Int v1, Color color)
{
if (v0.y > v1.y) Vector2Int::swap(v0, v1);
int32_t dx = v1.x - v0.x;
int32_t dy = v1.y - v0.y;
int32_t dir = dx < 0 ? -1 : 1;
dx *= dir;
if (dy == 0) return;
int32_t x = v0.x;
int32_t p = 2 * dx - dy;
for (int32_t y = v0.y; y <= v1.y; y++)
{
SetPixel(Vector2Int(x, y), color);
// 当 p >= 0 时,取上方像素点
if (p >= 0)
{
x += dir;
p -= 2 * dy;
}
// 当 p < 0 时,取下方像素点
p += 2 * dx;
}
}
/// <summary>
/// 在给定的起始点和结束点之间绘制一条线段,并使用指定的颜色填充
/// </summary>
/// <param name="v0">直线顶点 1</param>
/// <param name="v1">直线顶点 2</param>
/// <param name="color">绘制的颜色</param>
/// <remarks>
/// bresenham 画线算法
/// </remarks>
void Rasterization::DrawLine(Vector2Int v0, Vector2Int v1, Color color)
{
int32_t x0 = v0.x, y0 = v0.y;
int32_t x1 = v1.x, y1 = v1.y;
if (std::abs(x1 - x0) > std::abs(y1 - y0))
{
DrawLineHorizontal(v0, v1, color);
}
else
{
DrawLineVertical(v0, v1, color);
}
}
void Rasterization::Clear(const Color color)
{
uint32_t colorValue = static_cast<uint32_t>(color);
std::fill(frameBuffer.begin(), frameBuffer.end(), colorValue);
}
void Rasterization::SetPixel(const Vector2Int pos, const Color color)
{
uint32_t colorValue = static_cast<uint32_t>(color);
if (pos.x < 0 || pos.y < 0 || pos.x >= width || pos.y >= height) return;
const size_t pixelIndex = static_cast<size_t>(pos.y) * static_cast<size_t>(width) + static_cast<size_t>(pos.x);
frameBuffer[pixelIndex] = colorValue;
}
void Rasterization::DrawWireTriangle(const Vector2Int v0, const Vector2Int v1, const Vector2Int v2, Color color)
{
DrawLine(v0, v1, color);
DrawLine(v0, v2, color);
DrawLine(v1, v2, color);
}
void Rasterization::DrawFillTriangle(const Vector2Int v0, const Vector2Int v1, const Vector2Int v2, Color color)
{
Vector2Int aa, bb;
aa.x = std::min({ v0.x, v1.x, v2.x });
aa.y = std::min({ v0.y, v1.y, v2.y });
bb.x = std::max({ v0.x, v1.x, v2.x });
bb.y = std::max({ v0.y, v1.y, v2.y });
Triangle triangle(v0, v1, v2);
for (int x = aa.x; x <= bb.x; x++)
{
for (int y = aa.y; y <= bb.y; y++)
{
if (triangle.IsInTriangle(Vector2Int(x, y)))
{
SetPixel(Vector2Int(x, y), color);
}
}
}
}

View File

@ -1,34 +0,0 @@
#pragma once
#include "StructType.h"
#include <vector>
#include <cstdint>
using namespace CustomStructs;
class Rasterization
{
private:
int32_t width;
int32_t height;
public:
std::vector<uint32_t> frameBuffer;
private:
void DrawLineHorizontal(Vector2Int v0, Vector2Int v1, Color color);
void DrawLineVertical(Vector2Int v0, Vector2Int v1, Color color);
public:
Rasterization(const int32_t width, const int32_t height)
: width(width), height(height), frameBuffer(std::vector<uint32_t>(static_cast<size_t>(width)* static_cast<size_t>(height))) {}
void Clear(const Color color);
void SetPixel(const Vector2Int pos, const Color color);
void DrawLine(const Vector2Int v0, const Vector2Int v1, Color color);
void DrawWireTriangle(const Vector2Int v0, const Vector2Int v1, const Vector2Int v2, Color color);
void DrawFillTriangle(const Vector2Int v0, const Vector2Int v1, const Vector2Int v2, Color color);
};

View File

@ -0,0 +1,102 @@
#include "Rasterizer.h"
#include <Vector2.h>
#include "Color.h"
#include <cmath>
#include <cstdint>
namespace Rasterizer
{
using namespace Math;
using namespace RenderData;
void Rasterizer::DrawLineHorizontal(const Vector2Int v0, const Vector2Int v1, const Color color)
{
Vector2Int start = v0, end = v1;
if (v0.x > v1.x)
{
start = v1;
end = v0;
}
int32_t dx = end.x - start.x;
int32_t dy = end.y - start.y;
int32_t dir = dy < 0 ? -1 : 1;
dy *= dir;
if (dx == 0) return;
int32_t y = start.y;
int32_t p = 2 * dy - dx;
for (int32_t x = start.x; x <= end.x; x++)
{
frameBuffer.set_pixel(x, y, color.to_rgba());
// 当 p >= 0 时,取上方像素点
if (p >= 0)
{
y += dir;
p -= 2 * dx;
}
// 当 p < 0 时,取下方像素点
p += 2 * dy;
}
}
void Rasterizer::DrawLineVertical(const Vector2Int v0, const Vector2Int v1, const Color color)
{
Vector2Int start = v0, end = v1;
if (v0.y > v1.y)
{
start = v1;
end = v0;
}
int32_t dx = end.x - start.x;
int32_t dy = end.y - start.y;
int32_t dir = dx < 0 ? -1 : 1;
dx *= dir;
if (dy == 0) return;
int32_t x = start.x;
int32_t p = 2 * dx - dy;
for (int32_t y = start.y; y <= end.y; y++)
{
frameBuffer.set_pixel(x, y, color.to_rgba());
// 当 p >= 0 时,取上方像素点
if (p >= 0)
{
x += dir;
p -= 2 * dy;
}
// 当 p < 0 时,取下方像素点
p += 2 * dx;
}
}
/// <summary>
/// 在给定的起始点和结束点之间绘制一条线段,并使用指定的颜色填充
/// </summary>
/// <param name="v0">直线顶点 1</param>
/// <param name="v1">直线顶点 2</param>
/// <param name="color">绘制的颜色</param>
/// <remarks>
/// bresenham 画线算法
/// </remarks>
void Rasterizer::DrawLine(const Vector2Int v0, const Vector2Int v1, const Color color)
{
int32_t x0 = v0.x, y0 = v0.y;
int32_t x1 = v1.x, y1 = v1.y;
if (std::abs(x1 - x0) > std::abs(y1 - y0))
{
DrawLineHorizontal(v0, v1, color);
}
else
{
DrawLineVertical(v0, v1, color);
}
}
}

View File

@ -0,0 +1,21 @@
#pragma once
#include "Color.h"
#include "FrameBuffer.h"
#include <Vector2.h>
namespace Rasterizer
{
class Rasterizer
{
private:
Core::FrameBuffer& frameBuffer;
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) {};
void DrawLine(const Math::Vector2Int v0, const Math::Vector2Int v1, const RenderData::Color color);
};
}

View File

@ -0,0 +1,25 @@
#include "TriangleRasterizer.h"
#include <Triangle.h>
#include <Color.h>
#include "BoundingBox.h"
#include <Vector2.h>
using namespace RenderData;
namespace Rasterizer
{
void TriangleRasterizer::DrawTriangle2D(const Triangle2D triangle, const Color color)
{
auto boundingBox = triangle.get_boundingBox();
for (int x = boundingBox.min.x; x <= boundingBox.max.x; x++)
{
for (int y = boundingBox.min.y; y <= boundingBox.max.y; y++)
{
if (triangle.ContainsPixel(Vector2(x, y)))
{
frameBuffer.set_pixel(Vector2Int(x, y), color.to_rgba());
}
}
}
}
}

View File

@ -0,0 +1,19 @@
#pragma once
#include "Triangle.h"
#include "Color.h"
#include "FrameBuffer.h"
namespace Rasterizer
{
class TriangleRasterizer
{
private:
Core::FrameBuffer& frameBuffer;
public:
explicit TriangleRasterizer(Core::FrameBuffer& frameBuffer) :frameBuffer(frameBuffer) {};
void DrawTriangle2D(const RenderData::Triangle2D triangle, const RenderData::Color color);
};
}

View File

@ -0,0 +1,14 @@
#pragma once
#include "Vector2.h"
namespace RenderData
{
struct BoundingBox2D
{
Math::Vector2 min;
Math::Vector2 max;
BoundingBox2D() : min(), max() {}
BoundingBox2D(const Math::Vector2 min, const Math::Vector2 max) : min(min), max(max) {}
};
}

View File

@ -0,0 +1,34 @@
#pragma once
#include <cstdint>
namespace RenderData
{
struct Color
{
uint8_t r;
uint8_t g;
uint8_t b;
uint8_t a;
Color() : r(0), g(0), b(0), a(0) {}
Color(uint8_t r, uint8_t g, uint8_t b, uint8_t a)
{
this->r = ClampToByte(r);
this->g = ClampToByte(g);
this->b = ClampToByte(b);
this->a = ClampToByte(a);
}
uint32_t to_rgba() const
{
uint32_t value = (static_cast<uint32_t>(r) << 24) | (static_cast<uint32_t>(g) << 16) | (static_cast<uint32_t>(b) << 8) | (static_cast<uint32_t>(a));
return value;
}
static uint8_t ClampToByte(const int32_t value)
{
if (value < 0) return 0;
if (value > 255) return 255;
return static_cast<uint8_t>(value);
}
};
}

View File

@ -0,0 +1,47 @@
#pragma once
#include "Vector2.h"
#include "BoundingBox.h"
#include <algorithm>
namespace RenderData
{
using namespace Math;
struct Triangle2D
{
Vector2 v0;
Vector2 v1;
Vector2 v2;
Triangle2D() : v0(), v1(), v2() {}
Triangle2D(const Vector2 a, const Vector2 b, const Vector2 c) : v0(a), v1(b), v2(c) {}
BoundingBox2D get_boundingBox() const
{
Vector2 min, max;
min = Vector2(std::min({ v0.x, v1.x, v2.x }), min.y = std::min({ v0.y, v1.y, v2.y }));
max = Vector2(std::max({ v0.x, v1.x, v2.x }), max.y = std::max({ v0.y, v1.y, v2.y }));
return BoundingBox2D(min, max);
}
bool ContainsPixel(const Vector2 point) const
{
auto cross = [](const Vector2& p1, const Vector2& p2, const Vector2& p3) -> float
{
const float x1 = p2.x - p1.x;
const float y1 = p2.y - p1.y;
const float x2 = p3.x - p1.x;
const float y2 = p3.y - p1.y;
return x1 * y2 - y1 * x2;
};
const float c0 = cross(v0, v1, point);
const float c1 = cross(v1, v2, point);
const float c2 = cross(v2, v0, point);
const bool hasNeg = (c0 < 0) || (c1 < 0) || (c2 < 0);
const bool hasPos = (c0 > 0) || (c1 > 0) || (c2 > 0);
return !(hasNeg && hasPos);
}
};
}

View File

@ -0,0 +1,7 @@
#pragma once
namespace Scene
{
class Camera
{};
}

View File

@ -0,0 +1,7 @@
#pragma once
namespace Scene
{
class Mesh
{};
}

View File

@ -0,0 +1,7 @@
#pragma once
namespace Scene
{
class Model
{};
}

View File

@ -0,0 +1,7 @@
#pragma once
namespace Scene
{
class Transform
{};
}

View File

@ -0,0 +1,7 @@
#pragma once
namespace Scene
{
class Vertex
{};
}

View File

@ -0,0 +1,7 @@
#pragma once
namespace Shading
{
class BlinnPhongShader
{};
}

View File

@ -0,0 +1,9 @@
#pragma once
namespace Shading
{
enum class ShaderType
{
BlinnPhong,
};
}

View File

@ -1,142 +0,0 @@
#pragma once
#include <cstdint>
#include <utility>
namespace CustomStructs
{
struct Vector2Int
{
int32_t x;
int32_t y;
Vector2Int() : x(0), y(0) {}
Vector2Int(int32_t x, int32_t y) : x(x), y(y) {}
/// <summary>
/// 交换 x 和 y 的值
/// </summary>
void swap()
{
std::swap(x, y);
}
/// <summary>
/// 交换当前 Vector2Int 对象与另一个 Vector2Int 对象的 x 和 y 的值
/// </summary>
/// <param name="other">要交换的对象</param>
static void swap(Vector2Int& vec1, Vector2Int& vec2)
{
std::swap(vec1.x, vec2.x);
std::swap(vec1.y, vec2.y);
}
};
struct Vector2
{
float x;
float y;
Vector2() : x(0), y(0) {}
Vector2(float x, float y) : x(x), y(y) {}
Vector2(const Vector2Int& v) : x(static_cast<float>(v.x)), y(static_cast<float>(v.y)) {}
/// <summary>
/// 交换 x 和 y 的值
/// </summary>
void swap()
{
std::swap(x, y);
}
/// <summary>
/// 交换当前 Vector2 对象与另一个 Vector2 对象的 x 和 y 的值
/// </summary>
/// <param name="other">要交换的对象</param>
static void swap(Vector2& vec1, Vector2& vec2)
{
std::swap(vec1.x, vec2.x);
std::swap(vec1.y, vec2.y);
}
};
struct Vector3Int
{
int32_t x;
int32_t y;
int32_t z;
Vector3Int() : x(0), y(0), z(0) {}
Vector3Int(int32_t x, int32_t y, int32_t z) : x(x), y(y), z(z) {}
};
struct Vector3
{
float x;
float y;
float z;
Vector3() : x(0), y(0), z(0) {}
Vector3(float x, float y, float z) : x(x), y(y), z(z) {}
Vector3(const Vector3Int& v) : x(static_cast<float>(v.x)), y(static_cast<float>(v.y)), z(static_cast<float>(v.z)) {}
};
struct Triangle
{
Vector2Int a;
Vector2Int b;
Vector2Int c;
Triangle() : a(), b(), c() {}
Triangle(const Vector2Int a, const Vector2Int b, const Vector2Int c) : a(a), b(b), c(c) {}
bool IsInTriangle(const Vector2Int point) const
{
auto cross = [](const Vector2Int& p1, const Vector2Int& p2, const Vector2Int& p3) -> int64_t
{
const int64_t x1 = static_cast<int64_t>(p2.x) - p1.x;
const int64_t y1 = static_cast<int64_t>(p2.y) - p1.y;
const int64_t x2 = static_cast<int64_t>(p3.x) - p1.x;
const int64_t y2 = static_cast<int64_t>(p3.y) - p1.y;
return x1 * y2 - y1 * x2;
};
const int64_t c0 = cross(a, b, point);
const int64_t c1 = cross(b, c, point);
const int64_t c2 = cross(c, a, point);
const bool hasNeg = (c0 < 0) || (c1 < 0) || (c2 < 0);
const bool hasPos = (c0 > 0) || (c1 > 0) || (c2 > 0);
return !(hasNeg && hasPos);
}
};
struct Color
{
uint8_t r;
uint8_t g;
uint8_t b;
uint8_t a;
Color() : r(0), g(0), b(0), a(0) {}
Color(uint8_t r, uint8_t g, uint8_t b, uint8_t a)
{
this->r = ClampToByte(static_cast<int32_t>(r));
this->g = ClampToByte(static_cast<int32_t>(g));
this->b = ClampToByte(static_cast<int32_t>(b));
this->a = ClampToByte(static_cast<int32_t>(a));
}
operator uint32_t() const
{
return
(
(static_cast<uint32_t>(r) << 24) |
(static_cast<uint32_t>(g) << 16) |
(static_cast<uint32_t>(b) << 8) |
(static_cast<uint32_t>(a))
);
}
static uint8_t ClampToByte(const int32_t value)
{
if (value < 0) return 0;
if (value > 255) return 255;
return static_cast<uint8_t>(value);
}
};
}

View File

@ -1,17 +1,17 @@
#include <vector> #include <iostream>
#include <iostream>
#include <SDL.h> #include <SDL.h>
#include "Rasterization.h"
#include "StructType.h"
#include "SDL_video.h" #include "SDL_video.h"
#include "SDL_render.h" #include "SDL_render.h"
#include <cstdint> #include <cstdint>
#include "SDL_error.h" #include "SDL_error.h"
#include <cmath> #include "Vector2.h"
#include "Color.h"
#include "FrameBuffer.h"
#include "Rasterizer.h"
const uint32_t SDL_INIT_FLAGS = SDL_INIT_VIDEO; const uint32_t SDL_INIT_FLAGS = SDL_INIT_VIDEO;
const int width = 800; const int32_t width = 800;
const int height = 600; const int32_t height = 600;
SDL_Window* window = nullptr; SDL_Window* window = nullptr;
SDL_Renderer* renderer = nullptr; SDL_Renderer* renderer = nullptr;
@ -93,17 +93,22 @@ int main(int argc, char* argv[])
SDL_Texture* texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_STREAMING, width, height); SDL_Texture* texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_STREAMING, width, height);
Rasterization* rasterization = new Rasterization(width, height); Core::FrameBuffer frameBuffer(width, height);
Rasterizer::Rasterizer rasterizer(frameBuffer);
CustomStructs::Vector2Int v0(100, 100); Math::Vector2Int v0(100, 100);
CustomStructs::Vector2Int v1(300, 100); Math::Vector2Int v1(300, 100);
CustomStructs::Vector2Int v2(300, 400); Math::Vector2Int v2(300, 400);
CustomStructs::Color color1(255, 0, 0, 255); RenderData::Color color0(255, 0, 0, 255);
rasterization->DrawFillTriangle(v0, v1, v2, color1); RenderData::Color color1(0, 255, 0, 255);
RenderData::Color color2(0, 0, 255, 255);
rasterizer.DrawLine(v0, v1, color0);
rasterizer.DrawLine(v1, v2, color1);
rasterizer.DrawLine(v2, v0, color2);
while (true) while (true)
{ {
SDL_UpdateTexture(texture, nullptr, rasterization->frameBuffer.data(), width * sizeof(uint32_t)); SDL_UpdateTexture(texture, nullptr, frameBuffer.get_buffer(), width * sizeof(uint32_t));
SDL_RenderClear(renderer); SDL_RenderClear(renderer);
SDL_RenderCopy(renderer, texture, nullptr, nullptr); SDL_RenderCopy(renderer, texture, nullptr, nullptr);

247
README.md
View File

@ -1,158 +1,161 @@
# CPU Software Renderer # CPU Software Renderer
一个基于 C++ 和 SDL2 的小型 CPU 渲染器练习项目。当前版本聚焦在最基础的 2D 光栅化能力上,通过 CPU 维护帧缓冲区,再将像素数据上传到 SDL 纹理并显示到窗口中 一个基于 C++20 和 SDL2 的 CPU 软光栅化练习项目
项目目标不是调用现成图形 API 去画三角形,而是从像素写入、直线绘制、三角形光栅化开始,逐步补齐一个软件渲染器所需的核心 pipeline。 这个仓库当前还处在早期阶段,重点不是调用现成图形 API 画三角形,而是自己维护帧缓冲、自己做基础光栅化,并逐步搭起一个小型 software renderer 的骨架。
## 项目定位
- 使用 CPU 完成像素级绘制和光栅化
- 使用 SDL2 负责窗口创建、纹理更新和屏幕展示
- 以最小可运行工程为基础,逐步扩展到 3D 渲染流程
## 当前状态 ## 当前状态
当前代码已经具备这些基础能力 目前已经完成或具备雏形的部分:
- 基于 `frameBuffer` 的软件像素输出 - 使用 SDL2 创建窗口、纹理和显示循环
- `SetPixel` 像素写入 - 在 CPU 侧维护 `FrameBuffer`
- Bresenham 直线绘制 - 像素写入接口 `set_pixel`
- 三角形线框绘制 - 基础直线光栅化模块 `Rasterizer`
- 三角形包围盒扫描填充 - 2D 三角形、包围盒、颜色等基础数据结构
- SDL2 窗口创建、纹理更新与显示 - 独立的 `TriangleRasterizer` 模块,用于后续填充三角形
当前 `main.cpp` 中已经可以直接绘制一个填充三角形,用来验证基础光栅化逻辑 当前 `main.cpp` 主要用于验证基础链路,程序启动后会在窗口中绘制三条彩色线段组成的三角形轮廓
## 技术选型 还没有完成的核心能力:
- 语言标准C++20 - 完整接入实心三角形渲染流程
- 工程类型Visual Studio C++ 项目(`.vcxproj` - MVP 变换
- 渲染方式CPU Software Rasterization - 深度测试
- 窗口与展示层SDL2 - 重心坐标插值
- 开发环境Windows + MSVC - 光照
- OBJ 加载
- 可交互相机
选择 SDL2 的原因很直接:它只负责跨平台窗口和像素展示,足够轻量,不会替代掉软件渲染器本身的核心逻辑。 ## 当前结构
## 依赖
项目当前依赖很少:
- SDL2
仓库内已经包含 SDL2 相关文件:
- 头文件目录:`libs/SDL2/include`
- x64 库目录:`libs/SDL2/lib/x64`
- 运行时动态库:`libs/SDL2/SDL2.dll`
## 构建环境
当前工程配置以 Windows 本地开发为主,推荐环境:
- Visual Studio 2022
- MSVC 工具链
- Windows 10/11 SDK
项目文件中启用了:
- `stdcpp20`
- `PlatformToolset=v145`
## 构建方式
1. 使用 Visual Studio 打开 `CPU-Software-Renderer.vcxproj`
2. 选择 `Debug | x64`
3. 直接构建并运行
说明:
- 当前工程的 SDL2 include/lib 路径写在 `.vcxproj`
- 现有配置里 `Debug | x64` 已配置 SDL2 头文件和链接目录
- 如果你移动了仓库位置,可能需要同步调整工程中的绝对路径
## 当前工程结构
```text ```text
CPU-Software-Renderer/ CPU-Software-Renderer/
├─ main.cpp # 程序入口SDL 初始化与显示循环 ├─ CPU-Software-Renderer/
├─ Rasterization.h/.cpp # 帧缓冲、画线、三角形绘制 │ ├─ main.cpp
├─ StructType.h # 向量、三角形、颜色等基础结构 │ ├─ Core/
├─ Color.h/.cpp # 颜色相关封装 │ │ ├─ FrameBuffer.h/.cpp
├─ libs/SDL2/ # SDL2 头文件、库和运行时文件 │ │ ├─ DepthBuffer.h/.cpp
└─ TODO.md # 后续功能路线图 │ │ └─ Renderer.h/.cpp
│ ├─ Math/
│ │ ├─ Vector2.h
│ │ ├─ Vector3.h
│ │ ├─ Vector4.h
│ │ ├─ Matrix4x4.h
│ │ └─ MathUtil.h
│ ├─ RenderData/
│ │ ├─ Color.h
│ │ ├─ BoundingBox.h
│ │ └─ Triangle.h
│ ├─ Rasterizer/
│ │ ├─ Rasterizer.h/.cpp
│ │ └─ TriangleRasterizer.h/.cpp
│ ├─ Scene/
│ │ ├─ Vertex.h
│ │ ├─ Mesh.h
│ │ ├─ Transform.h
│ │ ├─ Model.h
│ │ └─ Camera.h
│ ├─ Asset/
│ │ └─ ObjLoader.h/.cpp
│ ├─ Shading/
│ │ ├─ ShaderTypes.h
│ │ └─ BlinnPhongShader.h/.cpp
│ ├─ libs/SDL2/
│ └─ TODO.md
└─ README.md
``` ```
## 已实现模块 ## 模块说明
### 1. Frame Buffer ### Core
渲染结果先写入 CPU 侧的 `std::vector<uint32_t>` 帧缓冲区,再通过 `SDL_UpdateTexture` 更新到纹理。 - `FrameBuffer`:管理 CPU 侧颜色缓冲
- `DepthBuffer`:为后续深度测试预留
- `Renderer`:为后续统一调度渲染流程预留
### 2. Rasterizer ### Math
当前已经实现: - 放通用数学类型
- 当前以 `Vector2`、`Vector2Int`、`Vector3` 为主
- `Vector4``Matrix4x4` 目前还是占位
- `DrawLine` ### RenderData
- `DrawWireTriangle`
- `DrawFillTriangle`
其中直线绘制使用 Bresenham 思路,填充三角形使用包围盒扫描配合点在三角形内测试。 - 放渲染领域数据,而不是底层数学类型
- 当前包含 `Color`、`BoundingBox2D`、`Triangle2D`
### 3. 基础数学类型 ### Rasterizer
当前工程已经定义了: - `Rasterizer`:负责基础线段光栅化
- `TriangleRasterizer`:负责三角形填充相关逻辑
- `Vector2Int` ### Scene / Asset / Shading
- `Vector2`
- `Vector3Int`
- `Vector3`
- `Triangle`
- `Color`
这些结构会作为后续扩展 MVP 变换、深度测试、法线和属性插值的基础。 这些目录已经预留出来了,方便后面扩展到 3D 渲染流程,但当前多数还是占位类。
## 构建环境
- Windows
- Visual Studio 2022
- MSVC
- C++20
- SDL2
工程文件是 Visual Studio 的 `.vcxproj`
## 依赖
仓库内已经包含 SDL2
- 头文件:`CPU-Software-Renderer/libs/SDL2/include`
- Win32 库:`CPU-Software-Renderer/libs/SDL2/lib/x86`
- x64 库:`CPU-Software-Renderer/libs/SDL2/lib/x64`
## 构建与运行
1. 用 Visual Studio 打开 `CPU-Software-Renderer/CPU-Software-Renderer.vcxproj`
2. 选择 `Debug``Release`
3. 选择 `Win32``x64`
4. 构建并运行
说明:
- 工程里已经分别配置了 Win32 和 x64 的 SDL2 include/lib 路径
- 运行时需要让程序找到与平台匹配的 `SDL2.dll`
- 如果你移动了仓库位置,可能需要同步检查 `.vcxproj` 里的绝对路径
## 设计取向
当前代码结构遵循一个比较简单的原则:
- 纯数据类型放在 `Math``RenderData`
- 做事的模块放在 `Core`、`Rasterizer`、`Asset`、`Shading`
- 先把 2D 基础链路理顺,再逐步加 3D pipeline
这意味着现阶段更强调“结构和边界先理清”,而不是一次性把所有功能堆进去。
## 后续计划 ## 后续计划
1. 完成稳定的三角形光栅化基础 `TODO.md` 的路线,后续会逐步补齐:
2. 加入 MVP 变换,实现 3D 顶点到屏幕空间的投影
3. 加入 Z-buffer解决遮挡关系
4. 实现重心坐标属性插值
5. 实现 Blinn-Phong 光照
6. 支持 OBJ 模型加载
7. 实现相机控制
如果后续继续扩展,比较值得加入的方向还有: 1. 稳定的三角形填充
2. MVP 变换
3. Z-buffer
4. 属性插值
5. Blinn-Phong 光照
6. OBJ 模型加载
7. 相机控制
如果后续继续扩展,还可以考虑:
- Texture Mapping - Texture Mapping
- MSAA 抗锯齿 - MSAA
- 更完整的数学库 - 更完整的数学库
- Shader 结构拆分 - 更清晰的 shader 输入输出结构
## 这个项目最终会变成什么
按当前路线推进后,这个项目会逐步具备一个小型软件渲染器的基本结构:
```text
Renderer
├─ Rasterizer
├─ Shader
├─ Camera
├─ Math
├─ OBJLoader
└─ ZBuffer
```
最终目标是实现一个不依赖 GPU 光栅化管线、但具备基本 3D 渲染能力的 CPU Renderer。
## 适合用来做什么
这个项目比较适合:
- 学习软件渲染器的基本实现方式
- 理解三角形光栅化、像素写入和屏幕空间坐标
- 作为后续学习图形学、渲染 pipeline、光照和模型加载的实验场
- 用于整理个人图形学项目经历
## 说明 ## 说明
当前项目仍在早期阶段很多功能还处于逐步实现中。README 中的“后续计划”部分表示目标路线,不代表这些能力已经全部完成。 这个项目现在更接近“正在搭骨架的 renderer”不是一个已经完成的 3D 渲染器。
README 中提到的很多模块和目录,目的是反映当前的架构方向;其中一部分已经有初步实现,另一部分还只是为后续阶段预留。