Last week of rasterizer
:p silly cats FTW
This commit is contained in:
@@ -21,8 +21,6 @@ set(IMGUI_SOURCES
|
|||||||
"imgui/backends/imgui_impl_sdlrenderer2.cpp"
|
"imgui/backends/imgui_impl_sdlrenderer2.cpp"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Create the executable
|
# Create the executable
|
||||||
add_executable(${PROJECT_NAME} ${SOURCES})
|
add_executable(${PROJECT_NAME} ${SOURCES})
|
||||||
#add_executable(${PROJECT_NAME} ${SOURCES} ${IMGUI_SOURCES})
|
#add_executable(${PROJECT_NAME} ${SOURCES} ${IMGUI_SOURCES})
|
||||||
|
|||||||
BIN
project/resources/cat.png
Normal file
BIN
project/resources/cat.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 68 KiB |
@@ -40,9 +40,10 @@ namespace dae {
|
|||||||
float zNear{.1f};
|
float zNear{.1f};
|
||||||
float zFar{100.f};
|
float zFar{100.f};
|
||||||
|
|
||||||
void Initialize(float _fovAngle = 90.f, Vector3 _origin = {0.f, 0.f, 0.f}) {
|
void Initialize(float _fovAngle = 90.f, Vector3 _origin = {0.f, 0.f, 0.f}, float _aspect = 1.f) {
|
||||||
fovAngle = _fovAngle;
|
fovAngle = _fovAngle;
|
||||||
fov = tanf((fovAngle * TO_RADIANS) / 2.f);
|
fov = tanf((fovAngle * TO_RADIANS) / 2.f);
|
||||||
|
aspect = _aspect;
|
||||||
|
|
||||||
origin = _origin;
|
origin = _origin;
|
||||||
}
|
}
|
||||||
@@ -54,15 +55,14 @@ namespace dae {
|
|||||||
|
|
||||||
void CalculateViewMatrix() {
|
void CalculateViewMatrix() {
|
||||||
|
|
||||||
viewMatrix = Matrix::CreateLookAtLH(origin, forward, up);
|
viewMatrix = Matrix::CreateLookAtLH(origin, origin + forward, Vector3::UnitY);
|
||||||
invViewMatrix = Matrix::Inverse(viewMatrix);
|
Matrix temp = viewMatrix;
|
||||||
|
|
||||||
//TODO W1
|
invViewMatrix = temp.Inverse();
|
||||||
//ONB => invViewMatrix
|
|
||||||
//Inverse(ONB) => ViewMatrix
|
|
||||||
|
|
||||||
//ViewMatrix => Matrix::CreateLookAtLH(...) [not implemented yet]
|
right = invViewMatrix.GetAxisX();
|
||||||
//DirectX Implementation => https://learn.microsoft.com/en-us/windows/win32/direct3d9/d3dxmatrixlookatlh
|
up = invViewMatrix.GetAxisY();
|
||||||
|
forward = invViewMatrix.GetAxisZ();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CalculateProjectionMatrix() {
|
void CalculateProjectionMatrix() {
|
||||||
@@ -84,31 +84,38 @@ namespace dae {
|
|||||||
|
|
||||||
float MovementSpeed{ 10.f };
|
float MovementSpeed{ 10.f };
|
||||||
|
|
||||||
if (pKeyboardState[SDL_SCANCODE_LSHIFT]) {
|
if (pKeyboardState[SDL_SCANCODE_LSHIFT])
|
||||||
|
{
|
||||||
MovementSpeed *= 2;
|
MovementSpeed *= 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pKeyboardState[SDL_SCANCODE_W]) {
|
if (pKeyboardState[SDL_SCANCODE_W])
|
||||||
|
{
|
||||||
origin += forward * deltaTime * MovementSpeed;
|
origin += forward * deltaTime * MovementSpeed;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pKeyboardState[SDL_SCANCODE_A]) {
|
if (pKeyboardState[SDL_SCANCODE_A])
|
||||||
|
{
|
||||||
origin -= right * deltaTime * MovementSpeed;
|
origin -= right * deltaTime * MovementSpeed;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pKeyboardState[SDL_SCANCODE_S]) {
|
if (pKeyboardState[SDL_SCANCODE_S])
|
||||||
|
{
|
||||||
origin -= forward * deltaTime * MovementSpeed;
|
origin -= forward * deltaTime * MovementSpeed;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pKeyboardState[SDL_SCANCODE_D]) {
|
if (pKeyboardState[SDL_SCANCODE_D])
|
||||||
|
{
|
||||||
origin += right * deltaTime * MovementSpeed;
|
origin += right * deltaTime * MovementSpeed;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pKeyboardState[SDL_SCANCODE_E]) {
|
if (pKeyboardState[SDL_SCANCODE_E])
|
||||||
|
{
|
||||||
origin += up * deltaTime * MovementSpeed;
|
origin += up * deltaTime * MovementSpeed;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pKeyboardState[SDL_SCANCODE_Q]) {
|
if (pKeyboardState[SDL_SCANCODE_Q])
|
||||||
|
{
|
||||||
origin -= up * deltaTime * MovementSpeed;
|
origin -= up * deltaTime * MovementSpeed;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -125,13 +132,16 @@ namespace dae {
|
|||||||
totalPitch += (static_cast<float>(mouseY) * mouseSens) * TO_RADIANS;
|
totalPitch += (static_cast<float>(mouseY) * mouseSens) * TO_RADIANS;
|
||||||
|
|
||||||
mousePosChange = true;
|
mousePosChange = true;
|
||||||
} else if (mouseState == SDL_BUTTON_LEFT) {
|
}
|
||||||
|
else if (mouseState == SDL_BUTTON_LEFT)
|
||||||
|
{
|
||||||
zDirection = forward.Normalized() * static_cast<float>(-mouseY);
|
zDirection = forward.Normalized() * static_cast<float>(-mouseY);
|
||||||
|
|
||||||
totalYaw += static_cast<float>(mouseX) * mouseSens * TO_RADIANS;
|
totalYaw += static_cast<float>(mouseX) * mouseSens * TO_RADIANS;
|
||||||
|
|
||||||
mousePosChange = true;
|
mousePosChange = true;
|
||||||
} else if (mouseState == SDL_BUTTON_X2) //lmb + rmb
|
}
|
||||||
|
else if (mouseState == SDL_BUTTON_X2) //lmb + rmb
|
||||||
{
|
{
|
||||||
origin.y += static_cast<float>(mouseY) / 2;
|
origin.y += static_cast<float>(mouseY) / 2;
|
||||||
|
|
||||||
@@ -140,7 +150,8 @@ namespace dae {
|
|||||||
|
|
||||||
origin += ((zDirection + xDirection + yDirection) * cameraSpeed * deltaTime);
|
origin += ((zDirection + xDirection + yDirection) * cameraSpeed * deltaTime);
|
||||||
|
|
||||||
if (mousePosChange) {
|
if (mousePosChange)
|
||||||
|
{
|
||||||
const Matrix yawMatrix{ Matrix::CreateRotationY(totalYaw) };
|
const Matrix yawMatrix{ Matrix::CreateRotationY(totalYaw) };
|
||||||
const Matrix pitchMatrix{ Matrix::CreateRotationX(totalPitch) };
|
const Matrix pitchMatrix{ Matrix::CreateRotationX(totalPitch) };
|
||||||
|
|
||||||
@@ -152,6 +163,7 @@ namespace dae {
|
|||||||
//Update Matrices
|
//Update Matrices
|
||||||
CalculateViewMatrix();
|
CalculateViewMatrix();
|
||||||
CalculateProjectionMatrix(); //Try to optimize this - should only be called once or when fov/aspectRatio changes
|
CalculateProjectionMatrix(); //Try to optimize this - should only be called once or when fov/aspectRatio changes
|
||||||
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "MathHelpers.h"
|
#include "MathHelpers.h"
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
namespace dae
|
namespace dae
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -7,23 +7,24 @@
|
|||||||
namespace dae
|
namespace dae
|
||||||
{
|
{
|
||||||
struct Vertex
|
struct Vertex
|
||||||
{
|
|
||||||
Vector3 position{};
|
|
||||||
ColorRGB color{colors::White};
|
|
||||||
Vector2 uv{}; //W2
|
|
||||||
//Vector3 normal{}; //W4
|
|
||||||
//Vector3 tangent{}; //W4
|
|
||||||
//Vector3 viewDirection{}; //W4
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Vertex_Out
|
|
||||||
{
|
{
|
||||||
Vector4 position{};
|
Vector4 position{};
|
||||||
ColorRGB color{colors::White};
|
ColorRGB color{colors::White};
|
||||||
Vector2 uv{};
|
Vector2 uv{};
|
||||||
//Vector3 normal{};
|
bool valid{ true };
|
||||||
//Vector3 tangent{};
|
Vector3 normal{};
|
||||||
//Vector3 viewDirection{};
|
Vector3 tangent{};
|
||||||
|
Vector3 viewDir{};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Sample
|
||||||
|
{
|
||||||
|
Vector2 uv{};
|
||||||
|
Vector3 normal{};
|
||||||
|
Vector3 tangent{};
|
||||||
|
Vector3 viewDirection{};
|
||||||
|
float depth{};
|
||||||
|
Vector3 weight{};
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class PrimitiveTopology
|
enum class PrimitiveTopology
|
||||||
@@ -36,9 +37,9 @@ namespace dae
|
|||||||
{
|
{
|
||||||
std::vector<Vertex> vertices{};
|
std::vector<Vertex> vertices{};
|
||||||
std::vector<uint32_t> indices{};
|
std::vector<uint32_t> indices{};
|
||||||
PrimitiveTopology primitiveTopology{ PrimitiveTopology::TriangleStrip };
|
PrimitiveTopology primitiveTopology{ PrimitiveTopology::TriangleList };
|
||||||
|
|
||||||
std::vector<Vertex_Out> vertices_out{};
|
std::vector<Vertex> vertices_out{};
|
||||||
Matrix worldMatrix{};
|
Matrix worldMatrix{};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,11 +15,84 @@ float max(float a, float b, float c) {
|
|||||||
|
|
||||||
float CrossZ(const Vector3& p0, const Vector3& p1, const Vector3& point)
|
float CrossZ(const Vector3& p0, const Vector3& p1, const Vector3& point)
|
||||||
{
|
{
|
||||||
return (point.x - p0.x) * (p1.y - p0.y)
|
return (p1.x - p0.x) * (point.y - p0.y)
|
||||||
- (point.y - p0.y) * (p1.x - p0.x);
|
- (p1.y - p0.y) * (point.x - p0.x);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<typename Type>
|
||||||
|
Type interpolate(const Type& val0, const Type& val1, const Type& val2, float depth, float weight)
|
||||||
|
{
|
||||||
|
return {
|
||||||
|
val0 * depth * weight +
|
||||||
|
val1 * depth * weight +
|
||||||
|
val2 * depth * weight
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<Sample> HitTest::TriangleHitTest(const Vector3& fragPos, const Vertex& v0, const Vertex& v1, const Vertex& v2)
|
||||||
|
{
|
||||||
|
Vector3 weights;
|
||||||
|
|
||||||
|
weights.x = CrossZ(v2.position, v1.position, fragPos);
|
||||||
|
if ( weights.x > 0 )
|
||||||
|
return std::nullopt;
|
||||||
|
|
||||||
|
weights.y = CrossZ(v0.position, v2.position, fragPos);
|
||||||
|
if ( weights.y > 0 )
|
||||||
|
return std::nullopt;
|
||||||
|
|
||||||
|
weights.z = CrossZ(v1.position, v0.position, fragPos);
|
||||||
|
if ( weights.z > 0 )
|
||||||
|
return std::nullopt;
|
||||||
|
|
||||||
|
const float totalWeight{ weights.x + weights.y + weights.z };
|
||||||
|
|
||||||
|
const float invTotalWeight{ 1.0f / totalWeight };
|
||||||
|
const Vector3 normWeights{
|
||||||
|
weights.x * invTotalWeight,
|
||||||
|
weights.y * invTotalWeight,
|
||||||
|
weights.z * invTotalWeight
|
||||||
|
};
|
||||||
|
|
||||||
|
const float depth =
|
||||||
|
1 / (normWeights.x / v0.position.w +
|
||||||
|
normWeights.y / v1.position.w +
|
||||||
|
normWeights.z / v2.position.w);
|
||||||
|
|
||||||
|
const Vector2 uv =
|
||||||
|
v0.uv * depth * normWeights.x / v0.position.w +
|
||||||
|
v1.uv * depth * normWeights.y / v1.position.w +
|
||||||
|
v2.uv * depth * normWeights.z / v2.position.w;
|
||||||
|
|
||||||
|
const float interpolatedDepth = 1 / (normWeights.x / v0.position.w + normWeights.y / v1.position.w + normWeights.z / v2.position.w);
|
||||||
|
|
||||||
|
auto interpolate =
|
||||||
|
[&]<typename Type>(const Type& val0, const Type& val1, const Type& val2) -> Type
|
||||||
|
{
|
||||||
|
return (val0 / v0.position.w * normWeights.x +
|
||||||
|
val1 / v1.position.w * normWeights.y +
|
||||||
|
val2 / v2.position.w * normWeights.z) * interpolatedDepth;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
//Invert the normal
|
||||||
|
const Vector3 normal = interpolate(v0.normal, v1.normal, v2.normal).Normalized();
|
||||||
|
const Vector3 tangent = interpolate(v0.tangent, v1.tangent, v2.tangent).Normalized();
|
||||||
|
const Vector3 viewDir = interpolate(v0.viewDir, v1.viewDir, v2.viewDir).Normalized();
|
||||||
|
|
||||||
|
return Sample{
|
||||||
|
.uv = uv,
|
||||||
|
.normal = normal,
|
||||||
|
.tangent = tangent,
|
||||||
|
.viewDirection = viewDir,
|
||||||
|
.depth = depth,
|
||||||
|
.weight = normWeights
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
HitTest::HitTestSample HitTest::Triangle(const Vector3 &pos, const std::vector<Vertex> &vertices) {
|
HitTest::HitTestSample HitTest::Triangle(const Vector3 &pos, const std::vector<Vertex> &vertices) {
|
||||||
float minX = min(vertices[0].position.x, vertices[1].position.x, vertices[2].position.x);
|
float minX = min(vertices[0].position.x, vertices[1].position.x, vertices[2].position.x);
|
||||||
float maxX = max(vertices[0].position.x, vertices[1].position.x, vertices[2].position.x);
|
float maxX = max(vertices[0].position.x, vertices[1].position.x, vertices[2].position.x);
|
||||||
@@ -46,9 +119,10 @@ HitTest::HitTestSample HitTest::Triangle(const Vector3 &pos, const std::vector<V
|
|||||||
}
|
}
|
||||||
|
|
||||||
const double totalWeight{ w0 + w1 + w2 };
|
const double totalWeight{ w0 + w1 + w2 };
|
||||||
w0 /= totalWeight;
|
const float invTotalWeight{ static_cast<float>(1.0f / totalWeight) };
|
||||||
w1 /= totalWeight;
|
w0 *= invTotalWeight;
|
||||||
w2 /= totalWeight;
|
w1 *= invTotalWeight;
|
||||||
|
w2 *= invTotalWeight;
|
||||||
|
|
||||||
|
|
||||||
assert(std::abs(w0 + w1 + w2 - 1) < 0.0001);
|
assert(std::abs(w0 + w1 + w2 - 1) < 0.0001);
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
#ifndef GP1_RASTERIZER_HITTEST_H
|
#ifndef GP1_RASTERIZER_HITTEST_H
|
||||||
#define GP1_RASTERIZER_HITTEST_H
|
#define GP1_RASTERIZER_HITTEST_H
|
||||||
|
|
||||||
|
#include <optional>
|
||||||
#include "DataTypes.h"
|
#include "DataTypes.h"
|
||||||
#include "Maths.h"
|
#include "Maths.h"
|
||||||
|
|
||||||
@@ -17,6 +18,9 @@ namespace HitTest {
|
|||||||
};
|
};
|
||||||
|
|
||||||
HitTestSample Triangle(const Vector3& pos, const std::vector<Vertex>& vertices);
|
HitTestSample Triangle(const Vector3& pos, const std::vector<Vertex>& vertices);
|
||||||
|
|
||||||
|
|
||||||
|
std::optional<Sample> TriangleHitTest(const Vector3& fragPos, const Vertex& v0, const Vertex& v1, const Vertex& v2);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif //GP1_RASTERIZER_HITTEST_H
|
#endif //GP1_RASTERIZER_HITTEST_H
|
||||||
|
|||||||
@@ -7,33 +7,28 @@
|
|||||||
|
|
||||||
namespace dae {
|
namespace dae {
|
||||||
Matrix::Matrix(const Vector3 &xAxis, const Vector3 &yAxis, const Vector3 &zAxis, const Vector3 &t) :
|
Matrix::Matrix(const Vector3 &xAxis, const Vector3 &yAxis, const Vector3 &zAxis, const Vector3 &t) :
|
||||||
Matrix({ xAxis, 0 }, { yAxis, 0 }, { zAxis, 0 }, { t, 1 })
|
Matrix({xAxis, 0}, {yAxis, 0}, {zAxis, 0}, {t, 1}) {
|
||||||
{
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Matrix::Matrix(const Vector4& xAxis, const Vector4& yAxis, const Vector4& zAxis, const Vector4& t)
|
Matrix::Matrix(const Vector4 &xAxis, const Vector4 &yAxis, const Vector4 &zAxis, const Vector4 &t) {
|
||||||
{
|
|
||||||
data[0] = xAxis;
|
data[0] = xAxis;
|
||||||
data[1] = yAxis;
|
data[1] = yAxis;
|
||||||
data[2] = zAxis;
|
data[2] = zAxis;
|
||||||
data[3] = t;
|
data[3] = t;
|
||||||
}
|
}
|
||||||
|
|
||||||
Matrix::Matrix(const Matrix& m)
|
Matrix::Matrix(const Matrix &m) {
|
||||||
{
|
|
||||||
data[0] = m[0];
|
data[0] = m[0];
|
||||||
data[1] = m[1];
|
data[1] = m[1];
|
||||||
data[2] = m[2];
|
data[2] = m[2];
|
||||||
data[3] = m[3];
|
data[3] = m[3];
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector3 Matrix::TransformVector(const Vector3& v) const
|
Vector3 Matrix::TransformVector(const Vector3 &v) const {
|
||||||
{
|
|
||||||
return TransformVector(v.x, v.y, v.z);
|
return TransformVector(v.x, v.y, v.z);
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector3 Matrix::TransformVector(float x, float y, float z) const
|
Vector3 Matrix::TransformVector(float x, float y, float z) const {
|
||||||
{
|
|
||||||
return Vector3{
|
return Vector3{
|
||||||
data[0].x * x + data[1].x * y + data[2].x * z,
|
data[0].x * x + data[1].x * y + data[2].x * z,
|
||||||
data[0].y * x + data[1].y * y + data[2].y * z,
|
data[0].y * x + data[1].y * y + data[2].y * z,
|
||||||
@@ -41,13 +36,11 @@ namespace dae {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector3 Matrix::TransformPoint(const Vector3& p) const
|
Vector3 Matrix::TransformPoint(const Vector3 &p) const {
|
||||||
{
|
|
||||||
return TransformPoint(p.x, p.y, p.z);
|
return TransformPoint(p.x, p.y, p.z);
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector3 Matrix::TransformPoint(float x, float y, float z) const
|
Vector3 Matrix::TransformPoint(float x, float y, float z) const {
|
||||||
{
|
|
||||||
return Vector3{
|
return Vector3{
|
||||||
data[0].x * x + data[1].x * y + data[2].x * z + data[3].x,
|
data[0].x * x + data[1].x * y + data[2].x * z + data[3].x,
|
||||||
data[0].y * x + data[1].y * y + data[2].y * z + data[3].y,
|
data[0].y * x + data[1].y * y + data[2].y * z + data[3].y,
|
||||||
@@ -55,13 +48,11 @@ namespace dae {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector4 Matrix::TransformPoint(const Vector4& p) const
|
Vector4 Matrix::TransformPoint(const Vector4 &p) const {
|
||||||
{
|
|
||||||
return TransformPoint(p.x, p.y, p.z, p.w);
|
return TransformPoint(p.x, p.y, p.z, p.w);
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector4 Matrix::TransformPoint(float x, float y, float z, float w) const
|
Vector4 Matrix::TransformPoint(float x, float y, float z, float w) const {
|
||||||
{
|
|
||||||
return Vector4{
|
return Vector4{
|
||||||
data[0].x * x + data[1].x * y + data[2].x * z + data[3].x,
|
data[0].x * x + data[1].x * y + data[2].x * z + data[3].x,
|
||||||
data[0].y * x + data[1].y * y + data[2].y * z + data[3].y,
|
data[0].y * x + data[1].y * y + data[2].y * z + data[3].y,
|
||||||
@@ -70,13 +61,10 @@ namespace dae {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const Matrix& Matrix::Transpose()
|
const Matrix &Matrix::Transpose() {
|
||||||
{
|
|
||||||
Matrix result{};
|
Matrix result{};
|
||||||
for (int r{ 0 }; r < 4; ++r)
|
for (int r{0}; r < 4; ++r) {
|
||||||
{
|
for (int c{0}; c < 4; ++c) {
|
||||||
for (int c{ 0 }; c < 4; ++c)
|
|
||||||
{
|
|
||||||
result[r][c] = data[c][r];
|
result[r][c] = data[c][r];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -89,8 +77,7 @@ namespace dae {
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Matrix& Matrix::Inverse()
|
const Matrix &Matrix::Inverse() {
|
||||||
{
|
|
||||||
//Optimized Inverse as explained in FGED1 - used widely in other libraries too.
|
//Optimized Inverse as explained in FGED1 - used widely in other libraries too.
|
||||||
const Vector3 &a = data[0];
|
const Vector3 &a = data[0];
|
||||||
const Vector3 &b = data[1];
|
const Vector3 &b = data[1];
|
||||||
@@ -111,7 +98,10 @@ namespace dae {
|
|||||||
assert((!AreEqual(det, 0.f)) && "ERROR: determinant is 0, there is no INVERSE!");
|
assert((!AreEqual(det, 0.f)) && "ERROR: determinant is 0, there is no INVERSE!");
|
||||||
float invDet = 1.f / det;
|
float invDet = 1.f / det;
|
||||||
|
|
||||||
s *= invDet; t *= invDet; u *= invDet; v *= invDet;
|
s *= invDet;
|
||||||
|
t *= invDet;
|
||||||
|
u *= invDet;
|
||||||
|
v *= invDet;
|
||||||
|
|
||||||
Vector3 r0 = Vector3::Cross(b, v) + t * y;
|
Vector3 r0 = Vector3::Cross(b, v) + t * y;
|
||||||
Vector3 r1 = Vector3::Cross(v, a) - t * x;
|
Vector3 r1 = Vector3::Cross(v, a) - t * x;
|
||||||
@@ -121,79 +111,90 @@ namespace dae {
|
|||||||
data[0] = Vector4{r0.x, r1.x, r2.x, 0.f};
|
data[0] = Vector4{r0.x, r1.x, r2.x, 0.f};
|
||||||
data[1] = Vector4{r0.y, r1.y, r2.y, 0.f};
|
data[1] = Vector4{r0.y, r1.y, r2.y, 0.f};
|
||||||
data[2] = Vector4{r0.z, r1.z, r2.z, 0.f};
|
data[2] = Vector4{r0.z, r1.z, r2.z, 0.f};
|
||||||
data[3] = { { -Vector3::Dot(b, t)},{Vector3::Dot(a, t)},{-Vector3::Dot(d, s)},{Vector3::Dot(c, s)} };
|
data[3] = {{-Vector3::Dot(b, t)},
|
||||||
|
{Vector3::Dot(a, t)},
|
||||||
|
{-Vector3::Dot(d, s)},
|
||||||
|
{Vector3::Dot(c, s)}};
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
Matrix Matrix::Transpose(const Matrix& m)
|
Matrix Matrix::Transpose(const Matrix &m) {
|
||||||
{
|
|
||||||
Matrix out{m};
|
Matrix out{m};
|
||||||
out.Transpose();
|
out.Transpose();
|
||||||
|
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
Matrix Matrix::Inverse(const Matrix& m)
|
Matrix Matrix::Inverse(const Matrix &m) {
|
||||||
{
|
|
||||||
Matrix out{m};
|
Matrix out{m};
|
||||||
out.Inverse();
|
out.Inverse();
|
||||||
|
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
Matrix Matrix::CreateLookAtLH(const Vector3& origin, const Vector3& forward, const Vector3& up)
|
Matrix Matrix::CreateLookAtLH(const Vector3 &origin, const Vector3 &forward, const Vector3 &up) {
|
||||||
{
|
Vector3 zAxis = (forward - origin).Normalized();
|
||||||
Vector3 zAxis = forward.Normalized();
|
|
||||||
Vector3 xAxis = Vector3::Cross(up, zAxis).Normalized();
|
Vector3 xAxis = Vector3::Cross(up, zAxis).Normalized();
|
||||||
Vector3 yAxis = Vector3::Cross(zAxis, xAxis);
|
Vector3 yAxis = Vector3::Cross(zAxis, xAxis).Normalized();
|
||||||
|
Vector3 trans =
|
||||||
return { xAxis, yAxis, zAxis, origin };
|
{
|
||||||
}
|
-Vector3::Dot(xAxis, origin),
|
||||||
|
-Vector3::Dot(yAxis, origin),
|
||||||
Matrix Matrix::CreatePerspectiveFovLH(float fov, float aspect, float zn, float zf) {
|
-Vector3::Dot(zAxis, origin)
|
||||||
const float yScale = 1.f / tanf(fov / 2.f);
|
};
|
||||||
const float xScale = yScale / aspect;
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
{ xScale, 0, 0, 0 },
|
{xAxis.x, yAxis.x, zAxis.x},
|
||||||
{ 0, yScale, 0, 0 },
|
{xAxis.y, yAxis.y, zAxis.y},
|
||||||
{ 0, 0, zf / (zf - zn), 1 },
|
{xAxis.z, yAxis.z, zAxis.z},
|
||||||
{ 0, 0, -zn * zf / (zf - zn), 0 }
|
{trans.x, trans.y, trans.z}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
Vector3 Matrix::GetAxisX() const
|
|
||||||
{
|
Matrix Matrix::CreatePerspectiveFovLH(float fovy, float aspect, float zn, float zf) {
|
||||||
|
// const float yScale = 1.f / tanf(fovy / 2.f);
|
||||||
|
// const float xScale = yScale / aspect;
|
||||||
|
//
|
||||||
|
// return {
|
||||||
|
// {xScale, 0, 0, 0},
|
||||||
|
// {0, yScale, 0, 0},
|
||||||
|
// {0, 0, zf / (zf - zn), 1},
|
||||||
|
// {0, 0, -zn * zf / (zf - zn), 0}
|
||||||
|
// };
|
||||||
|
|
||||||
|
return Matrix(
|
||||||
|
{ 1.f / (aspect * fovy), 0, 0, 0 },
|
||||||
|
{ 0, 1.f / fovy, 0, 0 },
|
||||||
|
{ 0, 0, (zf) / (zf - zn), 1 },
|
||||||
|
{ 0, 0, -(zf * zn) / (zf - zn), 0 }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector3 Matrix::GetAxisX() const {
|
||||||
return data[0];
|
return data[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector3 Matrix::GetAxisY() const
|
Vector3 Matrix::GetAxisY() const {
|
||||||
{
|
|
||||||
return data[1];
|
return data[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector3 Matrix::GetAxisZ() const
|
Vector3 Matrix::GetAxisZ() const {
|
||||||
{
|
|
||||||
return data[2];
|
return data[2];
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector3 Matrix::GetTranslation() const
|
Vector3 Matrix::GetTranslation() const {
|
||||||
{
|
|
||||||
return data[3];
|
return data[3];
|
||||||
}
|
}
|
||||||
|
|
||||||
Matrix Matrix::CreateTranslation(float x, float y, float z)
|
Matrix Matrix::CreateTranslation(float x, float y, float z) {
|
||||||
{
|
|
||||||
return CreateTranslation({x, y, z});
|
return CreateTranslation({x, y, z});
|
||||||
}
|
}
|
||||||
|
|
||||||
Matrix Matrix::CreateTranslation(const Vector3& t)
|
Matrix Matrix::CreateTranslation(const Vector3 &t) {
|
||||||
{
|
|
||||||
return {Vector3::UnitX, Vector3::UnitY, Vector3::UnitZ, t};
|
return {Vector3::UnitX, Vector3::UnitY, Vector3::UnitZ, t};
|
||||||
}
|
}
|
||||||
|
|
||||||
Matrix Matrix::CreateRotationX(float pitch)
|
Matrix Matrix::CreateRotationX(float pitch) {
|
||||||
{
|
|
||||||
return {
|
return {
|
||||||
{1, 0, 0, 0},
|
{1, 0, 0, 0},
|
||||||
{0, cos(pitch), -sin(pitch), 0},
|
{0, cos(pitch), -sin(pitch), 0},
|
||||||
@@ -202,8 +203,7 @@ namespace dae {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
Matrix Matrix::CreateRotationY(float yaw)
|
Matrix Matrix::CreateRotationY(float yaw) {
|
||||||
{
|
|
||||||
return {
|
return {
|
||||||
{cos(yaw), 0, -sin(yaw), 0},
|
{cos(yaw), 0, -sin(yaw), 0},
|
||||||
{0, 1, 0, 0},
|
{0, 1, 0, 0},
|
||||||
@@ -212,8 +212,7 @@ namespace dae {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
Matrix Matrix::CreateRotationZ(float roll)
|
Matrix Matrix::CreateRotationZ(float roll) {
|
||||||
{
|
|
||||||
return {
|
return {
|
||||||
{cos(roll), sin(roll), 0, 0},
|
{cos(roll), sin(roll), 0, 0},
|
||||||
{-sin(roll), cos(roll), 0, 0},
|
{-sin(roll), cos(roll), 0, 0},
|
||||||
@@ -222,48 +221,40 @@ namespace dae {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
Matrix Matrix::CreateRotation(float pitch, float yaw, float roll)
|
Matrix Matrix::CreateRotation(float pitch, float yaw, float roll) {
|
||||||
{
|
|
||||||
return CreateRotation({pitch, yaw, roll});
|
return CreateRotation({pitch, yaw, roll});
|
||||||
}
|
}
|
||||||
|
|
||||||
Matrix Matrix::CreateRotation(const Vector3& r)
|
Matrix Matrix::CreateRotation(const Vector3 &r) {
|
||||||
{
|
|
||||||
return CreateRotationX(r[0]) * CreateRotationY(r[1]) * CreateRotationZ(r[2]);
|
return CreateRotationX(r[0]) * CreateRotationY(r[1]) * CreateRotationZ(r[2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
Matrix Matrix::CreateScale(float sx, float sy, float sz)
|
Matrix Matrix::CreateScale(float sx, float sy, float sz) {
|
||||||
{
|
|
||||||
return {{sx, 0, 0}, {0, sy, 0}, {0, 0, sz}, Vector3::Zero};
|
return {{sx, 0, 0}, {0, sy, 0}, {0, 0, sz}, Vector3::Zero};
|
||||||
}
|
}
|
||||||
|
|
||||||
Matrix Matrix::CreateScale(const Vector3& s)
|
Matrix Matrix::CreateScale(const Vector3 &s) {
|
||||||
{
|
|
||||||
return CreateScale(s[0], s[1], s[2]);
|
return CreateScale(s[0], s[1], s[2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma region Operator Overloads
|
#pragma region Operator Overloads
|
||||||
Vector4& Matrix::operator[](int index)
|
|
||||||
{
|
Vector4 &Matrix::operator[](int index) {
|
||||||
assert(index <= 3 && index >= 0);
|
assert(index <= 3 && index >= 0);
|
||||||
return data[index];
|
return data[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector4 Matrix::operator[](int index) const
|
Vector4 Matrix::operator[](int index) const {
|
||||||
{
|
|
||||||
assert(index <= 3 && index >= 0);
|
assert(index <= 3 && index >= 0);
|
||||||
return data[index];
|
return data[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
Matrix Matrix::operator*(const Matrix& m) const
|
Matrix Matrix::operator*(const Matrix &m) const {
|
||||||
{
|
|
||||||
Matrix result{};
|
Matrix result{};
|
||||||
Matrix m_transposed = Transpose(m);
|
Matrix m_transposed = Transpose(m);
|
||||||
|
|
||||||
for (int r{ 0 }; r < 4; ++r)
|
for (int r{0}; r < 4; ++r) {
|
||||||
{
|
for (int c{0}; c < 4; ++c) {
|
||||||
for (int c{ 0 }; c < 4; ++c)
|
|
||||||
{
|
|
||||||
result[r][c] = Vector4::Dot(data[r], m_transposed[c]);
|
result[r][c] = Vector4::Dot(data[r], m_transposed[c]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -271,15 +262,12 @@ namespace dae {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Matrix& Matrix::operator*=(const Matrix& m)
|
const Matrix &Matrix::operator*=(const Matrix &m) {
|
||||||
{
|
|
||||||
Matrix copy{*this};
|
Matrix copy{*this};
|
||||||
Matrix m_transposed = Transpose(m);
|
Matrix m_transposed = Transpose(m);
|
||||||
|
|
||||||
for (int r{ 0 }; r < 4; ++r)
|
for (int r{0}; r < 4; ++r) {
|
||||||
{
|
for (int c{0}; c < 4; ++c) {
|
||||||
for (int c{ 0 }; c < 4; ++c)
|
|
||||||
{
|
|
||||||
data[r][c] = Vector4::Dot(copy[r], m_transposed[c]);
|
data[r][c] = Vector4::Dot(copy[r], m_transposed[c]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -287,8 +275,7 @@ namespace dae {
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Matrix::operator==(const Matrix& m) const
|
bool Matrix::operator==(const Matrix &m) const {
|
||||||
{
|
|
||||||
return data[0] == m.data[0]
|
return data[0] == m.data[0]
|
||||||
&& data[1] == m.data[1]
|
&& data[1] == m.data[1]
|
||||||
&& data[2] == m.data[2]
|
&& data[2] == m.data[2]
|
||||||
|
|||||||
@@ -1,11 +1,14 @@
|
|||||||
//External includes
|
//External includes
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <SDL.h>
|
||||||
|
#include <array>
|
||||||
#include "SDL_surface.h"
|
#include "SDL_surface.h"
|
||||||
|
|
||||||
//Project includes
|
//Project includes
|
||||||
#include "Renderer.h"
|
#include "Renderer.h"
|
||||||
#include "Maths.h"
|
#include "Maths.h"
|
||||||
#include "HitTest.h"
|
#include "HitTest.h"
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
using namespace dae;
|
using namespace dae;
|
||||||
|
|
||||||
@@ -21,13 +24,16 @@ Renderer::Renderer(SDL_Window *pWindow) : m_pWindow(pWindow) {
|
|||||||
m_pDepthBufferPixels = new float[m_Width * m_Height];
|
m_pDepthBufferPixels = new float[m_Width * m_Height];
|
||||||
|
|
||||||
//Initialize Camera
|
//Initialize Camera
|
||||||
m_Camera.Initialize(60.f, {.0f, .0f, -10.f});
|
|
||||||
|
|
||||||
//Initialize Camera
|
|
||||||
m_Camera.Initialize(60.f, {.0f, .0f, -10.f});
|
|
||||||
m_aspectRatio = static_cast<float>(m_Width) / static_cast<float>(m_Height);
|
m_aspectRatio = static_cast<float>(m_Width) / static_cast<float>(m_Height);
|
||||||
|
m_Camera.Initialize(45.f, {.0f, 5.0f, -64.f}, m_aspectRatio);
|
||||||
|
|
||||||
m_pTexture = Texture::LoadFromFile("./Resources/uv_grid_2.png");
|
m_currentDiffuse = Texture::LoadFromFile("./Resources/vehicle_diffuse.png");
|
||||||
|
m_currentGloss = Texture::LoadFromFile("./Resources/vehicle_gloss.png");
|
||||||
|
m_currentNormal = Texture::LoadFromFile("./Resources/vehicle_normal.png");
|
||||||
|
m_currentSpecular = Texture::LoadFromFile("./Resources/vehicle_specular.png");
|
||||||
|
|
||||||
|
Utils::ParseOBJ("./Resources/vehicle.obj", m_mesh.vertices, m_mesh.indices, false);
|
||||||
|
m_worldMeshes.push_back(m_mesh);
|
||||||
}
|
}
|
||||||
|
|
||||||
Renderer::~Renderer() {
|
Renderer::~Renderer() {
|
||||||
@@ -36,6 +42,11 @@ Renderer::~Renderer() {
|
|||||||
|
|
||||||
void Renderer::Update(Timer *pTimer) {
|
void Renderer::Update(Timer *pTimer) {
|
||||||
m_Camera.Update(pTimer);
|
m_Camera.Update(pTimer);
|
||||||
|
|
||||||
|
//Rotate the mesh
|
||||||
|
if(m_isRotating){
|
||||||
|
m_worldMeshes[0].worldMatrix = Matrix::CreateRotationY(SDL_GetTicks() / 1000.f);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Renderer::Render() {
|
void Renderer::Render() {
|
||||||
@@ -54,10 +65,11 @@ void Renderer::Render() {
|
|||||||
constexpr int numVerticies = 3;
|
constexpr int numVerticies = 3;
|
||||||
|
|
||||||
std::vector<Vertex> verticiesScreenSpace{};
|
std::vector<Vertex> verticiesScreenSpace{};
|
||||||
// VertexTransformationFunction(m_verticiesWorld, verticiesScreenSpace);
|
|
||||||
|
|
||||||
for (const Mesh ¤tMesh: m_meshesWorldStrip) {
|
for (const Mesh ¤tMesh: m_worldMeshes) {
|
||||||
VertexTransformationFunction(currentMesh.vertices, verticiesScreenSpace);
|
|
||||||
|
const Matrix worldViewProjectionMatrix{ currentMesh.worldMatrix * m_Camera.viewMatrix * m_Camera.ProjectionMatrix };
|
||||||
|
VertexTransformationFunction(worldViewProjectionMatrix, currentMesh, currentMesh.vertices, verticiesScreenSpace);
|
||||||
|
|
||||||
int numTriangles{};
|
int numTriangles{};
|
||||||
|
|
||||||
@@ -97,6 +109,10 @@ void Renderer::Render() {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (!vertex0.valid and !vertex1.valid and !vertex2.valid) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
const float minX{std::min(vertex0.position.x, std::min(vertex1.position.x, vertex2.position.x))};
|
const float minX{std::min(vertex0.position.x, std::min(vertex1.position.x, vertex2.position.x))};
|
||||||
const float minY{std::min(vertex0.position.y, std::min(vertex1.position.y, vertex2.position.y))};
|
const float minY{std::min(vertex0.position.y, std::min(vertex1.position.y, vertex2.position.y))};
|
||||||
@@ -127,44 +143,31 @@ void Renderer::Render() {
|
|||||||
|
|
||||||
Vector3 P{static_cast<float>(px) + 0.5f, static_cast<float>(py) + 0.5f, 1.f};
|
Vector3 P{static_cast<float>(px) + 0.5f, static_cast<float>(py) + 0.5f, 1.f};
|
||||||
|
|
||||||
const Vector3 cross0{Vector3::Cross(vertex2.position - vertex1.position, P - vertex1.position)};
|
auto sample{ HitTest::TriangleHitTest(P, vertex0, vertex1, vertex2) };
|
||||||
if (cross0.z < 0) {
|
|
||||||
continue;
|
if (!sample.has_value()) {
|
||||||
}
|
|
||||||
const Vector3 cross1{Vector3::Cross(vertex0.position - vertex2.position, P - vertex2.position)};
|
|
||||||
if (cross1.z < 0) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
const Vector3 cross2{Vector3::Cross(vertex1.position - vertex0.position, P - vertex0.position)};
|
|
||||||
if (cross2.z < 0) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const int depthBufferIndex{px + (py * m_Width)};
|
const Vector3 fragPos{ static_cast<float>(px) + 0.5f, static_cast<float>(py) + 0.5f, 1.f };
|
||||||
|
|
||||||
float totalWeight{cross0.z + cross1.z + cross2.z};
|
int depthBufferIndex{ px + (py * m_Width) };
|
||||||
Vector3 weights{
|
|
||||||
cross0.z / totalWeight,
|
|
||||||
cross1.z / totalWeight,
|
|
||||||
cross2.z / totalWeight,
|
|
||||||
};
|
|
||||||
|
|
||||||
const float currentDepth =
|
float min{.985f};
|
||||||
1 / (weights.x / vertex0.position.z +
|
float max{1.f};
|
||||||
weights.y / vertex1.position.z +
|
float depthBuffer{(sample.value().depth - min) * (max - min)};
|
||||||
weights.z / vertex2.position.z);
|
float currentDepth = sample.value().depth;
|
||||||
|
|
||||||
const Vector2 UvCoords =
|
if (m_pDepthBufferPixels[depthBufferIndex] > currentDepth) {
|
||||||
vertex0.uv * currentDepth * weights.x / vertex0.position.z +
|
|
||||||
vertex1.uv * currentDepth * weights.y / vertex1.position.z +
|
|
||||||
vertex2.uv * currentDepth * weights.z / vertex2.position.z;
|
|
||||||
|
|
||||||
|
|
||||||
if (m_pDepthBufferPixels[depthBufferIndex] >= currentDepth) {
|
|
||||||
m_pDepthBufferPixels[depthBufferIndex] = currentDepth;
|
m_pDepthBufferPixels[depthBufferIndex] = currentDepth;
|
||||||
|
|
||||||
//Update Color in Buffer
|
if (m_isDepthBuffer) {
|
||||||
finalColor = m_pTexture->Sample(UvCoords);
|
finalColor = ColorRGB{depthBuffer, depthBuffer, depthBuffer};
|
||||||
|
} else {
|
||||||
|
// finalColor = m_pTexture->Sample(UvCoords);
|
||||||
|
finalColor = shadePixel(sample.value());
|
||||||
|
}
|
||||||
|
|
||||||
finalColor.MaxToOne();
|
finalColor.MaxToOne();
|
||||||
|
|
||||||
m_pBackBufferPixels[px + (py * m_Width)] = SDL_MapRGB(m_pBackBuffer->format,
|
m_pBackBufferPixels[px + (py * m_Width)] = SDL_MapRGB(m_pBackBuffer->format,
|
||||||
@@ -174,28 +177,14 @@ void Renderer::Render() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int x, y{0};
|
|
||||||
//For loop over all the pixels
|
|
||||||
for (int px{}; px < 100; ++px) {
|
|
||||||
for (int py{}; py < 100; ++py) {
|
|
||||||
//Get the pixel position
|
|
||||||
x = px;
|
|
||||||
y = py;
|
|
||||||
|
|
||||||
ColorRGB test = m_pTexture->Sample(Vector2{static_cast<float>(px) / 100, static_cast<float>(py) / 100});
|
|
||||||
m_pBackBufferPixels[x + (y * m_Width)] = SDL_MapRGB(m_pBackBuffer->format,
|
|
||||||
static_cast<uint8_t>(test.r * 255),
|
|
||||||
static_cast<uint8_t>(test.g * 255),
|
|
||||||
static_cast<uint8_t>(test.b * 255));
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
//RENDER LOGIC
|
//RENDER LOGIC
|
||||||
|
|
||||||
@@ -205,20 +194,117 @@ void Renderer::Render() {
|
|||||||
SDL_UpdateWindowSurface(m_pWindow);
|
SDL_UpdateWindowSurface(m_pWindow);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Renderer::VertexTransformationFunction(const std::vector<Vertex> &vertices_in,
|
void Renderer::VertexTransformationFunction(const Matrix& WorldViewProjectionMatrix, const Mesh& mesh, const std::vector<Vertex> &vertices_in,
|
||||||
std::vector<Vertex> &vertices_out) const {
|
std::vector<Vertex> &vertices_out) const {
|
||||||
for (const Vertex &vert: vertices_in) {
|
// vertices_out.clear();
|
||||||
Vector3 vertPos{m_Camera.invViewMatrix.TransformPoint(vert.position)};
|
for (const Vertex& vert : vertices_in)
|
||||||
|
{
|
||||||
|
Vertex vertex_out{};
|
||||||
|
|
||||||
vertPos.x = (vertPos.x / vertPos.z) / (m_aspectRatio * m_Camera.fov);
|
Vector4 vertPos{ WorldViewProjectionMatrix.TransformPoint({vert.position.GetXYZ(), 1}) };
|
||||||
vertPos.y = (vertPos.y / vertPos.z) / m_Camera.fov;
|
|
||||||
|
|
||||||
vertPos.x = (vertPos.x + 1) / 2 * static_cast<float>(m_Width);
|
const Vector3 normal{ mesh.worldMatrix.TransformVector(vert.normal) };
|
||||||
vertPos.y = (1 - vertPos.y) / 2 * static_cast<float>(m_Height);
|
const Vector3 tangent{ mesh.worldMatrix.TransformVector(vert.tangent) };
|
||||||
vertices_out.push_back(Vertex{vertPos, vert.color, vert.uv});
|
|
||||||
|
|
||||||
|
|
||||||
|
vertPos.x /= vertPos.w;
|
||||||
|
vertPos.y /= vertPos.w;
|
||||||
|
vertPos.z /= vertPos.w;
|
||||||
|
|
||||||
|
bool isValid{ true };
|
||||||
|
|
||||||
|
//Check if the vertex is inside the screen
|
||||||
|
if (vertPos.x < -1.f || vertPos.x > 1.f ||
|
||||||
|
vertPos.y < -1.f || vertPos.y > 1.f ||
|
||||||
|
vertPos.z < 0.f || vertPos.z > 1.f)
|
||||||
|
isValid = false;
|
||||||
|
|
||||||
|
vertPos.x = ((vertPos.x + 1.f) / 2.f) * static_cast<float>(m_Width);
|
||||||
|
vertPos.y = ((1.f - vertPos.y) / 2.f) * static_cast<float>(m_Height);
|
||||||
|
|
||||||
|
vertex_out.position = vertPos;
|
||||||
|
vertex_out.color = vert.color;
|
||||||
|
vertex_out.uv = vert.uv;
|
||||||
|
vertex_out.normal = normal;
|
||||||
|
vertex_out.tangent = tangent;
|
||||||
|
vertex_out.viewDir = WorldViewProjectionMatrix.TransformVector(vert.viewDir);
|
||||||
|
vertex_out.valid = isValid;
|
||||||
|
|
||||||
|
vertices_out.push_back(vertex_out);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Renderer::SaveBufferToImage() const {
|
bool Renderer::SaveBufferToImage() const {
|
||||||
return SDL_SaveBMP(m_pBackBuffer, "Rasterizer_ColorBuffer.bmp");
|
return SDL_SaveBMP(m_pBackBuffer, "Rasterizer_ColorBuffer.bmp");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ColorRGB Renderer::shadePixel(const Sample &sample) {
|
||||||
|
Vector3 lightDirection = { .577f, -.577f, .577f};
|
||||||
|
Vector3 normal = sample.normal.Normalized();
|
||||||
|
constexpr float lightIntensity{ 7.f };
|
||||||
|
|
||||||
|
ColorRGB color{ 1, 1, 1 };
|
||||||
|
constexpr ColorRGB ambient{ .03f, .03f, .03f};
|
||||||
|
|
||||||
|
if(m_useNormals){
|
||||||
|
const ColorRGB normalSample{ m_currentNormal->Sample(sample.uv) };
|
||||||
|
const Vector4 normalMapSample{
|
||||||
|
2.f * normalSample.r - 1.f,
|
||||||
|
2.f * normalSample.g - 1.f,
|
||||||
|
2.f * normalSample.b - 1.f,
|
||||||
|
0.f
|
||||||
|
};
|
||||||
|
|
||||||
|
const Vector3 biNormal{ Vector3::Cross(normal, sample.tangent) };
|
||||||
|
const Matrix tangentToWorld{
|
||||||
|
Vector4{ sample.tangent, 0.f },
|
||||||
|
Vector4{ biNormal, 0.f },
|
||||||
|
Vector4{ normal, 0.f },
|
||||||
|
Vector4{ 0.f, 0.f, 0.f, 1.f }
|
||||||
|
};
|
||||||
|
normal = tangentToWorld.TransformVector(normalMapSample).Normalized();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const ColorRGB diffuseSample{ m_currentDiffuse->Sample(sample.uv) };
|
||||||
|
double invPi = 1.0 / PI;
|
||||||
|
const ColorRGB lambert{ diffuseSample * lightIntensity * invPi };
|
||||||
|
|
||||||
|
//TODO: ask why deviding by PI causses Segmentation fault
|
||||||
|
// const ColorRGB lambert{ diffuseSample * lightIntensity / PI };
|
||||||
|
|
||||||
|
|
||||||
|
float specularReflectance{ 1.f };
|
||||||
|
float shininess{ 25.f };
|
||||||
|
|
||||||
|
specularReflectance *= m_currentGloss->Sample(sample.uv).r;
|
||||||
|
shininess *= m_currentSpecular->Sample(sample.uv).r;
|
||||||
|
|
||||||
|
const float cosAngle = Vector3::Dot(normal, -lightDirection);
|
||||||
|
|
||||||
|
const ColorRGB specular = specularReflectance * powf(cosAngle, shininess) * colors::White;
|
||||||
|
|
||||||
|
if (cosAngle < 0) {
|
||||||
|
return ambient;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(m_ShadeMode){
|
||||||
|
case ShadeMode::ObservedArea:
|
||||||
|
break;
|
||||||
|
case ShadeMode::Diffuse:
|
||||||
|
color = lambert;
|
||||||
|
break;
|
||||||
|
case ShadeMode::Specular:
|
||||||
|
color = specular;
|
||||||
|
break;
|
||||||
|
case ShadeMode::Combined:
|
||||||
|
color = lambert + specular + ambient;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
color *= ColorRGB{ cosAngle, cosAngle, cosAngle };
|
||||||
|
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
|||||||
@@ -11,8 +11,16 @@
|
|||||||
struct SDL_Window;
|
struct SDL_Window;
|
||||||
struct SDL_Surface;
|
struct SDL_Surface;
|
||||||
|
|
||||||
|
|
||||||
namespace dae {
|
namespace dae {
|
||||||
|
|
||||||
|
enum class ShadeMode{
|
||||||
|
ObservedArea,
|
||||||
|
Diffuse,
|
||||||
|
Specular,
|
||||||
|
Combined
|
||||||
|
};
|
||||||
|
|
||||||
struct Mesh;
|
struct Mesh;
|
||||||
|
|
||||||
class Timer;
|
class Timer;
|
||||||
@@ -40,7 +48,48 @@ namespace dae {
|
|||||||
bool SaveBufferToImage() const;
|
bool SaveBufferToImage() const;
|
||||||
|
|
||||||
void
|
void
|
||||||
VertexTransformationFunction(const std::vector<Vertex> &vertices_in, std::vector<Vertex> &vertices_out) const;
|
VertexTransformationFunction(const Matrix& WorldViewProjectionMatrix, const Mesh& mesh, const std::vector<Vertex> &vertices_in, std::vector<Vertex> &vertices_out) const;
|
||||||
|
|
||||||
|
ColorRGB shadePixel(const Sample& sample);
|
||||||
|
|
||||||
|
void SwitchDepthBuffer(){
|
||||||
|
m_isDepthBuffer = !m_isDepthBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetShadeMode(ShadeMode mode) {
|
||||||
|
m_ShadeMode = mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ToggleRotation(){
|
||||||
|
m_isRotating = !m_isRotating;
|
||||||
|
std::cout << "Rotation: " << m_isRotating << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ToggleNormals(){
|
||||||
|
m_useNormals = !m_useNormals;
|
||||||
|
std::cout << "Use Normals: " << m_useNormals << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CycleRenderingMode(){
|
||||||
|
switch (m_ShadeMode) {
|
||||||
|
case ShadeMode::ObservedArea:
|
||||||
|
m_ShadeMode = ShadeMode::Diffuse;
|
||||||
|
std::cout << "Diffuse" << std::endl;
|
||||||
|
break;
|
||||||
|
case ShadeMode::Diffuse:
|
||||||
|
m_ShadeMode = ShadeMode::Specular;
|
||||||
|
std::cout << "Specular" << std::endl;
|
||||||
|
break;
|
||||||
|
case ShadeMode::Specular:
|
||||||
|
m_ShadeMode = ShadeMode::Combined;
|
||||||
|
std::cout << "Combined" << std::endl;
|
||||||
|
break;
|
||||||
|
case ShadeMode::Combined:
|
||||||
|
m_ShadeMode = ShadeMode::ObservedArea;
|
||||||
|
std::cout << "Observed Area" << std::endl;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SDL_Window *m_pWindow{};
|
SDL_Window *m_pWindow{};
|
||||||
@@ -56,83 +105,22 @@ namespace dae {
|
|||||||
|
|
||||||
float m_aspectRatio{};
|
float m_aspectRatio{};
|
||||||
|
|
||||||
Texture* m_pTexture{ nullptr };
|
Texture* m_currentDiffuse{ nullptr };
|
||||||
//
|
Texture* m_currentGloss{ nullptr };
|
||||||
// std::vector<Vertex> m_verticiesWorld{
|
Texture* m_currentNormal{ nullptr };
|
||||||
// //Triangle 0
|
Texture* m_currentSpecular{ nullptr };
|
||||||
// {{0.f,2.f,0.f}, {1,0,0}},
|
|
||||||
// {{1.5f,-1.f,0.f}, {1,0,0}},
|
|
||||||
// {{-1.5f,-1.f,0.f}, {1,0,0}},
|
|
||||||
//
|
|
||||||
// //Triangle 1
|
|
||||||
// {{0.f,4.f,2.f}, {1,0,0}},
|
|
||||||
// {{3.f,-2.f,2.f}, {0,1,0}},
|
|
||||||
// {{-3.f,-2.f,2.f}, {0,0,1}}
|
|
||||||
// };
|
|
||||||
|
|
||||||
std::vector<Mesh> m_meshesWorldList
|
|
||||||
{
|
|
||||||
Mesh
|
|
||||||
{
|
|
||||||
{
|
|
||||||
Vertex{ {-3, 3, -2 }, { 1, 1, 1 }, { 0.0f, 0.0f } },
|
|
||||||
Vertex{ { 0, 3, -2 }, { 1, 1, 1 }, { 0.5f, 0.0f } },
|
|
||||||
Vertex{ { 3, 3, -2 }, { 1, 1, 1 }, { 1.0f, 0.0f } },
|
|
||||||
Vertex{ {-3, 0, -2 }, { 1, 1, 1 }, { 0.0f, 0.5f } },
|
|
||||||
Vertex{ { 0, 0, -2 }, { 1, 1, 1 }, { 0.5f, 0.5f } },
|
|
||||||
Vertex{ { 3, 0, -2 }, { 1, 1, 1 }, { 1.0f, 0.5f } },
|
|
||||||
Vertex{ {-3, -3, -2 }, { 1, 1, 1 }, { 0.0f, 1.0f } },
|
|
||||||
Vertex{ { 0, -3, -2 }, { 1, 1, 1 }, { 0.5f, 1.0f } },
|
|
||||||
Vertex{ { 3, -3, -2 }, { 1, 1, 1 }, { 1.0f, 1.0f } }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
3, 0, 1, 1, 4, 3, 4, 1 ,2,
|
|
||||||
2, 5, 4, 6, 3, 4, 4, 7, 6,
|
|
||||||
7, 4, 5, 5, 8, 7
|
|
||||||
},
|
|
||||||
PrimitiveTopology::TriangleList
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
std::vector<Mesh> m_meshesWorldStrip
|
ShadeMode m_ShadeMode{ ShadeMode::Combined };
|
||||||
{
|
bool m_isRotating{ true };
|
||||||
Mesh
|
bool m_useNormals{ true };
|
||||||
{
|
|
||||||
std::vector<Vertex>{
|
Mesh m_mesh{};
|
||||||
{{-3, 3, -2}, {colors::White}, {0,0} },
|
|
||||||
{{0, 3, -2}, {colors::Red}, {0.5,0}},
|
bool m_isDepthBuffer{ false };
|
||||||
{{3, 3, -2}, {colors::Blue}, {1,0}},
|
|
||||||
{{-3, 0, -2}, {colors::Red}, {0,0.5}},
|
|
||||||
{{0, 0, -2}, {colors::Yellow}, {0.5, 0.5}},
|
std::vector<Mesh> m_worldMeshes{};
|
||||||
{{3, 0, -2}, {colors::White}, {1, 0.5}},
|
|
||||||
{{-3, -3, -2}, {colors::White}, {0,1}},
|
|
||||||
{{0, -3, -2}, {colors::White}, {0.5,1}},
|
|
||||||
{{3, -3, -2}, {colors::White}, {1,1}},
|
|
||||||
},
|
|
||||||
std::vector<uint32_t>{
|
|
||||||
3, 0, 4, 1, 5, 2,
|
|
||||||
2, 6,
|
|
||||||
6, 3, 7, 4, 8, 5,
|
|
||||||
},
|
|
||||||
PrimitiveTopology::TriangleStrip,
|
|
||||||
}
|
|
||||||
};
|
|
||||||
//square
|
|
||||||
std::vector<Mesh> testMesh{
|
|
||||||
Mesh{
|
|
||||||
std::vector<Vertex>{
|
|
||||||
{{-1, 1, 0}, {colors::White}, {0, 0}},
|
|
||||||
{{1, 1, 0}, {colors::White}, {1, 0}},
|
|
||||||
{{-1, -1, 0}, {colors::White}, {0, 1}},
|
|
||||||
{{1, -1, 0}, {colors::White}, {1, 1}},
|
|
||||||
},
|
|
||||||
std::vector<uint32_t>{
|
|
||||||
0, 1, 2, 1, 3, 2
|
|
||||||
},
|
|
||||||
PrimitiveTopology::TriangleList
|
|
||||||
}
|
|
||||||
};
|
|
||||||
// std::vector<Vertex> m_verticies_screenSpace{};
|
|
||||||
|
|
||||||
float* m_pDepthBufferPixels{};
|
float* m_pDepthBufferPixels{};
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
#include "Maths.h"
|
#include "Maths.h"
|
||||||
#include "DataTypes.h"
|
#include "DataTypes.h"
|
||||||
|
|
||||||
#define DISABLE_OBJ
|
//#define DISABLE_OBJ
|
||||||
|
|
||||||
namespace dae
|
namespace dae
|
||||||
{
|
{
|
||||||
@@ -84,7 +84,7 @@ namespace dae
|
|||||||
{
|
{
|
||||||
// OBJ format uses 1-based arrays
|
// OBJ format uses 1-based arrays
|
||||||
file >> iPosition;
|
file >> iPosition;
|
||||||
vertex.position = positions[iPosition - 1];
|
vertex.position = positions[iPosition - 1].ToVector4();
|
||||||
|
|
||||||
if ('/' == file.peek())//is next in buffer == '/' ?
|
if ('/' == file.peek())//is next in buffer == '/' ?
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -6,10 +6,10 @@ namespace dae
|
|||||||
struct Vector3;
|
struct Vector3;
|
||||||
struct Vector4
|
struct Vector4
|
||||||
{
|
{
|
||||||
float x;
|
float x{};
|
||||||
float y;
|
float y{};
|
||||||
float z;
|
float z{};
|
||||||
float w;
|
float w{};
|
||||||
|
|
||||||
Vector4() = default;
|
Vector4() = default;
|
||||||
Vector4(float _x, float _y, float _z, float _w);
|
Vector4(float _x, float _y, float _z, float _w);
|
||||||
@@ -20,8 +20,8 @@ namespace dae
|
|||||||
float Normalize();
|
float Normalize();
|
||||||
Vector4 Normalized() const;
|
Vector4 Normalized() const;
|
||||||
|
|
||||||
Vector2 GetXY() const;
|
[[nodiscard]] Vector2 GetXY() const;
|
||||||
Vector3 GetXYZ() const;
|
[[nodiscard]] Vector3 GetXYZ() const;
|
||||||
|
|
||||||
static float Dot(const Vector4& v1, const Vector4& v2);
|
static float Dot(const Vector4& v1, const Vector4& v2);
|
||||||
|
|
||||||
|
|||||||
@@ -2,8 +2,10 @@
|
|||||||
#ifdef ENABLE_VLD
|
#ifdef ENABLE_VLD
|
||||||
#include "vld.h"
|
#include "vld.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "SDL.h"
|
#include "SDL.h"
|
||||||
#include "SDL_surface.h"
|
#include "SDL_surface.h"
|
||||||
|
|
||||||
#undef main
|
#undef main
|
||||||
|
|
||||||
//Standard includes
|
//Standard includes
|
||||||
@@ -15,14 +17,12 @@
|
|||||||
|
|
||||||
using namespace dae;
|
using namespace dae;
|
||||||
|
|
||||||
void ShutDown(SDL_Window* pWindow)
|
void ShutDown(SDL_Window *pWindow) {
|
||||||
{
|
|
||||||
SDL_DestroyWindow(pWindow);
|
SDL_DestroyWindow(pWindow);
|
||||||
SDL_Quit();
|
SDL_Quit();
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char* args[])
|
int main(int argc, char *args[]) {
|
||||||
{
|
|
||||||
//Unreferenced parameters
|
//Unreferenced parameters
|
||||||
(void) argc;
|
(void) argc;
|
||||||
(void) args;
|
(void) args;
|
||||||
@@ -34,7 +34,7 @@ int main(int argc, char* args[])
|
|||||||
const uint32_t height = 480;
|
const uint32_t height = 480;
|
||||||
|
|
||||||
SDL_Window *pWindow = SDL_CreateWindow(
|
SDL_Window *pWindow = SDL_CreateWindow(
|
||||||
"Rasterizer - **Insert Name**",
|
"Rasterizer - Bram Verhulst",
|
||||||
SDL_WINDOWPOS_UNDEFINED,
|
SDL_WINDOWPOS_UNDEFINED,
|
||||||
SDL_WINDOWPOS_UNDEFINED,
|
SDL_WINDOWPOS_UNDEFINED,
|
||||||
width, height, 0);
|
width, height, 0);
|
||||||
@@ -55,14 +55,11 @@ int main(int argc, char* args[])
|
|||||||
float printTimer = 0.f;
|
float printTimer = 0.f;
|
||||||
bool isLooping = true;
|
bool isLooping = true;
|
||||||
bool takeScreenshot = false;
|
bool takeScreenshot = false;
|
||||||
while (isLooping)
|
while (isLooping) {
|
||||||
{
|
|
||||||
//--------- Get input events ---------
|
//--------- Get input events ---------
|
||||||
SDL_Event e;
|
SDL_Event e;
|
||||||
while (SDL_PollEvent(&e))
|
while (SDL_PollEvent(&e)) {
|
||||||
{
|
switch (e.type) {
|
||||||
switch (e.type)
|
|
||||||
{
|
|
||||||
case SDL_QUIT:
|
case SDL_QUIT:
|
||||||
isLooping = false;
|
isLooping = false;
|
||||||
break;
|
break;
|
||||||
@@ -70,6 +67,21 @@ int main(int argc, char* args[])
|
|||||||
if (e.key.keysym.scancode == SDL_SCANCODE_X)
|
if (e.key.keysym.scancode == SDL_SCANCODE_X)
|
||||||
takeScreenshot = true;
|
takeScreenshot = true;
|
||||||
break;
|
break;
|
||||||
|
case SDL_KEYDOWN: {
|
||||||
|
auto key = e.key.keysym.scancode;
|
||||||
|
if (key == SDL_SCANCODE_F4) {
|
||||||
|
pRenderer->SwitchDepthBuffer();
|
||||||
|
}
|
||||||
|
if (key == SDL_SCANCODE_F5) {
|
||||||
|
pRenderer->ToggleRotation();
|
||||||
|
}
|
||||||
|
if (key == SDL_SCANCODE_F6) {
|
||||||
|
pRenderer->ToggleNormals();
|
||||||
|
}
|
||||||
|
if (key == SDL_SCANCODE_F7) {
|
||||||
|
pRenderer->CycleRenderingMode();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -82,15 +94,13 @@ int main(int argc, char* args[])
|
|||||||
//--------- Timer ---------
|
//--------- Timer ---------
|
||||||
pTimer->Update();
|
pTimer->Update();
|
||||||
printTimer += pTimer->GetElapsed();
|
printTimer += pTimer->GetElapsed();
|
||||||
if (printTimer >= 1.f)
|
if (printTimer >= 1.f) {
|
||||||
{
|
|
||||||
printTimer = 0.f;
|
printTimer = 0.f;
|
||||||
std::cout << "dFPS: " << pTimer->GetdFPS() << std::endl;
|
std::cout << "dFPS: " << pTimer->GetdFPS() << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Save screenshot after full render
|
//Save screenshot after full render
|
||||||
if (takeScreenshot)
|
if (takeScreenshot) {
|
||||||
{
|
|
||||||
if (!pRenderer->SaveBufferToImage())
|
if (!pRenderer->SaveBufferToImage())
|
||||||
std::cout << "Screenshot saved!" << std::endl;
|
std::cout << "Screenshot saved!" << std::endl;
|
||||||
else
|
else
|
||||||
|
|||||||
Reference in New Issue
Block a user