9#include <glm/gtc/type_ptr.hpp>
16constexpr float kFloatingOriginThreshold = 1.0e6f;
17constexpr float kNearClipDepthFraction = 0.05f;
18constexpr float kFarClipPaddingMultiplier = 1.25f;
19constexpr float kMinFarthestDepthOffset = 1.0f;
20constexpr float kMaxNearClipFractionOfFarClip = 0.5f;
22float maxAbsComponent(
const glm::vec3& v) {
23 return std::max({std::abs(v.x), std::abs(v.y), std::abs(v.z)});
26std::optional<std::pair<float, float>> viewDepthSpan(
const SceneObject& obj,
const glm::vec3& cameraPosition,
const glm::vec3& cameraFront) {
28 if (!mesh)
return std::nullopt;
32 const glm::vec3 max = aabb.getAABBMax();
35 float nearDepth = std::numeric_limits<float>::max();
36 float farDepth = -std::numeric_limits<float>::max();
38 for (
int x = 0; x < 2; ++x) {
39 for (
int y = 0; y < 2; ++y) {
40 for (
int z = 0; z < 2; ++z) {
41 const glm::vec3 corner(
46 const glm::vec3 world = glm::vec3(model * glm::vec4(corner, 1.0f));
47 const float depth = glm::dot(world - cameraPosition, cameraFront);
48 nearDepth = std::min(nearDepth, depth);
49 farDepth = std::max(farDepth, depth);
54 if (!std::isfinite(nearDepth) || !std::isfinite(farDepth)) {
58 return std::pair{nearDepth, farDepth};
72Scene::Scene(QOpenGLFunctions_4_5_Core* glFuncs) : funcs(glFuncs), camera(
Camera(glm::vec3(0.0f, 10.0f, 30.0f))), basicShader(nullptr), cameraUBO(2*sizeof(glm::mat4), 0, funcs), hoverUBO(sizeof(glm::ivec4) * 1024, 1, funcs), selectUBO(sizeof(glm::ivec4) * 1024, 2, funcs) {
74 basicShader =
ResourceManager::loadShader(
"assets/shaders/primitive/primitive.vert",
"assets/shaders/primitive/primitive.frag",
"basic");
75 ResourceManager::loadShader(
"assets/shaders/primitive/checkerboard.vert",
"assets/shaders/primitive/checkerboard.frag",
"checkerboard");
79 if (!freeIDs.empty()) {
80 uint32_t
id = freeIDs.back();
88 freeIDs.push_back(objID);
91void Scene::draw(
const std::optional<std::vector<ObjectSnapshot>>& snaps,
const std::unordered_set<uint32_t>& hoveredIDs,
const std::unordered_set<uint32_t>& selectedIDs) {
94 renderPositions.reserve(snaps->size());
95 for (
const auto &s : *snaps) {
96 renderPositions.emplace(s.body, s.position);
101 glm::vec3 renderTargetPosition;
102 const glm::vec3* renderTargetPositionPtr =
nullptr;
106 for (
const auto& snapshot : *snaps) {
107 if (snapshot.body == targetBody) {
108 renderTargetPosition = snapshot.position;
109 renderTargetPositionPtr = &renderTargetPosition;
115 camera.
update(renderTargetPositionPtr);
117 float nearestDepth = std::numeric_limits<float>::max();
119 bool foundVisibleDepth =
false;
121 for (
auto* drawable : instancedDrawables) {
125 const auto depthSpan = viewDepthSpan(*obj, camera.
position, camera.
front);
126 if (!depthSpan)
continue;
129 foundVisibleDepth =
true;
131 farthestDepth = std::max(farthestDepth, depthSpan->second);
134 if (foundVisibleDepth) {
136 const float nearClip = nearestDepth == std::numeric_limits<float>::max()
138 : std::clamp(nearestDepth * kNearClipDepthFraction,
Camera::kDefaultNearClip, farClip * kMaxNearClipFractionOfFarClip);
144 const bool useFloatingOrigin = maxAbsComponent(camera.
position) >= kFloatingOriginThreshold;
147 glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
148 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
152 cameraUBO.
updateData(glm::value_ptr(viewMatrix),
sizeof(glm::mat4),
sizeof(glm::mat4));
154 std::vector<glm::ivec4> hoverVec(1024, glm::ivec4(0));
155 for (uint32_t
id : hoveredIDs) {
156 if (
id < hoverVec.size()) {
157 hoverVec[id] = glm::ivec4(1);
161 std::vector<glm::ivec4> selectVec(1024, glm::ivec4(0));
162 for (uint32_t
id : selectedIDs) {
163 if (
id < selectVec.size()) {
164 selectVec[id] = glm::ivec4(1);
168 hoverUBO.
updateData(hoverVec.data(), hoverVec.size() *
sizeof(glm::ivec4));
169 selectUBO.
updateData(selectVec.data(), selectVec.size() *
sizeof(glm::ivec4));
172 std::map<BatchKey, std::vector<Rendering::InstanceData>> batches;
174 for (
auto* obj : instancedDrawables) {
179 for (
auto& [key, instances] : batches) {
182 key.mesh->drawInstanced(instances);
185 for (
auto* obj : customDrawables) {
195 assert(drawable !=
nullptr);
198 instancedDrawables.push_back(instanced);
200 customDrawables.push_back(custom);
205 assert(drawable !=
nullptr);
208 instancedDrawables.erase(
209 std::remove(instancedDrawables.begin(), instancedDrawables.end(), instanced),
210 instancedDrawables.end()
213 customDrawables.erase(
214 std::remove(customDrawables.begin(), customDrawables.end(), custom),
215 customDrawables.end()
Mathematical utility functions for 3D graphics and physics.
glm::mat4 getProjMatrix() const
void update(const glm::vec3 *renderTargetPosition=nullptr)
glm::mat4 getViewMatrix() const
void setClipRange(float nearPlane, float farPlane)
glm::mat4 getRenderViewMatrix() const
const SceneObject * getTarget() const
static constexpr float kDefaultNearClip
static constexpr float kDefaultFarClip
Interface for objects with specialized rendering requirements.
Base interface for all renderable objects in the scene.
Interface for objects that support GPU instanced rendering.
GPU mesh representation with support for instanced rendering.
const Physics::Bounding::AABB & getLocalAABB() const
Gets the local-space axis-aligned bounding box.
glm::vec3 getAABBMin() const override
Gets the minimum, maximum corner of the axis-aligned bounding box (AABB) that contains this collider.
static void loadPrimitives()
static Shader * loadShader(const std::string &vShaderPath, const std::string &fShaderPath, const std::string &name)
glm::mat4 getModelMatrix() const override
Gets the model transformation matrix for this instance.
static glm::vec3 getRenderOrigin()
Rendering::InstanceData getInstanceData() const override
Gets the complete per-instance data for GPU upload.
std::unordered_map< Physics::PhysicsBody *, glm::vec3 > PosMap
Shader * getShader() const override
Gets the shader used to render this object.
Physics::PhysicsBody * getPhysicsBody() const
static void setPhysicsPosMap(const PosMap &m)
static void setRenderOrigin(const glm::vec3 &origin)
Mesh * getMesh() const override
Gets the mesh geometry for this object.
void freeObjectID(uint32_t objID)
void removeDrawable(IDrawable *drawable)
uint32_t allocateObjectID()
void addDrawable(IDrawable *drawable)
Scene(QOpenGLFunctions_4_5_Core *glFuncs)
void draw(const std::optional< std::vector< ObjectSnapshot > > &snapshots, const std::unordered_set< uint32_t > &hoverIDs, const std::unordered_set< uint32_t > &selectIDs)
bool operator<(const BatchKey &other) const