mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-03-22 15:05:03 +01:00
Merge pull request #31 from wls50/master
support mouse picking in experimental renderer
This commit is contained in:
3
.gitmodules
vendored
3
.gitmodules
vendored
@@ -29,3 +29,6 @@
|
||||
[submodule "ref/json"]
|
||||
path = ref/json
|
||||
url = https://github.com/nlohmann/json
|
||||
[submodule "betterRenderer/thirdparty/bvh"]
|
||||
path = betterRenderer/thirdparty/bvh
|
||||
url = https://github.com/madmann91/bvh.git
|
||||
|
||||
@@ -22,6 +22,9 @@ add_subdirectory("thirdparty/fmt")
|
||||
add_subdirectory("thirdparty/entt")
|
||||
add_subdirectory("thirdparty/fsr2")
|
||||
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
add_subdirectory("thirdparty/bvh")
|
||||
|
||||
add_subdirectory("mashadercompiler")
|
||||
add_subdirectory("shaders")
|
||||
|
||||
@@ -105,5 +108,5 @@ endif ()
|
||||
|
||||
target_sources(${LIBMANUL_NAME} INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}/eu07_source/register.cpp")
|
||||
set_target_properties(nvrhi yaml-cpp fmt EnTT glfw yaml-cpp-parse yaml-cpp-read yaml-cpp-sandbox PROPERTIES FOLDER "libraries")
|
||||
target_link_libraries(${LIBMANUL_NAME} ${LIBMANUL_NAME}_fsr2 nvrhi yaml-cpp fmt EnTT glfw)
|
||||
target_link_libraries(${LIBMANUL_NAME} ${LIBMANUL_NAME}_fsr2 nvrhi yaml-cpp fmt EnTT glfw bvh)
|
||||
add_dependencies(${LIBMANUL_NAME} ${LIBMANUL_NAME}_shaders)
|
||||
@@ -25,12 +25,15 @@
|
||||
#include <Classes.h>
|
||||
#include <scene.h>
|
||||
|
||||
#include "nvrenderer_enums.h"
|
||||
#include "quadtree.h"
|
||||
#include "renderer.h"
|
||||
#include "nvrenderer_enums.h"
|
||||
#include "resource_registry.h"
|
||||
#include "sky.h"
|
||||
|
||||
namespace Rt {
|
||||
struct IRtModel;
|
||||
}
|
||||
template <typename Renderer>
|
||||
struct MaRendererConstants {
|
||||
static constexpr size_t NumMaterialPasses() noexcept {
|
||||
@@ -188,6 +191,9 @@ class NvRenderer : public gfx_renderer, public MaResourceRegistry {
|
||||
std::shared_ptr<struct Sky> m_sky;
|
||||
std::shared_ptr<struct MaAutoExposure> m_auto_exposure;
|
||||
|
||||
std::unordered_map<TModel3d const *, std::shared_ptr<Rt::IRtModel>> rt_models;
|
||||
std::shared_ptr<Rt::IRtModel> GetRtModel(TModel3d const *);
|
||||
|
||||
std::shared_ptr<struct MaConfig> m_config;
|
||||
struct MaConfig *GetConfig() const { return m_config.get(); }
|
||||
static struct MaConfig *Config();
|
||||
@@ -213,6 +219,10 @@ class NvRenderer : public gfx_renderer, public MaResourceRegistry {
|
||||
glm::dvec3 m_previous_env_position;
|
||||
uint64_t m_previous_env_frame;
|
||||
|
||||
glm::dvec3 m_mouse_ro;
|
||||
glm::dvec3 m_mouse_rd;
|
||||
TSubModel const *m_picked_submodel = nullptr;
|
||||
|
||||
using section_sequence = std::vector<scene::basic_section *>;
|
||||
using distancecell_pair = std::pair<double, scene::basic_cell *>;
|
||||
using cell_sequence = std::vector<distancecell_pair>;
|
||||
|
||||
@@ -14,18 +14,16 @@ struct MaResourceMapping {
|
||||
entt::hashed_string m_key;
|
||||
nvrhi::ResourceType m_type;
|
||||
|
||||
#define MA_RESOURCE_MAPPING_INITIALIZER(type) \
|
||||
template <typename KeyType> \
|
||||
static MaResourceMapping type(int slot, const KeyType& key) { \
|
||||
MaResourceMapping mapping{}; \
|
||||
mapping.m_slot = slot; \
|
||||
mapping.m_key = static_cast<entt::hashed_string>(key); \
|
||||
mapping.m_type = nvrhi::ResourceType::type; \
|
||||
return mapping; \
|
||||
#define MA_RESOURCE_MAPPING_INITIALIZER(type) \
|
||||
static MaResourceMapping type(int slot, const char* key) { \
|
||||
MaResourceMapping mapping{}; \
|
||||
mapping.m_slot = slot; \
|
||||
mapping.m_key = static_cast<entt::hashed_string>(key); \
|
||||
mapping.m_type = nvrhi::ResourceType::type; \
|
||||
return mapping; \
|
||||
}
|
||||
|
||||
template <typename KeyType>
|
||||
static MaResourceMapping Texture_SRV(int slot, const KeyType& key) {
|
||||
static MaResourceMapping Texture_SRV(int slot, const char* key) {
|
||||
MaResourceMapping mapping{};
|
||||
mapping.m_slot = slot;
|
||||
mapping.m_key = static_cast<entt::hashed_string>(key);
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
#include <fmt/chrono.h>
|
||||
#include <fmt/format.h>
|
||||
|
||||
#include "rt_model.h"
|
||||
#include "tinyexr.h"
|
||||
|
||||
bool NvRenderer::Init(GLFWwindow *Window) {
|
||||
@@ -71,8 +72,8 @@ bool NvRenderer::Init(GLFWwindow *Window) {
|
||||
InitResourceRegistry();
|
||||
|
||||
RegisterTexture("noise_2d_ldr",
|
||||
GetTextureManager()->FetchTexture(
|
||||
"textures/noise/LDR_RGB1_0", GL_RGBA, 0, false));
|
||||
GetTextureManager()->FetchTexture("textures/noise/LDR_RGB1_0",
|
||||
GL_RGBA, 0, false));
|
||||
|
||||
m_imgui_renderer = std::make_shared<NvImguiRenderer>(this);
|
||||
m_gbuffer = std::make_shared<NvGbuffer>(this);
|
||||
@@ -374,6 +375,22 @@ bool NvRenderer::Render() {
|
||||
m_backend->GetDevice()->executeCommandList(command_list_sky);
|
||||
}
|
||||
|
||||
{
|
||||
glm::dvec2 const mousepos =
|
||||
glm::dvec2(2., -2.) *
|
||||
(static_cast<glm::dvec2>(Global.cursor_pos) /
|
||||
static_cast<glm::dvec2>(Global.window_size) -
|
||||
.5);
|
||||
m_mouse_ro = pass.m_origin;
|
||||
glm::dvec4 mouse_rd_norm =
|
||||
inverse(projection) * glm::dvec4(mousepos, 1., 1.);
|
||||
mouse_rd_norm /= mouse_rd_norm.w;
|
||||
m_mouse_rd =
|
||||
normalize(inverse(transform) * glm::dvec4(mouse_rd_norm.xyz, 0.));
|
||||
}
|
||||
|
||||
m_picked_submodel = nullptr;
|
||||
|
||||
if (!m_pause_animations) {
|
||||
Animate(pass.m_origin, pass.m_draw_range, pass.m_frame_index);
|
||||
}
|
||||
@@ -729,10 +746,9 @@ void NvRenderer::SwapBuffers() {
|
||||
m_backend->GetDevice()->runGarbageCollection();
|
||||
}
|
||||
|
||||
float NvRenderer::Framerate() {
|
||||
|
||||
return 1000.f / (Timer::subsystem.mainloop_total.average());
|
||||
//return 0.0f;
|
||||
float NvRenderer::Framerate() {
|
||||
return 1000.f / (Timer::subsystem.mainloop_total.average());
|
||||
// return 0.0f;
|
||||
}
|
||||
|
||||
gfx::geometrybank_handle NvRenderer::Create_Bank() {
|
||||
@@ -1061,12 +1077,14 @@ ITexture const &NvRenderer::Texture(texture_handle const Texture) const {
|
||||
}
|
||||
|
||||
void NvRenderer::Pick_Control_Callback(
|
||||
std::function<void(TSubModel const *, const glm::vec2)> Callback) {}
|
||||
std::function<void(TSubModel const *, const glm::vec2)> Callback) {
|
||||
Callback(m_picked_submodel, {});
|
||||
}
|
||||
|
||||
void NvRenderer::Pick_Node_Callback(
|
||||
std::function<void(scene::basic_node *)> Callback) {}
|
||||
|
||||
TSubModel const *NvRenderer::Pick_Control() const { return nullptr; }
|
||||
TSubModel const *NvRenderer::Pick_Control() const { return m_picked_submodel; }
|
||||
|
||||
scene::basic_node const *NvRenderer::Pick_Node() const { return nullptr; }
|
||||
|
||||
@@ -1217,6 +1235,17 @@ void NvRenderer::MakeScreenshot() {
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<Rt::IRtModel> NvRenderer::GetRtModel(TModel3d const *model) {
|
||||
if (!model) {
|
||||
return nullptr;
|
||||
}
|
||||
auto &entry = rt_models[model];
|
||||
if (!entry) {
|
||||
entry = Rt::CreateRtModel(model, this);
|
||||
}
|
||||
return entry;
|
||||
}
|
||||
|
||||
MaConfig *NvRenderer::Config() {
|
||||
NvRenderer *me = dynamic_cast<NvRenderer *>(GfxRenderer.get());
|
||||
return me ? me->GetConfig() : nullptr;
|
||||
@@ -1873,6 +1902,10 @@ void NvRenderer::Animate(DynObj &instance, const glm::dvec3 &origin,
|
||||
if (render_kabina) {
|
||||
Animate(instance.m_renderable_kabina, instance.m_dynamic->mdKabina,
|
||||
material, instance.m_distance, dynamic_transform, frame);
|
||||
if (auto const rt_model = GetRtModel(instance.m_dynamic->mdKabina)) {
|
||||
m_picked_submodel = rt_model->Intersect(instance.m_renderable_kabina,
|
||||
m_mouse_ro, m_mouse_rd);
|
||||
}
|
||||
}
|
||||
|
||||
if (instance.m_dynamic->btnOn) instance.m_dynamic->TurnOff();
|
||||
|
||||
@@ -386,12 +386,12 @@ bool NvTexture::CreateRhiTexture() {
|
||||
.setHeight(m_height)
|
||||
.setMipLevels(m_data.size())
|
||||
.setFormat(m_format)
|
||||
.setInitialState(nvrhi::ResourceStates::CopyDest)
|
||||
.setInitialState(nvrhi::ResourceStates::ShaderResource)
|
||||
.setKeepInitialState(true));
|
||||
nvrhi::CommandListHandle command_list =
|
||||
backend->GetDevice()->createCommandList(
|
||||
nvrhi::CommandListParameters()
|
||||
.setQueueType(nvrhi::CommandQueue::Copy)
|
||||
.setQueueType(nvrhi::CommandQueue::Graphics)
|
||||
.setEnableImmediateExecution(false));
|
||||
command_list->open();
|
||||
for (int mip = 0; mip < m_data.size(); ++mip) {
|
||||
@@ -400,7 +400,7 @@ bool NvTexture::CreateRhiTexture() {
|
||||
}
|
||||
command_list->close();
|
||||
backend->GetDevice()->executeCommandList(command_list,
|
||||
nvrhi::CommandQueue::Copy);
|
||||
nvrhi::CommandQueue::Graphics);
|
||||
if (m_sz_texture->get_type() == "make:") {
|
||||
auto const components{Split(std::string(m_sz_texture->get_name()), '?')};
|
||||
|
||||
|
||||
151
betterRenderer/renderer/source/rt_model.cpp
Normal file
151
betterRenderer/renderer/source/rt_model.cpp
Normal file
@@ -0,0 +1,151 @@
|
||||
#include "rt_model.h"
|
||||
|
||||
#include <bvh/v2/bvh.h>
|
||||
#include <bvh/v2/default_builder.h>
|
||||
#include <bvh/v2/executor.h>
|
||||
#include <bvh/v2/stack.h>
|
||||
#include <bvh/v2/thread_pool.h>
|
||||
#include <bvh/v2/tri.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "Model3d.h"
|
||||
|
||||
namespace Rt {
|
||||
|
||||
using Bbox = bvh::v2::BBox<float, 3>;
|
||||
using Vec = bvh::v2::Vec<float, 3>;
|
||||
using Tri = bvh::v2::PrecomputedTri<float>;
|
||||
using Node = bvh::v2::Node<float, 3>;
|
||||
|
||||
struct RtSubmodel {
|
||||
TSubModel const* submodel;
|
||||
bvh::v2::Bvh<Node> bvh;
|
||||
std::vector<Tri> tris;
|
||||
};
|
||||
|
||||
struct RtModel : IRtModel {
|
||||
std::vector<RtSubmodel> submodels;
|
||||
std::unordered_map<size_t, int> submodel_mapping;
|
||||
|
||||
RtModel& FromModel3d(TModel3d const* src, NvRenderer const* owner);
|
||||
void FromSubmodel(TSubModel const* submodel, NvRenderer const* owner);
|
||||
const TSubModel* Intersect(NvRenderer::Renderable const& renderable,
|
||||
glm::dvec3 const& ro,
|
||||
glm::dvec3 const& rd) const override;
|
||||
};
|
||||
} // namespace Rt
|
||||
|
||||
std::shared_ptr<Rt::IRtModel> Rt::CreateRtModel(TModel3d const* src,
|
||||
NvRenderer const* owner) {
|
||||
auto model = std::make_shared<RtModel>();
|
||||
model->FromModel3d(src, owner);
|
||||
return model;
|
||||
}
|
||||
|
||||
Rt::RtModel& Rt::RtModel::FromModel3d(TModel3d const* src,
|
||||
NvRenderer const* owner) {
|
||||
FromSubmodel(src->Root, owner);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void Rt::RtModel::FromSubmodel(TSubModel const* submodel,
|
||||
NvRenderer const* owner) {
|
||||
if (!submodel) {
|
||||
return;
|
||||
}
|
||||
for (; !!submodel; submodel = submodel->Next) {
|
||||
if (submodel->fSquareMinDist >
|
||||
0.) { // Only LOD0 contributes to RT structure
|
||||
continue;
|
||||
}
|
||||
if (submodel->eType == GL_TRIANGLES ||
|
||||
submodel->eType == GL_TRIANGLE_STRIP) {
|
||||
submodel_mapping[submodel->m_geometry.handle] = submodels.size();
|
||||
auto& dest = submodels.emplace_back();
|
||||
auto const& verts = owner->Vertices(submodel->m_geometry.handle);
|
||||
auto const& indices = owner->Indices(submodel->m_geometry.handle);
|
||||
auto add_triangle = [&](glm::vec3 const& a, glm::vec3 const& b,
|
||||
glm::vec3 const& c) {
|
||||
dest.tris.emplace_back(Vec(a.x, a.y, a.z), Vec(b.x, b.y, b.z),
|
||||
Vec(c.x, c.y, c.z));
|
||||
};
|
||||
bool const is_indexed = !indices.empty();
|
||||
for (int idx = 0, num = is_indexed ? indices.size() : verts.size();
|
||||
idx < num; idx += 3) {
|
||||
std::array<int, 3> tri_indices;
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
if (is_indexed)
|
||||
tri_indices[i] = indices[idx + i];
|
||||
else
|
||||
tri_indices[i] = idx + i;
|
||||
}
|
||||
add_triangle(verts[tri_indices[0]].position,
|
||||
verts[tri_indices[1]].position,
|
||||
verts[tri_indices[2]].position);
|
||||
}
|
||||
|
||||
bvh::v2::ThreadPool thread_pool;
|
||||
bvh::v2::ParallelExecutor executor(thread_pool);
|
||||
|
||||
// Get triangle centers and bounding boxes (required for BVH builder)
|
||||
std::vector<Bbox> bboxes(dest.tris.size());
|
||||
std::vector<Vec> centers(dest.tris.size());
|
||||
executor.for_each(0, dest.tris.size(), [&](size_t begin, size_t end) {
|
||||
for (size_t i = begin; i < end; ++i) {
|
||||
bboxes[i] = dest.tris[i].get_bbox();
|
||||
centers[i] = dest.tris[i].get_center();
|
||||
}
|
||||
});
|
||||
|
||||
dest.submodel = submodel;
|
||||
|
||||
bvh::v2::DefaultBuilder<Node>::Config config;
|
||||
config.quality = bvh::v2::DefaultBuilder<Node>::Quality::High;
|
||||
dest.bvh = bvh::v2::DefaultBuilder<Node>::build(thread_pool, bboxes,
|
||||
centers, config);
|
||||
}
|
||||
FromSubmodel(submodel->Child, owner);
|
||||
}
|
||||
}
|
||||
|
||||
const TSubModel* Rt::RtModel::Intersect(
|
||||
NvRenderer::Renderable const& renderable, glm::dvec3 const& ro,
|
||||
glm::dvec3 const& rd) const {
|
||||
TSubModel const* result = nullptr;
|
||||
bvh::v2::SmallStack<bvh::v2::Bvh<Node>::Index, 64> stack;
|
||||
bvh::v2::Ray<float, 3> ray{};
|
||||
ray.tmax = std::numeric_limits<float>::max();
|
||||
for (auto const& item : renderable.m_items) {
|
||||
if (item.m_sqr_distance_min > 0. || item.m_render_in_forward) {
|
||||
continue;
|
||||
}
|
||||
if (auto const it = submodel_mapping.find(item.m_geometry);
|
||||
it != submodel_mapping.end()) {
|
||||
auto const& submodel = submodels[it->second];
|
||||
glm::dmat4 const submodel_matrix =
|
||||
glm::inverse(glm::dmat4(item.m_transform));
|
||||
glm::vec3 ro_local = submodel_matrix * glm::dvec4(ro, 1.);
|
||||
glm::vec3 rd_local = normalize(submodel_matrix * glm::dvec4(rd, 0.));
|
||||
ray.org = {ro_local.x, ro_local.y, ro_local.z};
|
||||
ray.dir = {rd_local.x, rd_local.y, rd_local.z};
|
||||
float u, v;
|
||||
size_t prim_id = std::numeric_limits<size_t>::max();
|
||||
stack.size = 0;
|
||||
submodel.bvh.intersect<true, false>(
|
||||
ray, submodel.bvh.get_root().index, stack,
|
||||
[&](size_t const begin, size_t const end) {
|
||||
for (size_t i = begin; i < end; ++i) {
|
||||
size_t const j = submodel.bvh.prim_ids[i];
|
||||
if (auto hit = submodel.tris[j].intersect(ray)) {
|
||||
prim_id = i;
|
||||
std::tie(ray.tmax, u, v) = *hit;
|
||||
result = submodel.submodel;
|
||||
}
|
||||
}
|
||||
return prim_id != std::numeric_limits<size_t>::max();
|
||||
});
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
24
betterRenderer/renderer/source/rt_model.h
Normal file
24
betterRenderer/renderer/source/rt_model.h
Normal file
@@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
|
||||
#include <glm/vec3.hpp>
|
||||
#include <memory>
|
||||
|
||||
#include "nvrenderer/nvrenderer.h"
|
||||
|
||||
class TSubModel;
|
||||
class TModel3d;
|
||||
|
||||
namespace Rt {
|
||||
struct IRtModel {
|
||||
virtual TSubModel const* Intersect(NvRenderer::Renderable const& renderable,
|
||||
glm::dvec3 const& ro,
|
||||
glm::dvec3 const& rd) const {
|
||||
return nullptr;
|
||||
}
|
||||
virtual ~IRtModel() = default;
|
||||
};
|
||||
|
||||
std::shared_ptr<IRtModel> CreateRtModel(TModel3d const* src,
|
||||
NvRenderer const* owner);
|
||||
|
||||
} // namespace Rt
|
||||
@@ -239,7 +239,7 @@ void CS_CullLights(in ComputeShaderInput input) {
|
||||
bool is_opaque = false;
|
||||
|
||||
if(light.m_cos_outer < -1.5) {
|
||||
while(dist < maxDist) {
|
||||
for(int i = 0; i < 100 && dist < maxDist; ++i) {
|
||||
float3 ro = dist * rd;
|
||||
float distance = sdSphere(ro - lightPosVS, light.m_radius);
|
||||
if(distance <= dist * tan_angle) {
|
||||
@@ -252,7 +252,7 @@ void CS_CullLights(in ComputeShaderInput input) {
|
||||
|
||||
if(!is_opaque) {
|
||||
dist = minDistOpaque - 1.e-2;
|
||||
while(dist < maxDist) {
|
||||
for(int i = 0; i < 100 && dist < maxDist; ++i) {
|
||||
float3 ro = dist * rd;
|
||||
float distance = sdSphere(ro - lightPosVS, light.m_radius);
|
||||
if(distance <= dist * tan_angle) {
|
||||
@@ -271,7 +271,7 @@ void CS_CullLights(in ComputeShaderInput input) {
|
||||
float3x3 transform = {tang, lightDirVS, bitang};
|
||||
|
||||
float2 angle = {sqrt(1. - light.m_cos_outer * light.m_cos_outer), light.m_cos_outer};
|
||||
while(dist < maxDist) {
|
||||
for(int i = 0; i < 100 && dist < maxDist; ++i) {
|
||||
float3 ro = dist * rd;
|
||||
float distance = sdSolidAngle(mul(transform, ro - lightPosVS), angle, light.m_radius);
|
||||
if(distance <= dist * tan_angle) {
|
||||
@@ -284,7 +284,7 @@ void CS_CullLights(in ComputeShaderInput input) {
|
||||
|
||||
if(!is_opaque) {
|
||||
dist = minDistOpaque - 1.e-2;
|
||||
while(dist < maxDist) {
|
||||
for(int i = 0; i < 100 && dist < maxDist; ++i) {
|
||||
float3 ro = dist * rd;
|
||||
float distance = sdSolidAngle(mul(transform, ro - lightPosVS), angle, light.m_radius);
|
||||
if(distance <= dist * tan_angle) {
|
||||
|
||||
1
betterRenderer/thirdparty/bvh
vendored
Submodule
1
betterRenderer/thirdparty/bvh
vendored
Submodule
Submodule betterRenderer/thirdparty/bvh added at ac41ab88a3
Reference in New Issue
Block a user