Merge remote-tracking branch 'origin/master' into DefenderShield
# Conflicts: # resources/Schema/Components.xsd
This commit is contained in:
@@ -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,43 +229,338 @@ 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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
@@ -25,33 +26,34 @@ void CollisionSystem::UpdateComponent(EntityWrapper& entity, ComponentWrapper& c
|
||||
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;
|
||||
(bool)cPhysics["IsOnGround"] = isOnGround;
|
||||
} else {
|
||||
(bool)cPhysics["IsOnGround"] = false;
|
||||
}
|
||||
} else if (Collision::AABBVsAABB(boxA, boxB, resolutionVector)) {
|
||||
//Enter here if boxB has no Model.
|
||||
(glm::vec3&)cTransform["Position"] += resolutionVector;
|
||||
if (resolutionVector.y > 0) {
|
||||
(bool)cPhysics["IsOnGround"] = resolutionVector.y > 0;
|
||||
if ((bool)cPhysics["IsOnGround"]){
|
||||
((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;
|
||||
// }
|
||||
//}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
@@ -258,11 +258,11 @@ void Client::parseSnapshot(Packet& packet)
|
||||
}
|
||||
}
|
||||
|
||||
int Client::receive(char* data)
|
||||
size_t Client::receive(char* data)
|
||||
{
|
||||
boost::system::error_code error;
|
||||
|
||||
int bytesReceived = m_Socket.receive_from(boost
|
||||
size_t bytesReceived = m_Socket.receive_from(boost
|
||||
::asio::buffer((void*)data, INPUTSIZE),
|
||||
m_ReceiverEndpoint,
|
||||
0, error);
|
||||
@@ -390,7 +390,7 @@ void Client::identifyPacketLoss()
|
||||
bool Client::hasServerTimedOut()
|
||||
{
|
||||
// Time in ms
|
||||
float timeSincePing = 1000 * (std::clock() - m_StartPingTime) / static_cast<double>(CLOCKS_PER_SEC);
|
||||
double timeSincePing = 1000 * (std::clock() - m_StartPingTime) / static_cast<double>(CLOCKS_PER_SEC);
|
||||
if (timeSincePing > m_TimeoutMs) {
|
||||
// Clear everything and go to menu.
|
||||
LOG_INFO("Server has timed out, returning to menu, Beep Boop.");
|
||||
|
||||
@@ -26,10 +26,10 @@ void Network::saveToFile()
|
||||
outfile << "Total messages received," + std::to_string(m_NetworkData.AmountOfMessagesReceived) + "\n";
|
||||
outfile << "Total messages sent," + std::to_string(m_NetworkData.AmountOfMessagesSent) + "\n";
|
||||
|
||||
float messagesReceivedPerSec = (float)m_NetworkData.AmountOfMessagesReceived / (m_NetworkData.TotalTime / 1000);
|
||||
float messagesSentPerSec = (float)m_NetworkData.AmountOfMessagesSent / (m_NetworkData.TotalTime / 1000);
|
||||
float dataReceivedPerSec = (float)m_NetworkData.TotalDataReceived / (m_NetworkData.TotalTime / 1000);
|
||||
float dataSentPerSec = (float)m_NetworkData.TotalDataSent / (m_NetworkData.TotalTime / 1000);
|
||||
double messagesReceivedPerSec = m_NetworkData.AmountOfMessagesReceived / (m_NetworkData.TotalTime / 1000);
|
||||
double messagesSentPerSec = m_NetworkData.AmountOfMessagesSent / (m_NetworkData.TotalTime / 1000);
|
||||
double dataReceivedPerSec = m_NetworkData.TotalDataReceived / (m_NetworkData.TotalTime / 1000);
|
||||
double dataSentPerSec = m_NetworkData.TotalDataSent / (m_NetworkData.TotalTime / 1000);
|
||||
outfile << "Avarage messages received / s: " + std::to_string(messagesReceivedPerSec) + "\n";
|
||||
outfile << "Avarage messages sents / s: " + std::to_string(messagesSentPerSec) + "\n";
|
||||
outfile << "Avarage data received B/s: " + std::to_string(dataReceivedPerSec) + "\n";
|
||||
@@ -52,7 +52,7 @@ void Network::updateNetworkData()
|
||||
if (m_SaveDataIntervalMs < (1000 * (currentTime - m_SaveDataTimer) / (double)CLOCKS_PER_SEC)) {
|
||||
// Set values
|
||||
m_NetworkData.TotalTime += (1000 * (currentTime - m_SaveDataTimer) / (double)CLOCKS_PER_SEC);
|
||||
m_NetworkData.BandwidthBytes.push_back(std::pair<unsigned int, unsigned int>(m_NetworkData.DataReceivedThisInterval, m_NetworkData.DataSentThisInterval));
|
||||
m_NetworkData.BandwidthBytes.push_back(std::pair<size_t, size_t>(m_NetworkData.DataReceivedThisInterval, m_NetworkData.DataSentThisInterval));
|
||||
// Reset interval stuff
|
||||
m_SaveDataTimer = std::clock();
|
||||
m_NetworkData.DataSentThisInterval = 0;
|
||||
|
||||
@@ -7,7 +7,7 @@ Packet::Packet(MessageType type, unsigned int& packetID)
|
||||
}
|
||||
|
||||
// Create message
|
||||
Packet::Packet(char* data, const int sizeOfPacket)
|
||||
Packet::Packet(char* data, const size_t sizeOfPacket)
|
||||
{
|
||||
// Resize message
|
||||
m_MaxPacketSize = sizeOfPacket;
|
||||
@@ -45,7 +45,7 @@ void Packet::Init(MessageType type, unsigned int & packetID)
|
||||
void Packet::WriteString(const std::string& str)
|
||||
{
|
||||
// Message, add one extra byte for null terminator
|
||||
int sizeOfString = str.size() + 1;
|
||||
size_t sizeOfString = str.size() + 1;
|
||||
if (m_Offset + sizeOfString > m_MaxPacketSize) {
|
||||
//LOG_WARNING("Package::WriteString(): Data size in packet exceeded maximum package size. New size is %i bytes\n", m_MaxPacketSize*2);
|
||||
resizeData();
|
||||
@@ -82,7 +82,7 @@ char * Packet::ReadData(int SizeOfData)
|
||||
//LOG_WARNING("packet ReadData(): Oh no! You are trying to remove things outside my memory kingdom");
|
||||
return nullptr;
|
||||
}
|
||||
unsigned int oldReturnDataOffset = m_ReturnDataOffset;
|
||||
size_t oldReturnDataOffset = m_ReturnDataOffset;
|
||||
m_ReturnDataOffset += SizeOfData;
|
||||
return (m_Data + oldReturnDataOffset);
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ Server::Server() : m_Socket(m_IOService, boost::asio::ip::udp::endpoint(boost::a
|
||||
{
|
||||
Network::initialize();
|
||||
ConfigFile* config = ResourceManager::Load<ConfigFile>("Config.ini");
|
||||
snapshotInterval = 1000 * config->Get<float>("Networking.SnapshotInterval", 0.05);
|
||||
snapshotInterval = 1000 * config->Get<float>("Networking.SnapshotInterval", 0.05f);
|
||||
pingIntervalMs = config->Get<float>("Networking.PingIntervalMs", 1000);
|
||||
|
||||
}
|
||||
@@ -43,7 +43,7 @@ void Server::readFromClients()
|
||||
bytesRead = receive(readBuffer);
|
||||
Packet packet(readBuffer, bytesRead);
|
||||
parseMessageType(packet);
|
||||
} catch (const std::exception& err) {
|
||||
} catch (const std::exception&) {
|
||||
//LOG_ERROR("%i: Read from client crashed %s", m_PacketID, err.what());
|
||||
}
|
||||
}
|
||||
@@ -103,9 +103,9 @@ void Server::parseMessageType(Packet& packet)
|
||||
}
|
||||
}
|
||||
|
||||
int Server::receive(char * data)
|
||||
size_t Server::receive(char * data)
|
||||
{
|
||||
unsigned int length = m_Socket.receive_from(
|
||||
size_t length = m_Socket.receive_from(
|
||||
boost::asio::buffer((void*)data
|
||||
, INPUTSIZE)
|
||||
, m_ReceiverEndpoint, 0);
|
||||
@@ -121,7 +121,7 @@ int Server::receive(char * data)
|
||||
void Server::send(PlayerID player, Packet& packet)
|
||||
{
|
||||
try {
|
||||
int bytesSent = m_Socket.send_to(
|
||||
size_t bytesSent = m_Socket.send_to(
|
||||
boost::asio::buffer(packet.Data(), packet.Size()),
|
||||
m_ConnectedPlayers[player].Endpoint,
|
||||
0);
|
||||
@@ -131,7 +131,7 @@ void Server::send(PlayerID player, Packet& packet)
|
||||
m_NetworkData.DataSentThisInterval += packet.Size();
|
||||
m_NetworkData.AmountOfMessagesSent++;
|
||||
}
|
||||
} catch (const boost::system::system_error& e) {
|
||||
} catch (const boost::system::system_error&) {
|
||||
// TODO: Clean up invalid endpoints out of m_ConnectedPlayers later
|
||||
m_ConnectedPlayers[player].Endpoint = boost::asio::ip::udp::endpoint();
|
||||
}
|
||||
@@ -231,12 +231,12 @@ void Server::sendPing()
|
||||
|
||||
void Server::checkForTimeOuts()
|
||||
{
|
||||
int startPing = 1000 * m_StartPingTime
|
||||
double startPing = 1000 * m_StartPingTime
|
||||
/ static_cast<double>(CLOCKS_PER_SEC);
|
||||
|
||||
for (int i = 0; i < m_ConnectedPlayers.size(); i++) {
|
||||
if (m_ConnectedPlayers[i].Endpoint.address() != boost::asio::ip::address()) {
|
||||
int stopPing = 1000 * m_ConnectedPlayers[i].StopTime /
|
||||
double stopPing = 1000 * m_ConnectedPlayers[i].StopTime /
|
||||
static_cast<double>(CLOCKS_PER_SEC);
|
||||
if (startPing > stopPing + m_TimeoutMs) {
|
||||
LOG_INFO("User %i timed out!", i);
|
||||
|
||||
@@ -25,7 +25,7 @@ void DrawColorCorrectionPass::Draw(GLuint sceneTexture, GLuint bloomTexture, GLu
|
||||
|
||||
DrawScreenQuadPassState state = DrawScreenQuadPassState();
|
||||
m_ColorCorrectionProgram->Bind();
|
||||
//glClear(GL_COLOR_BUFFER_BIT);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
glUniform1f(glGetUniformLocation(m_ColorCorrectionProgram->GetHandle(), "Exposure"), exposure);
|
||||
glUniform1f(glGetUniformLocation(m_ColorCorrectionProgram->GetHandle(), "Gamma"), gamma);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user