#include "3DRenderer.hpp" // Rendering order: // model matrix (Object SRT) -> view matrix (camera matrix inverted) -> proj matrix -> clipping -> perspective divide -> viewport transformation -> Rasterizer (draw pixels inside projected triangles on 2D screen) // object coordinate -> world coordinate -> camera coordinate -> clip/screen coordinate // // Rasterizer inputs elements: // - texture-buffer (2D array of pixels color value) // - z-buffer (2D array of float representing the nearest pixel's depth, all pixels beyond are ignored) // - projected vertices-buffer on screen (using vertices-buffer and projection function) // // Refs: // * https://en.wikipedia.org/wiki/3D_projection // * https://www.scratchapixel.com/lessons/3d-basic-rendering/rasterization-practical-implementation/overview-rasterization-algorithm.html Graphic3DRenderer::Graphic3DRenderer() { if (mMainCamera == nullptr) { mMainCamera = std::make_unique(); mMainCamera->SetPosition(0.0f, 3.0f, -20.0f); mMainCamera->SetFrustrum(90.0f, 1280.f/324.f, 1.0f, 100.f); mMainCamera->UpdateCamView(); } } Graphic3DRenderer::~Graphic3DRenderer() {} void Graphic3DRenderer::Draw(sf::RenderTexture& context) { sf::BlendMode sBM = sf::BlendNone; sf::RenderStates sRS(sBM); static float thetaAngle = 0.31f; thetaAngle = thetaAngle >= 6.283185f ? -6.283185f : thetaAngle + 0.004f; M3D_MATRIX viewMat = mMainCamera->GetView(); M3D_MATRIX projMat = mMainCamera->GetProj(); M3D_MATRIX modelMat = M3D_MIdentity() * M3D_TransformMatrixScaling(10.0f, 10.0f, 10.0f) * M3D_TransformMatrixRotationX(thetaAngle) * M3D_TransformMatrixRotationZ(0.5f*thetaAngle) * M3D_TransformMatrixTranslate(0.0f, 0.0f, 5.0f); M3D_MATRIX viewProjMat = (viewMat) * (projMat); M3D_MATRIX MVPMat = modelMat * viewProjMat; M3D_MATRIX viewportMat = M3D_TransformMatrixViewport(1280.0f, 324.f, 0.0f, 0.0f); sf::Vertex v_tri[4]; auto cubeMesh = testObj.GetObjectMesh(); // Do the vertices projection and perspective divide M3D_F3 projVertices[cubeMesh.vertices.size()]; M3D_V3TransformPersDiv(projVertices, sizeof(M3D_F3), (M3D_F3*)cubeMesh.vertices.data(), sizeof(Vertex), cubeMesh.vertices.size(), MVPMat); auto indicePtr = (uint32_t*)cubeMesh.parts[0].indices.data(); for (uint32_t i = 0; i < cubeMesh.parts[0].indices.size(); i += 3) { // Misscontructed indices tree failsafe if (i+2 > cubeMesh.parts[0].indices.size()) break; // Simple clipping //TODO: implement complete Cohen-Sutherland algo or similar if ((projVertices[indicePtr[i]]).z > 0 && (projVertices[indicePtr[i+1]]).z > 0 && (projVertices[indicePtr[i+2]]).z > 0) { M3D_VECTOR V1 = M3D_V4LoadF3(&projVertices[indicePtr[i]]); M3D_VECTOR V2 = M3D_V4LoadF3(&projVertices[indicePtr[i+1]]); M3D_VECTOR V3 = M3D_V4LoadF3(&projVertices[indicePtr[i+2]]); V1 = M3D_V3Transform(V1, viewportMat); V2 = M3D_V3Transform(V2, viewportMat); V3 = M3D_V3Transform(V3, viewportMat); //v_tri[v_cnt].position.z = ((far+near)/2)+((far-near)/2)*_2dCoord.z; //TODO: transform matrix is incomplete v_tri[0].position = sf::Vector2f(M3D_V4GetX(V1), M3D_V4GetY(V1)); v_tri[0].color = cubeMesh.vertices[indicePtr[i]].color; v_tri[3] = v_tri[0]; v_tri[1].position = sf::Vector2f(M3D_V4GetX(V2), M3D_V4GetY(V2)); v_tri[1].color = cubeMesh.vertices[indicePtr[i+1]].color; v_tri[2].position = sf::Vector2f(M3D_V4GetX(V3), M3D_V4GetY(V3)); v_tri[2].color = cubeMesh.vertices[indicePtr[i+2]].color; context.draw(v_tri, 4, sf::LineStrip, sRS); //context.draw(v_tri, 3, sf::Triangles, sRS); } //TODO: else cut triangle to the window (need vector crossing math...) } }