34 template <
class BufferType>
38 renderTarget.texture.height,
42 for (
int i = 0; i < renderTarget.width * renderTarget.height; ++i) {
43 depthTexture.texture.image[i] = 2;
44 renderTarget.texture.image[i * 3] = 0;
45 renderTarget.texture.image[i * 3 + 1] = 0;
46 renderTarget.texture.image[i * 3 + 2] = 0;
51 std::vector<std::reference_wrapper<Mesh>> meshes;
52 std::vector<std::reference_wrapper<Light>> lights;
53 std::stack<std::reference_wrapper<Object3D>> objects;
57 while (!objects.empty()) {
68 meshes.push_back(
static_cast<Mesh &
>(child));
72 if (child.isLight()) {
73 lights.push_back(
static_cast<Light &
>(child));
79 const auto cameraWorldPosHomo =
81 auto cameraWorldPos =
Vector3(cameraWorldPosHomo.x / cameraWorldPosHomo.w,
82 cameraWorldPosHomo.y / cameraWorldPosHomo.w,
83 cameraWorldPosHomo.z / cameraWorldPosHomo.w);
88 auto w = (cameraWorldPos -
Vector3(0, 0, 0)).normalize();
99 1, 0, 0, -cameraWorldPos.x,
100 0, 1, 0, -cameraWorldPos.y,
101 0, 0, 1, -cameraWorldPos.z,
111 renderTarget.width / 2.0, 0, 0, (renderTarget.width - 1) / 2.0,
112 0, renderTarget.height / 2.0, 0, (renderTarget.height - 1) / 2.0,
120 for (
Mesh &mesh : meshes) {
121 auto geometry = mesh.geometry;
122 auto modelViewMatrix = viewMatrix * mesh.modelMatrix;
124 mesh.modelMatrix.topLeft3x3Matrix().inverse().transpose();
126 if (geometry.faceIndices) {
127 for (
int i = 0; i < geometry.faceIndices.value().array.size(); i += 3) {
128 const int vertexAIndex = geometry.faceIndices.value().array.at(i);
129 const int vertexBIndex = geometry.faceIndices.value().array.at(i + 1);
130 const int vertexCIndex = geometry.faceIndices.value().array.at(i + 2);
132 processTriangle(vertexAIndex, vertexBIndex, vertexCIndex, geometry,
133 mesh, modelViewMatrix, camera, viewMatrix,
134 normalMatrix, cameraWorldPos, viewportMatrix, lights,
135 renderTarget, depthTexture);
138 for (
int i = 0; i < geometry.vertexPositions.array.size() / 3; i += 3) {
139 processTriangle(i, i + 1, i + 2, geometry, mesh, modelViewMatrix,
140 camera, viewMatrix, normalMatrix, cameraWorldPos,
141 viewportMatrix, lights, renderTarget, depthTexture);
148 template <
class BufferType>
149 void processTriangle(
int vertexAIndex,
int vertexBIndex,
int vertexCIndex,
154 std::vector<std::reference_wrapper<Light>> &lights,
173 viewMatrix, normalMatrix, cameraPosition};
174 Attributes attributes{localVertexA, vertexANormal};
175 Varyings varyingsVertexA = {localVertexA, vertexANormal};
176 Varyings varyingsVertexB = {localVertexB, vertexBNormal};
177 Varyings varyingsVertexC = {localVertexC, vertexCNormal};
179 const auto transformedVertexA =
182 attributes.localPosition = localVertexB;
183 attributes.localNormal = vertexBNormal;
184 const auto transformedVertexB =
187 attributes.localPosition = localVertexC;
188 attributes.localNormal = vertexCNormal;
189 const auto transformedVertexC =
192 auto screenSpaceVertexA = viewportMatrix * transformedVertexA;
193 auto screenSpaceVertexB = viewportMatrix * transformedVertexB;
194 auto screenSpaceVertexC = viewportMatrix * transformedVertexC;
196 screenSpaceVertexA /= screenSpaceVertexA.w;
197 screenSpaceVertexA.w = 1.0 / transformedVertexA.w;
198 screenSpaceVertexB /= screenSpaceVertexB.w;
199 screenSpaceVertexB.w = 1.0 / transformedVertexB.w;
200 screenSpaceVertexC /= screenSpaceVertexC.w;
201 screenSpaceVertexC.w = 1.0 / transformedVertexC.w;
203 const auto clockwiseMatrix = Matrix3x3(
204 screenSpaceVertexA.x, screenSpaceVertexA.y, 1, screenSpaceVertexB.x,
205 screenSpaceVertexB.y, 1, screenSpaceVertexC.x, screenSpaceVertexC.y, 1);
207 if (clockwiseMatrix.determinant() *
214 const auto maxY =
static_cast<int>(std::round(
215 std::max(std::max(screenSpaceVertexA.y, screenSpaceVertexB.y),
216 screenSpaceVertexC.y)));
217 const auto minY =
static_cast<int>(std::round(
218 std::min(std::min(screenSpaceVertexA.y, screenSpaceVertexB.y),
219 screenSpaceVertexC.y)));
220 const auto yDiff = maxY - minY;
222 std::vector<std::set<Fragment>> fragments(yDiff + 1);
224 const auto bresenhamAB =
225 bresenham(
static_cast<int>(std::round(screenSpaceVertexA.x)),
226 static_cast<int>(std::round(screenSpaceVertexA.y)),
227 static_cast<int>(std::round(screenSpaceVertexB.x)),
228 static_cast<int>(std::round(screenSpaceVertexB.y)));
229 const auto bresenhamBC =
230 bresenham(
static_cast<int>(std::round(screenSpaceVertexB.x)),
231 static_cast<int>(std::round(screenSpaceVertexB.y)),
232 static_cast<int>(std::round(screenSpaceVertexC.x)),
233 static_cast<int>(std::round(screenSpaceVertexC.y)));
234 const auto bresenhamCA =
235 bresenham(
static_cast<int>(std::round(screenSpaceVertexC.x)),
236 static_cast<int>(std::round(screenSpaceVertexC.y)),
237 static_cast<int>(std::round(screenSpaceVertexA.x)),
238 static_cast<int>(std::round(screenSpaceVertexA.y)));
240 for (
auto [x, y] : bresenhamAB) {
241 fragments[y - minY].insert(Fragment{x, y});
244 for (
auto [x, y] : bresenhamBC) {
245 fragments[y - minY].insert(Fragment{x, y});
248 for (
auto [x, y] : bresenhamCA) {
249 fragments[y - minY].insert(Fragment{x, y});
252 for (
auto &line : fragments) {
253 auto startFragment = line.begin();
254 auto endFragment = std::next(startFragment);
256 const auto y = startFragment->y;
258 while (endFragment != line.end()) {
259 for (
int x = startFragment->x; x <= endFragment->x; x++) {
262 Vector3(screenSpaceVertexA.x, screenSpaceVertexA.y, 0),
263 Vector3(screenSpaceVertexB.x, screenSpaceVertexB.y, 0),
264 Vector3(screenSpaceVertexC.x, screenSpaceVertexC.y, 0));
266 const auto perspectiveBary =
267 Vector3(bary.x * screenSpaceVertexA.w,
268 bary.y * screenSpaceVertexB.w,
269 bary.z * screenSpaceVertexC.w) /
270 (bary.x * screenSpaceVertexA.w + bary.y * screenSpaceVertexB.w +
271 bary.z * screenSpaceVertexC.w);
273 Vector3 localPosition =
274 varyingsVertexA.localPosition * perspectiveBary.x +
275 varyingsVertexB.localPosition * perspectiveBary.y +
276 varyingsVertexC.localPosition * perspectiveBary.z;
277 Vector3 localNormal =
278 varyingsVertexA.localNormal * perspectiveBary.x +
279 varyingsVertexB.localNormal * perspectiveBary.y +
280 varyingsVertexC.localNormal * perspectiveBary.z;
282 Varyings varyings = {localPosition, localNormal};
289 if (x < 0 || x >= renderTarget.width || y < 0 ||
290 y >= renderTarget.height) {
294 const double z = bary.
x * screenSpaceVertexA.z +
295 bary.y * screenSpaceVertexB.z +
296 bary.z * screenSpaceVertexC.z;
298 const auto currentDepth = depthTexture.read(x, y).
x;
301 renderTarget.write(x, y, color);
303 depthTexture.write(x, y, Color(z, 0.0, 0.0));
308 startFragment = std::next(startFragment);
309 endFragment = std::next(endFragment);