Skip to content

Commit

Permalink
Static light to VOB line-of-sight
Browse files Browse the repository at this point in the history
- implement line-of-sight check from VOBs to their static lights based on world mesh geometry
  - improve debug rendering
  - implement line-of-sight ray debug line rendering
- fix rayDownIntersectsFaceBB for naive impl
- implement SRGB to linear conversion for any colors / lights loaded from ZEN, apply conversion also to light weights
  • Loading branch information
Katharsas committed Apr 13, 2024
1 parent 6cdd6eb commit 1ef934c
Show file tree
Hide file tree
Showing 14 changed files with 204 additions and 29 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -252,4 +252,5 @@ imgui.ini
/ZenRen/lib/imgui/misc/
/ZenRen/data_*
*.tlog
*.log.txt
*.log.txt
/tmp/
2 changes: 2 additions & 0 deletions ZenRen/ZenRen.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,7 @@
<ClCompile Include="src\renderer\ShaderManager.cpp" />
<ClCompile Include="src\Util.cpp" />
<ClCompile Include="src\renderer\loader\StaticLightFromGroundFace.cpp" />
<ClCompile Include="src\renderer\loader\StaticLightFromVobLight.cpp" />
<ClCompile Include="stdafx.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='DebugFast|Win32'">Create</PrecompiledHeader>
Expand Down Expand Up @@ -413,6 +414,7 @@
<ClInclude Include="src\Settings.h" />
<ClInclude Include="src\Util.h" />
<ClInclude Include="src\renderer\loader\StaticLightFromGroundFace.h" />
<ClInclude Include="src\renderer\loader\StaticLightFromVobLight.h" />
<ClInclude Include="stdafx.h" />
<ClInclude Include="targetver.h" />
<ClInclude Include="src\game\TimerPrecision.h" />
Expand Down
2 changes: 2 additions & 0 deletions ZenRen/ZenRen.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@
<ClCompile Include="src\renderer\loader\VertPosLookup.cpp" />
<ClCompile Include="src\renderer\loader\StaticLightFromGroundFace.cpp" />
<ClCompile Include="src\renderer\loader\DebugMeshes.cpp" />
<ClCompile Include="src\renderer\loader\StaticLightFromVobLight.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="src\Util.h">
Expand Down Expand Up @@ -160,5 +161,6 @@
<ClInclude Include="lib\octree_attcs\octree_container.h" />
<ClInclude Include="src\renderer\loader\StaticLightFromGroundFace.h" />
<ClInclude Include="src\renderer\loader\DebugMeshes.h" />
<ClInclude Include="src\renderer\loader\StaticLightFromVobLight.h" />
</ItemGroup>
</Project>
42 changes: 40 additions & 2 deletions ZenRen/src/renderer/loader/DebugMeshes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ namespace renderer::loader
return result;
}

void loadPointDebugVisual(unordered_map<Material, VEC_VERTEX_DATA>& target, const VEC3& pos, const VEC3& scale)
void loadPointDebugVisual(unordered_map<Material, VEC_VERTEX_DATA>& target, const VEC3& pos, const VEC3& scale, const D3DXCOLOR& color)
{
vector<VERTEX_POS> facesPos;
vector<VERTEX_OTHER> facesOther;
Expand All @@ -107,11 +107,49 @@ namespace renderer::loader
faceNormal,
UV { 0, 0 },
ARRAY_UV { 0, 0, -1 },
D3DXCOLOR(1, 0, 0, 1)
color
});
}
}
const Material defaultMat = { "point.tga" };
insert(target, defaultMat, facesPos, facesOther);
}

