From 67c1489da098a14075850c17598827cbd8d5c769 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Till=20W=C3=BCbbers?= Date: Wed, 18 Jun 2025 00:28:40 +0200 Subject: [PATCH] heightmap wip --- src/game/Gen.cpp | 31 +++++++++++ src/game/Gen.h | 1 + src/game/Mesh.cpp | 96 ++++++++++++++++++++++++++++------ src/game/rendering/Rendering.h | 3 ++ 4 files changed, 114 insertions(+), 17 deletions(-) diff --git a/src/game/Gen.cpp b/src/game/Gen.cpp index 0c53bc0..fee978f 100644 --- a/src/game/Gen.cpp +++ b/src/game/Gen.cpp @@ -393,6 +393,37 @@ namespace Gen return true; } + bool RayTriangleIntersect(Vec3 l1, Vec3 l2, Vec3 p1, Vec3 p2, Vec3 p3, Vec3& out) + { + const float EPSILON = 1e-6f; + Vec3 dir = l2 - l1; // Ray direction + Vec3 edge1 = p2 - p1; + Vec3 edge2 = p3 - p1; + + Vec3 h = CrossProduct(dir, edge2); + float a = DotProduct(edge1, h); + + if (bx::abs(a) < EPSILON) return false; // Ray is parallel to the triangle + + float f = 1.0f / a; + Vec3 s = l1 - p1; + float u = f * DotProduct(s, h); + if (u < 0.0f || u > 1.0f) return false; + + Vec3 q = CrossProduct(s, edge1); + float v = f * DotProduct(dir, q); + if (v < 0.0f || u + v > 1.0f) return false; + + float t = f * DotProduct(edge2, q); + if (t > EPSILON) + { + out = l1 + dir * t; + return true; + } + + return false; + } + void Translate(Transform& trans, Vec3 offset) { trans.Position += Vec3{offset.x, offset.y, offset.z}; diff --git a/src/game/Gen.h b/src/game/Gen.h index adc3172..eca5183 100644 --- a/src/game/Gen.h +++ b/src/game/Gen.h @@ -81,6 +81,7 @@ namespace Gen Vec3 CrossProduct(Vec3 a, Vec3 b); Vec3 CrossProductFromPlane(Vec3 a, Vec3 b, Vec3 c); bool RayPlaneIntersect(Vec3 l1, Vec3 l2, Vec3 p1, Vec3 p2, Vec3 p3, Vec3& out); + bool RayTriangleIntersect(Vec3 l1, Vec3 l2, Vec3 p1, Vec3 p2, Vec3 p3, Vec3& out); void Translate(Transform& trans, Vec3 offset); void TranslateLocal(Transform& trans, Vec3 offset); diff --git a/src/game/Mesh.cpp b/src/game/Mesh.cpp index 4396f53..1fc5989 100644 --- a/src/game/Mesh.cpp +++ b/src/game/Mesh.cpp @@ -9,9 +9,11 @@ #include "bx/filepath.h" #include "bx/hash.h" #include "bx/string.h" +#include "bx/timer.h" #include "rendering/Rendering.h" #include "Instance.h" +#include #include #define TINYGLTF_IMPLEMENTATION @@ -61,23 +63,23 @@ namespace Game tinygltf::Primitive primitive = model.meshes[0].primitives[0]; { - tinygltf::Accessor accessor = model.accessors.at(primitive.indices); - tinygltf::BufferView bufferView = model.bufferViews.at(accessor.bufferView); - tinygltf::Buffer buffer = model.buffers[bufferView.buffer]; - const bgfx::Memory* ibMem = bgfx::alloc(bufferView.byteLength); - bx::memCopy(ibMem->data, &buffer.data.at(bufferView.byteOffset), bufferView.byteLength); + tinygltf::Accessor indexAccessor = model.accessors.at(primitive.indices); + tinygltf::BufferView indexBufferView = model.bufferViews.at(indexAccessor.bufferView); + int32_t indexStride = sizeof(uint16_t); + tinygltf::Buffer indexBuffer = model.buffers[indexBufferView.buffer]; + const bgfx::Memory* ibMem = bgfx::alloc(indexBufferView.byteLength); + bx::memCopy(ibMem->data, &indexBuffer.data.at(indexBufferView.byteOffset), indexBufferView.byteLength); mesh.IndexBuffer = bgfx::createIndexBuffer(ibMem); - } - { + tinygltf::Accessor posAccessor = model.accessors.at(primitive.attributes.at("POSITION")); tinygltf::Accessor normalAccessor = model.accessors.at(primitive.attributes.at("NORMAL")); tinygltf::Accessor uvAccessor = model.accessors.at(primitive.attributes.at("TEXCOORD_0")); tinygltf::BufferView posBufferView = model.bufferViews[posAccessor.bufferView]; tinygltf::BufferView normalBufferView = model.bufferViews[normalAccessor.bufferView]; tinygltf::BufferView uvBufferView = model.bufferViews[uvAccessor.bufferView]; - int posStride = posAccessor.ByteStride(posBufferView); - int normalStride = normalAccessor.ByteStride(normalBufferView); - int uvStride = uvAccessor.ByteStride(uvBufferView); + int32_t posStride = posAccessor.ByteStride(posBufferView); + int32_t normalStride = normalAccessor.ByteStride(normalBufferView); + int32_t uvStride = uvAccessor.ByteStride(uvBufferView); tinygltf::Buffer posBuffer = model.buffers[posBufferView.buffer]; tinygltf::Buffer normalBuffer = model.buffers[normalBufferView.buffer]; tinygltf::Buffer uvBuffer = model.buffers[uvBufferView.buffer]; @@ -95,15 +97,75 @@ namespace Game bx::memCopy(&v.uv_x, &uvBuffer.data.at(uvBufferView.byteOffset + i * uvStride), uvStride); } mesh.VertexBuffer = bgfx::createVertexBuffer(vbMem, mesh.VertLayout); + + constexpr float SIZE_LIMIT = 1000.0f; + mesh.MinPos = {SIZE_LIMIT, SIZE_LIMIT, SIZE_LIMIT}; + mesh.MaxPos = {-SIZE_LIMIT, -SIZE_LIMIT, -SIZE_LIMIT}; + + bx::memSet(mesh.Height.Values, 0, BX_COUNTOF(mesh.Height.Values)); + + int64_t startTime = bx::getHPCounter(); + for (int32_t i = 0; i < vertexCount; ++i) + { + Gen::Vec3* pos = + reinterpret_cast(&posBuffer.data[posBufferView.byteOffset + i * posStride]); + if (pos->x < mesh.MinPos.x) mesh.MinPos.x = pos->x; + if (pos->y < mesh.MinPos.y) mesh.MinPos.y = pos->y; + if (pos->z < mesh.MinPos.z) mesh.MinPos.z = pos->z; + if (pos->x > mesh.MaxPos.x) mesh.MaxPos.x = pos->x; + if (pos->y > mesh.MaxPos.y) mesh.MaxPos.y = pos->y; + if (pos->z > mesh.MaxPos.z) mesh.MaxPos.z = pos->z; + } + LOG("min/max: %lli", bx::getHPCounter() - startTime); + + mesh.Size = mesh.MaxPos - mesh.MinPos; + + startTime = bx::getHPCounter(); + for (uint32_t v = 0; v < HeightMap::Height; ++v) + { + float vPos = mesh.MinPos.y + (float)v / HeightMap::Height * mesh.Size.y; + + for (uint32_t u = 0; u < HeightMap::Width; ++u) + { + float uPos = mesh.MinPos.x + (float)u / HeightMap::Width * mesh.Size.x; + + Gen::Vec3 rayStart = {uPos, vPos, SIZE_LIMIT}; + Gen::Vec3 rayEnd = {uPos, vPos, -SIZE_LIMIT}; + Gen::Vec3 ptOut; + + for (int16_t i = 0; i < indexBufferView.byteLength; i += indexStride * 3) + { + uint16_t* idxA = reinterpret_cast(&indexBuffer.data[indexBufferView.byteOffset + i]); + uint16_t* idxB = reinterpret_cast( + &indexBuffer.data[indexBufferView.byteOffset + i + 1 * indexStride]); + uint16_t* idxC = reinterpret_cast( + &indexBuffer.data[indexBufferView.byteOffset + i + 2 * indexStride]); + Gen::Vec3* triA = + reinterpret_cast(&posBuffer.data[posBufferView.byteOffset + *idxA * posStride]); + Gen::Vec3* triB = + reinterpret_cast(&posBuffer.data[posBufferView.byteOffset + *idxB * posStride]); + Gen::Vec3* triC = + reinterpret_cast(&posBuffer.data[posBufferView.byteOffset + *idxC * posStride]); + if (Gen::RayTriangleIntersect(rayStart, rayEnd, *triA, *triB, *triC, ptOut)) + { + float len = mesh.MaxPos.z - ptOut.z; + uint8_t val = (uint8_t)(len / mesh.Size.z * UINT8_MAX); + int32_t idx = v * HeightMap::Width + u; + if (mesh.Height.Values[idx] < val) + { + mesh.Height.Values[idx] = val; + } + if (len < 0.0f) + { + LOG_ONCE("%f / %f = %u", len, mesh.Size.z, val); + } + } + } + } + } + LOG("heightmap: %lli", bx::getHPCounter() - startTime); } - for (uint32_t y = 0; y < HeightMap::Height; ++y) - { - for (uint32_t x = 0; x < HeightMap::Width; ++x) - { - mesh.Height.Values[y * HeightMap::Width + x] = (uint8_t)(((float)x / HeightMap::Width) * UINT8_MAX); - } - } const bgfx::Memory* mem = bgfx::makeRef(&mesh.Height.Values[0], sizeof(mesh.Height.Values)); mesh.HeightMapTexture = bgfx::createTexture2D(HeightMap::Width, HeightMap::Height, false, 1, bgfx::TextureFormat::R8, 0, mem); diff --git a/src/game/rendering/Rendering.h b/src/game/rendering/Rendering.h index 6f1ba66..3d947e3 100644 --- a/src/game/rendering/Rendering.h +++ b/src/game/rendering/Rendering.h @@ -58,6 +58,9 @@ namespace Game ModelSocket Sockets[MaxSocketCount]; HeightMap Height; bgfx::TextureHandle HeightMapTexture = {bgfx::kInvalidHandle}; + Gen::Vec3 MinPos; + Gen::Vec3 MaxPos; + Gen::Vec3 Size; char Name[128]{0}; };