Merge remote-tracking branch 'origin/master' into Animations
# Conflicts: # include/Engine/Rendering/DrawFinalPass.h # resources/Schema/Components.xsd # resources/Schema/Entities/CollisionTestLevel.xml # resources/Schema/Types/Entity.xsd # src/Engine/Collision/Collision.cpp # src/Engine/Rendering/DrawFinalPass.cpp # src/Engine/Rendering/RenderSystem.cpp
This commit is contained in:
@@ -1,18 +0,0 @@
|
||||
#include "Collision/CollidableOctreeSystem.h"
|
||||
|
||||
void CollidableOctreeSystem::Update(double dt)
|
||||
{
|
||||
m_Octree->ClearDynamicObjects();
|
||||
}
|
||||
|
||||
void CollidableOctreeSystem::UpdateComponent(EntityWrapper& entity, ComponentWrapper& component, double dt)
|
||||
{
|
||||
if (entity.HasComponent("AABB")) {
|
||||
boost::optional<EntityAABB> absoluteAABB = Collision::EntityAbsoluteAABB(entity);
|
||||
if (absoluteAABB) {
|
||||
m_Octree->AddDynamicObject(*absoluteAABB);
|
||||
}
|
||||
} else if (entity.HasComponent("Model")) {
|
||||
// TODO: Derive AABB from model
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "Engine/GLM.h"
|
||||
#include "Core/World.h"
|
||||
#include "Rendering/Model.h"
|
||||
#include "imgui/imgui.h"
|
||||
|
||||
namespace Collision
|
||||
{
|
||||
@@ -116,36 +117,79 @@ bool AABBVsAABB(const AABB& a, const AABB& b, glm::vec3& minimumTranslation)
|
||||
return glm::all(axisesIntersecting);
|
||||
}
|
||||
|
||||
bool RayVsTriangle(const Ray& ray,
|
||||
const glm::vec3& v0,
|
||||
const glm::vec3& v1,
|
||||
const glm::vec3& v2,
|
||||
bool trueOnNegativeDistance)
|
||||
{
|
||||
glm::vec3 e1 = v1 - v0; //v1 - v0
|
||||
glm::vec3 e2 = v2 - v0; //v2 - v0
|
||||
glm::vec3 m = ray.Origin() - v0;
|
||||
glm::vec3 MxE1 = glm::cross(m, e1);
|
||||
glm::vec3 DxE2 = glm::cross(ray.Direction(), e2);
|
||||
float DetInv = glm::dot(e1, DxE2);
|
||||
if (std::abs(DetInv) < FLT_EPSILON) {
|
||||
return false;
|
||||
}
|
||||
DetInv = 1.0f / DetInv;
|
||||
float u = glm::dot(m, DxE2) * DetInv;
|
||||
float v = glm::dot(ray.Direction(), MxE1) * DetInv;
|
||||
//u,v can be very close to 0 but still negative sometimes. added a deltafactor to compensate for that problem
|
||||
if ((u + 0.001f) < 0 || (v + 0.001f) < 0 || 1 < u + v) {
|
||||
return false;
|
||||
}
|
||||
//Here, u and v are positive, u+v <= 1, and if distance is positive - triangle is hit.
|
||||
return trueOnNegativeDistance || 0 <= glm::dot(e2, MxE1) * DetInv;
|
||||
}
|
||||
|
||||
bool RayVsModel(const Ray& ray,
|
||||
const std::vector<RawModel::Vertex>& modelVertices,
|
||||
const std::vector<unsigned int>& modelIndices)
|
||||
{
|
||||
for (int i = 0; i < modelIndices.size(); ++i) {
|
||||
glm::vec3 v0 = modelVertices[modelIndices[i]].Position;
|
||||
glm::vec3 e1 = modelVertices[modelIndices[++i]].Position - v0; //v1 - v0
|
||||
glm::vec3 e2 = modelVertices[modelIndices[++i]].Position - v0; //v2 - v0
|
||||
glm::vec3 m = ray.Origin() - v0;
|
||||
glm::vec3 MxE1 = glm::cross(m, e1);
|
||||
glm::vec3 DxE2 = glm::cross(ray.Direction(), e2);
|
||||
float DetInv = glm::dot(e1, DxE2);
|
||||
if (std::abs(DetInv) < FLT_EPSILON) {
|
||||
continue;
|
||||
}
|
||||
DetInv = 1.0f / DetInv;
|
||||
float u = glm::dot(m, DxE2) * DetInv;
|
||||
float v = glm::dot(ray.Direction(), MxE1) * DetInv;
|
||||
//u,v can be very close to 0 but still negative sometimes. added a deltafactor to compensate for that problem
|
||||
if ((u + 0.001f) < 0 || (v + 0.001f) < 0 || 1 < u + v) {
|
||||
continue;
|
||||
}
|
||||
//Here, u and v are positive, u+v <= 1, and if distance is positive - triangle is hit.
|
||||
if (0 <= glm::dot(e2, MxE1) * DetInv) {
|
||||
glm::vec3 v1 = modelVertices[modelIndices[++i]].Position;
|
||||
glm::vec3 v2 = modelVertices[modelIndices[++i]].Position;
|
||||
if (RayVsTriangle(ray, v0, v1, v2)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool RayVsTriangle(const Ray& ray,
|
||||
const glm::vec3& v0,
|
||||
const glm::vec3& v1,
|
||||
const glm::vec3& v2,
|
||||
float& outDistance,
|
||||
float& outUCoord,
|
||||
float& outVCoord,
|
||||
bool trueOnNegativeDistance)
|
||||
{
|
||||
glm::vec3 e1 = v1 - v0; //v1 - v0
|
||||
glm::vec3 e2 = v2 - v0; //v2 - v0
|
||||
glm::vec3 m = ray.Origin() - v0;
|
||||
glm::vec3 MxE1 = glm::cross(m, e1);
|
||||
glm::vec3 DxE2 = glm::cross(ray.Direction(), e2);//pVec
|
||||
float DetInv = glm::dot(e1, DxE2);
|
||||
if (std::abs(DetInv) < FLT_EPSILON) {
|
||||
return false;
|
||||
}
|
||||
DetInv = 1.0f / DetInv;
|
||||
float dist = glm::dot(e2, MxE1) * DetInv;
|
||||
if (dist >= outDistance) {
|
||||
return false;
|
||||
}
|
||||
outDistance = dist;
|
||||
outUCoord = glm::dot(m, DxE2) * DetInv;
|
||||
outVCoord = glm::dot(ray.Direction(), MxE1) * DetInv;
|
||||
|
||||
//u,v can be very close to 0 but still negative sometimes. added a deltafactor to compensate for that problem
|
||||
//If u and v are positive, u+v <= 1, dist is positive, and less than closest.
|
||||
return (0 <= (outUCoord + 0.001f) && 0 <= (outVCoord + 0.001f) && outUCoord + outVCoord <= 1 && (trueOnNegativeDistance || 0 <= dist));
|
||||
}
|
||||
|
||||
bool RayVsModel(const Ray& ray,
|
||||
const std::vector<RawModel::Vertex>& modelVertices,
|
||||
const std::vector<unsigned int>& modelIndices,
|
||||
@@ -157,26 +201,12 @@ bool RayVsModel(const Ray& ray,
|
||||
bool hit = false;
|
||||
for (int i = 0; i < modelIndices.size(); ++i) {
|
||||
glm::vec3 v0 = modelVertices[modelIndices[i]].Position;
|
||||
glm::vec3 e1 = modelVertices[modelIndices[++i]].Position - v0; //v1 - v0
|
||||
glm::vec3 e2 = modelVertices[modelIndices[++i]].Position - v0; //v2 - v0
|
||||
glm::vec3 m = ray.Origin() - v0;
|
||||
glm::vec3 MxE1 = glm::cross(m, e1);
|
||||
glm::vec3 DxE2 = glm::cross(ray.Direction(), e2);//pVec
|
||||
float DetInv = glm::dot(e1, DxE2);
|
||||
if (std::abs(DetInv) < FLT_EPSILON) {
|
||||
continue;
|
||||
}
|
||||
DetInv = 1.0f / DetInv;
|
||||
float dist = glm::dot(e2, MxE1) * DetInv;
|
||||
if (dist >= outDistance) {
|
||||
continue;
|
||||
}
|
||||
float u = glm::dot(m, DxE2) * DetInv;
|
||||
float v = glm::dot(ray.Direction(), MxE1) * DetInv;
|
||||
|
||||
//u,v can be very close to 0 but still negative sometimes. added a deltafactor to compensate for that problem
|
||||
//If u and v are positive, u+v <= 1, dist is positive, and less than closest.
|
||||
if (0 <= (u + 0.001f) && 0 <= (v + 0.001f) && u + v <= 1 && 0 <= dist) {
|
||||
glm::vec3 v1 = modelVertices[modelIndices[++i]].Position;
|
||||
glm::vec3 v2 = modelVertices[modelIndices[++i]].Position;
|
||||
float dist;
|
||||
float u;
|
||||
float v;
|
||||
if (RayVsTriangle(ray, v0, v1, v2, dist, u, v)) {
|
||||
outDistance = dist;
|
||||
outUCoord = u;
|
||||
outVCoord = v;
|
||||
@@ -199,74 +229,365 @@ bool RayVsModel(const Ray& ray,
|
||||
return hit;
|
||||
}
|
||||
|
||||
bool AABBvsTriangles(const AABB& box, const std::vector<RawModel::Vertex>& modelVertices, const std::vector<unsigned int>& modelIndices, const glm::mat4& modelMatrix, glm::vec3& outResolutionVector)
|
||||
constexpr inline int signNonZero(float x)
|
||||
{
|
||||
bool hit = false;
|
||||
|
||||
return x < 0 ? -1 : 1;
|
||||
}
|
||||
|
||||
inline glm::vec3 signNonZero(const glm::vec3& x)
|
||||
{
|
||||
glm::vec3 r;
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
r[i] = (float)signNonZero(x[i]);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool vectorHasLength(const T& vec)
|
||||
{
|
||||
return glm::any(glm::greaterThan(glm::abs(vec), T(0.0001f)));
|
||||
}
|
||||
|
||||
bool rectangleVsTriangle(const glm::vec2& boxMin,
|
||||
const glm::vec2& boxMax,
|
||||
const std::array<glm::vec2, 3>& triPos,
|
||||
glm::vec2& resolutionDirection,
|
||||
float& resolutionDistanceSq,
|
||||
bool& pushedFromTriNormal)
|
||||
{
|
||||
pushedFromTriNormal = false;
|
||||
resolutionDistanceSq = INFINITY;
|
||||
//Project along box normals (coordinate axes, since it's axis-aligned).
|
||||
for (int ax = 0; ax < 2; ++ax) {
|
||||
float minTri = INFINITY;
|
||||
float maxTri = -INFINITY;
|
||||
for (const glm::vec2& t : triPos) {
|
||||
minTri = std::min(t[ax], minTri);
|
||||
maxTri = std::max(t[ax], maxTri);
|
||||
}
|
||||
if (boxMax[ax] <= minTri || maxTri <= boxMin[ax]) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//Here: maxBox > minTri && minBox < maxTri
|
||||
//Left is negative.
|
||||
float leftRes = minTri - boxMax[ax];
|
||||
float rightRes = maxTri - boxMin[ax];
|
||||
float push = rightRes < -leftRes ? rightRes : leftRes;
|
||||
float absPushSq = abs(push);
|
||||
absPushSq *= absPushSq;
|
||||
|
||||
if (absPushSq < resolutionDistanceSq) {
|
||||
resolutionDistanceSq = absPushSq;
|
||||
resolutionDirection[1 - ax] = 0.f;
|
||||
resolutionDirection[ax] = push;
|
||||
}
|
||||
}
|
||||
//Project along triangle normals.
|
||||
//Put edges into normal vector, make normals in the loop.
|
||||
std::array<glm::vec2, 3> triNormals = {
|
||||
triPos[1] - triPos[0],
|
||||
triPos[2] - triPos[1],
|
||||
triPos[0] - triPos[2]
|
||||
};
|
||||
std::array<glm::vec2, 4> boxPos = {
|
||||
boxMax,
|
||||
glm::vec2(boxMax.x, boxMin.y),
|
||||
glm::vec2(boxMin.x, boxMax.y),
|
||||
boxMin
|
||||
};
|
||||
for (auto& normal : triNormals) {
|
||||
if (!vectorHasLength(normal)) {
|
||||
continue;
|
||||
}
|
||||
//Rotate edge to a normal.
|
||||
normal = glm::normalize(glm::vec2(-normal.y, normal.x));
|
||||
//Project triangle onto the normal.
|
||||
float minTri = INFINITY;
|
||||
float maxTri = -INFINITY;
|
||||
for (const glm::vec2& point : triPos) {
|
||||
float dot = glm::dot(normal, point);
|
||||
minTri = std::min(dot, minTri);
|
||||
maxTri = std::max(dot, maxTri);
|
||||
}
|
||||
//Project box onto the normal.
|
||||
float minBox = INFINITY;
|
||||
float maxBox = -INFINITY;
|
||||
for (const glm::vec2& point : boxPos) {
|
||||
float dot = glm::dot(normal, point);
|
||||
minBox = std::min(dot, minBox);
|
||||
maxBox = std::max(dot, maxBox);
|
||||
}
|
||||
if (maxBox <= minTri || maxTri <= minBox) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//Here: maxBox > minTri && minBox < maxTri
|
||||
//Left is negative.
|
||||
float leftRes = minTri - maxBox;
|
||||
float rightRes = maxTri - minBox;
|
||||
float push = rightRes < -leftRes ? rightRes : leftRes;
|
||||
float absPushSq = abs(push);
|
||||
absPushSq *= absPushSq;
|
||||
|
||||
if (absPushSq < resolutionDistanceSq) {
|
||||
resolutionDistanceSq = absPushSq;
|
||||
resolutionDirection = push * normal;
|
||||
pushedFromTriNormal = true;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
constexpr float SlopeConstant(float degrees)
|
||||
{
|
||||
return (1.0f - degrees / 90.f);
|
||||
}
|
||||
|
||||
//Returns true if the angle between horizon and the collision surface is less than 45 degrees.
|
||||
constexpr bool FaceIsGround(float faceNormalY)
|
||||
{
|
||||
//TODO: Perhaps the 45 degrees could be saved in a component or in the config..
|
||||
return faceNormalY > SlopeConstant(45.0f);
|
||||
}
|
||||
|
||||
//An array containing 3 int pairs { 0, 2 }, { 0, 1 }, { 1, 2 }
|
||||
constexpr std::array<std::pair<int, int>, 3> dimensionPairs({ std::pair<int, int>(0, 2), std::pair<int, int>(0, 1), std::pair<int, int>(1, 2) });
|
||||
|
||||
bool AABBvsTriangle(const AABB& box,
|
||||
const std::array<glm::vec3, 3>& triPos,
|
||||
const glm::vec3& originalBoxVelocity,
|
||||
float verticalStepHeight,
|
||||
bool& isOnGround,
|
||||
glm::vec3& boxVelocity,
|
||||
glm::vec3& outResolution)
|
||||
{
|
||||
//Check so we don't have a zero area triangle when calculating the normal.
|
||||
//Also, don't check a triangle facing away from the player.
|
||||
//Less checks, and we should be able to walk out from models if we are trapped inside.
|
||||
glm::vec3 triNormal = glm::cross(triPos[1] - triPos[0], triPos[2] - triPos[0]);
|
||||
if (!vectorHasLength(triNormal) || (glm::dot(triNormal, originalBoxVelocity) > 0)) {
|
||||
return false;
|
||||
}
|
||||
triNormal = glm::normalize(triNormal);
|
||||
|
||||
enum BoxTriResolveCase
|
||||
{
|
||||
ResolveDimX,
|
||||
ResolveDimY,
|
||||
ResolveDimZ,
|
||||
Line, //Box edge colliding with triangle line.
|
||||
Corner //Box corner colliding with the triangle face.
|
||||
};
|
||||
struct Resolution
|
||||
{
|
||||
Resolution()
|
||||
: DistanceSq(INFINITY)
|
||||
, Vector(0.f)
|
||||
{}
|
||||
BoxTriResolveCase Case;
|
||||
float DistanceSq;
|
||||
glm::vec3 Vector;
|
||||
};
|
||||
//The smallest resolution that solves the collision.
|
||||
Resolution resolveShortest;
|
||||
//The smallest resolution that solves the collision, that resolves upwards.
|
||||
Resolution resolveUpwards;
|
||||
//If player stands on the ground and collides with a ground triangle,
|
||||
//we might step up onto it if the step is small enough.
|
||||
bool canStairStepUp = isOnGround && FaceIsGround(triNormal.y);
|
||||
|
||||
const glm::vec3& origin = box.Origin();
|
||||
const glm::vec3& half = box.HalfSize();
|
||||
const glm::vec3& min = box.MinCorner();
|
||||
const glm::vec3& max = box.MaxCorner();
|
||||
|
||||
outResolutionVector.x = INFINITY;
|
||||
|
||||
for (int i = 0; i < modelIndices.size(); ++i) {
|
||||
glm::vec3 p = modelVertices[i].Position;
|
||||
p = glm::vec3(modelMatrix * glm::vec4(p.x, p.y, p.z, 1));
|
||||
|
||||
float distFromOrigin = glm::abs(origin.x - p.x);
|
||||
float penetration = box.HalfSize().x - distFromOrigin;
|
||||
if (penetration > 0 && penetration < glm::abs(outResolutionVector.x)) {
|
||||
if (p.x > origin.x) {
|
||||
outResolutionVector.x = -penetration;
|
||||
} else {
|
||||
outResolutionVector.x = penetration;
|
||||
//For each projection in xy-, xz-, and yx-planes.
|
||||
for (std::pair<int, int> dim : dimensionPairs) {
|
||||
//2D Triangle.
|
||||
//Project triangle.
|
||||
std::array<glm::vec2, 3> t2D = {
|
||||
glm::vec2(triPos[0][dim.first], triPos[0][dim.second]),
|
||||
glm::vec2(triPos[1][dim.first], triPos[1][dim.second]),
|
||||
glm::vec2(triPos[2][dim.first], triPos[2][dim.second])
|
||||
};
|
||||
//Project box.
|
||||
glm::vec2 boxMin(min[dim.first], min[dim.second]);
|
||||
glm::vec2 boxMax(max[dim.first], max[dim.second]);
|
||||
glm::vec2 resolutionVector;
|
||||
float resolutionDist;
|
||||
bool pushedFromTriangleLine;
|
||||
//if projections don't overlap, return false.
|
||||
if (!rectangleVsTriangle(boxMin, boxMax, t2D, resolutionVector, resolutionDist, pushedFromTriangleLine)) {
|
||||
return false;
|
||||
} else {
|
||||
//Overwrite the smallest resolution if this is smaller.
|
||||
if (resolutionDist < resolveShortest.DistanceSq) {
|
||||
resolveShortest.Vector = glm::vec3(0.f);
|
||||
resolveShortest.Vector[dim.first] = resolutionVector.x;
|
||||
resolveShortest.Vector[dim.second] = resolutionVector.y;
|
||||
resolveShortest.DistanceSq = resolutionDist;
|
||||
//If we pushed away from triangle line (edge), or if we
|
||||
//move the player along one coordinate axis (pick the dimension that isn't zero).
|
||||
resolveShortest.Case = pushedFromTriangleLine ? Line : static_cast<BoxTriResolveCase>((abs(resolveShortest.Vector[dim.first]) < 0.0001f) ? dim.second : dim.first);
|
||||
}
|
||||
//Overwrite the smallest upward resolution if this is smaller, and resolves upwards.
|
||||
constexpr int yAxis = 1;
|
||||
bool resIsUpwardsIn3D = dim.first == yAxis && resolutionVector.x > 0 || dim.second == yAxis && resolutionVector.y > 0;
|
||||
if (canStairStepUp && resIsUpwardsIn3D && resolutionDist < resolveUpwards.DistanceSq) {
|
||||
resolveUpwards.Vector = glm::vec3(0.f);
|
||||
resolveUpwards.Vector[dim.first] = resolutionVector.x;
|
||||
resolveUpwards.Vector[dim.second] = resolutionVector.y;
|
||||
resolveUpwards.DistanceSq = resolutionDist;
|
||||
//If we pushed away from triangle line (edge), or if we
|
||||
//move the player along one coordinate axis (pick the dimension that isn't zero).
|
||||
resolveUpwards.Case = pushedFromTriangleLine ? Line : static_cast<BoxTriResolveCase>((abs(resolveUpwards.Vector[dim.first]) < 0.0001f) ? dim.second : dim.first);
|
||||
}
|
||||
hit = true;
|
||||
}
|
||||
//glm::vec3 pLocal = origin - p;
|
||||
//for (int axis = 0; axis < 3; ++axis) {
|
||||
// if (p[axis] < min[axis] || p[axis] > max[axis]) {
|
||||
// continue;
|
||||
// }
|
||||
|
||||
// if (glm::abs(pLocal[axis]) < box.HalfSize()[axis]) {
|
||||
// outResolutionVector[axis] = (glm::sign(pLocal[axis]) * box.HalfSize()[axis]) - pLocal[axis];
|
||||
// hit = true;
|
||||
// }
|
||||
//}
|
||||
}
|
||||
|
||||
//If the triangle does intersect any of the cube diagonals, it will
|
||||
//intersect the cube diagonal that comes
|
||||
//closest to being perpendicular to the plane of the triangle.
|
||||
glm::vec3 diagonal = signNonZero(triNormal) * half;
|
||||
//The triangle plane contains all points P in dot(triNormal, P) == dot(triNormal, v0)
|
||||
//The diagonal line contains all points P in P = origin + diagonal * t.
|
||||
float t = glm::dot(triNormal, triPos[0] - origin) / glm::dot(triNormal, diagonal);
|
||||
//If intersection point between plane and diagonal is within the box.
|
||||
if (glm::abs(t) > 1) {
|
||||
return false;
|
||||
}
|
||||
glm::vec3 cornerResolution = (1+t) * diagonal;
|
||||
//Overwrite the smallest resolution if cornerResolution is smaller.
|
||||
float lenSq = glm::length2(cornerResolution);
|
||||
if (lenSq < resolveShortest.DistanceSq) {
|
||||
resolveShortest.Vector = cornerResolution;
|
||||
resolveShortest.Case = Corner;
|
||||
}
|
||||
if (canStairStepUp && cornerResolution.y > 0 && lenSq < resolveUpwards.DistanceSq) {
|
||||
resolveUpwards.Vector = cornerResolution;
|
||||
resolveUpwards.Case = Corner;
|
||||
resolveUpwards.DistanceSq = lenSq;
|
||||
}
|
||||
|
||||
//Force the resolution upwards if it is smaller than the threshold verticalStepHeight.
|
||||
//Else take the shortest resolution.
|
||||
bool takeUp = resolveUpwards.Vector.y > 0 && resolveUpwards.Vector.y < verticalStepHeight;
|
||||
Resolution& bestResolve = takeUp ? resolveUpwards : resolveShortest;
|
||||
outResolution = bestResolve.Vector;
|
||||
|
||||
glm::vec3 projNorm;
|
||||
switch (bestResolve.Case) {
|
||||
case ResolveDimY:
|
||||
boxVelocity.y = 0.f;
|
||||
if (outResolution.y > 0)
|
||||
isOnGround = true;
|
||||
case ResolveDimX:
|
||||
case ResolveDimZ:
|
||||
//If we get here, the resolution is along one coordinate axis.
|
||||
//set velocity to 0 in y if it is along y-axis.
|
||||
return true;
|
||||
case Line:
|
||||
projNorm = glm::normalize(outResolution);
|
||||
break;
|
||||
case Corner:
|
||||
projNorm = triNormal;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
//If the collision was not on steep wall or similarly (e.g. walking on the ground), force resolution in y only.
|
||||
if (FaceIsGround(projNorm.y)) {
|
||||
//Ensure that the player always is moved upwards, instead of sliding down.
|
||||
float len = glm::length(outResolution);
|
||||
float ang = glm::half_pi<float>() - glm::acos(outResolution.y / len);
|
||||
if (len > 0.0000001f && ang > 0.0000001f) {
|
||||
outResolution.x = 0;
|
||||
outResolution.y = len / glm::sin(ang);
|
||||
outResolution.z = 0;
|
||||
}
|
||||
//Also zero the vertical velocity, if it is positive, else project it onto the normal.
|
||||
//Project the velocity onto the normal of the hit line/face.
|
||||
//w = v - <v,n>*n, |n|==1.
|
||||
boxVelocity.y = std::min(boxVelocity.y - glm::dot(boxVelocity, projNorm) * projNorm.y, 0.f);
|
||||
isOnGround = true;
|
||||
} else {
|
||||
//Enter here if the triangle is a steep slope, and it is not facing downwards.
|
||||
//Project the velocity onto the normal of the hit line/face.
|
||||
//w = v - <v,n>*n, |n|==1.
|
||||
//"ice cream"-effect, air resistance + projected velocity.
|
||||
if (!isOnGround) {
|
||||
boxVelocity = boxVelocity - glm::dot(boxVelocity, projNorm) * projNorm;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AABBvsTriangles(const AABB& box,
|
||||
const std::vector<RawModel::Vertex>& modelVertices,
|
||||
const std::vector<unsigned int>& modelIndices,
|
||||
const glm::mat4& modelMatrix,
|
||||
glm::vec3& boxVelocity,
|
||||
float verticalStepHeight,
|
||||
bool& isOnGround,
|
||||
glm::vec3& outResolutionVector)
|
||||
{
|
||||
bool hit = false;
|
||||
|
||||
bool everHitTheGround = false;
|
||||
AABB newBox = box;
|
||||
outResolutionVector = glm::vec3(0.f);
|
||||
glm::vec3 originalBoxVelocity(boxVelocity);
|
||||
for (int i = 0; i < modelIndices.size(); ) {
|
||||
std::array<glm::vec3, 3> triVertices = {
|
||||
Transform::TransformPoint(modelVertices[modelIndices[i++]].Position, modelMatrix),
|
||||
Transform::TransformPoint(modelVertices[modelIndices[i++]].Position, modelMatrix),
|
||||
Transform::TransformPoint(modelVertices[modelIndices[i++]].Position, modelMatrix)
|
||||
};
|
||||
glm::vec3 outVec;
|
||||
bool collideWithGround = isOnGround;
|
||||
if (AABBvsTriangle(newBox, triVertices, originalBoxVelocity, verticalStepHeight, collideWithGround, boxVelocity, outVec)) {
|
||||
hit = true;
|
||||
outResolutionVector += outVec;
|
||||
newBox = AABB::FromOriginSize(newBox.Origin() + outVec, newBox.Size());
|
||||
if (collideWithGround) {
|
||||
everHitTheGround = isOnGround = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!everHitTheGround) {
|
||||
isOnGround = false;
|
||||
}
|
||||
return hit;
|
||||
}
|
||||
|
||||
bool attachAABBComponentFromModel(World* world, EntityID id)
|
||||
bool AttachAABBComponentFromModel(EntityWrapper entity)
|
||||
{
|
||||
if (!world->HasComponent(id, "Model")) {
|
||||
if (!entity.HasComponent("Model")) {
|
||||
return false;
|
||||
}
|
||||
ComponentWrapper model = world->GetComponent(id, "Model");
|
||||
ComponentWrapper collision = world->AttachComponent(id, "AABB");
|
||||
Model* modelRes = ResourceManager::Load<Model>(model["Resource"]);
|
||||
if (modelRes == nullptr) {
|
||||
//Derive AABB from model
|
||||
RawModel* model;
|
||||
try {
|
||||
model = ResourceManager::Load<RawModel, true>(entity["Model"]["Resource"]);
|
||||
} catch (const std::exception&) {
|
||||
return false;
|
||||
}
|
||||
|
||||
glm::mat4 modelMatrix = modelRes->Matrix();
|
||||
|
||||
glm::vec3 mini = glm::vec3(INFINITY, INFINITY, INFINITY);
|
||||
glm::vec3 maxi = glm::vec3(-INFINITY, -INFINITY, -INFINITY);
|
||||
glm::vec3 mini(INFINITY);
|
||||
glm::vec3 maxi(-INFINITY);
|
||||
for (const auto& v : model->m_Vertices) {
|
||||
mini = glm::min(mini, v.Position);
|
||||
for (unsigned int i = 0; i < modelRes->NumberOfVertices(); i++) {
|
||||
const auto& v = modelRes->Vertices()[i];
|
||||
const auto& wPos = modelMatrix * glm::vec4(v.Position.x, v.Position.y, v.Position.z, 1);
|
||||
maxi.x = std::max(wPos.x, maxi.x);
|
||||
maxi.y = std::max(wPos.y, maxi.y);
|
||||
maxi.z = std::max(wPos.z, maxi.z);
|
||||
mini.x = std::min(wPos.x, mini.x);
|
||||
mini.y = std::min(wPos.y, mini.y);
|
||||
mini.z = std::min(wPos.z, mini.z);
|
||||
}
|
||||
collision["Origin"] = 0.5f * (maxi + mini);
|
||||
collision["Size"] = maxi - mini;
|
||||
|
||||
entity.AttachComponent("AABB");
|
||||
entity["AABB"]["Origin"] = 0.5f * (maxi + mini);
|
||||
entity["AABB"]["Size"] = maxi - mini;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "Collision/Collision.h"
|
||||
#include "Collision/CollisionSystem.h"
|
||||
#include "Core/AABB.h"
|
||||
#include "Rendering/Model.h"
|
||||
|
||||
void CollisionSystem::UpdateComponent(EntityWrapper& entity, ComponentWrapper& component, double dt)
|
||||
{
|
||||
@@ -19,39 +20,48 @@ void CollisionSystem::UpdateComponent(EntityWrapper& entity, ComponentWrapper& c
|
||||
// Collide against octree items
|
||||
m_OctreeResult.clear();
|
||||
m_Octree->ObjectsInSameRegion(*boundingBox, m_OctreeResult);
|
||||
bool everHitTheGround = false;
|
||||
for (auto& boxB : m_OctreeResult) {
|
||||
glm::vec3 resolutionVector;
|
||||
if (boxA.Entity == boxB.Entity) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (Collision::AABBVsAABB(boxA, boxB, resolutionVector)) {
|
||||
if (boxB.Entity.HasComponent("Model") && Collision::AABBVsAABB(boxA, boxB)) {
|
||||
//Here we know boxB is a entity with Collideable, AABB, and Model.
|
||||
RawModel* model;
|
||||
try {
|
||||
model = ResourceManager::Load<RawModel, true>(boxB.Entity["Model"]["Resource"]);
|
||||
} catch (const std::exception&) {
|
||||
continue;
|
||||
}
|
||||
|
||||
glm::mat4 modelMatrix = Transform::ModelMatrix(boxB.Entity);
|
||||
|
||||
glm::vec3 inOutVelocity = (glm::vec3)cPhysics["Velocity"];
|
||||
bool isOnGround = (bool)cPhysics["IsOnGround"];
|
||||
float verticalStepHeight = (float)(double)cPhysics["VerticalStepHeight"];
|
||||
if (Collision::AABBvsTriangles(boxA, model->m_Vertices, model->m_Indices, modelMatrix, inOutVelocity, verticalStepHeight, isOnGround, resolutionVector)) {
|
||||
(glm::vec3&)cTransform["Position"] += resolutionVector;
|
||||
cPhysics["Velocity"] = inOutVelocity;
|
||||
if (isOnGround) {
|
||||
everHitTheGround = true;
|
||||
(bool)cPhysics["IsOnGround"] = true;
|
||||
}
|
||||
}
|
||||
} else if (Collision::AABBVsAABB(boxA, boxB, resolutionVector)) {
|
||||
//Enter here if boxB has no Model.
|
||||
(glm::vec3&)cTransform["Position"] += resolutionVector;
|
||||
if (resolutionVector.y > 0) {
|
||||
everHitTheGround = true;
|
||||
(bool)cPhysics["IsOnGround"] = true;
|
||||
((glm::vec3&)cPhysics["Velocity"]).y = 0.f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// HACK: Temporarily collide against all collidable models since they're not in the octree yet
|
||||
//auto otherCollidables = world->GetComponents("Model");
|
||||
//for (auto& cModel : *otherCollidables) {
|
||||
// if (cModel.EntityID == entity) {
|
||||
// continue;
|
||||
// }
|
||||
// if (!world->HasComponent(cModel.EntityID, "Collidable")) {
|
||||
// continue;
|
||||
// }
|
||||
|
||||
// auto absPosition = RenderQueueFactory::AbsolutePosition(world, cModel.EntityID);
|
||||
// auto absOrientation = RenderQueueFactory::AbsoluteOrientation(world, cModel.EntityID);
|
||||
// auto absScale = RenderQueueFactory::AbsoluteScale(world, cModel.EntityID);
|
||||
// glm::mat4 modelMatrix = glm::translate(absPosition); // *glm::toMat4(absOrientation) * glm::scale(absScale);
|
||||
|
||||
// auto model = ResourceManager::Load<Model>(cModel["Resource"]);
|
||||
// glm::vec3 resolutionVector;
|
||||
// if (Collision::AABBvsTriangles(boxA, model->m_Vertices, model->m_Indices, modelMatrix, resolutionVector)) {
|
||||
// (glm::vec3&)cTransform["Position"] += resolutionVector;
|
||||
// }
|
||||
//}
|
||||
}
|
||||
//This should apply air friction and such, iff zero models were hit.
|
||||
if (!everHitTheGround) {
|
||||
(bool)cPhysics["IsOnGround"] = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
#include "Collision/FillOctreeSystem.h"
|
||||
|
||||
void FillOctreeSystem::Update(double dt)
|
||||
{
|
||||
m_Octree->ClearDynamicObjects();
|
||||
}
|
||||
|
||||
void FillOctreeSystem::UpdateComponent(EntityWrapper& entity, ComponentWrapper& component, double dt)
|
||||
{
|
||||
if (!entity.HasComponent("AABB")) {
|
||||
//Derive AABB from model.
|
||||
if (!Collision::AttachAABBComponentFromModel(entity)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
boost::optional<EntityAABB> absoluteAABB = Collision::EntityAbsoluteAABB(entity);
|
||||
if (absoluteAABB) {
|
||||
m_Octree->AddDynamicObject(*absoluteAABB);
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,10 @@
|
||||
void TriggerSystem::UpdateComponent(EntityWrapper& triggerEntity, ComponentWrapper& cTrigger, double dt)
|
||||
{
|
||||
// The trigger *should* have a bounding box, or something, to test against so it can be triggered.
|
||||
// If it doesn't, add one as big as the model for now, then size can be modified in editor if necessary.
|
||||
if (!triggerEntity.HasComponent("AABB")) {
|
||||
Collision::AttachAABBComponentFromModel(triggerEntity);
|
||||
}
|
||||
boost::optional<EntityAABB> triggerBox = Collision::EntityAbsoluteAABB(triggerEntity);
|
||||
if (!triggerBox) {
|
||||
return;
|
||||
|
||||
@@ -16,6 +16,15 @@ bool EntityWrapper::HasComponent(const std::string& componentName)
|
||||
return World->HasComponent(ID, componentName);
|
||||
}
|
||||
|
||||
void EntityWrapper::AttachComponent(const char* componentName)
|
||||
{
|
||||
if (!Valid()) {
|
||||
LOG_WARNING("Could not attach \"%s\" component to #%i, entity is not valid.", componentName, ID);
|
||||
return;
|
||||
}
|
||||
World->AttachComponent(ID, componentName);
|
||||
}
|
||||
|
||||
EntityWrapper EntityWrapper::Parent()
|
||||
{
|
||||
if (this->World == nullptr || this->ID == EntityID_Invalid) {
|
||||
|
||||
@@ -275,9 +275,4 @@ std::vector<int> Child::childIndicesContainingBox(const AABB& box) const
|
||||
}
|
||||
}
|
||||
|
||||
bool Child::hasChildren() const
|
||||
{
|
||||
return m_Children[0] != nullptr;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -97,3 +97,7 @@ glm::mat4 Transform::ModelMatrix(EntityID entity, World* world)
|
||||
return modelMatrix;
|
||||
}
|
||||
|
||||
glm::vec3 Transform::TransformPoint(const glm::vec3& point, const glm::mat4& matrix)
|
||||
{
|
||||
return glm::vec3(matrix * glm::vec4(point.x, point.y, point.z, 1));
|
||||
}
|
||||
@@ -56,9 +56,9 @@ void EditorRenderSystem::Update(double dt)
|
||||
for (auto matGroup : model->MaterialGroups()) {
|
||||
std::shared_ptr<ModelJob> modelJob = std::make_shared<ModelJob>(model, scene.Camera, modelMatrix, matGroup, cModel, entity.World, glm::vec4(0), 0.f);
|
||||
if (cModel["Transparent"]) {
|
||||
scene.TransparentObjects.push_back(modelJob);
|
||||
scene.Jobs.TransparentObjects.push_back(modelJob);
|
||||
} else {
|
||||
scene.OpaqueObjects.push_back(modelJob);
|
||||
scene.Jobs.OpaqueObjects.push_back(modelJob);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -75,7 +75,7 @@ void EditorRenderSystem::Update(double dt)
|
||||
EntityWrapper entity(m_World, cPointLight.EntityID);
|
||||
ComponentWrapper& cTransform = entity["Transform"];
|
||||
std::shared_ptr<PointLightJob> pointLightJob = std::make_shared<PointLightJob>(cTransform, cPointLight, entity.World);
|
||||
scene.PointLightJobs.push_back(pointLightJob);
|
||||
scene.Jobs.PointLight.push_back(pointLightJob);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,8 +6,6 @@ DrawColorCorrectionPass::DrawColorCorrectionPass(IRenderer* renderer)
|
||||
|
||||
m_ScreenQuad = ResourceManager::Load<Model>("Models/Core/ScreenQuad.mesh");
|
||||
|
||||
//m_Exposure = 0.4; //TODO: Renderer: Fixa så att denna går att ändra på genom komponent eller setting.
|
||||
|
||||
InitializeShaderPrograms();
|
||||
}
|
||||
|
||||
@@ -20,7 +18,7 @@ void DrawColorCorrectionPass::InitializeShaderPrograms()
|
||||
m_ColorCorrectionProgram->Link();
|
||||
}
|
||||
|
||||
void DrawColorCorrectionPass::Draw(GLuint sceneTexture, GLuint bloomTexture, GLfloat gamma, GLfloat exposure)
|
||||
void DrawColorCorrectionPass::Draw(GLuint sceneTexture, GLuint bloomTexture, GLuint sceneTextureLowRes, GLuint bloomTextureLowRes, GLfloat gamma, GLfloat exposure)
|
||||
{
|
||||
//glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
GLERROR("DrawScreenQuadPass::Draw: Pre");
|
||||
@@ -35,6 +33,10 @@ void DrawColorCorrectionPass::Draw(GLuint sceneTexture, GLuint bloomTexture, GLf
|
||||
glBindTexture(GL_TEXTURE_2D, sceneTexture);
|
||||
glActiveTexture(GL_TEXTURE1);
|
||||
glBindTexture(GL_TEXTURE_2D, bloomTexture);
|
||||
glActiveTexture(GL_TEXTURE2);
|
||||
glBindTexture(GL_TEXTURE_2D, sceneTextureLowRes);
|
||||
glActiveTexture(GL_TEXTURE3);
|
||||
glBindTexture(GL_TEXTURE_2D, bloomTextureLowRes);
|
||||
|
||||
glBindVertexArray(m_ScreenQuad->VAO);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_ScreenQuad->ElementBuffer);
|
||||
|
||||
@@ -2,8 +2,10 @@
|
||||
|
||||
DrawFinalPass::DrawFinalPass(IRenderer* renderer, LightCullingPass* lightCullingPass)
|
||||
{
|
||||
//TODO: Make sure that uniforms are not sent into shader if not needed.
|
||||
m_Renderer = renderer;
|
||||
m_LightCullingPass = lightCullingPass;
|
||||
m_ShieldPixelRate = 8;
|
||||
InitializeTextures();
|
||||
InitializeShaderPrograms();
|
||||
InitializeFrameBuffers();
|
||||
@@ -21,18 +23,39 @@ void DrawFinalPass::InitializeFrameBuffers()
|
||||
{
|
||||
glGenRenderbuffers(1, &m_DepthBuffer);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, m_DepthBuffer);
|
||||
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, m_Renderer->GetViewportSize().Width, m_Renderer->GetViewportSize().Height);
|
||||
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, m_Renderer->GetViewportSize().Width, m_Renderer->GetViewportSize().Height);
|
||||
GLERROR("RenderBuffer generation");
|
||||
|
||||
GenerateTexture(&m_SceneTexture, GL_CLAMP_TO_EDGE, GL_LINEAR, glm::vec2(m_Renderer->GetViewportSize().Width, m_Renderer->GetViewportSize().Height), GL_RGB16F, GL_RGB, GL_FLOAT);
|
||||
//GenerateTexture(&m_BloomTexture, GL_CLAMP_TO_EDGE, GL_LINEAR, glm::vec2(m_Renderer->GetViewPortSize().Width, m_Renderer->GetViewPortSize().Height), GL_RGB16F, GL_RGB, GL_FLOAT);
|
||||
GenerateTexture(&m_BloomTexture, GL_CLAMP_TO_EDGE, GL_LINEAR, glm::vec2(m_Renderer->GetViewportSize().Width, m_Renderer->GetViewportSize().Height), GL_RGB16F, GL_RGB, GL_FLOAT);
|
||||
//GenerateMipMapTexture(&m_BloomTexture, GL_CLAMP_TO_EDGE, glm::vec2(m_Renderer->GetViewPortSize().Width, m_Renderer->GetViewPortSize().Height), GL_RGB16F, GL_FLOAT, 4);
|
||||
//GenerateTexture(&m_StencilTexture, GL_CLAMP_TO_EDGE, GL_LINEAR, glm::vec2(m_Renderer->GetViewportSize().Width, m_Renderer->GetViewportSize().Height), GL_STENCIL, GL_STENCIL_INDEX8, GL_INT);
|
||||
|
||||
m_FinalPassFrameBuffer.AddResource(std::shared_ptr<BufferResource>(new RenderBuffer(&m_DepthBuffer, GL_DEPTH_ATTACHMENT)));
|
||||
m_FinalPassFrameBuffer.AddResource(std::shared_ptr<BufferResource>(new RenderBuffer(&m_DepthBuffer, GL_DEPTH_STENCIL_ATTACHMENT)));
|
||||
//m_FinalPassFrameBuffer.AddResource(std::shared_ptr<BufferResource>(new Texture2D(&m_StencilTexture, GL_STENCIL_ATTACHMENT)));
|
||||
m_FinalPassFrameBuffer.AddResource(std::shared_ptr<BufferResource>(new Texture2D(&m_SceneTexture, GL_COLOR_ATTACHMENT0)));
|
||||
m_FinalPassFrameBuffer.AddResource(std::shared_ptr<BufferResource>(new Texture2D(&m_BloomTexture, GL_COLOR_ATTACHMENT1)));
|
||||
m_FinalPassFrameBuffer.Generate();
|
||||
GLERROR("FBO generation");
|
||||
|
||||
glGenRenderbuffers(1, &m_DepthBufferLowRes);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, m_DepthBufferLowRes);
|
||||
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, (int)(m_Renderer->GetViewportSize().Width/m_ShieldPixelRate), (int)(m_Renderer->GetViewportSize().Height/m_ShieldPixelRate));
|
||||
GLERROR("RenderBufferLowRes generation");
|
||||
|
||||
GenerateTexture(&m_SceneTextureLowRes, GL_CLAMP_TO_EDGE, GL_NEAREST, glm::vec2((int)(m_Renderer->GetViewportSize().Width/m_ShieldPixelRate), (int)(m_Renderer->GetViewportSize().Height/m_ShieldPixelRate)), GL_RGB16F, GL_RGB, GL_FLOAT);
|
||||
//GenerateTexture(&m_BloomTexture, GL_CLAMP_TO_EDGE, GL_LINEAR, glm::vec2(m_Renderer->GetViewPortSize().Width, m_Renderer->GetViewPortSize().Height), GL_RGB16F, GL_RGB, GL_FLOAT);
|
||||
GenerateTexture(&m_BloomTextureLowRes, GL_CLAMP_TO_EDGE, GL_NEAREST, glm::vec2((int)(m_Renderer->GetViewportSize().Width/m_ShieldPixelRate), (int)(m_Renderer->GetViewportSize().Height/m_ShieldPixelRate)), GL_RGB16F, GL_RGB, GL_FLOAT);
|
||||
//GenerateMipMapTexture(&m_BloomTexture, GL_CLAMP_TO_EDGE, glm::vec2(m_Renderer->GetViewPortSize().Width, m_Renderer->GetViewPortSize().Height), GL_RGB16F, GL_FLOAT, 4);
|
||||
//GenerateTexture(&m_StencilTexture, GL_CLAMP_TO_EDGE, GL_LINEAR, glm::vec2(m_Renderer->GetViewportSize().Width, m_Renderer->GetViewportSize().Height), GL_STENCIL, GL_STENCIL_INDEX8, GL_INT);
|
||||
|
||||
m_FinalPassFrameBufferLowRes.AddResource(std::shared_ptr<BufferResource>(new RenderBuffer(&m_DepthBufferLowRes, GL_DEPTH_STENCIL_ATTACHMENT)));
|
||||
//m_FinalPassFrameBufferLowRes.AddResource(std::shared_ptr<BufferResource>(new Texture2D(&m_StencilTexture, GL_STENCIL_ATTACHMENT)));
|
||||
m_FinalPassFrameBufferLowRes.AddResource(std::shared_ptr<BufferResource>(new Texture2D(&m_SceneTextureLowRes, GL_COLOR_ATTACHMENT0)));
|
||||
m_FinalPassFrameBufferLowRes.AddResource(std::shared_ptr<BufferResource>(new Texture2D(&m_BloomTextureLowRes, GL_COLOR_ATTACHMENT1)));
|
||||
m_FinalPassFrameBufferLowRes.Generate();
|
||||
GLERROR("FBO2 generation");
|
||||
}
|
||||
|
||||
void DrawFinalPass::InitializeShaderPrograms()
|
||||
@@ -111,6 +134,20 @@ void DrawFinalPass::InitializeShaderPrograms()
|
||||
m_ForwardPlusSplatMapSkinnedProgram->BindFragDataLocation(1, "bloomColor");
|
||||
m_ForwardPlusSplatMapSkinnedProgram->Link();
|
||||
GLERROR("Creating Forward SplatMap Skinned program");
|
||||
|
||||
m_ShieldToStencilProgram = ResourceManager::Load<ShaderProgram>("#ShieldToStencilProgram");
|
||||
m_ShieldToStencilProgram->AddShader(std::shared_ptr<Shader>(new VertexShader("Shaders/ShieldStencil.vert.glsl")));
|
||||
m_ShieldToStencilProgram->AddShader(std::shared_ptr<Shader>(new FragmentShader("Shaders/ShieldStencil.frag.glsl")));
|
||||
m_ShieldToStencilProgram->Compile();
|
||||
m_ShieldToStencilProgram->Link();
|
||||
GLERROR("Creating Shield program");
|
||||
|
||||
m_FillDepthBufferProgram = ResourceManager::Load<ShaderProgram>("#FillDepthBufferProgram");
|
||||
m_FillDepthBufferProgram->AddShader(std::shared_ptr<Shader>(new VertexShader("Shaders/FillDepthBuffer.vert.glsl")));
|
||||
m_FillDepthBufferProgram->AddShader(std::shared_ptr<Shader>(new FragmentShader("Shaders/FillDepthBuffer.frag.glsl")));
|
||||
m_FillDepthBufferProgram->Compile();
|
||||
m_FillDepthBufferProgram->Link();
|
||||
GLERROR("Creating DepthFill program");
|
||||
}
|
||||
|
||||
void DrawFinalPass::Draw(RenderScene& scene)
|
||||
@@ -121,20 +158,92 @@ void DrawFinalPass::Draw(RenderScene& scene)
|
||||
if (scene.ClearDepth) {
|
||||
glClear(GL_DEPTH_BUFFER_BIT);
|
||||
}
|
||||
//TODO: Do we need check for this or will it be per scene always?
|
||||
glClearStencil(0x00);
|
||||
glClear(GL_STENCIL_BUFFER_BIT);
|
||||
|
||||
DrawModelRenderQueues(scene.OpaqueObjects, scene);
|
||||
//Fill depth buffer
|
||||
|
||||
|
||||
state->StencilMask(0x00);
|
||||
DrawModelRenderQueues(scene.Jobs.OpaqueObjects, scene);
|
||||
GLERROR("OpaqueObjects");
|
||||
DrawModelRenderQueues(scene.TransparentObjects, scene);
|
||||
DrawModelRenderQueues(scene.Jobs.TransparentObjects, scene);
|
||||
GLERROR("TransparentObjects");
|
||||
|
||||
delete state;
|
||||
//DrawStencilState* stencilState = new DrawStencilState(m_FinalPassFrameBuffer.GetHandle());
|
||||
//Draw shields to stencil pass
|
||||
state->StencilFunc(GL_ALWAYS, 1, 0xFF);
|
||||
state->StencilMask(0xFF);
|
||||
DrawShieldToStencilBuffer(scene.Jobs.ShieldObjects, scene);
|
||||
GLERROR("StencilPass");
|
||||
|
||||
//Draw Opaque shielded objects
|
||||
state->StencilFunc(GL_NOTEQUAL, 1, 0xFF);
|
||||
state->StencilMask(0x00);
|
||||
DrawShieldedModelRenderQueue(scene.Jobs.OpaqueShieldedObjects, scene);
|
||||
GLERROR("Shielded Opaque object");
|
||||
|
||||
//Draw Transparen Shielded objects
|
||||
DrawShieldedModelRenderQueue(scene.Jobs.TransparentShieldedObjects, scene);
|
||||
GLERROR("Shielded Transparent objects");
|
||||
|
||||
GLERROR("END");
|
||||
delete state;
|
||||
|
||||
|
||||
DrawFinalPassState* stateLowRes = new DrawFinalPassState(m_FinalPassFrameBufferLowRes.GetHandle());
|
||||
//Draw the lowres texture that will be shown behind the shield.
|
||||
stateLowRes->Enable(GL_SCISSOR_TEST);
|
||||
stateLowRes->Enable(GL_DEPTH_TEST);
|
||||
//TODO: Viewports and scissor should be in state
|
||||
glViewport(0, 0, m_Renderer->GetViewportSize().Width/m_ShieldPixelRate, m_Renderer->GetViewportSize().Height/m_ShieldPixelRate);
|
||||
glScissor(0, 0, m_Renderer->GetViewportSize().Width, m_Renderer->GetViewportSize().Height);
|
||||
|
||||
glClearStencil(0x00);
|
||||
glClear(GL_STENCIL_BUFFER_BIT);
|
||||
|
||||
//TODO: This should not be here...
|
||||
stateLowRes->StencilFunc(GL_ALWAYS, 1, 0xFF);
|
||||
stateLowRes->StencilMask(0x00);
|
||||
DrawToDepthBuffer(scene.Jobs.OpaqueObjects, scene);
|
||||
DrawToDepthBuffer(scene.Jobs.TransparentObjects, scene);
|
||||
|
||||
//Draw shields to stencil pass
|
||||
stateLowRes->StencilFunc(GL_ALWAYS, 1, 0xFF);
|
||||
stateLowRes->StencilMask(0xFF);
|
||||
stateLowRes->Enable(GL_DEPTH_TEST);
|
||||
DrawShieldToStencilBuffer(scene.Jobs.ShieldObjects, scene);
|
||||
GLERROR("StencilPass");
|
||||
|
||||
glClear(GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
stateLowRes->Enable(GL_DEPTH_TEST);
|
||||
stateLowRes->StencilFunc(GL_LEQUAL, 1, 0xFF);
|
||||
stateLowRes->StencilMask(0x00);
|
||||
DrawModelRenderQueues(scene.Jobs.OpaqueObjects, scene);
|
||||
GLERROR("OpaqueObjects");
|
||||
DrawModelRenderQueues(scene.Jobs.TransparentObjects, scene);
|
||||
GLERROR("TransparentObjects");
|
||||
glViewport(0, 0, m_Renderer->GetViewportSize().Width, m_Renderer->GetViewportSize().Height);
|
||||
glScissor(0, 0, m_Renderer->GetViewportSize().Width, m_Renderer->GetViewportSize().Height);
|
||||
delete stateLowRes;
|
||||
}
|
||||
|
||||
|
||||
void DrawFinalPass::ClearBuffer()
|
||||
{
|
||||
m_FinalPassFrameBufferLowRes.Bind();
|
||||
glViewport(0, 0, m_Renderer->GetViewportSize().Width/m_ShieldPixelRate, m_Renderer->GetViewportSize().Height/m_ShieldPixelRate);
|
||||
glScissor(0, 0, m_Renderer->GetViewportSize().Width, m_Renderer->GetViewportSize().Height);
|
||||
glClearColor(0.f, 0.f, 0.f, 0.f);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
m_FinalPassFrameBufferLowRes.Unbind();
|
||||
|
||||
m_FinalPassFrameBuffer.Bind();
|
||||
glViewport(0, 0, m_Renderer->GetViewportSize().Width, m_Renderer->GetViewportSize().Height);
|
||||
glScissor(0, 0, m_Renderer->GetViewportSize().Width, m_Renderer->GetViewportSize().Height);
|
||||
glClearColor(0.f, 0.f, 0.f, 0.f);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
m_FinalPassFrameBuffer.Unbind();
|
||||
@@ -166,7 +275,7 @@ void DrawFinalPass::GenerateMipMapTexture(GLuint* texture, GLenum wrapping, glm:
|
||||
GLERROR("MipMap Texture initialization failed");
|
||||
}
|
||||
|
||||
void DrawFinalPass::DrawModelRenderQueues(std::list<std::shared_ptr<RenderJob>>& job, RenderScene& scene)
|
||||
void DrawFinalPass::DrawModelRenderQueues(std::list<std::shared_ptr<RenderJob>>& jobs, RenderScene& scene)
|
||||
{
|
||||
GLuint forwardHandle = m_ForwardPlusProgram->GetHandle();
|
||||
GLERROR("forwardHandle");
|
||||
@@ -189,10 +298,125 @@ void DrawFinalPass::DrawModelRenderQueues(std::list<std::shared_ptr<RenderJob>>&
|
||||
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, m_LightCullingPass->LightGridSSBO());
|
||||
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 4, m_LightCullingPass->LightIndexSSBO());
|
||||
|
||||
for(auto &job : job)
|
||||
for(auto &job : jobs)
|
||||
{
|
||||
auto explosionEffectJob = std::dynamic_pointer_cast<ExplosionEffectJob>(job);
|
||||
if(explosionEffectJob) {
|
||||
//Bind program
|
||||
if(GLERROR("Prebind")) {
|
||||
continue;
|
||||
}
|
||||
m_ExplosionEffectProgram->Bind();
|
||||
if(GLERROR("BindProgram")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
glDisable(GL_CULL_FACE);
|
||||
|
||||
//Bind uniforms
|
||||
BindExplosionUniforms(explosionHandle, explosionEffectJob, scene);
|
||||
if(GLERROR("BindExplosionUniforms")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (explosionEffectJob->Model->m_RawModel->m_Skeleton != nullptr) {
|
||||
|
||||
if (explosionEffectJob->Animation != nullptr) {
|
||||
std::vector<glm::mat4> frameBones = explosionEffectJob->Skeleton->GetFrameBones(*explosionEffectJob->Animation, explosionEffectJob->AnimationTime);
|
||||
glUniformMatrix4fv(glGetUniformLocation(explosionHandle, "Bones"), frameBones.size(), GL_FALSE, glm::value_ptr(frameBones[0]));
|
||||
}
|
||||
}
|
||||
if(GLERROR("Animation")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
//bind textures
|
||||
BindExplosionTextures(explosionEffectJob);
|
||||
if(GLERROR("BindExplosionTextures")) {
|
||||
continue;
|
||||
}
|
||||
//draw
|
||||
glBindVertexArray(explosionEffectJob->Model->VAO);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, explosionEffectJob->Model->ElementBuffer);
|
||||
glDrawElements(GL_TRIANGLES, explosionEffectJob->EndIndex - explosionEffectJob->StartIndex + 1, GL_UNSIGNED_INT, (void*)(explosionEffectJob->StartIndex*sizeof(unsigned int)));
|
||||
glEnable(GL_CULL_FACE);
|
||||
if(GLERROR("explosion effect end")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
} else {
|
||||
auto modelJob = std::dynamic_pointer_cast<ModelJob>(job);
|
||||
if (modelJob) {
|
||||
//bind forward program
|
||||
m_ForwardPlusProgram->Bind();
|
||||
glUniform2f(glGetUniformLocation(forwardHandle, "ScreenDimensions"), m_Renderer->GetViewportSize().Width, m_Renderer->GetViewportSize().Height);
|
||||
|
||||
//bind uniforms
|
||||
BindModelUniforms(forwardHandle, modelJob, scene);
|
||||
|
||||
//bind textures
|
||||
BindModelTextures(modelJob);
|
||||
|
||||
if (modelJob->Model->m_RawModel->m_Skeleton != nullptr) {
|
||||
|
||||
if (modelJob->Animation != nullptr) {
|
||||
std::vector<glm::mat4> frameBones = modelJob->Skeleton->GetFrameBones(*modelJob->Animation, modelJob->AnimationTime);
|
||||
glUniformMatrix4fv(glGetUniformLocation(forwardHandle, "Bones"), frameBones.size(), GL_FALSE, glm::value_ptr(frameBones[0]));
|
||||
}
|
||||
}
|
||||
|
||||
//draw
|
||||
glBindVertexArray(modelJob->Model->VAO);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, modelJob->Model->ElementBuffer);
|
||||
glDrawElements(GL_TRIANGLES, modelJob->EndIndex - modelJob->StartIndex + 1, GL_UNSIGNED_INT, (void*)(modelJob->StartIndex*sizeof(unsigned int)));
|
||||
if(GLERROR("models end")) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void DrawFinalPass::DrawShieldToStencilBuffer(std::list<std::shared_ptr<RenderJob>>& jobs, RenderScene& scene)
|
||||
{
|
||||
m_ShieldToStencilProgram->Bind();
|
||||
GLuint shaderHandle = m_ShieldToStencilProgram->GetHandle();
|
||||
|
||||
glUniformMatrix4fv(glGetUniformLocation(shaderHandle, "V"), 1, GL_FALSE, glm::value_ptr(scene.Camera->ViewMatrix()));
|
||||
glUniformMatrix4fv(glGetUniformLocation(shaderHandle, "P"), 1, GL_FALSE, glm::value_ptr(scene.Camera->ProjectionMatrix()));
|
||||
|
||||
for (auto &job : jobs) {
|
||||
auto modelJob = std::dynamic_pointer_cast<ModelJob>(job);
|
||||
if (modelJob) {
|
||||
glUniformMatrix4fv(glGetUniformLocation(shaderHandle, "M"), 1, GL_FALSE, glm::value_ptr(modelJob->Matrix));
|
||||
|
||||
|
||||
glBindVertexArray(modelJob->Model->VAO);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, modelJob->Model->ElementBuffer);
|
||||
glDrawElements(GL_TRIANGLES, modelJob->EndIndex - modelJob->StartIndex + 1, GL_UNSIGNED_INT, (void*)(modelJob->StartIndex*sizeof(unsigned int)));
|
||||
if (GLERROR("models end")) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DrawFinalPass::DrawShieldedModelRenderQueue(std::list<std::shared_ptr<RenderJob>>& jobs, RenderScene& scene)
|
||||
{
|
||||
GLuint forwardHandle = m_ForwardPlusProgram->GetHandle();
|
||||
GLERROR("forwardHandle");
|
||||
GLuint explosionHandle = m_ExplosionEffectProgram->GetHandle();
|
||||
GLERROR("explosionHandle");
|
||||
|
||||
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, m_LightCullingPass->LightSSBO());
|
||||
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, m_LightCullingPass->LightGridSSBO());
|
||||
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 4, m_LightCullingPass->LightIndexSSBO());
|
||||
|
||||
for (auto &job : jobs) {
|
||||
auto explosionEffectJob = std::dynamic_pointer_cast<ExplosionEffectJob>(job);
|
||||
if (explosionEffectJob) {
|
||||
switch (explosionEffectJob->Type) {
|
||||
case RawModel::MaterialType::Basic:
|
||||
case RawModel::MaterialType::SingleTextures:
|
||||
@@ -331,12 +555,44 @@ void DrawFinalPass::DrawModelRenderQueues(std::list<std::shared_ptr<RenderJob>>&
|
||||
glBindVertexArray(modelJob->Model->VAO);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, modelJob->Model->ElementBuffer);
|
||||
glDrawElements(GL_TRIANGLES, modelJob->EndIndex - modelJob->StartIndex + 1, GL_UNSIGNED_INT, (void*)(modelJob->StartIndex*sizeof(unsigned int)));
|
||||
if(GLERROR("models end")) {
|
||||
if (GLERROR("models end")) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void DrawFinalPass::DrawToDepthBuffer(std::list<std::shared_ptr<RenderJob>>& jobs, RenderScene& scene)
|
||||
{
|
||||
m_FillDepthBufferProgram->Bind();
|
||||
GLuint shaderHandle = m_FillDepthBufferProgram->GetHandle();
|
||||
glUniformMatrix4fv(glGetUniformLocation(shaderHandle, "V"), 1, GL_FALSE, glm::value_ptr(scene.Camera->ViewMatrix()));
|
||||
glUniformMatrix4fv(glGetUniformLocation(shaderHandle, "P"), 1, GL_FALSE, glm::value_ptr(scene.Camera->ProjectionMatrix()));
|
||||
|
||||
for (auto &job : jobs) {
|
||||
auto modelJob = std::dynamic_pointer_cast<ModelJob>(job);
|
||||
|
||||
//bind uniforms
|
||||
glUniformMatrix4fv(glGetUniformLocation(shaderHandle, "M"), 1, GL_FALSE, glm::value_ptr(modelJob->Matrix));
|
||||
|
||||
if (modelJob->Model->m_RawModel->m_Skeleton != nullptr) {
|
||||
|
||||
if (modelJob->Animation != nullptr) {
|
||||
std::vector<glm::mat4> frameBones = modelJob->Skeleton->GetFrameBones(*modelJob->Animation, modelJob->AnimationTime);
|
||||
glUniformMatrix4fv(glGetUniformLocation(shaderHandle, "Bones"), frameBones.size(), GL_FALSE, glm::value_ptr(frameBones[0]));
|
||||
}
|
||||
}
|
||||
|
||||
//draw
|
||||
glBindVertexArray(modelJob->Model->VAO);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, modelJob->Model->ElementBuffer);
|
||||
glDrawElements(GL_TRIANGLES, modelJob->EndIndex - modelJob->StartIndex + 1, GL_UNSIGNED_INT, (void*)(modelJob->StartIndex*sizeof(unsigned int)));
|
||||
if (GLERROR("models end")) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "Rendering/DrawFinalPassState.h"
|
||||
|
||||
|
||||
|
||||
DrawFinalPassState::DrawFinalPassState(GLuint frameBuffer)
|
||||
{
|
||||
BindFramebuffer(frameBuffer);
|
||||
@@ -8,6 +9,10 @@ DrawFinalPassState::DrawFinalPassState(GLuint frameBuffer)
|
||||
BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
Enable(GL_DEPTH_TEST);
|
||||
Enable(GL_CULL_FACE);
|
||||
Enable(GL_STENCIL_TEST);
|
||||
StencilFunc(GL_NOTEQUAL, 1, 0xFF);
|
||||
StencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
|
||||
StencilMask(0xFF);
|
||||
ClearColor(glm::vec4(0.f, 0.f, 0.f, 0.f));
|
||||
}
|
||||
|
||||
@@ -15,3 +20,20 @@ DrawFinalPassState::~DrawFinalPassState()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
DrawStencilState::DrawStencilState(GLuint frameBuffer)
|
||||
{
|
||||
BindFramebuffer(frameBuffer);
|
||||
Enable(GL_STENCIL_TEST);
|
||||
StencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
|
||||
StencilFunc(GL_ALWAYS, 1, 0xFF);
|
||||
StencilMask(0xFF);
|
||||
Enable(GL_DEPTH_TEST);
|
||||
ClearColor(glm::vec4(0.f));
|
||||
}
|
||||
|
||||
DrawStencilState::~DrawStencilState()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -39,10 +39,13 @@ void FrameBuffer::AddResource(std::shared_ptr<BufferResource> resource)
|
||||
|
||||
void FrameBuffer::Generate()
|
||||
{
|
||||
GLERROR("PRE");
|
||||
|
||||
std::vector<GLenum> attachments;
|
||||
|
||||
glGenFramebuffers(1, &m_BufferHandle);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, m_BufferHandle);
|
||||
GLERROR("1");
|
||||
|
||||
for (auto it = m_Resources.begin(); it != m_Resources.end(); it++) {
|
||||
switch ((*it)->m_ResourceType) {
|
||||
@@ -56,20 +59,30 @@ void FrameBuffer::Generate()
|
||||
GLERROR("FrameBuffer generate: glFramebufferRenderbuffer");
|
||||
break;
|
||||
}
|
||||
|
||||
GLERROR("2");
|
||||
|
||||
if ((*it)->m_Attachment != GL_DEPTH_ATTACHMENT) {
|
||||
if ((*it)->m_Attachment != GL_DEPTH_ATTACHMENT && (*it)->m_Attachment != GL_STENCIL_ATTACHMENT && (*it)->m_Attachment != GL_DEPTH_STENCIL_ATTACHMENT) {
|
||||
attachments.push_back((*it)->m_Attachment);
|
||||
}
|
||||
GLERROR("Attachment");
|
||||
|
||||
}
|
||||
|
||||
GLERROR("3");
|
||||
|
||||
|
||||
GLenum* bufferTextures = &attachments[0];
|
||||
glDrawBuffers(attachments.size(), bufferTextures);
|
||||
if(GLERROR("4")) {
|
||||
printf("hello");
|
||||
}
|
||||
|
||||
if (GLenum frameBufferStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
|
||||
LOG_ERROR("FrameBuffer incomplete: 0x%x\n", frameBufferStatus);
|
||||
GLERROR("Framebuffer incomplete");
|
||||
//LOG_ERROR("FrameBuffer incomplete: 0x%x\n", frameBufferStatus);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
GLERROR("END");
|
||||
|
||||
}
|
||||
|
||||
void FrameBuffer::Bind()
|
||||
|
||||
@@ -16,7 +16,7 @@ LightCullingPass::~LightCullingPass()
|
||||
|
||||
void LightCullingPass::GenerateNewFrustum(RenderScene& scene)
|
||||
{
|
||||
if (scene.PointLightJobs.size() == 0)
|
||||
if (scene.Jobs.PointLight.size() == 0)
|
||||
return;
|
||||
|
||||
GLERROR("CalculateFrustum Error: Pre");
|
||||
@@ -83,7 +83,7 @@ void LightCullingPass::FillLightList(RenderScene& scene)
|
||||
{
|
||||
m_LightSources.clear();
|
||||
|
||||
for(auto &job : scene.PointLightJobs) {
|
||||
for(auto &job : scene.Jobs.PointLight) {
|
||||
auto pointLightjob = std::dynamic_pointer_cast<PointLightJob>(job);
|
||||
if (pointLightjob) {
|
||||
LightSource p;
|
||||
@@ -97,7 +97,7 @@ void LightCullingPass::FillLightList(RenderScene& scene)
|
||||
m_LightSources.push_back(p);
|
||||
}
|
||||
}
|
||||
for(auto &job : scene.DirectionalLightJobs) {
|
||||
for(auto &job : scene.Jobs.DirectionalLight) {
|
||||
auto directionalLightJob = std::dynamic_pointer_cast<DirectionalLightJob>(job);
|
||||
if(directionalLightJob) {
|
||||
LightSource p;
|
||||
|
||||
@@ -65,7 +65,7 @@ void PickingPass::Draw(RenderScene& scene)
|
||||
}
|
||||
m_Camera = scene.Camera;
|
||||
|
||||
for (auto &job : scene.OpaqueObjects) {
|
||||
for (auto &job : scene.Jobs.OpaqueObjects) {
|
||||
auto modelJob = std::dynamic_pointer_cast<ModelJob>(job);
|
||||
|
||||
if (modelJob) {
|
||||
@@ -152,7 +152,99 @@ void PickingPass::Draw(RenderScene& scene)
|
||||
}
|
||||
}
|
||||
|
||||
for (auto &job : scene.TransparentObjects) {
|
||||
for (auto &job : scene.Jobs.TransparentObjects) {
|
||||
auto modelJob = std::dynamic_pointer_cast<ModelJob>(job);
|
||||
|
||||
if (modelJob) {
|
||||
int pickColor[2] = { m_ColorCounter[0], m_ColorCounter[1] };
|
||||
|
||||
PickingInfo pickInfo;
|
||||
pickInfo.Entity = modelJob->Entity;
|
||||
pickInfo.World = modelJob->World;
|
||||
pickInfo.Camera = scene.Camera;
|
||||
|
||||
auto color = m_EntityColors.find(std::make_tuple(pickInfo.Entity, pickInfo.World, pickInfo.Camera));
|
||||
if (color != m_EntityColors.end()) {
|
||||
pickColor[0] = color->second[0];
|
||||
pickColor[1] = color->second[1];
|
||||
} else {
|
||||
m_EntityColors[std::make_tuple(pickInfo.Entity, pickInfo.World, pickInfo.Camera)] = glm::ivec2(pickColor[0], pickColor[1]);
|
||||
if (m_ColorCounter[0] > 255) {
|
||||
m_ColorCounter[0] = 0;
|
||||
m_ColorCounter[1] += 1;
|
||||
} else {
|
||||
m_ColorCounter[0] += 1;
|
||||
}
|
||||
}
|
||||
|
||||
m_PickingColorsToEntity[glm::ivec2(pickColor[0], pickColor[1])] = pickInfo;
|
||||
|
||||
glUniformMatrix4fv(glGetUniformLocation(shaderHandle, "M"), 1, GL_FALSE, glm::value_ptr(modelJob->Matrix));
|
||||
glUniformMatrix4fv(glGetUniformLocation(shaderHandle, "V"), 1, GL_FALSE, glm::value_ptr(scene.Camera->ViewMatrix()));
|
||||
glUniformMatrix4fv(glGetUniformLocation(shaderHandle, "P"), 1, GL_FALSE, glm::value_ptr(scene.Camera->ProjectionMatrix()));
|
||||
glUniform2fv(glGetUniformLocation(shaderHandle, "PickingColor"), 1, glm::value_ptr(glm::vec2(pickColor[0], pickColor[1])));
|
||||
|
||||
if (modelJob->Model->m_RawModel->m_Skeleton != nullptr) {
|
||||
|
||||
if (modelJob->Animation != nullptr) {
|
||||
std::vector<glm::mat4> frameBones = modelJob->Skeleton->GetFrameBones(*modelJob->Animation, modelJob->AnimationTime);
|
||||
glUniformMatrix4fv(glGetUniformLocation(shaderHandle, "Bones"), frameBones.size(), GL_FALSE, glm::value_ptr(frameBones[0]));
|
||||
}
|
||||
}
|
||||
|
||||
glBindVertexArray(modelJob->Model->VAO);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, modelJob->Model->ElementBuffer);
|
||||
glDrawElements(GL_TRIANGLES, modelJob->EndIndex - modelJob->StartIndex + 1, GL_UNSIGNED_INT, (void*)(modelJob->StartIndex * sizeof(unsigned int)));
|
||||
}
|
||||
}
|
||||
|
||||
for (auto &job : scene.Jobs.OpaqueShieldedObjects) {
|
||||
auto modelJob = std::dynamic_pointer_cast<ModelJob>(job);
|
||||
|
||||
if (modelJob) {
|
||||
int pickColor[2] = { m_ColorCounter[0], m_ColorCounter[1] };
|
||||
|
||||
PickingInfo pickInfo;
|
||||
pickInfo.Entity = modelJob->Entity;
|
||||
pickInfo.World = modelJob->World;
|
||||
pickInfo.Camera = scene.Camera;
|
||||
|
||||
auto color = m_EntityColors.find(std::make_tuple(pickInfo.Entity, pickInfo.World, pickInfo.Camera));
|
||||
if (color != m_EntityColors.end()) {
|
||||
pickColor[0] = color->second[0];
|
||||
pickColor[1] = color->second[1];
|
||||
} else {
|
||||
m_EntityColors[std::make_tuple(pickInfo.Entity, pickInfo.World, pickInfo.Camera)] = glm::ivec2(pickColor[0], pickColor[1]);
|
||||
if (m_ColorCounter[0] > 255) {
|
||||
m_ColorCounter[0] = 0;
|
||||
m_ColorCounter[1] += 1;
|
||||
} else {
|
||||
m_ColorCounter[0] += 1;
|
||||
}
|
||||
}
|
||||
|
||||
m_PickingColorsToEntity[glm::ivec2(pickColor[0], pickColor[1])] = pickInfo;
|
||||
|
||||
glUniformMatrix4fv(glGetUniformLocation(shaderHandle, "M"), 1, GL_FALSE, glm::value_ptr(modelJob->Matrix));
|
||||
glUniformMatrix4fv(glGetUniformLocation(shaderHandle, "V"), 1, GL_FALSE, glm::value_ptr(scene.Camera->ViewMatrix()));
|
||||
glUniformMatrix4fv(glGetUniformLocation(shaderHandle, "P"), 1, GL_FALSE, glm::value_ptr(scene.Camera->ProjectionMatrix()));
|
||||
glUniform2fv(glGetUniformLocation(shaderHandle, "PickingColor"), 1, glm::value_ptr(glm::vec2(pickColor[0], pickColor[1])));
|
||||
|
||||
if (modelJob->Model->m_RawModel->m_Skeleton != nullptr) {
|
||||
|
||||
if (modelJob->Animation != nullptr) {
|
||||
std::vector<glm::mat4> frameBones = modelJob->Skeleton->GetFrameBones(*modelJob->Animation, modelJob->AnimationTime);
|
||||
glUniformMatrix4fv(glGetUniformLocation(shaderHandle, "Bones"), frameBones.size(), GL_FALSE, glm::value_ptr(frameBones[0]));
|
||||
}
|
||||
}
|
||||
|
||||
glBindVertexArray(modelJob->Model->VAO);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, modelJob->Model->ElementBuffer);
|
||||
glDrawElements(GL_TRIANGLES, modelJob->EndIndex - modelJob->StartIndex + 1, GL_UNSIGNED_INT, (void*)(modelJob->StartIndex * sizeof(unsigned int)));
|
||||
}
|
||||
}
|
||||
|
||||
for (auto &job : scene.Jobs.TransparentShieldedObjects) {
|
||||
auto modelJob = std::dynamic_pointer_cast<ModelJob>(job);
|
||||
|
||||
if (modelJob) {
|
||||
|
||||
@@ -6,9 +6,10 @@ bool RenderState::Enable(GLenum cap)
|
||||
//LOG_WARNING("Trying to enable somthing that is already enabled.");
|
||||
return false;
|
||||
}
|
||||
|
||||
m_ResetFunctions.push_back(std::bind(glDisable, cap));
|
||||
glEnable(cap);
|
||||
return !GLERROR("RenderState::Enable");
|
||||
return !GLERROR("Enable");
|
||||
}
|
||||
|
||||
bool RenderState::Disable(GLenum cap)
|
||||
@@ -16,9 +17,10 @@ bool RenderState::Disable(GLenum cap)
|
||||
if (!glIsEnabled(cap)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
m_ResetFunctions.push_back(std::bind(glEnable, cap));
|
||||
glDisable(cap);
|
||||
return !GLERROR("RenderState::Disable");
|
||||
return !GLERROR("Disable");
|
||||
}
|
||||
|
||||
bool RenderState::CullFace(GLenum mode)
|
||||
@@ -32,7 +34,7 @@ bool RenderState::CullFace(GLenum mode)
|
||||
glGetIntegerv(GL_CULL_FACE_MODE, &original);
|
||||
m_ResetFunctions.push_back(std::bind(glCullFace, original));
|
||||
glCullFace(mode);
|
||||
return !GLERROR("RenderState::CullFace");
|
||||
return !GLERROR("CullFace");
|
||||
}
|
||||
|
||||
bool RenderState::ClearColor(glm::vec4 color)
|
||||
@@ -41,7 +43,7 @@ bool RenderState::ClearColor(glm::vec4 color)
|
||||
glGetFloatv(GL_COLOR_CLEAR_VALUE, &original[0]);
|
||||
m_ResetFunctions.push_back(std::bind(glClearColor, original[0], original[1], original[2], original[3]));
|
||||
glClearColor(color.r, color.g, color.b, color.a);
|
||||
return !GLERROR("RenderState::ClearColor");
|
||||
return !GLERROR("ClearColor");
|
||||
}
|
||||
|
||||
bool RenderState::BindFramebuffer(GLint framebuffer)
|
||||
@@ -55,7 +57,7 @@ bool RenderState::BindFramebuffer(GLint framebuffer)
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, originalDraw);
|
||||
});
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
|
||||
return !GLERROR("RenderState::BindBuffer");
|
||||
return !GLERROR("BindBuffer");
|
||||
}
|
||||
|
||||
|
||||
@@ -67,7 +69,7 @@ bool RenderState::BlendEquation(GLenum mode)
|
||||
glGetIntegerv(GL_BLEND_EQUATION_ALPHA, &originalAlpha);
|
||||
m_ResetFunctions.push_back(std::bind(glBlendEquationSeparate, originalRGB, originalAlpha));
|
||||
glBlendEquation(mode);
|
||||
return !GLERROR("RenderState::BlendEquation");
|
||||
return !GLERROR("BlendEquation");
|
||||
}
|
||||
|
||||
bool RenderState::BlendFunc(GLenum sfactor, GLenum dfactor)
|
||||
@@ -82,7 +84,46 @@ bool RenderState::BlendFunc(GLenum sfactor, GLenum dfactor)
|
||||
glGetIntegerv(GL_BLEND_DST_ALPHA, &originalDestAlpha);
|
||||
m_ResetFunctions.push_back(std::bind(glBlendFuncSeparate, originalSrcRGB, originalSrcAlpha, originalDestRGB, originalDestAlpha));
|
||||
glBlendFunc(sfactor, dfactor);
|
||||
return !GLERROR("RenderState::BlendFunc");
|
||||
return !GLERROR("BlendFunc");
|
||||
}
|
||||
|
||||
|
||||
bool RenderState::StencilOp(GLenum sfail, GLenum dpfail, GLenum dppass)
|
||||
{
|
||||
GLint originalSFail;
|
||||
glGetIntegerv(GL_STENCIL_FAIL, &originalSFail);
|
||||
GLint originalDPFail;
|
||||
glGetIntegerv(GL_STENCIL_PASS_DEPTH_FAIL, &originalDPFail);
|
||||
GLint originalDPPass;
|
||||
glGetIntegerv(GL_STENCIL_PASS_DEPTH_PASS, &originalDPPass);
|
||||
m_ResetFunctions.push_back(std::bind(glStencilOp, originalSFail, originalDPFail, originalDPPass));
|
||||
glStencilOp(sfail, dpfail, dppass);
|
||||
return !GLERROR("StencilOp");
|
||||
}
|
||||
|
||||
|
||||
bool RenderState::StencilFunc(GLenum func, GLint ref, GLuint mask)
|
||||
{
|
||||
GLint originalFunc;
|
||||
glGetIntegerv(GL_STENCIL_FUNC, &originalFunc);
|
||||
GLint originalRef;
|
||||
glGetIntegerv(GL_STENCIL_REF, &originalRef);
|
||||
GLint originalMask;
|
||||
glGetIntegerv(GL_STENCIL_VALUE_MASK, &originalMask);
|
||||
m_ResetFunctions.push_back(std::bind(glStencilFunc, originalFunc, originalRef, originalMask));
|
||||
glStencilFunc(func, ref, mask);
|
||||
return !GLERROR("StencilFunc");
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool RenderState::StencilMask(GLuint mask)
|
||||
{
|
||||
GLint originalMask;
|
||||
glGetIntegerv(GL_STENCIL_WRITEMASK, &originalMask);
|
||||
m_ResetFunctions.push_back(std::bind(glStencilMask, mask));
|
||||
glStencilMask(mask);
|
||||
return !GLERROR("StencilMask");
|
||||
}
|
||||
|
||||
bool RenderState::DepthMask(GLboolean flag)
|
||||
@@ -91,12 +132,12 @@ bool RenderState::DepthMask(GLboolean flag)
|
||||
glGetBooleanv(GL_DEPTH_WRITEMASK, &original);
|
||||
m_ResetFunctions.push_back(std::bind(glDepthMask, original));
|
||||
glDepthMask(flag);
|
||||
return !GLERROR("RenderState::DepthMask");
|
||||
return !GLERROR("DepthMask");
|
||||
}
|
||||
|
||||
RenderState::~RenderState()
|
||||
{
|
||||
for (auto& f : m_ResetFunctions) {
|
||||
for (auto& f : boost::adaptors::reverse(m_ResetFunctions)) {
|
||||
f();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ bool RenderSystem::isChildOfCurrentCamera(EntityWrapper entity)
|
||||
return entity == m_CurrentCamera || entity.IsChildOf(m_CurrentCamera);
|
||||
}
|
||||
|
||||
void RenderSystem::fillModels(std::list<std::shared_ptr<RenderJob>>& opaqueJobs, std::list<std::shared_ptr<RenderJob>>& transparentJobs)
|
||||
void RenderSystem::fillModels(RenderScene::Queues &Jobs)
|
||||
{
|
||||
auto models = m_World->GetComponents("Model");
|
||||
if (models == nullptr) {
|
||||
@@ -92,7 +92,9 @@ void RenderSystem::fillModels(std::list<std::shared_ptr<RenderJob>>& opaqueJobs,
|
||||
}
|
||||
|
||||
glm::mat4 modelMatrix = Transform::ModelMatrix(cModel.EntityID, m_World);
|
||||
//Loop through all materialgroups of a model
|
||||
for (auto matGroup : model->MaterialGroups()) {
|
||||
//If the model has an explosioneffect component, we will add an explosioneffectjob
|
||||
if (m_World->HasComponent(cModel.EntityID, "ExplosionEffect")) {
|
||||
auto explosionEffectComponent = m_World->GetComponent(cModel.EntityID, "ExplosionEffect");
|
||||
std::shared_ptr<ExplosionEffectJob> explosionEffectJob = std::shared_ptr<ExplosionEffectJob>(new ExplosionEffectJob(
|
||||
@@ -106,15 +108,35 @@ void RenderSystem::fillModels(std::list<std::shared_ptr<RenderJob>>& opaqueJobs,
|
||||
fillColor,
|
||||
fillPercentage
|
||||
));
|
||||
if(explosionEffectJob->Color.a != 1.f || explosionEffectJob->EndColor.a != 1.f || explosionEffectJob->DiffuseColor.a != 1.f) {
|
||||
cModel["Transparent"] = true;
|
||||
}
|
||||
if (m_World->HasComponent(cModel.EntityID, "Shield")){
|
||||
TODO Calc hash
|
||||
Jobs.ShieldObjects.push_back(explosionEffectJob);
|
||||
} else if (m_World->HasComponent(cModel.EntityID, "Shielded")
|
||||
|| m_World->HasComponent(cModel.EntityID, "Player")) {
|
||||
|
||||
if (cModel["Transparent"]) {
|
||||
transparentJobs.push_back(explosionEffectJob);
|
||||
} else {
|
||||
if (explosionEffectJob->Color.a != 1.f || explosionEffectJob->EndColor.a != 1.f || explosionEffectJob->DiffuseColor.a != 1.f) {
|
||||
cModel["Transparent"] = true;
|
||||
}
|
||||
|
||||
if (cModel["Transparent"]) {
|
||||
TODO: Calc hash
|
||||
Jobs.TransparentShieldedObjects.push_back(explosionEffectJob);
|
||||
} else {
|
||||
explosionEffectJob->CalculateHash();
|
||||
opaqueJobs.push_back(explosionEffectJob);
|
||||
Jobs.OpaqueShieldedObjects.push_back(explosionEffectJob);
|
||||
}
|
||||
} else {
|
||||
if (explosionEffectJob->Color.a != 1.f || explosionEffectJob->EndColor.a != 1.f || explosionEffectJob->DiffuseColor.a != 1.f) {
|
||||
cModel["Transparent"] = true;
|
||||
}
|
||||
|
||||
if (cModel["Transparent"]) {
|
||||
TODO CALC HASH
|
||||
Jobs.TransparentObjects.push_back(explosionEffectJob);
|
||||
} else {
|
||||
TODO CALC HASH
|
||||
Jobs.OpaqueObjects.push_back(explosionEffectJob);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
std::shared_ptr<ModelJob> modelJob = std::shared_ptr<ModelJob>(new ModelJob(
|
||||
@@ -127,14 +149,35 @@ void RenderSystem::fillModels(std::list<std::shared_ptr<RenderJob>>& opaqueJobs,
|
||||
fillColor,
|
||||
fillPercentage
|
||||
));
|
||||
if (modelJob->Color.a != 1.f || modelJob->DiffuseColor.a != 1.f) {
|
||||
cModel["Transparent"] = true;
|
||||
}
|
||||
if (cModel["Transparent"]) {
|
||||
transparentJobs.push_back(modelJob);
|
||||
} else {
|
||||
if (m_World->HasComponent(cModel.EntityID, "Shield")) {
|
||||
TODO: CALC HASH
|
||||
Jobs.ShieldObjects.push_back(modelJob);
|
||||
} else if (m_World->HasComponent(cModel.EntityID, "Shielded")
|
||||
|| m_World->HasComponent(cModel.EntityID, "Player")) {
|
||||
|
||||
if (modelJob->Color.a != 1.f || modelJob->DiffuseColor.a != 1.f) {
|
||||
cModel["Transparent"] = true;
|
||||
}
|
||||
|
||||
if (cModel["Transparent"]) {
|
||||
TODO CALC HASH
|
||||
Jobs.TransparentShieldedObjects.push_back(modelJob);
|
||||
} else {
|
||||
modelJob->CalculateHash();
|
||||
opaqueJobs.push_back(modelJob);
|
||||
Jobs.OpaqueShieldedObjects.push_back(modelJob);
|
||||
}
|
||||
} else {
|
||||
if (modelJob->Color.a != 1.f || modelJob->DiffuseColor.a != 1.f) {
|
||||
cModel["Transparent"] = true;
|
||||
}
|
||||
|
||||
if (cModel["Transparent"]) {
|
||||
CALC HASH
|
||||
Jobs.TransparentObjects.push_back(modelJob);
|
||||
} else {
|
||||
CALC HASH
|
||||
Jobs.OpaqueObjects.push_back(modelJob);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -253,11 +296,11 @@ void RenderSystem::Update(double dt)
|
||||
scene.AmbientColor = (glm::vec4)(*cSceneLight->begin())["AmbientColor"];
|
||||
}
|
||||
|
||||
fillModels(scene.OpaqueObjects, scene.TransparentObjects);
|
||||
fillModels(scene.Jobs);
|
||||
fillPointLights(scene.Jobs.PointLight, m_World);
|
||||
scene.OpaqueObjects.sort();
|
||||
fillPointLights(scene.PointLightJobs, m_World);
|
||||
fillDirectionalLights(scene.DirectionalLightJobs, m_World);
|
||||
fillText(scene.TextJobs, m_World);
|
||||
fillDirectionalLights(scene.Jobs.DirectionalLight, m_World);
|
||||
fillText(scene.Jobs.Text, m_World);
|
||||
m_RenderFrame->Add(scene);
|
||||
|
||||
}
|
||||
@@ -93,7 +93,7 @@ void Renderer::Update(double dt)
|
||||
|
||||
void Renderer::Draw(RenderFrame& frame)
|
||||
{
|
||||
ImGui::Combo("Draw textures", &m_DebugTextureToDraw, "Final\0Scene\0Bloom\0Gaussian\0Picking");
|
||||
ImGui::Combo("Draw textures", &m_DebugTextureToDraw, "Final\0Scene\0Bloom\0SceneLowRes\0BloomLowRes\0Gaussian\0Picking");
|
||||
//clear buffer 0
|
||||
glClearColor(0.f, 0.f, 0.f, 0.f);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
@@ -120,7 +120,7 @@ void Renderer::Draw(RenderFrame& frame)
|
||||
}
|
||||
m_DrawBloomPass->Draw(m_DrawFinalPass->BloomTexture());
|
||||
if (m_DebugTextureToDraw == 0) {
|
||||
m_DrawColorCorrectionPass->Draw(m_DrawFinalPass->SceneTexture(), m_DrawBloomPass->GaussianTexture(), frame.Gamma, frame.Exposure);
|
||||
m_DrawColorCorrectionPass->Draw(m_DrawFinalPass->SceneTexture(), m_DrawBloomPass->GaussianTexture(), m_DrawFinalPass->SceneTextureLowRes(), m_DrawFinalPass->BloomTextureLowRes(), frame.Gamma, frame.Exposure);
|
||||
}
|
||||
if (m_DebugTextureToDraw == 1) {
|
||||
m_DrawScreenQuadPass->Draw(m_DrawFinalPass->SceneTexture());
|
||||
@@ -129,9 +129,15 @@ void Renderer::Draw(RenderFrame& frame)
|
||||
m_DrawScreenQuadPass->Draw(m_DrawFinalPass->BloomTexture());
|
||||
}
|
||||
if (m_DebugTextureToDraw == 3) {
|
||||
m_DrawScreenQuadPass->Draw(m_DrawBloomPass->GaussianTexture());
|
||||
m_DrawScreenQuadPass->Draw(m_DrawFinalPass->SceneTextureLowRes());
|
||||
}
|
||||
if (m_DebugTextureToDraw == 4) {
|
||||
m_DrawScreenQuadPass->Draw(m_DrawFinalPass->BloomTextureLowRes());
|
||||
}
|
||||
if (m_DebugTextureToDraw == 5) {
|
||||
m_DrawScreenQuadPass->Draw(m_DrawBloomPass->GaussianTexture());
|
||||
}
|
||||
if (m_DebugTextureToDraw == 6) {
|
||||
m_DrawScreenQuadPass->Draw(m_PickingPass->PickingTexture());
|
||||
}
|
||||
|
||||
@@ -154,7 +160,7 @@ void Renderer::InitializeTextures()
|
||||
void Renderer::SortRenderJobsByDepth(RenderScene &scene)
|
||||
{
|
||||
//Sort all forward jobs so transparency is good.
|
||||
scene.TransparentObjects.sort(Renderer::DepthSort);
|
||||
scene.Jobs.TransparentObjects.sort(Renderer::DepthSort);
|
||||
}
|
||||
|
||||
void Renderer::GenerateTexture(GLuint* texture, GLenum wrapping, GLenum filtering, glm::vec2 dimensions, GLint internalFormat, GLint format, GLenum type)
|
||||
|
||||
@@ -35,7 +35,7 @@ void TextPass::Draw(RenderScene& scene, FrameBuffer& frameBuffer)
|
||||
{
|
||||
GLERROR("Derp1");
|
||||
TextPassState* state = new TextPassState(frameBuffer.GetHandle());
|
||||
for (auto &job : scene.TextJobs) {
|
||||
for (auto &job : scene.Jobs.Text) {
|
||||
auto textJob = std::dynamic_pointer_cast<TextJob>(job);
|
||||
if (textJob) {
|
||||
|
||||
|
||||
Reference in New Issue
Block a user