vector<array<XMVECTOR, 3>> createDebugLineVerts(const VEC3& posStart, const VEC3& posEnd, const float width)
{
float minWidth = 0.01f;
float actualWidth = std::max(minWidth, width);
VEC3 posStartTop = { posStart.x, posStart.y + actualWidth, posStart.z };
VEC3 posEndTop = { posEnd.x, posEnd.y + actualWidth, posEnd.z };

vector result = {
posToXM4({ posStart, posEnd, posEndTop }),
posToXM4({ posStart, posEndTop, posStartTop }),
// make double sided
posToXM4({ posStart, posStartTop, posEndTop }),
posToXM4({ posStart, posEndTop, posEnd }),
};
return result;
}

void loadLineDebugVisual(unordered_map<Material, VEC_VERTEX_DATA>& target, const VEC3& posStart, VEC3& posEnd, const D3DXCOLOR& color)
{
vector<VERTEX_POS> facesPos;
vector<VERTEX_OTHER> facesOther;
const auto& bboxFacesXm = createDebugLineVerts(posStart, posEnd, 0.02f);
for (auto& posXm : bboxFacesXm) {
const auto faceNormal = toVec3(calcFlatFaceNormal(posXm));
for (int32_t i = 0; i < 3; i++) {
facesPos.push_back(toVec3(posXm[i]));
facesOther.push_back({
faceNormal,
UV { 0, 0 },
ARRAY_UV { 0, 0, -1 },
color
});
}
}
const Material defaultMat = { "line.tga" };
insert(target, defaultMat, facesPos, facesOther);
}
}
3 changes: 2 additions & 1 deletion ZenRen/src/renderer/loader/DebugMeshes.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@
namespace renderer::loader
{
void loadInstanceMeshBboxDebugVisual(std::unordered_map<Material, VEC_VERTEX_DATA>& target, const StaticInstance& instance);
void loadPointDebugVisual(std::unordered_map<Material, VEC_VERTEX_DATA>& target, const VEC3& pos, const VEC3& scale = { 0.f, 0.f, 0.f });
void loadPointDebugVisual(std::unordered_map<Material, VEC_VERTEX_DATA>& target, const VEC3& pos, const VEC3& scale = { 0.f, 0.f, 0.f }, const D3DXCOLOR& color = D3DXCOLOR(1, 0, 0, 1));
void loadLineDebugVisual(std::unordered_map<Material, VEC_VERTEX_DATA>& target, const VEC3& posStart, VEC3& posEnd, const D3DXCOLOR& color = D3DXCOLOR(1, 0, 0, 1));
}
2 changes: 1 addition & 1 deletion ZenRen/src/renderer/loader/MeshFromVdfLoader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ namespace renderer::loader {
VERTEX_OTHER other;
other.normal = from(zenVert.Normal);
other.uvDiffuse = from(zenVert.TexCoord);
other.colLight = D3DXCOLOR(zenVert.Color);
other.colLight = fromSRGB(D3DXCOLOR(zenVert.Color));
//other.colLight = D3DXCOLOR(1, 1, 1, 0.f);

if (faceLightmapIndex == -1) {
Expand Down
13 changes: 13 additions & 0 deletions ZenRen/src/renderer/loader/MeshUtil.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,4 +50,17 @@ namespace renderer::loader
LOG(INFO) << "Vector was not normalized! " << source << " | " << normalized << " | " << nearEqualXm;
}
}

inline float fromSRGB(const float channel) {
return (channel <= 0.04045f) ? (channel / 12.92f) : pow((channel + 0.055f) / 1.055f, 2.4f);
}

D3DXCOLOR fromSRGB(const D3DXCOLOR color) {
auto result = color;
const float gamma = 2.2f;
result.r = fromSRGB(result.r);
result.g = fromSRGB(result.g);
result.b = fromSRGB(result.b);
return result;
}
}
3 changes: 3 additions & 0 deletions ZenRen/src/renderer/loader/MeshUtil.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,7 @@ namespace renderer::loader
}

void warnIfNotNormalized(const DirectX::XMVECTOR& source);

