diff --git a/.gitignore b/.gitignore index a55757c1..f3840b8a 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,7 @@ # Engine specific files console.log +*.dump # shader content dumps for debuging # Engine local configurations AssetsPathConfig.json @@ -69,4 +70,3 @@ xcuserdata/ # Exculdes from ignore !**/ThirdParty/** - diff --git a/PolyEngine/Core/Src/Math/AABox.cpp b/PolyEngine/Core/Src/Math/AABox.cpp index ce28bd87..afeba5af 100644 --- a/PolyEngine/Core/Src/Math/AABox.cpp +++ b/PolyEngine/Core/Src/Math/AABox.cpp @@ -5,8 +5,8 @@ using namespace Poly; //------------------------------------------------------------------------------ -AABox::AABox(const Vector& position, const Vector& size) - : Pos(position), Size(size) +AABox::AABox(const Vector& min, const Vector& size) + : Min(min), Size(size) { ASSERTE(Size.X >= 0 && Size.Y >= 0 && Size.Z >= 0, "Invalid aabox size!"); } @@ -14,19 +14,19 @@ AABox::AABox(const Vector& position, const Vector& size) //------------------------------------------------------------------------------ AABox AABox::GetIntersectionVolume(const AABox& rhs) const { - const float r1MinX = std::min(Pos.X, Pos.X + Size.X); - const float r1MaxX = std::max(Pos.X, Pos.X + Size.X); - const float r1MinY = std::min(Pos.Y, Pos.Y + Size.Y); - const float r1MaxY = std::max(Pos.Y, Pos.Y + Size.Y); - const float r1MinZ = std::min(Pos.Z, Pos.Z + Size.Z); - const float r1MaxZ = std::max(Pos.Z, Pos.Z + Size.Z); + const float r1MinX = std::min(Min.X, Min.X + Size.X); + const float r1MaxX = std::max(Min.X, Min.X + Size.X); + const float r1MinY = std::min(Min.Y, Min.Y + Size.Y); + const float r1MaxY = std::max(Min.Y, Min.Y + Size.Y); + const float r1MinZ = std::min(Min.Z, Min.Z + Size.Z); + const float r1MaxZ = std::max(Min.Z, Min.Z + Size.Z); - const float r2MinX = std::min(rhs.Pos.X, rhs.Pos.X + rhs.Size.X); - const float r2MaxX = std::max(rhs.Pos.X, rhs.Pos.X + rhs.Size.X); - const float r2MinY = std::min(rhs.Pos.Y, rhs.Pos.Y + rhs.Size.Y); - const float r2MaxY = std::max(rhs.Pos.Y, rhs.Pos.Y + rhs.Size.Y); - const float r2MinZ = std::min(rhs.Pos.Z, rhs.Pos.Z + rhs.Size.Z); - const float r2MaxZ = std::max(rhs.Pos.Z, rhs.Pos.Z + rhs.Size.Z); + const float r2MinX = std::min(rhs.Min.X, rhs.Min.X + rhs.Size.X); + const float r2MaxX = std::max(rhs.Min.X, rhs.Min.X + rhs.Size.X); + const float r2MinY = std::min(rhs.Min.Y, rhs.Min.Y + rhs.Size.Y); + const float r2MaxY = std::max(rhs.Min.Y, rhs.Min.Y + rhs.Size.Y); + const float r2MinZ = std::min(rhs.Min.Z, rhs.Min.Z + rhs.Size.Z); + const float r2MaxZ = std::max(rhs.Min.Z, rhs.Min.Z + rhs.Size.Z); const float interLeft = std::max(r1MinX, r2MinX); const float interTop = std::max(r1MinY, r2MinY); @@ -36,9 +36,7 @@ AABox AABox::GetIntersectionVolume(const AABox& rhs) const const float interDown = std::min(r1MaxZ, r2MaxZ); if ((interLeft < interRight) && (interTop < interBottom) && (interUp < interDown)) - { return AABox(Vector(interLeft, interTop, interUp), Vector(interRight - interLeft, interBottom - interTop, interDown - interUp)); - } else return AABox(Vector::ZERO, Vector::ZERO); } @@ -47,34 +45,34 @@ std::array Poly::AABox::GetVertices() const { SILENCE_CLANG_WARNING(-Wmissing-braces, "Everything is ok here."); return std::array{ - Pos, - Pos + Vector(Size.X, 0, 0), - Pos + Vector(Size.X, Size.Y, 0), - Pos + Vector(Size.X, Size.Y, Size.Z), - Pos + Vector(0, Size.Y, Size.Z), - Pos + Vector(0, 0, Size.Z), - Pos + Vector(0, Size.Y, 0), - Pos + Vector(Size.X, 0, Size.Z) + Min, + Min + Vector(Size.X, 0, 0), + Min + Vector(Size.X, Size.Y, 0), + Min + Vector(Size.X, Size.Y, Size.Z), + Min + Vector(0, Size.Y, Size.Z), + Min + Vector(0, 0, Size.Z), + Min + Vector(0, Size.Y, 0), + Min + Vector(Size.X, 0, Size.Z) }; UNSILENCE_CLANG_WARNING(); } AABox Poly::AABox::GetTransformed(const Matrix& transform) const { - Vector min = transform * Pos; + Vector min = transform * Min; Vector max = min; // Gather other 7 points SILENCE_CLANG_WARNING(-Wmissing-braces, "Everything is ok here."); std::array points = { - Pos + Vector(Size.X, 0, 0), - Pos + Vector(Size.X, Size.Y, 0), - Pos + Vector(Size.X, Size.Y, Size.Z), - Pos + Vector(0, Size.Y, Size.Z), - Pos + Vector(0, 0, Size.Z), - Pos + Vector(0, Size.Y, 0), - Pos + Vector(Size.X, 0, Size.Z) + Min + Vector(Size.X, 0, 0), + Min + Vector(Size.X, Size.Y, 0), + Min + Vector(Size.X, Size.Y, Size.Z), + Min + Vector(0, Size.Y, Size.Z), + Min + Vector(0, 0, Size.Z), + Min + Vector(0, Size.Y, 0), + Min + Vector(Size.X, 0, Size.Z) }; UNSILENCE_CLANG_WARNING(); @@ -93,7 +91,16 @@ Poly::AABox& Poly::AABox::Expand(const AABox& rhs) { Vector min = Vector::Min(GetMin(), rhs.GetMin()); Vector max = Vector::Max(GetMax(), rhs.GetMax()); - Pos = min; + Min = min; + Size = max - min; + return *this; +} + +Poly::AABox& Poly::AABox::Expand(const Vector& rhs) +{ + Vector min = Vector::Min(GetMin(), rhs); + Vector max = Vector::Max(GetMax(), rhs); + Min = min; Size = max - min; return *this; } @@ -102,6 +109,6 @@ Poly::AABox& Poly::AABox::Expand(const AABox& rhs) namespace Poly { std::ostream & operator<<(std::ostream& stream, const AABox& rect) { - return stream << "AABox[Pos: " << rect.Pos << " Size: " << rect.Size << " ]"; + return stream << "AABox[Pos: " << rect.Min << " Size: " << rect.Size << " ]"; } } diff --git a/PolyEngine/Core/Src/Math/AABox.hpp b/PolyEngine/Core/Src/Math/AABox.hpp index bb2c6222..5110c482 100644 --- a/PolyEngine/Core/Src/Math/AABox.hpp +++ b/PolyEngine/Core/Src/Math/AABox.hpp @@ -12,23 +12,23 @@ namespace Poly { { public: - /// Constructor from position and size. - /// Position of the min point of the box. + /// Constructor from min and size. + /// Position of the min point of the box. /// Size (extent) of the box in each of the directions. - AABox(const Vector& position, const Vector& size); + AABox(const Vector& min, const Vector& size); AABox() = default; /// Calculates center of the box. /// Center of the box. - Vector GetCenter() const { return Pos + (Size * 0.5f); } + Vector GetCenter() const { return Min + (Size * 0.5f); } /// Returns the min point of the box. (posiiton) /// Min point of the box. - const Vector& GetMin() const { return Pos; } + const Vector& GetMin() const { return Min; } /// Returns the max point of the box. /// Max point of the box. - Vector GetMax() const { return Pos + Size; } + Vector GetMax() const { return Min + Size; } /// Returns Size of the box in all three dimensions. /// Size of the box. (extent) @@ -36,30 +36,68 @@ namespace Poly { /// Sets position of the box. /// New position - void SetPosition(const Vector& pos) { Pos = pos; } + void SetMin(const Vector& pos) { Min = pos; } /// Sets size of the box. /// New size void SetSize(const Vector& size) { Size = size; } + /// Checks whether a given AABox is interecting with this AABox. + /// Other box. + /// + inline bool Intersects(const AABox& rhs) const + { + return (abs(Min.X - rhs.Min.X) * 2.0f < (Size.X + rhs.Size.X)) + && (abs(Min.Y - rhs.Min.Y) * 2.0f < (Size.Y + rhs.Size.Y)) + && (abs(Min.Z - rhs.Min.Z) * 2.0f < (Size.Z + rhs.Size.Z)); + } + /// Checks whether this AABox contains a given point. /// Point to be checked. /// inline bool Contains(const Vector& point) const { - return point.X >= Pos.X && point.X <= (Pos.X + Size.X) - && point.Y >= Pos.Y && point.Y <= (Pos.Y + Size.Y) - && point.Z >= Pos.Z && point.Z <= (Pos.Z + Size.Z); + return point.X >= Min.X && point.X <= (Min.X + Size.X) + && point.Y >= Min.Y && point.Y <= (Min.Y + Size.Y) + && point.Z >= Min.Z && point.Z <= (Min.Z + Size.Z); } - /// Checks whether a given AABox is interecting with this AABox. + /// Checks whether a given AABox contains this AABox on all axes. /// Other box. - /// - inline bool Intersects(const AABox& rhs) const - { - return (abs(Pos.X - rhs.Pos.X) * 2 < (Size.X + rhs.Size.X)) - && (abs(Pos.Y - rhs.Pos.Y) * 2 < (Size.Y + rhs.Size.Y)) - && (abs(Pos.Z - rhs.Pos.Z) * 2 < (Size.Z + rhs.Size.Z)); + inline bool Contains(const AABox& rhs) const + { + return ContainsX(rhs) && ContainsY(rhs) && ContainsZ(rhs); + } + + /// Checks whether a given AABox contains this AABox on XY plane. + /// Other box. + inline bool ContainsXY(const AABox& rhs) const + { + return ContainsX(rhs) && ContainsY(rhs); + } + + /// Checks whether a given AABox contains this AABox on X axis. + /// Other box. + inline bool ContainsX(const AABox& rhs) const + { + return (Min.X <= rhs.Min.X + rhs.Size.X) + && (Min.X + Size.X >= rhs.Min.X); + } + + /// Checks whether a given AABox contains this AABox on Y axis. + /// Other box. + inline bool ContainsY(const AABox& rhs) const + { + return (Min.Y <= rhs.Min.Y + rhs.Size.Y) + && (Min.Y + Size.Y >= rhs.Min.Y); + } + + /// Checks whether a given AABox contains this AABox on Z axis. + /// Other box. + inline bool ContainsZ(const AABox& rhs) const + { + return (Min.Z <= rhs.Min.Z + rhs.Size.Z) + && (Min.Z + Size.Z >= rhs.Min.Z); } std::array GetVertices() const; @@ -74,9 +112,11 @@ namespace Poly { AABox& Expand(const AABox& rhs); + AABox& Expand(const Vector& rhs); + CORE_DLLEXPORT friend std::ostream& operator<< (std::ostream& stream, const AABox& color); private: - Vector Pos; + Vector Min; Vector Size; }; } \ No newline at end of file diff --git a/PolyEngine/Core/Src/Math/Matrix.cpp b/PolyEngine/Core/Src/Math/Matrix.cpp index 96256129..38844612 100644 --- a/PolyEngine/Core/Src/Math/Matrix.cpp +++ b/PolyEngine/Core/Src/Math/Matrix.cpp @@ -224,25 +224,27 @@ Matrix& Matrix::SetScale(const Vector& scale) { //------------------------------------------------------------------------------ Matrix& Matrix::SetLookAt(const Vector& pos, const Vector& lookAt, const Vector& up) { + const Vector front((lookAt - pos).GetNormalized()); + const Vector side(front.Cross(up).GetNormalized()); + const Vector newUp(side.Cross(front)); + SetIdentity(); + // same as GLM_FUNC_QUALIFIER mat<4, 4, T, Q> lookAtRH(vec<3, T, Q> const& eye, vec<3, T, Q> const& center, vec<3, T, Q> const& up) + Data[0] = side.X; // glm[0][0] + Data[1] = side.Y; // glm[1][0] + Data[2] = side.Z; // glm[2][0] - Vector zAxis = pos - lookAt; - zAxis.Normalize(); - Vector xAxis = up.Cross(zAxis); - xAxis.Normalize(); - Vector yAxis = zAxis.Cross(xAxis); + Data[4] = newUp.X; // glm[0][1] + Data[5] = newUp.Y; // glm[1][1] + Data[6] = newUp.Z; // glm[2][1] - Data[0] = xAxis.X; - Data[1] = yAxis.X; - Data[2] = zAxis.X; + Data[8] = -front.X; // glm[0][2] + Data[9] = -front.Y; // glm[1][2] + Data[10] = -front.Z; // glm[2][2] - Data[4] = xAxis.Y; - Data[5] = yAxis.Y; - Data[6] = zAxis.Y; - - Data[8] = xAxis.Z; - Data[9] = yAxis.Z; - Data[10] = zAxis.Z; + Data[12] = -(side.Dot(pos)); // glm[3][0] + Data[13] = -(newUp.Dot(pos)); // glm[3][1] + Data[14] = front.Dot(pos); // glm[3][2] return *this; } @@ -276,27 +278,47 @@ Matrix& Poly::Matrix::SetPerspective(Angle fov, float aspect, float near, float } //------------------------------------------------------------------------------ -Matrix& Poly::Matrix::SetOrthographic(float bottom, float top, float left, float right, float near, float far) +Matrix& Poly::Matrix::SetOrthographicZO(float bottom, float top, float left, float right, float near, float far) { - Data[0] = 2.0f / (right - left); - Data[1] = 0; - Data[2] = 0; - Data[3] = -(right + left) / (right - left); - - Data[4] = 0; - Data[5] = 2.0f / (top - bottom); - Data[6] = 0; - Data[7] = -(top + bottom) / (top - bottom); + SetIdentity(); + // same as orthoRH_ZO: GLM_RIGHT_HANDED && GLM_DEPTH_ZERO_TO_ONE + Data[0] = 2.0f / (right - left); // glm[0][0] + Data[1] = 0.0f; + Data[2] = 0.0f; + Data[3] = -(right + left) / (right - left); // glm[3][0] + + Data[4] = 0.0f; + Data[5] = 2.0f / (top - bottom); // glm[1][1] + Data[6] = 0.0f; + Data[7] = -(top + bottom) / (top - bottom); // glm[3][1] + + Data[8] = 0.0f; + Data[9] = 0.0f; + Data[10] = 1.0f / (far - near); // glm[2][2] + Data[11] = near / (far - near); // glm[3][2] - Data[8] = 0; - Data[9] = 0; - Data[10] = 2.0f / (far - near); - Data[11] = -(far + near) / (far - near); + return *this; +} - Data[12] = 0; - Data[13] = 0; - Data[14] = 0; - Data[15] = 1; +//------------------------------------------------------------------------------ +Matrix& Poly::Matrix::SetOrthographic(float bottom, float top, float left, float right, float near, float far) +{ + SetIdentity(); + // same as orthoRH_NO: GLM_RIGHT_HANDED && GLM_DEPTH_NEGATIVE_ONE_TO_ONE + Data[0] = 2.0f / (right - left); // glm[0][0] + Data[1] = 0.0f; + Data[2] = 0.0f; + Data[3] = -(right + left) / (right - left); // glm[3][0] + + Data[4] = 0.0f; + Data[5] = 2.0f / (top - bottom); // glm[1][1] + Data[6] = 0.0f; + Data[7] = -(top + bottom) / (top - bottom); // glm[3][1] + + Data[8] = 0.0f; + Data[9] = 0.0f; + Data[10] = 2.0f / (far - near); // glm[2][2] + Data[11] = -(far + near) / (far - near); // glm[3][2] return *this; } diff --git a/PolyEngine/Core/Src/Math/Matrix.hpp b/PolyEngine/Core/Src/Math/Matrix.hpp index 94c7fcfb..6ec22699 100644 --- a/PolyEngine/Core/Src/Math/Matrix.hpp +++ b/PolyEngine/Core/Src/Math/Matrix.hpp @@ -92,6 +92,15 @@ namespace Poly /// Reference to itself. Matrix& SetPerspective(Angle fov, float aspect, float near, float far); + /// Initializes matrix with orthographics projection in range of [0, 1] + /// Top dimension. + /// Bottom dimension. + /// Left dimension. + /// Right dimension + /// Near Z plane. + /// Far Z plane. + /// Reference to itself. + Matrix& SetOrthographicZO(float top, float bottom, float left, float right, float near, float far); /// Initializes matrix with orthographics projection /// Top dimension. diff --git a/PolyEngine/Core/Src/Math/Quaternion.cpp b/PolyEngine/Core/Src/Math/Quaternion.cpp index 368eef42..87443991 100644 --- a/PolyEngine/Core/Src/Math/Quaternion.cpp +++ b/PolyEngine/Core/Src/Math/Quaternion.cpp @@ -62,33 +62,10 @@ Vector Quaternion::operator*(const Vector& rhs) const { //------------------------------------------------------------------------------ Quaternion Poly::Quaternion::LookAt(const Vector& pos, const Vector& target, const Vector& oldUp) { - Vector forward = (target - pos).Normalize(); - Vector side = forward.Cross(oldUp).Normalize(); - Vector up = side.Cross(forward).Normalize(); - - Matrix m; - m.Data[0] = side.Data[0]; - m.Data[4] = side.Data[1]; - m.Data[8] = side.Data[2]; - m.Data[12] = 0.0; - // -------------------- - m.Data[1] = up.Data[0]; - m.Data[5] = up.Data[1]; - m.Data[9] = up.Data[2]; - m.Data[13] = 0.0; - // -------------------- - m.Data[2] = -forward.Data[0]; - m.Data[6] = -forward.Data[1]; - m.Data[10] = -forward.Data[2]; - m.Data[14] = 0.0; - // -------------------- - m.Data[3] = m.Data[7] = m.Data[11] = 0.0; - m.Data[15] = 1.0; - - Vector v, s; - Quaternion rot; - m.Decompose(v, rot, s); - return rot; + Vector v, s; + Quaternion rot; + Matrix(pos, target, oldUp).Decompose(v, rot, s); + return rot; } //------------------------------------------------------------------------------ diff --git a/PolyEngine/Engine/Res/Shaders/evsm.blur.frag.glsl b/PolyEngine/Engine/Res/Shaders/evsm.blur.frag.glsl new file mode 100644 index 00000000..9e3cdb53 --- /dev/null +++ b/PolyEngine/Engine/Res/Shaders/evsm.blur.frag.glsl @@ -0,0 +1,36 @@ +// based on: http://mynameismjp.wordpress.com/2013/09/10/shadow-maps/ +// based on: https://github.com/bartwronski/CSharpRenderer + +#version 400 core + +in vec2 vUV; + +uniform sampler2D uEVSMap; +uniform int uIsHorizontal; + +out vec4 oColor; + +uniform const float gaussianWeights[6] = float[] ( + 0.12801535629105684, + 0.12299580237376932, + 0.10908749075572069, + 0.08931328345781858, + 0.06750152753344589, + 0.047094217733717074 +); + +void main() +{ + vec4 sum = vec4(0.0); + + for (int x = -5; x < 6; ++x) + { + // unoptimal + // TDOO: bilinear filtering + sum += gaussianWeights[abs(x)] * textureLodOffset(uEVSMap, vUV, 0, + 1 == uIsHorizontal ? ivec2(x, 0) : ivec2(0, x) + ); + } + + oColor = sum; +} \ No newline at end of file diff --git a/PolyEngine/Engine/Res/Shaders/evsm.inc.glsl b/PolyEngine/Engine/Res/Shaders/evsm.inc.glsl new file mode 100644 index 00000000..ced78a83 --- /dev/null +++ b/PolyEngine/Engine/Res/Shaders/evsm.inc.glsl @@ -0,0 +1,77 @@ +// Based on: http://mynameismjp.wordpress.com/2013/09/10/shadow-maps/ + +uniform sampler2D uDirEVSMap; +uniform float uPositiveExponent; +uniform float uNegativeExponent; +uniform float uEVSMBias; +uniform float uLightBleedingReduction; + +vec2 WarpDepth(float depth) +{ + vec2 exponents = vec2(uPositiveExponent, uNegativeExponent); + // Rescale depth into [-1, 1] + depth = depth * 2.0f - 1.0f; + float pos = exp( exponents.x * depth); + float neg = -exp(-exponents.y * depth); + return vec2(pos, neg); +} + +float Linstep(float a, float b, float v) +{ + return clamp((v - a) / (b - a), 0.0, 1.0); +} + +// Reduces VSM light bleedning +float ReduceLightBleeding(float pMax, float amount) +{ + // Remove the [0, amount] tail and linearly rescale (amount, 1]. + return Linstep(amount, 1.0, pMax); +} + +float ChebyshevUpperBound(vec2 moments, float mean, float minVariance, float lightBleedingReduction) +{ + // Compute variance + float variance = moments.y - (moments.x * moments.x); + variance = max(variance, minVariance); + + // Compute probabilistic upper bound + float d = mean - moments.x; + float pMax = variance / (variance + (d * d)); + + pMax = ReduceLightBleeding(pMax, lightBleedingReduction); + + // One-tailed Chebyshev + return (mean <= moments.x ? 1.0 : pMax); +} + +float calculateShadowEVSM4(vec4 moments, float smSpaceDepth) +{ + vec2 exponents = vec2(uPositiveExponent, uNegativeExponent); + vec2 warpedDepth = WarpDepth(smSpaceDepth); + + // Derivative of warping at depth + vec2 depthScale = uEVSMBias * 0.01 * exponents * warpedDepth; + vec2 minVariance = depthScale * depthScale; + + float posContrib = ChebyshevUpperBound(moments.xz, warpedDepth.x, minVariance.x, uLightBleedingReduction); + float negContrib = ChebyshevUpperBound(moments.yw, warpedDepth.y, minVariance.y, uLightBleedingReduction); + return min(posContrib, negContrib); +} + +float calculateShadowEVSM2(vec4 moments, float smSpaceDepth) +{ + vec2 exponents = vec2(uPositiveExponent, uNegativeExponent); + vec2 warpedDepth = WarpDepth(smSpaceDepth); + + // Derivative of warping at depth + vec2 depthScale = uEVSMBias * 0.01 * exponents * warpedDepth; + vec2 minVariance = depthScale * depthScale; + + return ChebyshevUpperBound(moments.xy, warpedDepth.x, minVariance.x, uLightBleedingReduction); +} + +float calculateShadowESM(vec4 moments, float smSpaceDepth) +{ + vec2 warpedDepth = WarpDepth(smSpaceDepth); + return clamp(moments.x / warpedDepth.x, 0.0, 1.0); +} \ No newline at end of file diff --git a/PolyEngine/Engine/Res/Shaders/evsm.resolve.frag.glsl b/PolyEngine/Engine/Res/Shaders/evsm.resolve.frag.glsl new file mode 100644 index 00000000..d1d961d4 --- /dev/null +++ b/PolyEngine/Engine/Res/Shaders/evsm.resolve.frag.glsl @@ -0,0 +1,34 @@ +// Based on: http://mynameismjp.wordpress.com/2013/09/10/shadow-maps/ +// Based on: https://github.com/bartwronski/CSharpRenderer + +#version 400 core + +in vec2 vUV; + +uniform sampler2D uDepth; + +out vec4 oColor; + +#pragma include "evsm.inc.glsl" + +void main() +{ + vec4 depth = textureGather(uDepth, vUV, 0); + + vec2 warpedDepth[4]; + warpedDepth[0] = WarpDepth(depth.x); + warpedDepth[1] = WarpDepth(depth.y); + warpedDepth[2] = WarpDepth(depth.z); + warpedDepth[3] = WarpDepth(depth.w); + + vec4 outputEVSM[4]; + outputEVSM[0] = vec4(warpedDepth[0], warpedDepth[0] * warpedDepth[0]); + outputEVSM[1] = vec4(warpedDepth[1], warpedDepth[1] * warpedDepth[1]); + outputEVSM[2] = vec4(warpedDepth[2], warpedDepth[2] * warpedDepth[2]); + outputEVSM[3] = vec4(warpedDepth[3], warpedDepth[3] * warpedDepth[3]); + + vec4 finalOutput = outputEVSM[0] + outputEVSM[1] + outputEVSM[2] + outputEVSM[3]; + finalOutput *= 0.25f; + + oColor = finalOutput; +} \ No newline at end of file diff --git a/PolyEngine/Engine/Res/Shaders/lightAccumulation.frag.glsl b/PolyEngine/Engine/Res/Shaders/lightAccumulation.frag.glsl index 095ed728..f58ae512 100644 --- a/PolyEngine/Engine/Res/Shaders/lightAccumulation.frag.glsl +++ b/PolyEngine/Engine/Res/Shaders/lightAccumulation.frag.glsl @@ -12,7 +12,7 @@ in VERTEX_OUT mat3 tangentFromWorld; vec3 viewPositionInTangent; vec3 fragmentPositionInTangent; - vec4 fragmentPositionInDirLight; + vec4 fragmentPositionInDirLight; } fragment_in; @@ -43,7 +43,7 @@ layout(std430, binding = 0) readonly buffer LightBuffer layout(std430, binding = 1) readonly buffer VisibleLightIndicesBuffer { - VisibleIndex bVisibleIndicies[]; + VisibleIndex bVisibleIndicies[]; }; struct Material @@ -60,7 +60,6 @@ const uint MAX_NUM_LIGHTS = 1024; uniform sampler2D uBrdfLUT; uniform samplerCube uIrradianceMap; uniform samplerCube uPrefilterMap; -uniform sampler2D uDirShadowMap; uniform sampler2D uEmissiveMap; uniform sampler2D uAlbedoMap; @@ -69,7 +68,6 @@ uniform sampler2D uMetallicMap; uniform sampler2D uNormalMap; uniform sampler2D uAmbientOcclusionMap; - uniform float uTime; uniform Material uMaterial; @@ -122,51 +120,52 @@ float GeometrySmith(vec3 N, vec3 V, vec3 L, float roughness) vec3 fresnelSchlick(float cosTheta, vec3 F0) { - return F0 + (1.0 - F0) * pow(clamp(1.0 - cosTheta, 0.001, 1.0), 5.0); // clamp to prevent NaNs + return F0 + (1.0 - F0) * pow(clamp(1.0 - cosTheta, 0.001, 1.0), 5.0); // clamp to prevent NaNs } vec3 fresnelSchlickRoughness(float cosTheta, vec3 F0, float roughness) { - return F0 + (max(vec3(1.0 - roughness), F0) - F0) * pow(clamp(1.0 - cosTheta, 0.001, 1.0), 5.0); // clamp to prevent NaNs + return F0 + (max(vec3(1.0 - roughness), F0) - F0) * pow(clamp(1.0 - cosTheta, 0.001, 1.0), 5.0); // clamp to prevent NaNs } -float calcShadow(vec4 fragPosInDirLight, float NdotL) +#pragma include "pcf.inc.glsl" +#pragma include "evsm.inc.glsl" + +uniform int uShadowType; +// TODO: use defines +const int _ShadowType_NONE = 0; +const int _ShadowType_PCF = 1; +const int _ShadowType_EVSM2 = 2; +const int _ShadowType_EVSM4 = 3; + +float calculateShadow(vec4 fragPosInDirLight) { - // perform perspective divide - // vec3 projCoords = fragPosInDirLight.xyz / fragPosInDirLight.w; - vec3 projCoords = fragPosInDirLight.xyz; - // transform to [0,1] range - projCoords = projCoords * 0.5 + 0.5; - - if (projCoords.z > 1.0) - return 1.0; - - // get closest depth value from light's perspective (using [0,1] range fragPosLight as coords) - float closestDepth = texture(uDirShadowMap, projCoords.xy).r; - // get depth of current fragment from light's perspective - float currentDepth = projCoords.z; - // check whether current frag pos is in shadow - float bias = max(0.05 * (1.0 - NdotL), 0.005); - - float shadow = 0.0; - vec2 texelSize = 1.0 / textureSize(uDirShadowMap, 0); - for (int x = -1; x <= 1; ++x) - { - for (int y = -1; y <= 1; ++y) - { - float pcfDepth = texture(uDirShadowMap, projCoords.xy + vec2(x, y) * texelSize).r; - shadow += currentDepth - bias > pcfDepth ? 0.0 : 1.0; - } - } - shadow /= 9.0; - - - return shadow; + vec3 posInLight = fragPosInDirLight.xyz / fragPosInDirLight.w; // ClipSpace to NDC + posInLight = posInLight * 0.5 + 0.5; // NDC to [0, 1] + + if (uShadowType == _ShadowType_PCF) + { + return calculateShadowPCF(posInLight); + } + else if (uShadowType == _ShadowType_EVSM2) + { + vec4 moments = textureLod(uDirEVSMap, posInLight.xy, 0.0); + return calculateShadowEVSM2(moments, posInLight.z); + } + else if (uShadowType == _ShadowType_EVSM4) + { + vec4 moments = textureLod(uDirEVSMap, posInLight.xy, 0.0); + return calculateShadowEVSM4(moments, posInLight.z); + } + else + { + return 1.0; + } } void main() { - float debugLightCount = 0.0; + float debugLightCount = 0.0; vec4 emissive = uMaterial.Emissive * texture(uEmissiveMap, fragment_in.uv); vec4 albedo = uMaterial.Albedo * texture(uAlbedoMap, fragment_in.uv); @@ -175,10 +174,10 @@ void main() vec3 normal = normalize(texture(uNormalMap, fragment_in.uv).rgb * 2.0 - 1.0); float ao = texture(uAmbientOcclusionMap, fragment_in.uv).r; - albedo = clamp(albedo, vec4(0.0), vec4(1.0)); - roughness = clamp(roughness, 0.0, 1.0); - metallic = clamp(metallic, 0.0, 1.0); - ao = clamp(ao, 0.0, 1.0); + albedo = clamp(albedo, vec4(0.0), vec4(1.0)); + roughness = clamp(roughness, 0.0, 1.0); + metallic = clamp(metallic, 0.0, 1.0); + ao = clamp(ao, 0.0, 1.0); if (albedo.a < uMaterial.OpacityMaskThreshold) { @@ -229,7 +228,7 @@ void main() float G = GeometrySmith(N, V, L, roughness); vec3 F = fresnelSchlick(max(dot(H, V), 0.0), F0); - vec3 nominator = clamp(NDF * G * F, 0.0, 1000.0); // clamp to prevent NaN from fireflies + vec3 nominator = clamp(NDF * G * F, 0.0, 1000.0); // clamp to prevent NaN from fireflies float denominator = 4.0 * max(dot(N, V), 0.0) * max(dot(N, L), 0.0) + 0.001; // 0.001 to prevent divide by zero. vec3 specular = nominator / denominator; @@ -268,7 +267,7 @@ void main() float G = GeometrySmith(N, V, L, roughness); vec3 F = fresnelSchlick(max(dot(H, V), 0.0), F0); - vec3 nominator = min(NDF * G * F, 1000.0); // clamp to prevent NaN from fireflies + vec3 nominator = min(NDF * G * F, 1000.0); // clamp to prevent NaN from fireflies float denominator = 4 * max(dot(N, V), 0.0) * max(dot(N, L), 0.0) + 0.001; // 0.001 to prevent divide by zero. vec3 specular = nominator / denominator; @@ -285,22 +284,22 @@ void main() // scale light by NdotL float NdotL = max(dot(N, L), 0.0); - - float shadow = 1.0; - if (i == 0) - { - shadow = calcShadow(fragment_in.fragmentPositionInDirLight, NdotL); - } + + float shadow = 1.0; + if (i == 0) + { + shadow = calculateShadow(fragment_in.fragmentPositionInDirLight); + } // add to outgoing radiance Lo - Lo += shadow * (kD * albedo.rgb / PI + specular) * radiance * NdotL; // note that we already multiplied the BRDF by the Fresnel (kS) so we won't multiply by kS again - } + Lo += shadow * (kD * albedo.rgb / PI + specular) * radiance * NdotL; // note that we already multiplied the BRDF by the Fresnel (kS) so we won't multiply by kS again + } vec3 amF = fresnelSchlickRoughness(max(dot(N, V), 0.0), F0, roughness); // ambient lighting (note that the next IBL tutorial will replace // this ambient lighting with environment lighting). - vec3 amkS = amF; + vec3 amkS = amF; vec3 amkD = 1.0 - amkS; vec3 irradiance = texture(uIrradianceMap, N).rgb; vec3 diffuse = irradiance * albedo.rgb; @@ -308,10 +307,10 @@ void main() const float MAX_REFLECTION_LOD = 4.0; vec3 prefilteredColor = textureLod(uPrefilterMap, R, roughness * MAX_REFLECTION_LOD).rgb; vec2 envBRDF = texture(uBrdfLUT, vec2(max(dot(N, V), 0.0), roughness)).rg; - vec3 specular = prefilteredColor * (amF * envBRDF.x + envBRDF.y); - + vec3 specular = prefilteredColor * (amF * envBRDF.x + envBRDF.y); + vec3 ambient = (amkD * diffuse + specular) * ao; - oColor.rgb = ambient + emissive.rgb + Lo; + oColor.rgb = ambient + emissive.rgb + Lo; oNormal.rgb = (WorldFromTangent * normal) * 0.5 + 0.5; } diff --git a/PolyEngine/Engine/Res/Shaders/pcf.inc.glsl b/PolyEngine/Engine/Res/Shaders/pcf.inc.glsl new file mode 100644 index 00000000..1b0f2227 --- /dev/null +++ b/PolyEngine/Engine/Res/Shaders/pcf.inc.glsl @@ -0,0 +1,44 @@ +// based on: http://codeflow.org/entries/2013/feb/15/soft-shadow-mapping/ + +uniform sampler2D uDirShadowMap; +uniform float uShadowBias; + +float texture2DCompare(sampler2D depthTex, vec2 uv, float compare) +{ + float depth = texture(depthTex, uv).r; + return step(compare, depth); +} + +float texture2DShadowLerp(sampler2D depth, vec2 size, vec2 uv, float compare) +{ + vec2 texelSize = 1.0 / size; + vec2 f = fract(uv * size + 0.5); + vec2 centroidUV = floor(uv * size + 0.5) / size; + + float lb = texture2DCompare(depth, centroidUV + texelSize * vec2(0.0, 0.0), compare); + float lt = texture2DCompare(depth, centroidUV + texelSize * vec2(0.0, 1.0), compare); + float rb = texture2DCompare(depth, centroidUV + texelSize * vec2(1.0, 0.0), compare); + float rt = texture2DCompare(depth, centroidUV + texelSize * vec2(1.0, 1.0), compare); + float a = mix(lb, lt, f.y); + float b = mix(rb, rt, f.y); + float c = mix(a, b, f.x); + return c; +} + +float calculateShadowPCF(vec3 posInLight) +{ + float compare = posInLight.z - uShadowBias; + vec2 uv = posInLight.xy; + vec2 size = textureSize(uDirShadowMap, 0); + + float result = 0.0; + for(int x =- 1; x <= 1; x++) + { + for(int y = -1; y <= 1; y++) + { + vec2 off = vec2(x, y) / size; + result += texture2DShadowLerp(uDirShadowMap, size, uv + off, compare); + } + } + return result / 9.0; +} \ No newline at end of file diff --git a/PolyEngine/Engine/Res/Shaders/shadowMap.frag.glsl b/PolyEngine/Engine/Res/Shaders/shadowMap.frag.glsl index 862000f5..66f93852 100644 --- a/PolyEngine/Engine/Res/Shaders/shadowMap.frag.glsl +++ b/PolyEngine/Engine/Res/Shaders/shadowMap.frag.glsl @@ -1,5 +1,11 @@ #version 330 +in vec4 vPosition; + +out vec4 oColor; + void main() { - // We are not drawing anything to the screen, so nothing to be done here + float depth = vPosition.z / vPosition.w; + depth = depth * 0.5 + 0.5; + oColor = vec4(depth, 0.0, 0.0, 0.0); } diff --git a/PolyEngine/Engine/Res/Shaders/shadowMap.vert.glsl b/PolyEngine/Engine/Res/Shaders/shadowMap.vert.glsl index 8e0f5532..4bb4bca5 100644 --- a/PolyEngine/Engine/Res/Shaders/shadowMap.vert.glsl +++ b/PolyEngine/Engine/Res/Shaders/shadowMap.vert.glsl @@ -1,11 +1,12 @@ #version 330 layout(location = 0) in vec4 aPos; -// layout(location = 1) in vec2 aTexCoord; -// layout(location = 2) in vec3 aNormal; uniform mat4 uClipFromModel; +out vec4 vPosition; + void main() { - gl_Position = uClipFromModel * aPos; + vPosition = uClipFromModel * aPos; + gl_Position = vPosition; } \ No newline at end of file diff --git a/PolyEngine/Engine/Src/Debugging/DebugDrawSystem.cpp b/PolyEngine/Engine/Src/Debugging/DebugDrawSystem.cpp index 4b893a9b..c57ad65d 100644 --- a/PolyEngine/Engine/Src/Debugging/DebugDrawSystem.cpp +++ b/PolyEngine/Engine/Src/Debugging/DebugDrawSystem.cpp @@ -48,17 +48,17 @@ namespace Util } } -void DebugDrawSystem::DebugRenderingUpdatePhase(Scene* world) +void DebugDrawSystem::DebugRenderingUpdatePhase(Scene* scene) { gDebugConfig.DebugRender = false; - for (auto& kv : world->GetWorldComponent()->GetViewports()) + for (auto& kv : scene->GetWorldComponent()->GetViewports()) { CameraComponent* cameraCmp = kv.second.GetCamera(); if (cameraCmp->GetRenderingMode() == eRenderingModeType::IMMEDIATE_DEBUG) gDebugConfig.DebugRender = true; } - auto debugDrawWorldCmp = world->GetWorldComponent(); + auto debugDrawWorldCmp = scene->GetWorldComponent(); if (!gDebugConfig.DebugRender) { debugDrawWorldCmp->Clear(); @@ -85,8 +85,8 @@ void DebugDrawSystem::DebugRenderingUpdatePhase(Scene* world) if (!entToUse) { - entToUse = DeferredTaskSystem::SpawnEntityImmediate(world); - DeferredTaskSystem::AddComponentImmediate(world, entToUse, Vector2i::ZERO, "Fonts/Raleway/Raleway-Regular.ttf", eResourceSource::ENGINE, 0); + entToUse = DeferredTaskSystem::SpawnEntityImmediate(scene); + DeferredTaskSystem::AddComponentImmediate(scene, entToUse, Vector2i::ZERO, "Fonts/Raleway/Raleway-Regular.ttf", eResourceSource::ENGINE, 0); debugDrawWorldCmp->Text2DEntityPool.PushBack(entToUse); ++usedTextEntites; } @@ -126,7 +126,7 @@ void DebugDrawSystem::DebugRenderingUpdatePhase(Scene* world) // iterate RenderMode::_COUNT times to create shapes defining debug primitives for(int renderMode = static_cast(RenderMode::LINE); renderMode < static_cast(RenderMode::_COUNT); ++renderMode) { - for(auto componentsTuple : world->IterateComponents()) + for(auto componentsTuple : scene->IterateComponents()) { const auto ddrawCmp = std::get(componentsTuple); const auto meshCmp = std::get(componentsTuple); @@ -152,13 +152,13 @@ void DebugDrawSystem::DebugRenderingUpdatePhase(Scene* world) minVector -= boundingOffset; maxVector += boundingOffset; - DrawBox(world, minVector, maxVector, Color::GREEN); + DrawBox(scene, minVector, maxVector, Color::GREEN); } } // @fixme // move iteration over RigidBody2DComponent to different debug-system (f.ex. PhysicsDebugDrawSystem) - for(auto componentsTuple : world->IterateComponents()) + for(auto componentsTuple : scene->IterateComponents()) { const auto rigidbodyCmp = std::get(componentsTuple); const auto ddrawCmp = std::get(componentsTuple); @@ -176,11 +176,11 @@ void DebugDrawSystem::DebugRenderingUpdatePhase(Scene* world) if(velocity.LengthSquared() == 0.0f) continue; - DrawArrow(world, localTrans, velocity, Color::RED); + DrawArrow(scene, localTrans, velocity, Color::RED); } - for(auto componentsTuple : world->IterateComponents()) + for(auto componentsTuple : scene->IterateComponents()) { const auto dirLightCmp = std::get(componentsTuple); const auto ddrawCmp = std::get(componentsTuple); @@ -194,26 +194,26 @@ void DebugDrawSystem::DebugRenderingUpdatePhase(Scene* world) auto localTrans = transform.GetLocalTranslation(); //auto lightDirection = Vector(1.0f, 1.0f, 1.0f); - auto directionRotation = MovementSystem::GetGlobalForward(transform); + auto directionRotation = transform.GetGlobalForward(); auto lightMagnitude = dirLightCmp->GetIntensity() * 2.0f; - DrawArrow(world, localTrans, directionRotation*lightMagnitude, Color::WHITE); + DrawArrow(scene, localTrans, directionRotation*lightMagnitude, Color::WHITE); } } } -void Poly::DebugDrawSystem::DrawLine(Scene* world, const Vector& begin, const Vector& end, const Color& color) +void Poly::DebugDrawSystem::DrawLine(Scene* scene, const Vector& begin, const Vector& end, const Color& color) { if (!gDebugConfig.DebugRender) return; Vector3f meshvecBegin(begin.X, begin.Y, begin.Z), meshvecEnd(end.X, end.Y, end.Z); - auto debugLinesComponent = world->GetWorldComponent(); + auto debugLinesComponent = scene->GetWorldComponent(); debugLinesComponent->DebugLines.PushBack(DebugDrawStateWorldComponent::DebugLine{ meshvecBegin, meshvecEnd }); debugLinesComponent->DebugLinesColors.PushBack(DebugDrawStateWorldComponent::DebugLineColor{ color, color }); } -void Poly::DebugDrawSystem::DrawBox(Scene* world, const Vector& mins, const Vector& maxs, const Color& color) +void Poly::DebugDrawSystem::DrawBox(Scene* scene, const Vector& mins, const Vector& maxs, const Color& color) { if (!gDebugConfig.DebugRender) return; @@ -238,79 +238,133 @@ void Poly::DebugDrawSystem::DrawBox(Scene* world, const Vector& mins, const Vect // 7: 0 1 1 // bottom - DrawLine(world, points[0], points[4], color); - DrawLine(world, points[0], points[1], color); - DrawLine(world, points[5], points[4], color); - DrawLine(world, points[5], points[1], color); + DrawLine(scene, points[0], points[4], color); + DrawLine(scene, points[0], points[1], color); + DrawLine(scene, points[5], points[4], color); + DrawLine(scene, points[5], points[1], color); // top - DrawLine(world, points[3], points[7], color); - DrawLine(world, points[3], points[2], color); - DrawLine(world, points[6], points[7], color); - DrawLine(world, points[6], points[2], color); + DrawLine(scene, points[3], points[7], color); + DrawLine(scene, points[3], points[2], color); + DrawLine(scene, points[6], points[7], color); + DrawLine(scene, points[6], points[2], color); // top-bottom lines - DrawLine(world, points[0], points[3], color); - DrawLine(world, points[1], points[2], color); - DrawLine(world, points[4], points[7], color); - DrawLine(world, points[5], points[6], color); + DrawLine(scene, points[0], points[3], color); + DrawLine(scene, points[1], points[2], color); + DrawLine(scene, points[4], points[7], color); + DrawLine(scene, points[5], points[6], color); } -void Poly::DebugDrawSystem::DrawBox(Scene * world, const AABox & box, const Color & color) +void DebugDrawSystem::DrawBox(Scene* scene, const Vector& mins, const Vector& maxs, const Matrix& worldFromSpace, const Color& color) { - DrawBox(world, box.GetMin(), box.GetMax(), color); -} + if (!gDebugConfig.DebugRender) + return; -void Poly::DebugDrawSystem::DrawFrustum(Scene* world, const Frustum& frust, const Vector& pos, const Quaternion& rot, const Color& color, bool withNormals) -{ - const Quaternion rY = Quaternion(Vector::UNIT_Y, (frust.GetFov() / 2) * frust.GetAspect()); - const Quaternion rX = Quaternion(Vector::UNIT_X, (frust.GetFov() / 2)); + std::array points; + std::array minmaxVector = { { mins, maxs } }; - const Vector origin = pos; - const Vector lookDir = rot * -Vector::UNIT_Z; + for (unsigned int i = 0; i < points.size(); ++i) + { + points[i].X = minmaxVector[(i ^ (i >> 1)) & 1].X; + points[i].Y = minmaxVector[(i >> 1) & 1].Y; + points[i].Z = minmaxVector[(i >> 2) & 1].Z; + } + // i: X Y Z + // 0: 0 0 0 + // 1: 1 0 0 + // 2: 1 1 0 + // 3: 0 1 0 + // 4: 0 0 1 + // 5: 1 0 1 + // 6: 1 1 1 + // 7: 0 1 1 - std::array v; - v[0] = rY * rX * lookDir; - v[1] = rY * rX.GetConjugated() * lookDir; - v[2] = rY.GetConjugated() * rX.GetConjugated() * lookDir; - v[3] = rY.GetConjugated() * rX * lookDir; + // bottom + DebugDrawSystem::DrawLine(scene, worldFromSpace * points[0], worldFromSpace * points[4], color); + DebugDrawSystem::DrawLine(scene, worldFromSpace * points[0], worldFromSpace * points[1], color); + DebugDrawSystem::DrawLine(scene, worldFromSpace * points[5], worldFromSpace * points[4], color); + DebugDrawSystem::DrawLine(scene, worldFromSpace * points[5], worldFromSpace * points[1], color); - const float cosHalfFovW = Cos(frust.GetFov() / 2 * frust.GetAspect()); - const float cosHalfFovH = Cos(frust.GetFov() / 2); + // top + DebugDrawSystem::DrawLine(scene, worldFromSpace * points[3], worldFromSpace * points[2], color); + DebugDrawSystem::DrawLine(scene, worldFromSpace * points[3], worldFromSpace * points[7], color); + DebugDrawSystem::DrawLine(scene, worldFromSpace * points[6], worldFromSpace * points[7], color); + DebugDrawSystem::DrawLine(scene, worldFromSpace * points[6], worldFromSpace * points[2], color); - const float nDist = frust.GetZNear() / (cosHalfFovW * cosHalfFovH); - std::array n; - for (size_t i = 0; i < 4; ++i) - n[i] = origin + v[i] * nDist; + // top-bottom lines + DebugDrawSystem::DrawLine(scene, worldFromSpace * points[0], worldFromSpace * points[3], color); + DebugDrawSystem::DrawLine(scene, worldFromSpace * points[1], worldFromSpace * points[2], color); + DebugDrawSystem::DrawLine(scene, worldFromSpace * points[4], worldFromSpace * points[7], color); + DebugDrawSystem::DrawLine(scene, worldFromSpace * points[5], worldFromSpace * points[6], color); +} - const float fDist = frust.GetZFar() / (cosHalfFovW * cosHalfFovH); - std::array f; - for (size_t i = 0; i < 4; ++i) - f[i] = origin + v[i] * fDist; +void Poly::DebugDrawSystem::DrawBox(Scene* scene, const AABox & box, const Color & color) +{ + DrawBox(scene, box.GetMin(), box.GetMax(), color); +} - for (size_t i = 0; i < 4; ++i) +void Poly::DebugDrawSystem::DrawFrustum(Scene* scene, const Frustum& frustum, const Matrix& viewFromWorld, const Color color) +{ + Matrix clipFromView; + clipFromView.SetPerspective(frustum.GetFov(), frustum.GetAspect(), frustum.GetZNear(), frustum.GetZFar()); + Matrix clipFromWorld = clipFromView * viewFromWorld; + + // Transform frustum corners to DirLightSpace + Dynarray cornersInNDC{ + Vector(-1.0f, 1.0f, -1.0f), // back left top + Vector( 1.0f, 1.0f, -1.0f), // back right top + Vector(-1.0f, -1.0f, -1.0f), // back left bot + Vector( 1.0f, -1.0f, -1.0f), // back right bot + Vector(-1.0f, 1.0f, 1.0f), // front left top + Vector( 1.0f, 1.0f, 1.0f), // front right top + Vector(-1.0f, -1.0f, 1.0f), // front left bot + Vector( 1.0f, -1.0f, 1.0f) // front right bot + }; + + // Transform frustum corners from NDC to World + // could be done in one iteration but we need to do perspective division by W + Matrix worldFromClip = clipFromWorld.GetInversed(); + Dynarray cornersInWS; + for (Vector posInClip : cornersInNDC) { - size_t nextI = (i + 1) % 4; + Vector posInWS = worldFromClip * posInClip; + posInWS.X /= posInWS.W; + posInWS.Y /= posInWS.W; + posInWS.Z /= posInWS.W; + cornersInWS.PushBack(posInWS); + } - DrawLine(world, origin, n[i], color); - DrawLine(world, n[i], f[i], color); + DrawFrustumPoints(scene, cornersInWS, color); +} - DrawLine(world, n[i], n[nextI], color); - DrawLine(world, f[i], f[nextI], color); - } +void Poly::DebugDrawSystem::DrawFrustumPoints(Scene* scene, const Dynarray& cornersInWorld, const Color color) +{ + // Vertives should be in order: + // back left top + // back right top + // back left bot + // back right bot + // front left top + // front right top + // front left bot + // front right bot + + ASSERTE(cornersInWorld.GetSize() == 8, "Wrong number of frustum corners to draw"); + + for (size_t i = 0; i < 4; ++i) + DebugDrawSystem::DrawLine(scene, cornersInWorld[i], cornersInWorld[i + 4], color); - if (withNormals) + for (size_t i = 0; i < 2; ++i) { - DrawArrow(world, (n[0] + n[1] + f[0] + f[1]) / 4, rot * frust.GetPlanes()[eFrustumPlane::LEFT].GetNormal(), color); - DrawArrow(world, (n[1] + n[2] + f[1] + f[2]) / 4, rot * frust.GetPlanes()[eFrustumPlane::UP].GetNormal(), color); - DrawArrow(world, (n[2] + n[3] + f[2] + f[3]) / 4, rot * frust.GetPlanes()[eFrustumPlane::RIGHT].GetNormal(), color); - DrawArrow(world, (n[3] + n[0] + f[3] + f[0]) / 4, rot * frust.GetPlanes()[eFrustumPlane::DOWN].GetNormal(), color); - DrawArrow(world, origin + lookDir * frust.GetZNear(), rot * frust.GetPlanes()[eFrustumPlane::ZNEAR].GetNormal(), color); - DrawArrow(world, origin + lookDir * frust.GetZFar(), rot * frust.GetPlanes()[eFrustumPlane::ZFAR].GetNormal(), color); + DebugDrawSystem::DrawLine(scene, cornersInWorld[0 + i * 4], cornersInWorld[1 + i * 4], color); + DebugDrawSystem::DrawLine(scene, cornersInWorld[2 + i * 4], cornersInWorld[3 + i * 4], color); + DebugDrawSystem::DrawLine(scene, cornersInWorld[0 + i * 4], cornersInWorld[2 + i * 4], color); + DebugDrawSystem::DrawLine(scene, cornersInWorld[1 + i * 4], cornersInWorld[3 + i * 4], color); } } -void Poly::DebugDrawSystem::DrawCircle(Scene* world, const Vector& position, float radius, Vector orientation, const Color& color) +void Poly::DebugDrawSystem::DrawCircle(Scene* scene, const Vector& position, float radius, Vector orientation, const Color& color) { if (!gDebugConfig.DebugRender) return; @@ -331,23 +385,23 @@ void Poly::DebugDrawSystem::DrawCircle(Scene* world, const Vector& position, flo { Vector previousSegmentPoint = right; right = rotAroundCircle*right; - DrawLine(world, position + previousSegmentPoint, position + right, color); + DrawLine(scene, position + previousSegmentPoint, position + right, color); } - DrawArrow(world, position, right, color); + DrawArrow(scene, position, right, color); } -void Poly::DebugDrawSystem::DrawSphere(Scene* world, const Vector& position, float radius, const Color& color) +void Poly::DebugDrawSystem::DrawSphere(Scene* scene, const Vector& position, float radius, const Color& color) { if (!gDebugConfig.DebugRender) return; - DrawCircle(world, position, radius, Vector(1.0f, 0.0f, 0.0f), color); - DrawCircle(world, position, radius, Vector(0.0f, 1.0f, 0.0f), color); - DrawCircle(world, position, radius, Vector(0.0f, 0.0f, 1.0f), color); + DrawCircle(scene, position, radius, Vector(1.0f, 0.0f, 0.0f), color); + DrawCircle(scene, position, radius, Vector(0.0f, 1.0f, 0.0f), color); + DrawCircle(scene, position, radius, Vector(0.0f, 0.0f, 1.0f), color); } -void Poly::DebugDrawSystem::DrawArrow(Scene* world, Vector position, Vector directionVector, const Color& color) +void Poly::DebugDrawSystem::DrawArrow(Scene* scene, Vector position, Vector directionVector, const Color& color) { if (!gDebugConfig.DebugRender) return; @@ -357,7 +411,7 @@ void Poly::DebugDrawSystem::DrawArrow(Scene* world, Vector position, Vector dire // body line auto arrowTip = position + directionVector*arrowLengthScale; - DrawLine(world, position, arrowTip, color); + DrawLine(scene, position, arrowTip, color); directionVector.Normalize(); // arrowhead @@ -381,17 +435,17 @@ void Poly::DebugDrawSystem::DrawArrow(Scene* world, Vector position, Vector dire for (float degrees = 0.0f; degrees < 360.0f; degrees += rotationStep.AsDegrees()) { - DrawLine(world, arrowTip, arrowTip + perpendicularVector, color); - DrawLine(world, arrowTip + perpendicularVector, arrowTip + directionVector*arrowheadScale, color); + DrawLine(scene, arrowTip, arrowTip + perpendicularVector, color); + DrawLine(scene, arrowTip + perpendicularVector, arrowTip + directionVector*arrowheadScale, color); perpendicularVector = rotAroundDirectionVector* perpendicularVector; } } -void Poly::DebugDrawSystem::DrawText2D(Scene* world, const Vector2i& screenPosition, String text, size_t fontSize, const Color& color) +void Poly::DebugDrawSystem::DrawText2D(Scene* scene, const Vector2i& screenPosition, String text, size_t fontSize, const Color& color) { if (!gDebugConfig.DebugRender) return; - auto debugLinesComponent = world->GetWorldComponent(); + auto debugLinesComponent = scene->GetWorldComponent(); debugLinesComponent->DebugTexts2D.PushBack({ std::move(text), screenPosition , fontSize, color }); } diff --git a/PolyEngine/Engine/Src/Debugging/DebugDrawSystem.hpp b/PolyEngine/Engine/Src/Debugging/DebugDrawSystem.hpp index f4e15a77..ff481c00 100644 --- a/PolyEngine/Engine/Src/Debugging/DebugDrawSystem.hpp +++ b/PolyEngine/Engine/Src/Debugging/DebugDrawSystem.hpp @@ -16,16 +16,17 @@ namespace Poly /// Emitters of elementary shapes void ENGINE_DLLEXPORT DrawLine(Scene* world, const Vector& begin, const Vector& end, const Color& color = Color::WHITE); void ENGINE_DLLEXPORT DrawBox(Scene* world, const Vector& mins, const Vector& maxs, const Color& color = Color::WHITE); + void ENGINE_DLLEXPORT DrawBox(Scene* world, const Vector& mins, const Vector& maxs, const Matrix& worldFromSpace, const Color& color = Color::WHITE); void ENGINE_DLLEXPORT DrawBox(Scene* world, const AABox& box, const Color& color = Color::WHITE); - void ENGINE_DLLEXPORT DrawFrustum(Scene* world, const Frustum& frust, - const Vector& pos = Vector::ZERO, const Quaternion& rot = Quaternion::IDENTITY, const Color& color = Color::WHITE, bool withNormals = false); + + void ENGINE_DLLEXPORT DrawFrustum(Scene* scene, const Frustum& frustum, const Matrix& viewFromWorld = Matrix(), Color color = Color::WHITE); + void ENGINE_DLLEXPORT DrawFrustumPoints(Scene* scene, const Dynarray& cornersInWorld, const Color color = Color::WHITE); /// Think of orientation as of normal vector void ENGINE_DLLEXPORT DrawCircle(Scene* world, const Vector& position, float radius, Vector orientation, const Color& color = Color::WHITE); void ENGINE_DLLEXPORT DrawSphere(Scene* world, const Vector& position, float radius, const Color& color = Color::WHITE); void ENGINE_DLLEXPORT DrawArrow(Scene* world, Vector position, Vector directionVector, const Color& color = Color::WHITE); - void ENGINE_DLLEXPORT DrawText2D(Scene* world, const Vector2i& screenPosition, String text, size_t fontSize = 16, const Color& color = Color::WHITE); } } \ No newline at end of file diff --git a/PolyEngine/Engine/Src/ECS/ComponentBase.hpp b/PolyEngine/Engine/Src/ECS/ComponentBase.hpp index e90509e1..5da5b5c4 100644 --- a/PolyEngine/Engine/Src/ECS/ComponentBase.hpp +++ b/PolyEngine/Engine/Src/ECS/ComponentBase.hpp @@ -65,7 +65,7 @@ namespace Poly { const EnumFlags& GetFlags() { return Flags; } bool CheckFlags(const EnumFlags& rhs) const { return (Flags & rhs) == rhs; } - virtual Optional GetBoundingBox(eEntityBoundingChannel channel) { return {}; } + virtual Optional GetBoundingBox(eEntityBoundingChannel channel) const { return {}; } private: Entity* Owner = nullptr; diff --git a/PolyEngine/Engine/Src/ECS/Entity.cpp b/PolyEngine/Engine/Src/ECS/Entity.cpp index 12733477..7c4b899b 100644 --- a/PolyEngine/Engine/Src/ECS/Entity.cpp +++ b/PolyEngine/Engine/Src/ECS/Entity.cpp @@ -122,7 +122,7 @@ const AABox& Poly::Entity::GetLocalBoundingBox(eEntityBoundingChannel channel) c { if (BBoxDirty[channel]) { - LocalBBox[channel].SetPosition(Vector::ZERO); + LocalBBox[channel].SetMin(Vector::ZERO); LocalBBox[channel].SetSize(Vector::ZERO); // Update bounding box by children boxes diff --git a/PolyEngine/Engine/Src/ECS/EntityTransform.hpp b/PolyEngine/Engine/Src/ECS/EntityTransform.hpp index c7774b76..06be667d 100644 --- a/PolyEngine/Engine/Src/ECS/EntityTransform.hpp +++ b/PolyEngine/Engine/Src/ECS/EntityTransform.hpp @@ -49,6 +49,13 @@ namespace Poly const Matrix& GetParentFromModel() const; const Matrix& GetWorldFromModel() const; void SetParentFromModel(const Matrix& parentFromModel); + + Vector GetLocalForward() const { return GetLocalRotation() * -Vector::UNIT_Z; } + Vector GetLocalRight() const { return GetLocalRotation() * Vector::UNIT_X; } + Vector GetLocalUp() const { return GetLocalRotation() * Vector::UNIT_Y; } + Vector GetGlobalForward() const { return GetGlobalRotation() * -Vector::UNIT_Z; } + Vector GetGlobalRight() const { return GetGlobalRotation() * Vector::UNIT_X; } + Vector GetGlobalUp() const { return GetGlobalRotation() * Vector::UNIT_Y; } private: void UpdateParentTransform(); diff --git a/PolyEngine/Engine/Src/Engine.cpp b/PolyEngine/Engine/Src/Engine.cpp index 7964b8e7..669349fe 100644 --- a/PolyEngine/Engine/Src/Engine.cpp +++ b/PolyEngine/Engine/Src/Engine.cpp @@ -169,7 +169,6 @@ void Poly::Engine::LoadDefaultScene() DeferredTaskSystem::AddWorldComponentImmediate(GetActiveScene(), physicsConfig); Physics3DConfig physics3DConfig; DeferredTaskSystem::AddWorldComponentImmediate(GetActiveScene(), physics3DConfig); - DeferredTaskSystem::AddWorldComponentImmediate(GetActiveScene(), Color(1, 1, 1, 1), 0.2f); DeferredTaskSystem::AddWorldComponentImmediate(GetActiveScene()); } diff --git a/PolyEngine/Engine/Src/Movement/MovementSystem.cpp b/PolyEngine/Engine/Src/Movement/MovementSystem.cpp index 8e603e22..36304d1c 100644 --- a/PolyEngine/Engine/Src/Movement/MovementSystem.cpp +++ b/PolyEngine/Engine/Src/Movement/MovementSystem.cpp @@ -66,34 +66,4 @@ void MovementSystem::MovementUpdatePhase(Scene* world) } } } -} - -Vector MovementSystem::GetLocalForward(const EntityTransform& transform) -{ - return transform.GetLocalRotation() * -Vector::UNIT_Z; -} - -Vector MovementSystem::GetLocalRight(const EntityTransform& transform) -{ - return transform.GetLocalRotation() * Vector::UNIT_X; -} - -Vector MovementSystem::GetLocalUp(const EntityTransform& transform) -{ - return transform.GetLocalRotation() * Vector::UNIT_Y; -} - -Vector MovementSystem::GetGlobalForward(const EntityTransform& transform) -{ - return transform.GetGlobalRotation() * -Vector::UNIT_Z; -} - -Vector MovementSystem::GetGlobalRight(const EntityTransform& transform) -{ - return transform.GetGlobalRotation() * Vector::UNIT_X; -} - -Vector MovementSystem::GetGlobalUp(const EntityTransform& transform) -{ - return transform.GetGlobalRotation() * Vector::UNIT_Y; -} +} \ No newline at end of file diff --git a/PolyEngine/Engine/Src/Rendering/Camera/CameraComponent.cpp b/PolyEngine/Engine/Src/Rendering/Camera/CameraComponent.cpp index 3802a8a5..a460549a 100644 --- a/PolyEngine/Engine/Src/Rendering/Camera/CameraComponent.cpp +++ b/PolyEngine/Engine/Src/Rendering/Camera/CameraComponent.cpp @@ -7,32 +7,36 @@ using namespace Poly; RTTI_DEFINE_COMPONENT(::Poly::CameraComponent) CameraComponent::CameraComponent(Angle fov, float zNear, float zFar) - : IsPerspective(true), Fov(fov), Near(zNear), Far(zFar), RenderingMode(eRenderingModeType::LIT), CameraFrustum({ fov, 1.f, zNear, zFar }) + : IsPerspective(true), Fov(fov), Near(zNear), Far(zFar), + RenderingMode(eRenderingModeType::LIT), CameraFrustum(fov, 1.f, zNear, zFar ) { } CameraComponent::CameraComponent(float top, float bottom, float left, float right, float zNear, float zFar) - : IsPerspective(false), Top(top), Bottom(bottom), Left(left), Right(right), Near(zNear), Far(zFar), RenderingMode(eRenderingModeType::LIT) + : IsPerspective(false), Top(top), Bottom(bottom), Left(left), Right(right), Near(zNear), Far(zFar), + RenderingMode(eRenderingModeType::LIT), CameraFrustum(45_deg, 1.f, zNear, zFar ) { - ASSERTE(false, "Orthographics projection is not yet implemented"); + ASSERTE(false, "Orthographic projection is not yet implemented"); } void Poly::CameraComponent::UpdateProjection() { if (IsPerspective) { - ScreenFromView.SetPerspective(Fov, Aspect, Near, Far); - CameraFrustum.Value().Update(Fov, Aspect, Near, Far); + ClipFromView.SetPerspective(Fov, Aspect, Near, Far); + CameraFrustum.Update(Fov, Aspect, Near, Far); } else - ScreenFromView.SetOrthographic(Top, Bottom, Left, Right, Near, Far); + { + ClipFromView.SetOrthographic(Top, Bottom, Left, Right, Near, Far); + } } bool Poly::CameraComponent::IsVisibleToCamera(const Entity* ent) const { if (IsPerspective) { - const Frustum::eObjectLocation loc = CameraFrustum.Value().GetObjectLocation( + const Frustum::eObjectLocation loc = CameraFrustum.GetObjectLocation( ent->GetGlobalBoundingBox(eEntityBoundingChannel::RENDERING), GetViewFromWorld()); return loc != Frustum::eObjectLocation::OUTSIDE; } diff --git a/PolyEngine/Engine/Src/Rendering/Camera/CameraComponent.hpp b/PolyEngine/Engine/Src/Rendering/Camera/CameraComponent.hpp index d1649eec..dee1e192 100644 --- a/PolyEngine/Engine/Src/Rendering/Camera/CameraComponent.hpp +++ b/PolyEngine/Engine/Src/Rendering/Camera/CameraComponent.hpp @@ -27,9 +27,9 @@ namespace Poly { CameraComponent(Angle fov, float zNear, float zFar); CameraComponent(float top, float bottom, float left, float right, float zNear, float zFar); - const Matrix& GetClipFromView() const { return ScreenFromView; } + const Matrix& GetClipFromView() const { return ClipFromView; } const Matrix& GetViewFromWorld() const { return ViewFromWorld; } - const Matrix& GetClipFromWorld() const { return ScreenFromWorld; } + const Matrix& GetClipFromWorld() const { return ClipFromWorld; } const float GetClippingPlaneNear() const { return Near; } const float GetClippingPlaneFar() const { return Far; } @@ -43,14 +43,16 @@ namespace Poly { void SetForcedRatio(bool value) { IsForcedRatio = value; } eRenderingModeType GetRenderingMode() const { return RenderingMode; } void SetRenderingMode(eRenderingModeType value) { RenderingMode = value; } + Frustum GetCameraFrustum() const { return CameraFrustum; }; void UpdateProjection(); bool IsVisibleToCamera(const Entity* ent) const; + private: - Matrix ScreenFromView; + Matrix ClipFromView; Matrix ViewFromWorld; - Matrix ScreenFromWorld; + Matrix ClipFromWorld; bool IsPerspective = false; @@ -74,7 +76,7 @@ namespace Poly { // RenderingMode eRenderingModeType RenderingMode; - Optional CameraFrustum; + Frustum CameraFrustum; }; REGISTER_COMPONENT(ComponentsIDGroup, CameraComponent) diff --git a/PolyEngine/Engine/Src/Rendering/Camera/CameraSystem.cpp b/PolyEngine/Engine/Src/Rendering/Camera/CameraSystem.cpp index f340f786..3e01a1a7 100644 --- a/PolyEngine/Engine/Src/Rendering/Camera/CameraSystem.cpp +++ b/PolyEngine/Engine/Src/Rendering/Camera/CameraSystem.cpp @@ -26,8 +26,7 @@ void Poly::CameraSystem::CameraUpdatePhase(Scene* world) } cameraCmp->ViewFromWorld = transform.GetWorldFromModel().GetInversed(); - cameraCmp->ScreenFromWorld = cameraCmp->ScreenFromView * cameraCmp->ViewFromWorld; - + cameraCmp->ClipFromWorld = cameraCmp->ClipFromView * cameraCmp->ViewFromWorld; InputWorldComponent* inputCmp = world->GetWorldComponent(); if (inputCmp->IsPressed(eKey::F5)) diff --git a/PolyEngine/Engine/Src/Rendering/Lighting/LightSourceComponent.hpp b/PolyEngine/Engine/Src/Rendering/Lighting/LightSourceComponent.hpp index cb99fcf6..bd50ac86 100644 --- a/PolyEngine/Engine/Src/Rendering/Lighting/LightSourceComponent.hpp +++ b/PolyEngine/Engine/Src/Rendering/Lighting/LightSourceComponent.hpp @@ -1,11 +1,12 @@ #pragma once #include -#include +#include "ECS/ComponentBase.hpp" +#include "Math/Frustum.hpp" +#include "Math/Matrix.hpp" namespace Poly { - class ENGINE_DLLEXPORT AmbientLightWorldComponent : public ComponentBase { public: @@ -34,6 +35,7 @@ namespace Poly const Color& GetColor() const { return LightColor; } float GetIntensity() const { return Intensity; } + private: Color LightColor; float Intensity = 1.0f; @@ -67,7 +69,6 @@ namespace Poly RTTI_DECLARE_COMPONENT(::Poly::SpotLightComponent) { NO_RTTI_PROPERTY(); } SpotLightComponent(const Color& color = Color::WHITE, float intensity = 1.0f, float range = 10.0f, float cutoff = 12.0f, float outerCutOff = 17.0f); - const Color& GetColor() const { return LightColor; } float GetIntensity() const { return Intensity; } void SetRange(float value) { Range = value; } diff --git a/PolyEngine/Engine/Src/Rendering/MeshRenderingComponent.cpp b/PolyEngine/Engine/Src/Rendering/MeshRenderingComponent.cpp index 575e54e5..87efd285 100644 --- a/PolyEngine/Engine/Src/Rendering/MeshRenderingComponent.cpp +++ b/PolyEngine/Engine/Src/Rendering/MeshRenderingComponent.cpp @@ -11,7 +11,9 @@ RTTI_DEFINE_COMPONENT(::Poly::MeshRenderingComponent) MeshRenderingComponent::MeshRenderingComponent(const String& meshPath, eResourceSource source) { Mesh = ResourceManager::Load(meshPath, source); - if (Mesh) { + + if (Mesh) + { size_t materialsNum = GetMesh()->GetSubMeshes().GetSize(); Materials.Resize(materialsNum); for (size_t i = 0; i < materialsNum; ++i) @@ -27,7 +29,7 @@ Poly::MeshRenderingComponent::~MeshRenderingComponent() ResourceManager::Release(Mesh); } -Optional Poly::MeshRenderingComponent::GetBoundingBox(eEntityBoundingChannel channel) +Optional Poly::MeshRenderingComponent::GetBoundingBox(eEntityBoundingChannel channel) const { if (channel != eEntityBoundingChannel::RENDERING || !Mesh) return {}; diff --git a/PolyEngine/Engine/Src/Rendering/MeshRenderingComponent.hpp b/PolyEngine/Engine/Src/Rendering/MeshRenderingComponent.hpp index 3c7a3b98..f0925c85 100644 --- a/PolyEngine/Engine/Src/Rendering/MeshRenderingComponent.hpp +++ b/PolyEngine/Engine/Src/Rendering/MeshRenderingComponent.hpp @@ -59,8 +59,8 @@ namespace Poly { void SetShadingModel(eShadingMode value) { ShadingMode = value; } void SetBlendingMode(eBlendingMode value) { BlendingMode = value; } + Optional GetBoundingBox(eEntityBoundingChannel channel) const override; - Optional GetBoundingBox(eEntityBoundingChannel channel) override; private: MeshResource* Mesh = nullptr; Dynarray Materials; diff --git a/PolyEngine/Engine/Src/Rendering/RenderingSettingsComponent.cpp b/PolyEngine/Engine/Src/Rendering/RenderingSettingsComponent.cpp new file mode 100644 index 00000000..6c1154cb --- /dev/null +++ b/PolyEngine/Engine/Src/Rendering/RenderingSettingsComponent.cpp @@ -0,0 +1,7 @@ +#include + +#include + +using namespace Poly; + +RTTI_DEFINE_COMPONENT(::Poly::RenderingSettingsComponent) \ No newline at end of file diff --git a/PolyEngine/Engine/Src/Rendering/RenderingSettingsComponent.hpp b/PolyEngine/Engine/Src/Rendering/RenderingSettingsComponent.hpp new file mode 100644 index 00000000..7290e625 --- /dev/null +++ b/PolyEngine/Engine/Src/Rendering/RenderingSettingsComponent.hpp @@ -0,0 +1,47 @@ +#pragma once + +#include +#include +#include + +namespace Poly { + + enum class eShadowType + { + NONE = 0, + PCF, + EVSM2, + EVSM4, + _COUNT + }; + + enum class eShadowMapSize + { + SIZE_512 = 0, + SIZE_1024, + SIZE_2048, + SIZE_4096, + _COUNT + }; + + class ENGINE_DLLEXPORT RenderingSettingsComponent : public ComponentBase + { + public: + RTTI_DECLARE_COMPONENT(::Poly::RenderingSettingsComponent) { NO_RTTI_PROPERTY(); } + + eShadowType ShadowType = eShadowType::EVSM4; + eShadowMapSize ShadowMapSize = eShadowMapSize::SIZE_4096; + + float EVSMPositiveExponent = 40.0f; + float EVSMNegativeExponent = 10.0f; + float EVSMBias = 0.01f; + float EVSMLghtBleedingReduction = 0.0f; + + float PCFBias = 0.01f; + + bool DebugDrawFrustumBounds = false; + bool DebugDrawShadowCastersBounds = false; + }; + + REGISTER_COMPONENT(ComponentsIDGroup, RenderingSettingsComponent) +} \ No newline at end of file diff --git a/PolyEngine/Engine/Src/Resources/MeshResource.cpp b/PolyEngine/Engine/Src/Resources/MeshResource.cpp index a23cb28e..f5ce9705 100644 --- a/PolyEngine/Engine/Src/Resources/MeshResource.cpp +++ b/PolyEngine/Engine/Src/Resources/MeshResource.cpp @@ -13,7 +13,8 @@ MeshResource::MeshResource(const String& path) Assimp::Importer importer; const aiScene *scene = importer.ReadFile(path.GetCStr(), aiProcessPreset_TargetRealtime_Fast); - if (!scene) { + if (!scene) + { gConsole.LogError("Error Importing Asset: {}", importer.GetErrorString()); throw ResourceLoadFailedException(); } @@ -24,14 +25,16 @@ MeshResource::MeshResource(const String& path) Vector min(maxFloat, maxFloat, maxFloat); Vector max(-maxFloat, -maxFloat, -maxFloat); - for (unsigned int i = 0; i < scene->mNumMeshes; ++i) { + for (unsigned int i = 0; i < scene->mNumMeshes; ++i) + { SubMeshes.PushBack(new SubMesh(path, scene->mMeshes[i], scene->mMaterials[scene->mMeshes[i]->mMaterialIndex])); min = Vector::Min(min, SubMeshes[i]->GetAABox().GetMin()); max = Vector::Max(max, SubMeshes[i]->GetAABox().GetMax()); } - for (size_t i = 0; i < scene->mNumAnimations; ++i) { + for (size_t i = 0; i < scene->mNumAnimations; ++i) + { Animations.PushBack(new Animation(scene->mAnimations[i])); } diff --git a/PolyEngine/RenderingDevice/OpenGL/Src/ForwardRenderer.cpp b/PolyEngine/RenderingDevice/OpenGL/Src/ForwardRenderer.cpp index 1228f5df..89feba02 100644 --- a/PolyEngine/RenderingDevice/OpenGL/Src/ForwardRenderer.cpp +++ b/PolyEngine/RenderingDevice/OpenGL/Src/ForwardRenderer.cpp @@ -36,30 +36,30 @@ void ForwardRenderer::Render(const SceneView& sceneView) switch (renderingMode) { case eRenderingModeType::LIT: - RenderLit(sceneView.WorldData, sceneView.Rect, sceneView.CameraCmp); + RenderLit(sceneView.SceneData, sceneView.Rect, sceneView.CameraCmp); break; case eRenderingModeType::UNLIT: - RenderUnlit(sceneView.WorldData, sceneView.Rect, sceneView.CameraCmp); + RenderUnlit(sceneView.SceneData, sceneView.Rect, sceneView.CameraCmp); break; case eRenderingModeType::WIREFRAME: - RenderWireframe(sceneView.WorldData, sceneView.Rect, sceneView.CameraCmp); + RenderWireframe(sceneView.SceneData, sceneView.Rect, sceneView.CameraCmp); break; case eRenderingModeType::DEBUG_NORMALS: - RenderNormals(sceneView.WorldData, sceneView.Rect, sceneView.CameraCmp); + RenderNormals(sceneView.SceneData, sceneView.Rect, sceneView.CameraCmp); break; case eRenderingModeType::DEBUG_NORMALS_WIREFRAME: - RenderNormalsWireframe(sceneView.WorldData, sceneView.Rect, sceneView.CameraCmp); + RenderNormalsWireframe(sceneView.SceneData, sceneView.Rect, sceneView.CameraCmp); break; default: ASSERTE(false, "Uknown eRenderingModeType"); } - PostRender(sceneView.WorldData, sceneView.CameraCmp, sceneView.Rect); + PostRender(sceneView.SceneData, sceneView.CameraCmp, sceneView.Rect); } void ForwardRenderer::PostRender(Scene* world, const CameraComponent* cameraCmp, const AARect& rect) diff --git a/PolyEngine/RenderingDevice/OpenGL/Src/GLRenderingDevice.hpp b/PolyEngine/RenderingDevice/OpenGL/Src/GLRenderingDevice.hpp index 72f9a0dc..5b1de499 100644 --- a/PolyEngine/RenderingDevice/OpenGL/Src/GLRenderingDevice.hpp +++ b/PolyEngine/RenderingDevice/OpenGL/Src/GLRenderingDevice.hpp @@ -2,14 +2,14 @@ #include #include +#include +#include #include struct SDL_Window; namespace Poly { - struct PrimitiveQuad; - struct PrimitiveCube; struct SceneView; class CameraComponent; class AARect; @@ -103,6 +103,8 @@ namespace Poly void CreateUtilityTextures(); void FillSceneView(SceneView& sceneView); + void CullDirLightQueue(SceneView& sceneView, const Dynarray& meshCmp); + void CullShadowCasters(SceneView& sceneView, const Matrix& dirLightFromWorld, const Matrix& worldFromDirLight, AABox& frustumAABBInLS); void EndFrame(); void CleanUpResources(); diff --git a/PolyEngine/RenderingDevice/OpenGL/Src/GLWorldRendering.cpp b/PolyEngine/RenderingDevice/OpenGL/Src/GLWorldRendering.cpp index 0473084b..ab6c8c7c 100644 --- a/PolyEngine/RenderingDevice/OpenGL/Src/GLWorldRendering.cpp +++ b/PolyEngine/RenderingDevice/OpenGL/Src/GLWorldRendering.cpp @@ -2,6 +2,8 @@ #include +#include // std::min + #include #include #include @@ -9,7 +11,7 @@ #include #include #include - +#include #include #include @@ -69,10 +71,24 @@ void GLRenderingDevice::RenderWorld(Scene* world) void GLRenderingDevice::FillSceneView(SceneView& sceneView) { - for (const auto componentsTuple : sceneView.WorldData->IterateComponents()) + for (const auto& [dirLightCmp] : sceneView.SceneData->IterateComponents()) { - const MeshRenderingComponent* meshCmp = std::get(componentsTuple); + sceneView.DirectionalLights.PushBack(dirLightCmp); + } + for (const auto& [pointLightCmp] : sceneView.SceneData->IterateComponents()) + { + sceneView.PointLights.PushBack(pointLightCmp); + } + + Dynarray meshCmps; + for (const auto& [meshCmp] : sceneView.SceneData->IterateComponents()) + { + meshCmps.PushBack(meshCmp); + } + + for (auto& meshCmp : meshCmps) + { if (sceneView.CameraCmp->IsVisibleToCamera(meshCmp->GetOwner())) { if (meshCmp->GetBlendingMode() == eBlendingMode::OPAUQE) @@ -84,21 +100,148 @@ void GLRenderingDevice::FillSceneView(SceneView& sceneView) sceneView.TranslucentQueue.PushBack(meshCmp); } } - else + } + + if (sceneView.DirectionalLights.GetSize() > 0) + CullDirLightQueue(sceneView, meshCmps); +} + +void GLRenderingDevice::CullDirLightQueue(SceneView& sceneView, const Dynarray& meshCmps) +{ + DirectionalLightComponent* dirLight = sceneView.DirectionalLights[0]; + + const CameraComponent* cameraCmp = sceneView.CameraCmp; + Frustum frustum = cameraCmp->GetCameraFrustum(); + + Matrix clipFromView; + clipFromView.SetPerspective(frustum.GetFov(), frustum.GetAspect(), frustum.GetZNear(), frustum.GetZFar()); + Matrix viewFromWorld = cameraCmp->GetViewFromWorld(); + Matrix clipFromWorld = clipFromView * viewFromWorld; + + // Transform frustum corners to DirLightSpace + Dynarray cornersInNDC { + Vector(-1.0f, 1.0f, -1.0f), // back left top + Vector( 1.0f, 1.0f, -1.0f), // back right top + Vector(-1.0f, -1.0f, -1.0f), // back left bot + Vector( 1.0f, -1.0f, -1.0f), // back right bot + Vector(-1.0f, 1.0f, 1.0f), // front left top + Vector( 1.0f, 1.0f, 1.0f), // front right top + Vector(-1.0f, -1.0f, 1.0f), // front left bot + Vector( 1.0f, -1.0f, 1.0f) // front right bot + }; + + // Transform frustum corners from NDC to World + // could be done in one iteration but we need to do perspective division by W + Matrix worldFromClip = clipFromWorld.GetInversed(); + Dynarray cornersInWS; + for (Vector posInClip : cornersInNDC) + { + Vector posInWS = worldFromClip * posInClip; + posInWS.X /= posInWS.W; + posInWS.Y /= posInWS.W; + posInWS.Z /= posInWS.W; + cornersInWS.PushBack(posInWS); + } + DebugDrawSystem::DrawFrustumPoints(sceneView.SceneData, cornersInWS, Color::RED); + + // // based on https://mynameismjp.wordpress.com/2013/09/10/shadow-maps/ + // // Stabilize shadow map: calculate sphere bounds around frustum to minimize AABB changes on frustum rotation + // // Calculate the centroid of the view frustum slice + Vector lightForward = dirLight->GetTransform().GetGlobalForward(); + Vector lightUp = dirLight->GetTransform().GetGlobalUp(); + Matrix lightFromWorld = Matrix(Vector::ZERO, lightForward, lightUp); + Matrix worldFromLight = lightFromWorld.GetInversed(); + + Vector frustumCenterInLS; + for (Vector posInWS : cornersInWS) + { + frustumCenterInLS += lightFromWorld * posInWS; + } + frustumCenterInLS *= 1.0f / 8.0f; + + float maxRadiusInLS = 0.0f; + for (Vector posInWS : cornersInWS) + { + float radius = (lightFromWorld * cornersInWS[0] - lightFromWorld * posInWS).Length(); + maxRadiusInLS = std::max(maxRadiusInLS, radius); + } + maxRadiusInLS = std::ceil(maxRadiusInLS * 16.0f) / 16.0f; // MJP version + + Vector frustumMinInLS = frustumCenterInLS - Vector::ONE * maxRadiusInLS; + Vector frustumMaxInLS = frustumCenterInLS + Vector::ONE * maxRadiusInLS; + AABox frustumAABBInLS(frustumMinInLS, frustumMaxInLS - frustumMinInLS); + + if (sceneView.SettingsCmp && sceneView.SettingsCmp->DebugDrawFrustumBounds) + DebugDrawSystem::DrawBox(sceneView.SceneData, frustumAABBInLS.GetMin(), frustumAABBInLS.GetMax(), worldFromLight, Color(1.0f, 1.0f, 0.0f)); + + CullShadowCasters(sceneView, lightFromWorld, worldFromLight, frustumAABBInLS); + + if (sceneView.SettingsCmp && sceneView.SettingsCmp->DebugDrawFrustumBounds) + DebugDrawSystem::DrawBox(sceneView.SceneData, frustumAABBInLS.GetMin(), frustumAABBInLS.GetMax(), lightFromWorld.GetInversed(), Color(1.0f, 1.0f, 0.0f)); + + sceneView.DirShadowAABBInLS = frustumAABBInLS; +} + +void GLRenderingDevice::CullShadowCasters(SceneView& sceneView, const Matrix& dirLightFromWorld, const Matrix& worldFromDirLight, AABox& frustumAABBInLS) +{ + const float maxFloat = std::numeric_limits::max(); + Scene* scene = sceneView.SceneData; + + Dynarray meshCmps; + for (auto [meshCmp] : scene->IterateComponents()) + { + meshCmps.PushBack(meshCmp); + } + // transform meshes AABB to DirLightSpace + Dynarray> boxMeshes; + for (const auto meshCmp : meshCmps) + { + const Matrix& dirLightFromModel = dirLightFromWorld * meshCmp->GetTransform().GetWorldFromModel(); + Optional boxWSOptional = meshCmp->GetBoundingBox(eEntityBoundingChannel::RENDERING); + if (boxWSOptional.HasValue()) { - sceneView.DirShadowOpaqueQueue.PushBack(meshCmp); + AABox boxWS = boxWSOptional.Value(); + AABox boxLS = boxWS.GetTransformed(dirLightFromModel); + boxMeshes.PushBack(std::tuple(boxLS, meshCmp)); + + if (sceneView.SettingsCmp && sceneView.SettingsCmp->DebugDrawShadowCastersBounds) + DebugDrawSystem::DrawBox(scene, boxLS.GetMin(), boxLS.GetMax(), worldFromDirLight, Color::WHITE); } } - for (const auto componentsTuple : sceneView.WorldData->IterateComponents()) + // find min Y for near clipping plane and max Y for far clipping plane + float maxZ = -maxFloat; + for (const auto& [boxLS, mesh] : boxMeshes) + { + // extend dir light AAbox only in Z based on objects in rect defined on dir light AABob XY plane + if (boxLS.ContainsXY(frustumAABBInLS)) + maxZ = std::max(maxZ, boxLS.GetMax().Z); + } + + if (maxZ > frustumAABBInLS.GetMax().Z) { - sceneView.DirectionalLights.PushBack(std::get(componentsTuple)); + Vector center = frustumAABBInLS.GetCenter(); // X and Z should be neutral so AABB expanded only on Y axis + frustumAABBInLS.Expand(Vector(center.X, center.Y, maxZ)); } - for (const auto componentsTuple : sceneView.WorldData->IterateComponents()) + if (sceneView.SettingsCmp && sceneView.SettingsCmp->DebugDrawShadowCastersBounds) + DebugDrawSystem::DrawBox(scene, frustumAABBInLS.GetMin(), frustumAABBInLS.GetMax(), worldFromDirLight, Color(0.5f, 0.5f, 0.0f)); + + // find all meshes that are inside extended DirLights AABB box + int shadowCastersCounter = 0; + for (auto& [box, meshCmp] : boxMeshes) { - sceneView.PointLights.PushBack(std::get(componentsTuple)); + if (frustumAABBInLS.Contains(box)) + { + sceneView.DirShadowOpaqueQueue.PushBack(meshCmp); + shadowCastersCounter++; + + if (sceneView.SettingsCmp && sceneView.SettingsCmp->DebugDrawShadowCastersBounds) + DebugDrawSystem::DrawBox(scene, box.GetMin(), box.GetMax(), worldFromDirLight, Color::GREEN); + } } + + // gConsole.LogInfo("GLRenderingDevice::FillDirLightQueue casters: {}/{}", shadowCastersCounter, meshCmps.GetSize()); } void GLRenderingDevice::CreateUtilityTextures() diff --git a/PolyEngine/RenderingDevice/OpenGL/Src/IRendererInterface.hpp b/PolyEngine/RenderingDevice/OpenGL/Src/IRendererInterface.hpp index afe036a1..e9f1fd83 100644 --- a/PolyEngine/RenderingDevice/OpenGL/Src/IRendererInterface.hpp +++ b/PolyEngine/RenderingDevice/OpenGL/Src/IRendererInterface.hpp @@ -3,6 +3,7 @@ #include #include #include +#include // TODO: inherit from BaseRenderPass - make multipass RenderPass @@ -18,19 +19,23 @@ namespace Poly { struct SceneView : public BaseObject<> { SceneView(Scene* w, const Viewport& v) - : WorldData(w), ViewportData(v), Rect(v.GetRect()), CameraCmp(v.GetCamera()) - {}; + : SceneData(w), ViewportData(v), Rect(v.GetRect()), CameraCmp(v.GetCamera()) + { + SettingsCmp = CameraCmp->GetSibling(); + }; - Scene* WorldData; + Scene* SceneData; const Viewport& ViewportData; const AARect& Rect; const CameraComponent* CameraCmp; + const RenderingSettingsComponent* SettingsCmp; Dynarray DirShadowOpaqueQueue; Dynarray OpaqueQueue; Dynarray TranslucentQueue; - Dynarray DirectionalLights; + AABox DirShadowAABBInLS; + Dynarray DirectionalLights; Dynarray PointLights; }; diff --git a/PolyEngine/RenderingDevice/OpenGL/Src/Pipeline/BlinnPhongRenderingPass.cpp b/PolyEngine/RenderingDevice/OpenGL/Src/Pipeline/BlinnPhongRenderingPass.cpp index 00d81f22..2e1bdbd2 100644 --- a/PolyEngine/RenderingDevice/OpenGL/Src/Pipeline/BlinnPhongRenderingPass.cpp +++ b/PolyEngine/RenderingDevice/OpenGL/Src/Pipeline/BlinnPhongRenderingPass.cpp @@ -68,7 +68,7 @@ void BlinnPhongRenderingPass::OnRun(Scene* world, const CameraComponent* camera, const EntityTransform& cameraTrans = camera->GetTransform(); Vector CameraPos = cameraTrans.GetGlobalTranslation(); - Vector CameraDir = MovementSystem::GetGlobalForward(cameraTrans); + Vector CameraDir = cameraTrans.GetGlobalForward(); GetProgram().SetUniform("uCameraPosition", CameraPos); GetProgram().SetUniform("uCameraForward", CameraDir); @@ -82,7 +82,7 @@ void BlinnPhongRenderingPass::OnRun(Scene* world, const CameraComponent* camera, DirectionalLightComponent* dirLightCmp = std::get(componentsTuple); const EntityTransform& transform = dirLightCmp->GetTransform(); String baseName = String("uDirectionalLight[") + String::From(dirLightsCount) + String("]."); - GetProgram().SetUniform(baseName + "Direction", MovementSystem::GetGlobalForward(transform)); + GetProgram().SetUniform(baseName + "Direction", transform.GetGlobalForward()); GetProgram().SetUniform(baseName + "Base.Color", dirLightCmp->GetColor()); GetProgram().SetUniform(baseName + "Base.Intensity", dirLightCmp->GetIntensity()); @@ -121,7 +121,7 @@ void BlinnPhongRenderingPass::OnRun(Scene* world, const CameraComponent* camera, GetProgram().SetUniform(baseName + "CutOff", Cos(1.0_deg * spotLightCmp->GetCutOff())); GetProgram().SetUniform(baseName + "OuterCutOff", Cos(1.0_deg * spotLightCmp->GetOuterCutOff())); GetProgram().SetUniform(baseName + "Position", transform.GetGlobalTranslation()); - GetProgram().SetUniform(baseName + "Direction", MovementSystem::GetGlobalForward(transform)); + GetProgram().SetUniform(baseName + "Direction", transform.GetGlobalForward()); GetProgram().SetUniform(baseName + "Base.Color", spotLightCmp->GetColor()); GetProgram().SetUniform(baseName + "Base.Intensity", spotLightCmp->GetIntensity()); diff --git a/PolyEngine/RenderingDevice/OpenGL/Src/Pipeline/EnvCapture.cpp b/PolyEngine/RenderingDevice/OpenGL/Src/Pipeline/EnvCapture.cpp index 11881bc3..17534191 100644 --- a/PolyEngine/RenderingDevice/OpenGL/Src/Pipeline/EnvCapture.cpp +++ b/PolyEngine/RenderingDevice/OpenGL/Src/Pipeline/EnvCapture.cpp @@ -6,6 +6,16 @@ using namespace Poly; +static const Matrix ViewFromModel[] = +{ + Matrix(Vector::ZERO, Vector( 1.0f, 0.0f, 0.0f), Vector(0.0f, -1.0f, 0.0f)), // GL_TEXTURE_CUBE_MAP_POSITIVE_X + Matrix(Vector::ZERO, Vector(-1.0f, 0.0f, 0.0f), Vector(0.0f, -1.0f, 0.0f)), // GL_TEXTURE_CUBE_MAP_NEGATIVE_X + Matrix(Vector::ZERO, Vector( 0.0f, 1.0f, 0.0f), Vector(0.0f, 0.0f, 1.0f)), // GL_TEXTURE_CUBE_MAP_POSITIVE_Y + Matrix(Vector::ZERO, Vector( 0.0f, -1.0f, 0.0f), Vector(0.0f, 0.0f, -1.0f)), // GL_TEXTURE_CUBE_MAP_NEGATIVE_Y + Matrix(Vector::ZERO, Vector( 0.0f, 0.0f, 1.0f), Vector(0.0f, -1.0f, 0.0f)), // GL_TEXTURE_CUBE_MAP_POSITIVE_Z + Matrix(Vector::ZERO, Vector( 0.0f, 0.0f, -1.0f), Vector(0.0f, -1.0f, 0.0f)) // GL_TEXTURE_CUBE_MAP_NEGATIVE_Z +}; + EnvCapture::EnvCapture(GLRenderingDevice* rdi) : RDI(rdi), EquirectangularToCubemapShader("Shaders/equiToCubemap.vert.glsl", "Shaders/equiToCubemap.frag.glsl"), @@ -53,8 +63,6 @@ void EnvCapture::UpdateEnv(const SkyboxWorldComponent* skyboxCmp) CaptureDiffuseIrradiance(); CaptureSpecularPrefilteredMap(); - - IsDirty = false; } void EnvCapture::CaptureCubemap(const SkyboxWorldComponent* skyboxCmp) @@ -97,16 +105,16 @@ void EnvCapture::CaptureCubemap(const SkyboxWorldComponent* skyboxCmp) Matrix uClipFromView; uClipFromView.SetPerspective(90.0_deg, 1.0f, 0.1f, 10.0f); - Matrix ViewFromModel[] = - { - Matrix(Vector::ZERO, Vector(1.0f, 0.0f, 0.0f), Vector(0.0f, -1.0f, 0.0f)), - Matrix(Vector::ZERO, Vector(-1.0f, 0.0f, 0.0f), Vector(0.0f, -1.0f, 0.0f)), - Matrix(Vector::ZERO, Vector(0.0f, -1.0f, 0.0f), Vector(0.0f, 0.0f, -1.0f)), - Matrix(Vector::ZERO, Vector(0.0f, 1.0f, 0.0f), Vector(0.0f, 0.0f, 1.0f)), - Matrix(Vector::ZERO, Vector(0.0f, 0.0f, 1.0f), Vector(0.0f, -1.0f, 0.0f)), - Matrix(Vector::ZERO, Vector(0.0f, 0.0f, -1.0f), Vector(0.0f, -1.0f, 0.0f)) - }; - gConsole.LogInfo("EnvCapture::CaptureCubemap matrices created"); + // Matrix ViewFromModel[] = + // { + // Matrix(Vector::ZERO, Vector( 1.0f, 0.0f, 0.0f), Vector(0.0f, -1.0f, 0.0f)), // GL_TEXTURE_CUBE_MAP_POSITIVE_X + // Matrix(Vector::ZERO, Vector(-1.0f, 0.0f, 0.0f), Vector(0.0f, -1.0f, 0.0f)), // GL_TEXTURE_CUBE_MAP_NEGATIVE_X + // Matrix(Vector::ZERO, Vector( 0.0f, 1.0f, 0.0f), Vector(0.0f, 0.0f, 1.0f)), // GL_TEXTURE_CUBE_MAP_POSITIVE_Y + // Matrix(Vector::ZERO, Vector( 0.0f, -1.0f, 0.0f), Vector(0.0f, 0.0f, -1.0f)), // GL_TEXTURE_CUBE_MAP_NEGATIVE_Y + // Matrix(Vector::ZERO, Vector( 0.0f, 0.0f, 1.0f), Vector(0.0f, -1.0f, 0.0f)), // GL_TEXTURE_CUBE_MAP_POSITIVE_Z + // Matrix(Vector::ZERO, Vector( 0.0f, 0.0f, -1.0f), Vector(0.0f, -1.0f, 0.0f)) // GL_TEXTURE_CUBE_MAP_NEGATIVE_Z + // }; + // gConsole.LogInfo("EnvCapture::CaptureCubemap matrices created"); // convert HDR equirectangular environment map to cubemap equivalent gConsole.LogInfo("EnvCapture::CaptureCubemap start cubemap rendering loop"); @@ -177,16 +185,16 @@ void EnvCapture::CaptureDiffuseIrradiance() Matrix uClipFromView; uClipFromView.SetPerspective(90.0_deg, 1.0f, 0.1f, 10.0f); - Matrix ViewFromModel[] = - { - Matrix(Vector::ZERO, Vector(1.0f, 0.0f, 0.0f), Vector(0.0f, -1.0f, 0.0f)), - Matrix(Vector::ZERO, Vector(-1.0f, 0.0f, 0.0f), Vector(0.0f, -1.0f, 0.0f)), - Matrix(Vector::ZERO, Vector(0.0f, -1.0f, 0.0f), Vector(0.0f, 0.0f, -1.0f)), - Matrix(Vector::ZERO, Vector(0.0f, 1.0f, 0.0f), Vector(0.0f, 0.0f, 1.0f)), - Matrix(Vector::ZERO, Vector(0.0f, 0.0f, 1.0f), Vector(0.0f, -1.0f, 0.0f)), - Matrix(Vector::ZERO, Vector(0.0f, 0.0f, -1.0f), Vector(0.0f, -1.0f, 0.0f)) - }; - gConsole.LogInfo("EnvCapture::CaptureIrradiance matrices created"); + // Matrix ViewFromModel[] = + // { + // Matrix(Vector::ZERO, Vector( 1.0f, 0.0f, 0.0f), Vector(0.0f, -1.0f, 0.0f)), + // Matrix(Vector::ZERO, Vector(-1.0f, 0.0f, 0.0f), Vector(0.0f, -1.0f, 0.0f)), + // Matrix(Vector::ZERO, Vector( 0.0f, 1.0f, 0.0f), Vector(0.0f, 0.0f, 1.0f)), + // Matrix(Vector::ZERO, Vector( 0.0f, -1.0f, 0.0f), Vector(0.0f, 0.0f, -1.0f)), + // Matrix(Vector::ZERO, Vector( 0.0f, 0.0f, 1.0f), Vector(0.0f, -1.0f, 0.0f)), + // Matrix(Vector::ZERO, Vector( 0.0f, 0.0f, -1.0f), Vector(0.0f, -1.0f, 0.0f)) + // }; + // gConsole.LogInfo("EnvCapture::CaptureIrradiance matrices created"); glBindFramebuffer(GL_FRAMEBUFFER, captureFBO); glBindRenderbuffer(GL_RENDERBUFFER, captureRBO); @@ -256,15 +264,15 @@ void EnvCapture::CaptureSpecularPrefilteredMap() Matrix uClipFromView; uClipFromView.SetPerspective(90.0_deg, 1.0f, 0.1f, 10.0f); - Matrix ViewFromModel[] = - { - Matrix(Vector::ZERO, Vector(1.0f, 0.0f, 0.0f), Vector(0.0f, -1.0f, 0.0f)), - Matrix(Vector::ZERO, Vector(-1.0f, 0.0f, 0.0f), Vector(0.0f, -1.0f, 0.0f)), - Matrix(Vector::ZERO, Vector(0.0f, -1.0f, 0.0f), Vector(0.0f, 0.0f, -1.0f)), - Matrix(Vector::ZERO, Vector(0.0f, 1.0f, 0.0f), Vector(0.0f, 0.0f, 1.0f)), - Matrix(Vector::ZERO, Vector(0.0f, 0.0f, 1.0f), Vector(0.0f, -1.0f, 0.0f)), - Matrix(Vector::ZERO, Vector(0.0f, 0.0f, -1.0f), Vector(0.0f, -1.0f, 0.0f)) - }; + // Matrix ViewFromModel[] = + // { + // Matrix(Vector::ZERO, Vector( 1.0f, 0.0f, 0.0f), Vector(0.0f, -1.0f, 0.0f)), + // Matrix(Vector::ZERO, Vector(-1.0f, 0.0f, 0.0f), Vector(0.0f, -1.0f, 0.0f)), + // Matrix(Vector::ZERO, Vector( 0.0f, 1.0f, 0.0f), Vector(0.0f, 0.0f, 1.0f)), + // Matrix(Vector::ZERO, Vector( 0.0f, -1.0f, 0.0f), Vector(0.0f, 0.0f, -1.0f)), + // Matrix(Vector::ZERO, Vector( 0.0f, 0.0f, 1.0f), Vector(0.0f, -1.0f, 0.0f)), + // Matrix(Vector::ZERO, Vector( 0.0f, 0.0f, -1.0f), Vector(0.0f, -1.0f, 0.0f)) + // }; gConsole.LogInfo("EnvCapture::CaptureSpecularPrefilteredMap capture prefiltered cubemap"); PrefilterCubemapShader.BindProgram(); diff --git a/PolyEngine/RenderingDevice/OpenGL/Src/Pipeline/EnvCapture.hpp b/PolyEngine/RenderingDevice/OpenGL/Src/Pipeline/EnvCapture.hpp index 99100e57..df7f69a1 100644 --- a/PolyEngine/RenderingDevice/OpenGL/Src/Pipeline/EnvCapture.hpp +++ b/PolyEngine/RenderingDevice/OpenGL/Src/Pipeline/EnvCapture.hpp @@ -21,8 +21,6 @@ namespace Poly void UpdateEnv(const SkyboxWorldComponent* skyboxCmp); - bool GetIsDirty() const { return IsDirty; }; - GLuint GetHDRPanorama() const { return HDRPanorama; }; GLuint GetEnvCubemap() const { return EnvCubemap; }; GLuint GetIrradianceMap() const { return IrradianceMap; }; @@ -30,8 +28,6 @@ namespace Poly private: - bool IsDirty = true; - GLRenderingDevice* RDI; // IBL textures and cubemaps diff --git a/PolyEngine/RenderingDevice/OpenGL/Src/Pipeline/ShadowMapPass.cpp b/PolyEngine/RenderingDevice/OpenGL/Src/Pipeline/ShadowMapPass.cpp new file mode 100644 index 00000000..15e552e8 --- /dev/null +++ b/PolyEngine/RenderingDevice/OpenGL/Src/Pipeline/ShadowMapPass.cpp @@ -0,0 +1,318 @@ +#include + +#include +#include +#include + +using namespace Poly; + +Matrix Poly::GetProjectionForShadowMap(const SceneView& sceneView, int shadowmapSize) +{ + ASSERTE(sceneView.DirectionalLights.GetSize() > 0, "GetProjectionForShadowMap has no directional light in scene view"); + const DirectionalLightComponent* dirLightCmp = sceneView.DirectionalLights[0]; + + Vector lightForward = dirLightCmp->GetTransform().GetGlobalForward(); + Vector lightUp = dirLightCmp->GetTransform().GetGlobalUp(); + Matrix lightViewFromWorld = Matrix(Vector::ZERO, lightForward, lightUp); + + Vector shadowAABBExtentsInLS = sceneView.DirShadowAABBInLS.GetSize() * 0.5f; + Matrix clipFromLightView; + // n > f, because we are looking down the negative z - axis at this volume of space + clipFromLightView.SetOrthographicZO( + -shadowAABBExtentsInLS.Y, // bottom + shadowAABBExtentsInLS.Y, // top + -shadowAABBExtentsInLS.X, // left + shadowAABBExtentsInLS.X, // right + 0.0f, // near + -shadowAABBExtentsInLS.Z // far + ); + + Matrix lightViewFromModel; + Vector shadowAABBCenterInLS = sceneView.DirShadowAABBInLS.GetCenter(); + lightViewFromModel.SetTranslation(-shadowAABBCenterInLS); + + Matrix clipFromWorld = clipFromLightView * lightViewFromModel * lightViewFromWorld; + StablizeShadowProjection(clipFromWorld, shadowmapSize); + + return clipFromWorld; +} + +void Poly::StablizeShadowProjection(Poly::Matrix& clipFromWorld, int shadowmapSize) +{ + // based on https://mynameismjp.wordpress.com/2013/09/10/shadow-maps/ + // Stabilize shadow map: move in texel size increments + // round matrix translation to texel size increments + Vector shadowOrigin = clipFromWorld * Vector::ZERO; + shadowOrigin *= 0.5f * shadowmapSize; + + Vector roundedOrigin = Vector( + roundf(shadowOrigin.X), + roundf(shadowOrigin.Y), + 0.0f + ); + + Vector roundOffset = roundedOrigin - shadowOrigin; + roundOffset *= 2.0f / shadowmapSize; + roundOffset.Z = 0.0f; + roundOffset.W = 0.0f; + + clipFromWorld.Data[3] += roundOffset.X; + clipFromWorld.Data[7] += roundOffset.Y; +} + +int Poly::GetShadowMapSize(const eShadowMapSize shadowMapSize) +{ + switch (shadowMapSize) + { + case eShadowMapSize::SIZE_512: return 512; + case eShadowMapSize::SIZE_1024: return 1024; + case eShadowMapSize::SIZE_2048: return 2048; + case eShadowMapSize::SIZE_4096: return 4096; + default: + ASSERTE(false, "Uknown shadowmap size setting enum"); + return 512; + } +} + +ShadowMapPass::ShadowMapPass(GLRenderingDevice* rdi) + : RDI(rdi), + ShadowMapShader("Shaders/shadowMap.vert.glsl", "Shaders/shadowMap.frag.glsl"), + EVSMResolveShader("Shaders/hdr.vert.glsl", "Shaders/evsm.resolve.frag.glsl"), + EVSMBlurShader("Shaders/hdr.vert.glsl", "Shaders/evsm.blur.frag.glsl") +{ + ShadowMapShader.RegisterUniform("mat4", "uClipFromModel"); + + EVSMResolveShader.RegisterUniform("sampler2D", "uDepth"); + EVSMResolveShader.RegisterUniform("float", "uNear"); + EVSMResolveShader.RegisterUniform("float", "uFar"); + EVSMResolveShader.RegisterUniform("float", "uPositiveExponent"); + EVSMResolveShader.RegisterUniform("float", "uNegativeExponent"); + + EVSMBlurShader.RegisterUniform("sampler2D", "uEVSMap"); + EVSMBlurShader.RegisterUniform("int", "uIsHorizontal"); +} + +ShadowMapPass::~ShadowMapPass() +{ +} + +void ShadowMapPass::Init(const SceneView& sceneView) +{ + gConsole.LogInfo("ShadowMapPass::Init"); + + if (sceneView.SettingsCmp == nullptr) + { + ShadowMapResolution = 1; // create dummy resource + ShadowType = eShadowType::NONE; + } + else + { + ShadowMapResolution = GetShadowMapSize(sceneView.SettingsCmp->ShadowMapSize); + ShadowType = sceneView.SettingsCmp->ShadowType; + } + + float shadowBorderColor[] = { 1.0f, 1.0f, 1.0f, 1.0f }; + glGenTextures(1, &DirShadowMapDepth); + glBindTexture(GL_TEXTURE_2D, DirShadowMapDepth); + glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, ShadowMapResolution, ShadowMapResolution, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); + glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, shadowBorderColor); + glBindTexture(GL_TEXTURE_2D, 0); + + glGenTextures(1, &DirShadowMapColor); + glBindTexture(GL_TEXTURE_2D, DirShadowMapColor); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16F, ShadowMapResolution, ShadowMapResolution, 0, GL_RGB, GL_FLOAT, NULL); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); + glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, shadowBorderColor); + glBindTexture(GL_TEXTURE_2D, 0); + + glGenFramebuffers(1, &FBOShadowDepthMap); + glBindFramebuffer(GL_FRAMEBUFFER, FBOShadowDepthMap); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, DirShadowMapDepth, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, DirShadowMapColor, 0); + // glDrawBuffer(GL_NONE); + // glReadBuffer(GL_NONE); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + // CHECK_GL_ERR(); + CHECK_FBO_STATUS(); + + // Create pair of frame buffers for evsm + glGenTextures(1, &EVSMap0); + glBindTexture(GL_TEXTURE_2D, EVSMap0); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB32F, ShadowMapResolution / 2, ShadowMapResolution / 2, 0, GL_RGB, GL_FLOAT, NULL); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glBindTexture(GL_TEXTURE_2D, 0); + + glGenFramebuffers(1, &FBOShadowMapResolve0); + glBindFramebuffer(GL_FRAMEBUFFER, FBOShadowMapResolve0); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, EVSMap0, 0); + + glGenTextures(1, &EVSMap1); + glBindTexture(GL_TEXTURE_2D, EVSMap1); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB32F, ShadowMapResolution / 2, ShadowMapResolution / 2, 0, GL_RGB, GL_FLOAT, NULL); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glBindTexture(GL_TEXTURE_2D, 0); + + glGenFramebuffers(1, &FBOShadowMapResolve1); + glBindFramebuffer(GL_FRAMEBUFFER, FBOShadowMapResolve1); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, EVSMap1, 0); + + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + CHECK_FBO_STATUS(); +} + +void ShadowMapPass::Deinit() +{ + gConsole.LogInfo("ShadowMapPass::Deinit"); + + if (FBOShadowDepthMap > 0) + glDeleteFramebuffers(1, &FBOShadowDepthMap); + + if (EVSMap0 > 0) + glDeleteTextures(1, &EVSMap0); + + if (FBOShadowMapResolve0 > 0) + glDeleteFramebuffers(1, &FBOShadowMapResolve0); + + if (FBOShadowMapResolve1 > 0) + glDeleteFramebuffers(1, &FBOShadowMapResolve1); +} + +void ShadowMapPass::Render(const SceneView& sceneView) +{ + // gConsole.LogInfo("ShadowMapPass::Render"); + + if (sceneView.DirectionalLights.GetSize() < 1) + return; + + if (sceneView.SettingsCmp == nullptr + || sceneView.SettingsCmp->ShadowType == eShadowType::NONE) + return; + + switch (sceneView.SettingsCmp->ShadowType) + { + case eShadowType::PCF: + RenderPCF(sceneView); + break; + case eShadowType::EVSM2: + case eShadowType::EVSM4: + RenderEVSM(sceneView); + break; + default: + break; + } +} + +void ShadowMapPass::RenderPCF(const SceneView& sceneView) +{ + glViewport(0, 0, ShadowMapResolution, ShadowMapResolution); + glBindFramebuffer(GL_FRAMEBUFFER, FBOShadowDepthMap); + glClearColor(1.0f, 1.0f, 1.0f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glDisable(GL_BLEND); + glEnable(GL_CULL_FACE); + glCullFace(GL_FRONT); + glDepthMask(GL_TRUE); + + Matrix orthoDirLightFromWorld = GetProjectionForShadowMap(sceneView, ShadowMapResolution); + + ShadowMapShader.BindProgram(); + + for (const MeshRenderingComponent* meshCmp : sceneView.DirShadowOpaqueQueue) + { + const Matrix& worldFromModel = meshCmp->GetTransform().GetWorldFromModel(); + ShadowMapShader.SetUniform("uClipFromModel", orthoDirLightFromWorld * worldFromModel); + + for (const MeshResource::SubMesh* subMesh : meshCmp->GetMesh()->GetSubMeshes()) + { + glBindVertexArray(subMesh->GetMeshProxy()->GetResourceID()); + glDrawElements(GL_TRIANGLES, (GLsizei)subMesh->GetMeshData().GetTriangleCount() * 3, GL_UNSIGNED_INT, NULL); + glBindTexture(GL_TEXTURE_2D, 0); + glBindVertexArray(0); + } + } + + glCullFace(GL_BACK); + + glBindFramebuffer(GL_FRAMEBUFFER, 0); +} + +void ShadowMapPass::RenderEVSM(const SceneView& sceneView) +{ + glViewport(0, 0, ShadowMapResolution, ShadowMapResolution); + glBindFramebuffer(GL_FRAMEBUFFER, FBOShadowDepthMap); + glClearColor(1.0f, 1.0f, 1.0f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glDisable(GL_BLEND); + glEnable(GL_CULL_FACE); + glCullFace(GL_FRONT); + glDepthMask(GL_TRUE); + + Matrix orthoDirLightFromWorld = GetProjectionForShadowMap(sceneView, ShadowMapResolution); + + ShadowMapShader.BindProgram(); + + for (const MeshRenderingComponent* meshCmp : sceneView.DirShadowOpaqueQueue) + { + const Matrix& worldFromModel = meshCmp->GetTransform().GetWorldFromModel(); + ShadowMapShader.SetUniform("uClipFromModel", orthoDirLightFromWorld * worldFromModel); + + for (const MeshResource::SubMesh* subMesh : meshCmp->GetMesh()->GetSubMeshes()) + { + glBindVertexArray(subMesh->GetMeshProxy()->GetResourceID()); + glDrawElements(GL_TRIANGLES, (GLsizei)subMesh->GetMeshData().GetTriangleCount() * 3, GL_UNSIGNED_INT, NULL); + glBindTexture(GL_TEXTURE_2D, 0); + glBindVertexArray(0); + } + } + + glViewport(0, 0, ShadowMapResolution / 2, ShadowMapResolution / 2); + glDepthMask(GL_FALSE); + glDisable(GL_CULL_FACE); + glBindFramebuffer(GL_FRAMEBUFFER, FBOShadowMapResolve0); + + EVSMResolveShader.BindProgram(); + EVSMResolveShader.BindSampler("uDepth", 0, DirShadowMapColor); + EVSMResolveShader.SetUniform("uNear", sceneView.CameraCmp->GetClippingPlaneNear()); + EVSMResolveShader.SetUniform("uFar", sceneView.CameraCmp->GetClippingPlaneFar()); + EVSMResolveShader.SetUniform("uPositiveExponent", sceneView.SettingsCmp->EVSMPositiveExponent); + EVSMResolveShader.SetUniform("uNegativeExponent", sceneView.SettingsCmp->EVSMNegativeExponent); + + glBindVertexArray(RDI->PrimitivesQuad->VAO); + glDrawArrays(GL_TRIANGLES, 0, 6); + glBindVertexArray(0); + + glBindFramebuffer(GL_FRAMEBUFFER, FBOShadowMapResolve1); + EVSMBlurShader.BindProgram(); + EVSMBlurShader.BindSampler("uEVSMap", 0, EVSMap0); + EVSMBlurShader.SetUniform("uIsHorizontal", 1); + + glBindVertexArray(RDI->PrimitivesQuad->VAO); + glDrawArrays(GL_TRIANGLES, 0, 6); + glBindVertexArray(0); + + glBindFramebuffer(GL_FRAMEBUFFER, FBOShadowMapResolve0); + EVSMBlurShader.BindProgram(); + EVSMBlurShader.BindSampler("uEVSMap", 0, EVSMap1); + EVSMBlurShader.SetUniform("uIsHorizontal", 0); + + glBindVertexArray(RDI->PrimitivesQuad->VAO); + glDrawArrays(GL_TRIANGLES, 0, 6); + glBindVertexArray(0); + + glBindFramebuffer(GL_FRAMEBUFFER, 0); +} \ No newline at end of file diff --git a/PolyEngine/RenderingDevice/OpenGL/Src/Pipeline/ShadowMapPass.hpp b/PolyEngine/RenderingDevice/OpenGL/Src/Pipeline/ShadowMapPass.hpp new file mode 100644 index 00000000..71e5f8da --- /dev/null +++ b/PolyEngine/RenderingDevice/OpenGL/Src/Pipeline/ShadowMapPass.hpp @@ -0,0 +1,59 @@ +#pragma once + +#include +#include +#include +#include + +namespace Poly +{ + class GLRenderingDevice; + class GLShaderProgram; + struct SceneView; + + Matrix GetProjectionForShadowMap(const SceneView& sceneView, int shadowmapSize); + + void StablizeShadowProjection(Poly::Matrix& clipFromWorld, int shadowmapSize); + + int GetShadowMapSize(const eShadowMapSize shadowMapSize); + + + class ShadowMapPass : public BaseObject<> + { + public: + + ShadowMapPass(GLRenderingDevice* rdi); + ~ShadowMapPass(); + + void Init(const SceneView& sceneView); + void Render(const SceneView& sceneView); + void Deinit(); + + GLuint GetDirShadowMapColor() const { return DirShadowMapColor; }; + GLuint GetEVSMap0() const { return EVSMap0; }; + int GetShadowMapResolution() const { return ShadowMapResolution; }; + eShadowType GetShadowType() const { return ShadowType; }; + + private: + + GLRenderingDevice* RDI; + + int ShadowMapResolution; + eShadowType ShadowType; + + GLuint DirShadowMapDepth; + GLuint DirShadowMapColor; + GLuint EVSMap0; + GLuint EVSMap1; + GLuint FBOShadowDepthMap; + GLuint FBOShadowMapResolve0; + GLuint FBOShadowMapResolve1; + + GLShaderProgram ShadowMapShader; + GLShaderProgram EVSMResolveShader; + GLShaderProgram EVSMBlurShader; + + void RenderEVSM(const SceneView& sceneView); + void RenderPCF(const SceneView& sceneView); + }; +} \ No newline at end of file diff --git a/PolyEngine/RenderingDevice/OpenGL/Src/PolyRenderingDeviceGLPCH.hpp b/PolyEngine/RenderingDevice/OpenGL/Src/PolyRenderingDeviceGLPCH.hpp index 38679d82..b44469e4 100644 --- a/PolyEngine/RenderingDevice/OpenGL/Src/PolyRenderingDeviceGLPCH.hpp +++ b/PolyEngine/RenderingDevice/OpenGL/Src/PolyRenderingDeviceGLPCH.hpp @@ -45,7 +45,6 @@ #include #include - // ECS #include #include @@ -69,10 +68,6 @@ // UI #include -// Movement -// @todo remove this include! -#include - // Debugging #include @@ -91,6 +86,5 @@ // SDL #include -// SILENCE_GCC_WARNING(-Wimplicit-fallthrough=, "Surpressing clang warnings in imstb_truetype") -#include -// UNSILENCE_GCC_WARNING() +// Imgui +#include \ No newline at end of file diff --git a/PolyEngine/RenderingDevice/OpenGL/Src/Proxy/GLShaderProgram.cpp b/PolyEngine/RenderingDevice/OpenGL/Src/Proxy/GLShaderProgram.cpp index d5d0a119..cc295f58 100644 --- a/PolyEngine/RenderingDevice/OpenGL/Src/Proxy/GLShaderProgram.cpp +++ b/PolyEngine/RenderingDevice/OpenGL/Src/Proxy/GLShaderProgram.cpp @@ -146,6 +146,10 @@ void GLShaderProgram::LoadShader(eShaderUnitType type, const String& shaderName) } ShaderCode[type] = sb.GetString(); + + String compiledPath = EvaluateFullResourcePath(eResourceSource::ENGINE, shaderName + String(".dump")); + gConsole.LogInfo("GLShaderProgram::LoadShader debugPath: {}", compiledPath); + SaveTextFileRelative(eResourceSource::ENGINE, shaderName + String(".dump"), ShaderCode[type]); } void GLShaderProgram::CompileShader(GLShaderProgram::eShaderUnitType type) diff --git a/PolyEngine/RenderingDevice/OpenGL/Src/Proxy/GLShaderProgram.hpp b/PolyEngine/RenderingDevice/OpenGL/Src/Proxy/GLShaderProgram.hpp index 990ba2dc..4af32805 100644 --- a/PolyEngine/RenderingDevice/OpenGL/Src/Proxy/GLShaderProgram.hpp +++ b/PolyEngine/RenderingDevice/OpenGL/Src/Proxy/GLShaderProgram.hpp @@ -69,7 +69,6 @@ namespace Poly static GLenum GetEnumFromShaderUnitType(eShaderUnitType type); - void FetchIncludes(eShaderUnitType type); void AnalyzeShaderCode(eShaderUnitType type); std::map Uniforms; diff --git a/PolyEngine/RenderingDevice/OpenGL/Src/Proxy/GLTextFieldBufferDeviceProxy.cpp b/PolyEngine/RenderingDevice/OpenGL/Src/Proxy/GLTextFieldBufferDeviceProxy.cpp index 08259092..576c7562 100644 --- a/PolyEngine/RenderingDevice/OpenGL/Src/Proxy/GLTextFieldBufferDeviceProxy.cpp +++ b/PolyEngine/RenderingDevice/OpenGL/Src/Proxy/GLTextFieldBufferDeviceProxy.cpp @@ -75,5 +75,5 @@ void GLTextFieldBufferDeviceProxy::SetContent(size_t count, const TextFieldLette glBindBuffer(GL_ARRAY_BUFFER, VBO); glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * vboData.GetSize(), vboData.GetData(), GL_DYNAMIC_DRAW); glBindBuffer(GL_ARRAY_BUFFER, 0); - CHECK_GL_ERR(); + // CHECK_GL_ERR(); // spams errors } \ No newline at end of file diff --git a/PolyEngine/RenderingDevice/OpenGL/Src/Proxy/imgui_impl_opengl3.cpp b/PolyEngine/RenderingDevice/OpenGL/Src/Proxy/imgui_impl_opengl3.cpp index ee04933b..dd5c438e 100644 --- a/PolyEngine/RenderingDevice/OpenGL/Src/Proxy/imgui_impl_opengl3.cpp +++ b/PolyEngine/RenderingDevice/OpenGL/Src/Proxy/imgui_impl_opengl3.cpp @@ -49,7 +49,7 @@ #include -#include "imgui_impl_opengl3.h" +#include #include // OpenGL Data diff --git a/PolyEngine/RenderingDevice/OpenGL/Src/TiledForwardRenderer.cpp b/PolyEngine/RenderingDevice/OpenGL/Src/TiledForwardRenderer.cpp index 64b50e25..34555b5e 100644 --- a/PolyEngine/RenderingDevice/OpenGL/Src/TiledForwardRenderer.cpp +++ b/PolyEngine/RenderingDevice/OpenGL/Src/TiledForwardRenderer.cpp @@ -11,8 +11,9 @@ #include #include #include +#include -#include "Proxy/imgui_impl_opengl3.h" +#include using namespace Poly; @@ -44,8 +45,9 @@ void RenderTargetPingPong::Deinit() TiledForwardRenderer::TiledForwardRenderer(GLRenderingDevice* rdi) - : IRendererInterface(rdi), SkyboxCapture(rdi), - ShadowMapShader("Shaders/shadowMap.vert.glsl", "Shaders/shadowMap.frag.glsl"), + : IRendererInterface(rdi), + ShadowMap(rdi), + SkyboxCapture(rdi), DepthShader("Shaders/depth.vert.glsl", "Shaders/depth.frag.glsl"), LightCullingShader("Shaders/lightCulling.comp.glsl"), LightAccumulationShader("Shaders/lightAccumulation.vert.glsl", "Shaders/lightAccumulation.frag.glsl"), @@ -71,7 +73,10 @@ TiledForwardRenderer::TiledForwardRenderer(GLRenderingDevice* rdi) DebugLightAccumShader("Shaders/debugLightAccum.vert.glsl", "Shaders/debugLightAccum.frag.glsl"), DebugTextureInputsShader("Shaders/lightAccumulation.vert.glsl", "Shaders/lightAccumulationTexDebug.frag.glsl") { - ShadowMapShader.RegisterUniform("mat4", "uClipFromModel"); + + LightAccumulationShader.RegisterUniform("mat4", "uDirLightFromWorld"); + LightAccumulationShader.RegisterUniform("float", "uShadowBiasMin"); + LightAccumulationShader.RegisterUniform("float", "uShadowBiasMax"); LightAccumulationShader.RegisterUniform("float", "uTime"); LightAccumulationShader.RegisterUniform("vec4", "uViewPosition"); @@ -93,6 +98,12 @@ TiledForwardRenderer::TiledForwardRenderer(GLRenderingDevice* rdi) LightAccumulationShader.RegisterUniform("sampler2D", "uNormalMap"); LightAccumulationShader.RegisterUniform("sampler2D", "uAmbientOcclusionMap"); LightAccumulationShader.RegisterUniform("sampler2D", "uDirShadowMap"); + LightAccumulationShader.RegisterUniform("sampler2D", "uDirEVSMap"); + LightAccumulationShader.RegisterUniform("float", "uPositiveExponent"); + LightAccumulationShader.RegisterUniform("float", "uNegativeExponent"); + LightAccumulationShader.RegisterUniform("float", "uVSMBias"); + LightAccumulationShader.RegisterUniform("float", "uLightBleedingReduction"); + LightAccumulationShader.RegisterUniform("int", "uShadowType"); for (int i = 0; i < 8; ++i) { @@ -236,6 +247,8 @@ void TiledForwardRenderer::Deinit() { gConsole.LogInfo("TiledForwardRenderer::Deinit"); + ShadowMap.Deinit(); + if (ImGui::GetCurrentContext() != nullptr) { // Imgui context is needed to propertly deinit textures. @@ -319,7 +332,7 @@ void TiledForwardRenderer::CreateLightBuffers(const ScreenSize& size) glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0); - // CHECK_GL_ERR(); + CHECK_GL_ERR(); } void TiledForwardRenderer::DeleteLightBuffers() @@ -353,7 +366,7 @@ void TiledForwardRenderer::CreateRenderTargets(const ScreenSize& size) glReadBuffer(GL_NONE); glBindFramebuffer(GL_FRAMEBUFFER, 0); - // CHECK_GL_ERR(); + CHECK_GL_ERR(); CHECK_FBO_STATUS(); // Create a floating point HDR frame buffer and a floating point color buffer (as a texture) @@ -390,7 +403,7 @@ void TiledForwardRenderer::CreateRenderTargets(const ScreenSize& size) glBindFramebuffer(GL_FRAMEBUFFER, 0); - // CHECK_GL_ERR(); + CHECK_GL_ERR(); CHECK_FBO_STATUS(); // Create pair of frame buffers for post process to swap @@ -409,7 +422,7 @@ void TiledForwardRenderer::CreateRenderTargets(const ScreenSize& size) glBindFramebuffer(GL_FRAMEBUFFER, 0); - // CHECK_GL_ERR(); + CHECK_GL_ERR(); CHECK_FBO_STATUS(); glGenFramebuffers(1, &FBOpost1); @@ -445,27 +458,7 @@ void TiledForwardRenderer::CreateRenderTargets(const ScreenSize& size) RTBloom.Init(screenSizeX / 2, screenSizeY / 2); - // CHECK_GL_ERR(); - CHECK_FBO_STATUS(); - - glGenTextures(1, &DirShadowMap); - glBindTexture(GL_TEXTURE_2D, DirShadowMap); - glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, SHADOW_WIDTH, SHADOW_HEIGHT, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); - float shadowBorderColor[] = { 1.0f, 1.0f, 1.0f, 1.0f }; - glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, shadowBorderColor); - - glGenFramebuffers(1, &FBOShadowDepthMap); - glBindFramebuffer(GL_FRAMEBUFFER, FBOShadowDepthMap); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, DirShadowMap, 0); - glDrawBuffer(GL_NONE); - glReadBuffer(GL_NONE); - glBindFramebuffer(GL_FRAMEBUFFER, 0); - - // CHECK_GL_ERR(); + CHECK_GL_ERR(); CHECK_FBO_STATUS(); } @@ -507,12 +500,8 @@ void TiledForwardRenderer::DeleteRenderTargets() if (FBOpost1 > 0) glDeleteFramebuffers(1, &FBOpost1); - if (FBOShadowDepthMap > 0) - glDeleteFramebuffers(1, &FBOShadowDepthMap); - RTBloom.Deinit(); - // CHECK_GL_ERR(); CHECK_FBO_STATUS(); } @@ -520,48 +509,33 @@ void TiledForwardRenderer::Render(const SceneView& sceneView) { //gConsole.LogInfo("TiledForwardRenderer::Render"); - // gConsole.LogInfo("TiledForwardRenderer::Render Aspect: {}, IsForcedRatio: {}, FOV: {}", - // sceneView.CameraCmp->GetAspect(), sceneView.CameraCmp->GetForcedRatio(), sceneView.CameraCmp->GetFOV()); - - // glViewport((int)(sceneView.Rect.GetMin().X * screenSize.Width), (int)(sceneView.Rect.GetMin().Y * screenSize.Height), - // (int)(sceneView.Rect.GetSize().X * screenSize.Width), (int)(sceneView.Rect.GetSize().Y * screenSize.Height)); + static bool isInitOnFirstFrame = false; - UpdateLightsBufferFromScene(sceneView); - - UpdateEnvCapture(sceneView); - - RenderShadowMap(sceneView); + if (!isInitOnFirstFrame) + { + ShadowMap.Init(sceneView); + UpdateEnvCapture(sceneView); + + isInitOnFirstFrame = true; + } + UpdateLightsBufferFromScene(sceneView); + ShadowMap.Render(sceneView); RenderDepthPrePass(sceneView); - ComputeLightCulling(sceneView); - RenderOpaqueLit(sceneView); - RenderSkybox(sceneView); - RenderTranslucentLit(sceneView); - - RenderParticleUnlit(sceneView.WorldData, sceneView.CameraCmp); - + RenderParticleUnlit(sceneView.SceneData, sceneView.CameraCmp); PostLinearizeDepth(sceneView); - PostMotionBlur(sceneView); - PostDepthOfField(sceneView); - PostBloom(sceneView); - PostTonemapper(sceneView); - PostFXAA(sceneView); - PostGamma(sceneView); - EditorDebug(sceneView); - UIText2D(sceneView); - UIImgui(); // ensure that copy of matrix is stored @@ -571,20 +545,11 @@ void TiledForwardRenderer::Render(const SceneView& sceneView) void TiledForwardRenderer::UpdateEnvCapture(const SceneView& sceneView) { - // gConsole.LogInfo("TiledForwardRenderer::UpdateEnvCapture"); - - if (SkyboxCapture.GetIsDirty()) - { - const SkyboxWorldComponent* SkyboxWorldCmp = sceneView.WorldData->GetWorldComponent(); - if (SkyboxWorldCmp != nullptr) - { - SkyboxCapture.UpdateEnv(SkyboxWorldCmp); - } - else - { - gConsole.LogInfo("TiledForwardRenderer::UpdateEnvCapture SkyboxWorldComponent not found!"); - } - } + const SkyboxWorldComponent* SkyboxWorldCmp = sceneView.SceneData->GetWorldComponent(); + if (SkyboxWorldCmp != nullptr) + SkyboxCapture.UpdateEnv(SkyboxWorldCmp); + else + gConsole.LogInfo("TiledForwardRenderer::UpdateEnvCapture SkyboxWorldComponent not found!"); } void TiledForwardRenderer::RenderEquiCube(const SceneView& sceneView) @@ -621,66 +586,6 @@ void TiledForwardRenderer::RenderEquiCube(const SceneView& sceneView) glBindFramebuffer(GL_FRAMEBUFFER, 0); } -Matrix TiledForwardRenderer::GetProjectionForShadowMap(const DirectionalLightComponent* dirLightCmp) const -{ - // TODO: calc bounding box and then determine projection size - // make sure contains all the objects - float near_plane = -4096.0f, far_plane = 4096.0f; - Matrix dirLightProjection; - dirLightProjection.SetOrthographic(-4096.0f, 4096.0f, -4096.0f, 4096.0f, near_plane, far_plane); - - Matrix dirLightFromWorld = dirLightCmp->GetTransform().GetWorldFromModel().GetInversed(); - return dirLightFromWorld * dirLightProjection; -} - -void TiledForwardRenderer::RenderShadowMap(const SceneView& sceneView) -{ - if (sceneView.DirectionalLights.GetSize() < 1) - return; - - glViewport(0, 0, SHADOW_WIDTH, SHADOW_HEIGHT); - glCullFace(GL_FRONT); - glBindFramebuffer(GL_FRAMEBUFFER, FBOShadowDepthMap); - glClear(GL_DEPTH_BUFFER_BIT); - - Matrix projDirLightFromWorld = GetProjectionForShadowMap(sceneView.DirectionalLights[0]); - - ShadowMapShader.BindProgram(); - - for (const MeshRenderingComponent* meshCmp : sceneView.OpaqueQueue) - { - const Matrix& worldFromModel = meshCmp->GetTransform().GetWorldFromModel(); - ShadowMapShader.SetUniform("uClipFromModel", projDirLightFromWorld * worldFromModel); - - for (const MeshResource::SubMesh* subMesh : meshCmp->GetMesh()->GetSubMeshes()) - { - glBindVertexArray(subMesh->GetMeshProxy()->GetResourceID()); - - glDrawElements(GL_TRIANGLES, (GLsizei)subMesh->GetMeshData().GetTriangleCount() * 3, GL_UNSIGNED_INT, NULL); - glBindTexture(GL_TEXTURE_2D, 0); - glBindVertexArray(0); - } - } - - for (const MeshRenderingComponent* meshCmp : sceneView.DirShadowOpaqueQueue) - { - const Matrix& worldFromModel = meshCmp->GetTransform().GetWorldFromModel(); - ShadowMapShader.SetUniform("uClipFromModel", projDirLightFromWorld * worldFromModel); - - for (const MeshResource::SubMesh* subMesh : meshCmp->GetMesh()->GetSubMeshes()) - { - glBindVertexArray(subMesh->GetMeshProxy()->GetResourceID()); - - glDrawElements(GL_TRIANGLES, (GLsizei)subMesh->GetMeshData().GetTriangleCount() * 3, GL_UNSIGNED_INT, NULL); - glBindTexture(GL_TEXTURE_2D, 0); - glBindVertexArray(0); - } - } - - glBindFramebuffer(GL_FRAMEBUFFER, 0); - glCullFace(GL_BACK); -} - void TiledForwardRenderer::RenderDepthPrePass(const SceneView& sceneView) { ScreenSize screenSize = RDI->GetScreenSize(); @@ -688,6 +593,9 @@ void TiledForwardRenderer::RenderDepthPrePass(const SceneView& sceneView) glBindFramebuffer(GL_FRAMEBUFFER, FBOdepthMap); glClear(GL_DEPTH_BUFFER_BIT); + glDepthMask(GL_TRUE); + glEnable(GL_CULL_FACE); + glCullFace(GL_BACK); DepthShader.BindProgram(); @@ -754,30 +662,49 @@ void TiledForwardRenderer::ComputeLightCulling(const SceneView& sceneView) void TiledForwardRenderer::RenderOpaqueLit(const SceneView& sceneView) { // gConsole.LogInfo("TiledForwardRenderer::AccumulateLights"); - float time = (float)TimeSystem::GetTimerElapsedTime(sceneView.WorldData, eEngineTimer::GAMEPLAY); + float time = (float)TimeSystem::GetTimerElapsedTime(sceneView.SceneData, eEngineTimer::GAMEPLAY); ScreenSize screenSize = RDI->GetScreenSize(); glViewport(0, 0, screenSize.Width, screenSize.Height); - for (int i = 9; i > 0; --i) + const int activeTextures = 10; + for (int i = activeTextures; i > 0; --i) { glActiveTexture(GL_TEXTURE0 + i); glBindTexture(GL_TEXTURE_2D, 0); } glBindFramebuffer(GL_FRAMEBUFFER, FBOhdr); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - LightAccumulationShader.BindProgram(); - - Matrix projDirLightFromWorld = sceneView.DirectionalLights.IsEmpty() ? Matrix() : GetProjectionForShadowMap(sceneView.DirectionalLights[0]); + // shadownap uniforms + Matrix projDirLightFromWorld = sceneView.DirectionalLights.IsEmpty() + ? Matrix() + : GetProjectionForShadowMap(sceneView, ShadowMap.GetShadowMapResolution()); + LightAccumulationShader.BindProgram(); LightAccumulationShader.SetUniform("uDirLightFromWorld", projDirLightFromWorld); - LightAccumulationShader.BindSampler("uDirShadowMap", 9, DirShadowMap); + LightAccumulationShader.SetUniform("uShadowType", (int)(ShadowMap.GetShadowType())); + switch (ShadowMap.GetShadowType()) + { + case eShadowType::PCF: + LightAccumulationShader.BindSampler("uDirShadowMap", 9, ShadowMap.GetDirShadowMapColor()); + LightAccumulationShader.SetUniform("uShadowBias", sceneView.SettingsCmp->PCFBias); + break; + case eShadowType::EVSM2: + case eShadowType::EVSM4: + LightAccumulationShader.BindSampler("uDirEVSMap", 10, ShadowMap.GetEVSMap0()); + LightAccumulationShader.SetUniform("uPositiveExponent", sceneView.SettingsCmp->EVSMPositiveExponent); + LightAccumulationShader.SetUniform("uNegativeExponent", sceneView.SettingsCmp->EVSMNegativeExponent); + LightAccumulationShader.SetUniform("uEVSMBias", sceneView.SettingsCmp->EVSMBias); + LightAccumulationShader.SetUniform("uLightBleedingReduction", sceneView.SettingsCmp->EVSMLghtBleedingReduction); + break; + default: + break; + } + // Lighting uniforms const EntityTransform& cameraTransform = sceneView.CameraCmp->GetTransform(); - LightAccumulationShader.SetUniform("uTime", time); LightAccumulationShader.SetUniform("uLightCount", (int)std::min((int)sceneView.PointLights.GetSize(), MAX_NUM_LIGHTS)); LightAccumulationShader.SetUniform("uWorkGroupsX", (int)WorkGroupsX); @@ -792,7 +719,7 @@ void TiledForwardRenderer::RenderOpaqueLit(const SceneView& sceneView) Color colorIntensity = dirLightCmp->GetColor(); colorIntensity.A = dirLightCmp->GetIntensity(); LightAccumulationShader.SetUniform(baseName + "ColorIntensity", colorIntensity); - LightAccumulationShader.SetUniform(baseName + "Direction", MovementSystem::GetGlobalForward(transform)); + LightAccumulationShader.SetUniform(baseName + "Direction", -transform.GetGlobalForward()); ++dirLightsCount; if (dirLightsCount == MAX_LIGHT_COUNT_DIRECTIONAL) @@ -856,7 +783,7 @@ void TiledForwardRenderer::RenderOpaqueLit(const SceneView& sceneView) // Clear bound resources glBindVertexArray(0); - for (int i = 9; i > 0; --i) + for (int i = activeTextures; i > 0; --i) { glActiveTexture(GL_TEXTURE0 + i); glBindTexture(GL_TEXTURE_2D, 0); @@ -875,7 +802,7 @@ void TiledForwardRenderer::RenderSkybox(const SceneView& sceneView) if (SkyboxCapture.GetEnvCubemap() > 0) { Color tint = Color::WHITE; - SkyboxWorldComponent* skyboxCmp = sceneView.WorldData->GetWorldComponent(); + SkyboxWorldComponent* skyboxCmp = sceneView.SceneData->GetWorldComponent(); if (skyboxCmp) { tint = skyboxCmp->GetTint(); @@ -949,7 +876,7 @@ void TiledForwardRenderer::RenderTranslucentLit(const SceneView& sceneView) Color colorIntensity = dirLightCmp->GetColor(); colorIntensity.A = dirLightCmp->GetIntensity(); TranslucentShader.SetUniform(baseName + "ColorIntensity", colorIntensity); - TranslucentShader.SetUniform(baseName + "Direction", MovementSystem::GetGlobalForward(transform)); + TranslucentShader.SetUniform(baseName + "Direction", -(transform.GetGlobalForward())); ++dirLightsCount; if (dirLightsCount == MAX_LIGHT_COUNT_DIRECTIONAL) @@ -1047,9 +974,8 @@ void TiledForwardRenderer::RenderParticleUnlit(Scene* world, const CameraCompone glBindFragDataLocation((GLuint)TranslucentShader.GetProgramHandle(), 0, "color"); glBindFragDataLocation((GLuint)TranslucentShader.GetProgramHandle(), 1, "normal"); - for (auto componentsTuple : world->IterateComponents()) + for (const auto& [particleCmp]: world->IterateComponents()) { - const ParticleComponent* particleCmp = std::get(componentsTuple); const EntityTransform& transform = particleCmp->GetTransform(); const Matrix& worldFromModel = particleCmp->GetEmitter()->GetSettings().SimulationSpace == ParticleEmitter::eSimulationSpace::LOCAL_SPACE ? transform.GetWorldFromModel() @@ -1115,7 +1041,6 @@ void TiledForwardRenderer::PostLinearizeDepth(const SceneView& sceneView) glBindVertexArray(0); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, PostColorBuffer1, 0); - glBindFramebuffer(GL_FRAMEBUFFER, 0); } @@ -1127,7 +1052,7 @@ void TiledForwardRenderer::PostMotionBlur(const SceneView& sceneView) motionBlurScale = postCmp->MotionBlurScale; } - float deltaTime = (float)(TimeSystem::GetTimerDeltaTime(sceneView.WorldData, Poly::eEngineTimer::GAMEPLAY)); + float deltaTime = (float)(TimeSystem::GetTimerDeltaTime(sceneView.SceneData, Poly::eEngineTimer::GAMEPLAY)); float currentFPS = 1.0f / deltaTime; float targetFPS = 60.0f; @@ -1310,7 +1235,7 @@ void TiledForwardRenderer::PostFXAA(const SceneView& sceneView) void TiledForwardRenderer::PostGamma(const SceneView& sceneView) { - float time = (float)TimeSystem::GetTimerElapsedTime(sceneView.WorldData, eEngineTimer::GAMEPLAY); + float time = (float)TimeSystem::GetTimerElapsedTime(sceneView.SceneData, eEngineTimer::GAMEPLAY); const ScreenSize screenSize = RDI->GetScreenSize(); @@ -1347,7 +1272,13 @@ void TiledForwardRenderer::PostGamma(const SceneView& sceneView) void TiledForwardRenderer::EditorDebug(const SceneView& sceneView) { + // gConsole.LogInfo("TiledForwardRenderer::EditorDebug"); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + ScreenSize screenSize = RDI->GetScreenSize(); + glViewport(0, 0, screenSize.Width, screenSize.Height); + glDisable(GL_DEPTH_TEST); const Matrix& clipFromWorld = sceneView.CameraCmp->GetClipFromWorld(); @@ -1356,7 +1287,7 @@ void TiledForwardRenderer::EditorDebug(const SceneView& sceneView) // Render Lines { - auto debugLinesComponent = sceneView.WorldData->GetWorldComponent(); + auto debugLinesComponent = sceneView.SceneData->GetWorldComponent(); auto& debugLines = debugLinesComponent->DebugLines; auto& debugLinesColors = debugLinesComponent->DebugLinesColors; @@ -1407,9 +1338,8 @@ void TiledForwardRenderer::UIText2D(const SceneView& sceneView) Text2DShader.BindProgram(); Text2DShader.SetUniform("u_projection", ortho); - for (auto componentsTuple : sceneView.WorldData->IterateComponents()) + for (const auto& [textCmp] : sceneView.SceneData->IterateComponents()) { - ScreenSpaceTextComponent* textCmp = std::get(componentsTuple); Text2D& text = textCmp->GetText(); Text2DShader.SetUniform("u_textColor", text.GetFontColor()); Text2DShader.SetUniform("u_position", Vector((float)textCmp->GetScreenPosition().X, (float)textCmp->GetScreenPosition().Y, 0)); @@ -1478,7 +1408,7 @@ void TiledForwardRenderer::UIImgui() void TiledForwardRenderer::DebugLightAccum(const SceneView& sceneView) { - float time = (float)(sceneView.WorldData->GetWorldComponent()->GetGameplayTime()); + float time = (float)(sceneView.SceneData->GetWorldComponent()->GetGameplayTime()); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); @@ -1492,9 +1422,8 @@ void TiledForwardRenderer::DebugLightAccum(const SceneView& sceneView) glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, VisibleLightIndicesBuffer); const Matrix& clipFromWorld = sceneView.CameraCmp->GetClipFromWorld(); - for (auto componentsTuple : sceneView.WorldData->IterateComponents()) + for (const auto& [meshCmp] : sceneView.SceneData->IterateComponents()) { - const MeshRenderingComponent* meshCmp = std::get(componentsTuple); const EntityTransform& transform = meshCmp->GetTransform(); const Matrix& worldFromModel = transform.GetWorldFromModel(); DebugLightAccumShader.SetUniform("uClipFromModel", clipFromWorld * worldFromModel); @@ -1604,4 +1533,4 @@ void TiledForwardRenderer::DebugDepthPrepass(const SceneView& sceneView) glBindVertexArray(RDI->PrimitivesQuad->VAO); glDrawArrays(GL_TRIANGLES, 0, 6); glBindVertexArray(0); -} +} \ No newline at end of file diff --git a/PolyEngine/RenderingDevice/OpenGL/Src/TiledForwardRenderer.hpp b/PolyEngine/RenderingDevice/OpenGL/Src/TiledForwardRenderer.hpp index 37991ed8..f9a7ea2c 100644 --- a/PolyEngine/RenderingDevice/OpenGL/Src/TiledForwardRenderer.hpp +++ b/PolyEngine/RenderingDevice/OpenGL/Src/TiledForwardRenderer.hpp @@ -5,6 +5,7 @@ #include #include #include +#include namespace Poly { @@ -74,9 +75,6 @@ namespace Poly { const int MAX_NUM_LIGHTS = 1024; const int MAX_LIGHT_COUNT_DIRECTIONAL = 8; - const unsigned int SHADOW_WIDTH = 4096; - const unsigned int SHADOW_HEIGHT = 4096; - // X and Y work group dimension variables for compute shader GLuint WorkGroupsX = 0; GLuint WorkGroupsY = 0; @@ -94,7 +92,6 @@ namespace Poly { GLuint PostColorBuffer1; GLuint PostColorBufferHalfRes; GLuint LinearDepth; - GLuint DirShadowMap; // IBL textures and cubemaps GLuint PreintegratedBrdfLUT; @@ -104,15 +101,14 @@ namespace Poly { GLuint FBOhdr; GLuint FBOpost0; GLuint FBOpost1; - GLuint FBOShadowDepthMap; // Render pass for IBL environment + ShadowMapPass ShadowMap; EnvCapture SkyboxCapture; RenderTargetPingPong RTBloom; TextureResource* Splash; // Shader programs - GLShaderProgram ShadowMapShader; GLShaderProgram DepthShader; GLShaderProgram LightCullingShader; GLShaderProgram LightAccumulationShader; @@ -161,10 +157,6 @@ namespace Poly { void RenderOpaqueLit(const SceneView& sceneView); void RenderSkybox(const SceneView& sceneView); - - void RenderShadowMap(const SceneView& sceneView); - - Matrix GetProjectionForShadowMap(const DirectionalLightComponent* dirLightCmp) const; void RenderEquiCube(const SceneView& sceneView); diff --git a/PolyEngine/UnitTests/Src/AABoxTests.cpp b/PolyEngine/UnitTests/Src/AABoxTests.cpp index b8e32b45..9d531499 100644 --- a/PolyEngine/UnitTests/Src/AABoxTests.cpp +++ b/PolyEngine/UnitTests/Src/AABoxTests.cpp @@ -6,15 +6,60 @@ using namespace Poly; TEST_CASE("AABox contains", "[AABox]") { - + // point const Vector position(1.f, 2.f, 3.f); const Vector size(1.f, 2.f, 3.f); const AABox ar(position, size); const Vector point(1.f, 3.f, 4.f); REQUIRE(ar.Contains(point) == true); - REQUIRE(ar.Contains(-point) == false); + + // other AABB inside ar AABB on each axis + const AABox aabbX( Vector(1.5f, 0.0f, 0.0f), Vector(0.5f, 0.5f, 0.5f)); + const AABox aabbY( Vector(0.0f, 2.5f, 0.0f), Vector(0.5f, 0.5f, 0.5f)); + const AABox aabbZ( Vector(0.0f, 0.0f, 3.5f), Vector(0.5f, 0.5f, 0.5f)); + const AABox aabbXY(Vector(1.5f, 2.5f, 0.0f), Vector(0.5f, 0.5f, 0.5f)); + + REQUIRE(ar.ContainsX(aabbX) == true); + REQUIRE(ar.ContainsX(aabbY) == false); + REQUIRE(ar.ContainsX(aabbZ) == false); + + REQUIRE(ar.ContainsY(aabbX) == false); + REQUIRE(ar.ContainsY(aabbY) == true); + REQUIRE(ar.ContainsY(aabbZ) == false); + + REQUIRE(ar.ContainsZ(aabbX) == false); + REQUIRE(ar.ContainsZ(aabbY) == false); + REQUIRE(ar.ContainsZ(aabbZ) == true); + + REQUIRE(ar.ContainsXY(aabbXY) == true); + REQUIRE(ar.ContainsXY(aabbX) == false); + REQUIRE(ar.ContainsXY(aabbY) == false); + REQUIRE(ar.ContainsXY(aabbZ) == false); + + // ar AABB inside other AABB on each axis + const AABox aabbX2( Vector::ZERO, Vector(10.0f, 0.5f, 0.5f)); + const AABox aabbY2( Vector::ZERO, Vector(0.5f, 10.0f, 0.5f)); + const AABox aabbZ2( Vector::ZERO, Vector(0.5f, 0.5f, 10.0f)); + const AABox aabbXY2(Vector::ZERO, Vector(10.0f, 10.0f, 0.5f)); + + REQUIRE(ar.ContainsX(aabbX2) == true); + REQUIRE(ar.ContainsX(aabbY2) == false); + REQUIRE(ar.ContainsX(aabbZ2) == false); + + REQUIRE(ar.ContainsY(aabbX2) == false); + REQUIRE(ar.ContainsY(aabbY2) == true); + REQUIRE(ar.ContainsY(aabbZ2) == false); + + REQUIRE(ar.ContainsZ(aabbX2) == false); + REQUIRE(ar.ContainsZ(aabbY2) == false); + REQUIRE(ar.ContainsZ(aabbZ2) == true); + + REQUIRE(ar.ContainsXY(aabbXY2) == true); + REQUIRE(ar.ContainsXY(aabbX2) == false); + REQUIRE(ar.ContainsXY(aabbY2) == false); + REQUIRE(ar.ContainsXY(aabbZ2) == false); } TEST_CASE("AABox collisions with other AABox", "[AABox]") { diff --git a/PolyEngine/UnitTests/Src/MatrixTests.cpp b/PolyEngine/UnitTests/Src/MatrixTests.cpp index fb817b27..0c0ce36a 100644 --- a/PolyEngine/UnitTests/Src/MatrixTests.cpp +++ b/PolyEngine/UnitTests/Src/MatrixTests.cpp @@ -32,9 +32,13 @@ TEST_CASE("Matrix constructors", "[Matrix]") { REQUIRE(m1.Data[i] == i); // look at contructor - Matrix m4(Vector::ZERO, Vector(0.0f, 0.0f, -1.0f), Vector(0.0f, 1.0f, 0.0f)); - for (int i = 0; i<16; ++i) - REQUIRE(m4.Data[i] == (i % 5 == 0 ? 1 : 0)); + float data4[] = { 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f }; + Matrix m4(data4); + Matrix mLa_NZ_PY(Vector::ZERO, Vector( 0.0f, 0.0f, -1.0f), Vector( 0.0f, 1.0f, 0.0f)); + REQUIRE(m4 == mLa_NZ_PY); } TEST_CASE("Matrix comparison operators", "[Matrix]") { @@ -242,23 +246,24 @@ TEST_CASE("Matrix set methods","[Matrix]") { } SECTION("Set rotation with look at method") { - float data2[] = { 1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0, 1, 0, - 0, 0, 0, 1 }; - Matrix m2(data2); + float data1[] = { 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f }; + Matrix m1(data1); // by default we look at -Z with +Y as up axis - m1.SetLookAt(Vector::ZERO, Vector(0.0f, 0.0f, -1.0f), Vector(0.0f, 1.0f, 0.0f)); + Matrix m2; + m2.SetLookAt(Vector::ZERO, Vector(0.0f, 0.0f, -1.0f), Vector(0.0f, 1.0f, 0.0f)); REQUIRE(m1 == m2); - float data3[] = { 0, 0, 1, 0, - 0, 1, 0, 0, - -1, 0, 0, 0, - 0, 0, 0, 1 }; + float data3[] = { 0.0f, 0.0f, -1.0f, 0.0f, + 0.0f, 1.0f, 0.0f, 0.0f, + 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f }; Matrix m3(data3); // rotate by 90_deg about Y axis - m1.SetLookAt(Vector::ZERO, Vector(-1.0f, 0.0f, 0.0f), Vector(0.0f, 1.0f, 0.0f)); - REQUIRE(m1 == m3); + m2.SetLookAt(Vector::ZERO, Vector(-1.0f, 0.0f, 0.0f), Vector(0.0f, 1.0f, 0.0f)); + REQUIRE(m3 == m2); } }