inline float fromSRGB(const float channel);
D3DXCOLOR fromSRGB(const D3DXCOLOR color);
}
28 changes: 28 additions & 0 deletions ZenRen/src/renderer/loader/StaticLightFromVobLight.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#include "stdafx.h"
#include "StaticLightFromVobLight.h"

#include "MeshUtil.h"

namespace renderer::loader
{
using namespace DirectX;
using ::std::vector;
using ::std::unordered_map;

bool rayIntersectsWorldFaces(XMVECTOR rayStart, XMVECTOR rayEnd, float maxDistance, const unordered_map<Material, VEC_VERTEX_DATA>& meshData, const VertLookupTree& vertLookup)
{
XMVECTOR direction = DirectX::XMVector3Normalize(rayEnd - rayStart);
vector<VertKey> vertKeys = rayIntersected(vertLookup, toVec3(rayStart), toVec3(rayEnd));
for (auto& vertKey : vertKeys) {
auto& face = vertKey.getPos(meshData);
XMVECTOR faceA = toXM4Pos(face[0]);
XMVECTOR faceB = toXM4Pos(face[1]);
XMVECTOR faceC = toXM4Pos(face[2]);
float distance;
bool intersects = TriangleTests::Intersects(rayStart, direction, faceA, faceB, faceC, distance);
if (intersects && distance <= maxDistance) {
return true;
}
}
}
}
9 changes: 9 additions & 0 deletions ZenRen/src/renderer/loader/StaticLightFromVobLight.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#pragma once

#include "../RendererCommon.h"
#include "VertPosLookup.h"

namespace renderer::loader
{
bool rayIntersectsWorldFaces(DirectX::XMVECTOR rayStart, DirectX::XMVECTOR rayEnd, float maxDistance, const std::unordered_map<Material, VEC_VERTEX_DATA>& meshData, const VertLookupTree& vertLookup);
}
50 changes: 36 additions & 14 deletions ZenRen/src/renderer/loader/VertPosLookup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,14 @@ namespace renderer::loader
{
using ::std::vector;
using ::std::unordered_map;
using ::std::array;

float rayIntersectTolerance = 0.1f;
const float rayIntersectTolerance = 0.0001f;

OrthoBoundingBox3D createBB3D(const vector<VERTEX_POS>& verts, uint32_t vertIndex)
{
float minX = FLT_MAX, minY = FLT_MAX, minZ = FLT_MAX;
float maxX = -FLT_MAX, maxY = -FLT_MAX, maxZ = -FLT_MAX;
//float minX = FLT_MAX, minZ = FLT_MAX;
//float maxX = -FLT_MAX, maxZ = -FLT_MAX;
for (uint32_t i = vertIndex; i < vertIndex + 3; i++) {
auto& vert = verts[i];
minX = std::min(minX, vert.x);
Expand All @@ -26,6 +25,22 @@ namespace renderer::loader
return OrthoTree::BoundingBoxND<3, float>{ {minX, minY, minZ}, {maxX, maxY, maxZ} };
}

OrthoBoundingBox3D createRaySearchBox(const array<VEC3, 2>& posStartEnd)
{
float minX = FLT_MAX, minY = FLT_MAX, minZ = FLT_MAX;
float maxX = -FLT_MAX, maxY = -FLT_MAX, maxZ = -FLT_MAX;
for (uint32_t i = 0; i < posStartEnd.size(); i++) {
auto& vert = posStartEnd[i];
minX = std::min(minX, vert.x);
minY = std::min(minY, vert.y);
minZ = std::min(minZ, vert.z);
maxX = std::max(maxX, vert.x);
maxY = std::max(maxY, vert.y);
maxZ = std::max(maxZ, vert.z);
}
return OrthoTree::BoundingBoxND<3, float>{ {minX, minY, minZ}, { maxX, maxY, maxZ } };
}

VertLookupTree createVertLookup(const unordered_map<Material, VEC_VERTEX_DATA>& meshData)
{
vector<OrthoBoundingBox3D> bboxes;
Expand Down Expand Up @@ -57,27 +72,34 @@ namespace renderer::loader
};

constexpr bool shouldFullyContain = false;
auto intersectedBoxesSorted = lookup.tree.RangeSearch<shouldFullyContain>(searchBox);
auto intersectedBoxes = lookup.tree.RangeSearch<shouldFullyContain>(searchBox);

// TODO while RayIntersectedAll should be equivalent from what i understand, it is missing most bboxes that RangeSearch finds
//auto intersectedBoxesSorted = cache.tree.RayIntersectedAll({ pos.x, pos.y, pos.z }, { 0, -1, 0 }, rayIntersectTolerance, searchSizeY);
//auto intersectedBoxes = lookup.tree.RayIntersectedAll({ pos.x, pos.y, pos.z }, { 0, -100.f, 0 }, rayIntersectTolerance, searchSizeY);

vector<VertKey> result;
for (auto id : intersectedBoxesSorted) {
const auto& vertKey = lookup.bboxIndexToVert.find(id)->second;
result.push_back(vertKey);
}
return result;
return lookup.bboxIdsToVertIds(intersectedBoxes);
}

vector<VertKey> rayIntersected(const VertLookupTree& lookup, const VEC3& rayPosStart, const VEC3& rayPosEnd) {
// TODO
// RayIntersectedAll is not giving the expected results, until then just get all boxes that intersect the bbox of the ray.
// This will be very slow for long rays but we just don't to long rays for now. We could also construct multiple bboxes along the ray.

auto searchBox = createRaySearchBox({ rayPosStart, rayPosEnd });

constexpr bool shouldFullyContain = false;
auto intersectedBoxes = lookup.tree.RangeSearch<shouldFullyContain>(searchBox);

return lookup.bboxIdsToVertIds(intersectedBoxes);
}

// ##############################################################################################################################
// Naive implementation does quadratic looping over all world faces each time, no spatial structure used. For debugging purposes.
// ##############################################################################################################################

__inline bool rayDownIntersectsFaceBB(const VEC3& pos, const vector<VERTEX_POS>& verts, const size_t vertIndex, const float searchSizeY) {
float minX = FLT_MAX, minZ = FLT_MAX;
float minY = -FLT_MAX, maxY = FLT_MAX;
float maxX = -FLT_MAX, maxZ = -FLT_MAX;
float minX = FLT_MAX, minY = FLT_MAX, minZ = FLT_MAX;
float maxX = -FLT_MAX, maxY = -FLT_MAX, maxZ = -FLT_MAX;

for (uint32_t i = vertIndex; i < vertIndex + 3; i++) {
const auto& vert = verts[i];
Expand Down
10 changes: 10 additions & 0 deletions ZenRen/src/renderer/loader/VertPosLookup.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,20 @@ namespace renderer::loader
struct VertLookupTree {
std::unordered_map<uint32_t, VertKey> bboxIndexToVert;
OrthoOctree tree;

const std::vector<VertKey> bboxIdsToVertIds(const std::vector<size_t>& bboxIds) const {
std::vector<VertKey> result;
for (auto id : bboxIds) {
const auto& vertKey = this->bboxIndexToVert.find(id)->second;
result.push_back(vertKey);
}
return result;
}
};

VertLookupTree createVertLookup(const std::unordered_map<Material, VEC_VERTEX_DATA>& meshData);
std::vector<VertKey> rayDownIntersected(const VertLookupTree& lookup, const VEC3& pos, float searchSizeY);
std::vector<VertKey> rayDownIntersectedNaive(const std::unordered_map<Material, VEC_VERTEX_DATA>& meshData, const VEC3& pos, float searchSizeY);
std::vector<VertKey> rayIntersected(const VertLookupTree& lookup, const VEC3& rayPosStart, const VEC3& rayPosEnd);
}

Loading

0 comments on commit 1ef934c

Please sign in to comment.