From 2e32d593982e142c87071b1070bfe789b5ae1f9e Mon Sep 17 00:00:00 2001 From: codereader Date: Sun, 5 Dec 2021 08:35:43 +0100 Subject: [PATCH] #5584: Prepare for light volume rendering. --- radiantcore/entity/light/LightNode.cpp | 31 ++++++++-- radiantcore/entity/light/LightNode.h | 4 ++ radiantcore/entity/light/Renderables.cpp | 58 ++++++++++++++++++ radiantcore/entity/light/Renderables.h | 76 +++++++++--------------- 4 files changed, 118 insertions(+), 51 deletions(-) diff --git a/radiantcore/entity/light/LightNode.cpp b/radiantcore/entity/light/LightNode.cpp index 401ecbb4cd..9f5d4e7c8c 100644 --- a/radiantcore/entity/light/LightNode.cpp +++ b/radiantcore/entity/light/LightNode.cpp @@ -26,6 +26,7 @@ LightNode::LightNode(const IEntityClassPtr& eclass) : _lightEndInstance(_light.endTransformed(), std::bind(&LightNode::selectedChangedComponent, this, std::placeholders::_1)), _dragPlanes(std::bind(&LightNode::selectedChangedComponent, this, std::placeholders::_1)), _renderableOctagon(*this), + _renderableLightVolume(*this), _renderableRadius(_light._lightBox.origin), _renderableFrustum(_light._lightBox.origin, _light._lightStartTransformed, _light._frustum), _overrideColKey(colours::RKEY_OVERRIDE_LIGHTCOL) @@ -48,6 +49,7 @@ LightNode::LightNode(const LightNode& other) : _lightEndInstance(_light.endTransformed(), std::bind(&LightNode::selectedChangedComponent, this,std::placeholders:: _1)), _dragPlanes(std::bind(&LightNode::selectedChangedComponent, this, std::placeholders::_1)), _renderableOctagon(*this), + _renderableLightVolume(*this), _renderableRadius(_light._lightBox.origin), _renderableFrustum(_light._lightBox.origin, _light._lightStartTransformed, _light._frustum), _overrideColKey(colours::RKEY_OVERRIDE_LIGHTCOL) @@ -107,6 +109,7 @@ void LightNode::onRemoveFromScene(scene::IMapRootNode& root) setSelectedComponents(false, selection::ComponentSelectionMode::Face); _renderableOctagon.clear(); + _renderableLightVolume.clear(); } void LightNode::testSelect(Selector& selector, SelectionTest& test) @@ -280,7 +283,19 @@ void LightNode::selectedChangedComponent(const ISelectable& selectable) { void LightNode::onPreRender(const VolumeTest& volume) { // Pick the colour shader according to our settings - _renderableOctagon.update(_overrideColKey.get() ? getColourShader() : _colourKey.getColourShader()); + const auto& colourShader = _overrideColKey.get() ? getColourShader() : _colourKey.getColourShader(); + _renderableOctagon.update(colourShader); + + // Depending on the selected status or the entity settings, we need to update the wireframe volume + if (_showLightVolumeWhenUnselected || isSelected()) + { + _renderableLightVolume.update(colourShader); + } + else + { + // Light volume is not visible, hide it + _renderableLightVolume.clear(); + } } void LightNode::renderSolid(IRenderableCollector& collector, const VolumeTest& volume) const @@ -308,22 +323,24 @@ void LightNode::renderWireframe(IRenderableCollector& collector, const VolumeTes void LightNode::renderHighlights(IRenderableCollector& collector, const VolumeTest& volume) { collector.addHighlightRenderable(_renderableOctagon, Matrix4::getIdentity()); + collector.addHighlightRenderable(_renderableLightVolume, Matrix4::getIdentity()); } void LightNode::renderLightVolume(IRenderableCollector& collector, const Matrix4& localToWorld, bool selected) const { +#if 0 // Obtain the appropriate Shader for the light volume colour const auto& colourShader = _overrideColKey.get() ? getWireShader() : _colourKey.getColourShader(); if (!colourShader) return; - +#endif #if 0 // Main render, submit the diamond that represents the light entity collector.addRenderable(*colourShader, *this, localToWorld); #endif - +#if 0 // Render bounding box if selected or the showAllLighRadii flag is set if (selected || EntitySettings::InstancePtr()->getShowAllLightRadii()) { @@ -340,6 +357,7 @@ void LightNode::renderLightVolume(IRenderableCollector& collector, collector.addRenderable(*colourShader, _renderableRadius, localToWorld); } } +#endif } /* greebo: Calculates the corners of the light radii box and rotates them according the rotation matrix. @@ -592,7 +610,9 @@ void LightNode::_onTransformationChanged() _light.revertTransform(); evaluateTransform(); _light.updateOrigin(); + _renderableOctagon.queueUpdate(); + _renderableLightVolume.queueUpdate(); } void LightNode::_applyTransformation() @@ -614,16 +634,19 @@ void LightNode::onVisibilityChanged(bool isVisibleNow) if (isVisibleNow) { _renderableOctagon.queueUpdate(); + _renderableLightVolume.queueUpdate(); } else { + _renderableLightVolume.clear(); _renderableOctagon.clear(); } } void LightNode::onEntitySettingsChanged() { - // TODO + _showLightVolumeWhenUnselected = EntitySettings::InstancePtr()->getShowAllLightRadii(); + _renderableLightVolume.queueUpdate(); } } // namespace entity diff --git a/radiantcore/entity/light/LightNode.h b/radiantcore/entity/light/LightNode.h index 4cdf6f4a96..27053f239e 100644 --- a/radiantcore/entity/light/LightNode.h +++ b/radiantcore/entity/light/LightNode.h @@ -7,6 +7,7 @@ #include "dragplanes.h" #include "../VertexInstance.h" #include "../EntityNode.h" +#include "Renderables.h" namespace entity { @@ -41,9 +42,12 @@ class LightNode : // Renderable components of this light RenderableLightOctagon _renderableOctagon; + RenderableLightVolume _renderableLightVolume; RenderLightRadiiBox _renderableRadius; RenderLightProjection _renderableFrustum; + bool _showLightVolumeWhenUnselected; + // a temporary variable for calculating the AABB of all (selected) components mutable AABB m_aabb_component; diff --git a/radiantcore/entity/light/Renderables.cpp b/radiantcore/entity/light/Renderables.cpp index ceeefc80af..53279bee01 100644 --- a/radiantcore/entity/light/Renderables.cpp +++ b/radiantcore/entity/light/Renderables.cpp @@ -174,4 +174,62 @@ void RenderLightProjection::render(const RenderInfo& info) const } } +void RenderableLightOctagon::updateGeometry() +{ + if (!_needsUpdate) return; + + _needsUpdate = false; + + // Generate the indexed vertex data + static Vector3 Origin(0, 0, 0); + static Vector3 Extents(8, 8, 8); + + // Calculate the light vertices of this bounding box and store them into + Vector3 max(Origin + Extents); + Vector3 min(Origin - Extents); + Vector3 mid(Origin); + + // top, bottom, tleft, tright, bright, bleft + std::vector vertices + { + ArbitraryMeshVertex({ mid[0], mid[1], max[2] }, {1,0,0}, {0,0}), + ArbitraryMeshVertex({ mid[0], mid[1], min[2] }, {1,0,0}, {0,0}), + ArbitraryMeshVertex({ min[0], max[1], mid[2] }, {1,0,0}, {0,0}), + ArbitraryMeshVertex({ max[0], max[1], mid[2] }, {1,0,0}, {0,0}), + ArbitraryMeshVertex({ max[0], min[1], mid[2] }, {1,0,0}, {0,0}), + ArbitraryMeshVertex({ min[0], min[1], mid[2] }, {1,0,0}, {0,0}), + }; + + // Orient the points using the transform + const auto& orientation = _owner.localToWorld(); + for (auto& vertex : vertices) + { + vertex.vertex = orientation * vertex.vertex; + } + + // Indices are always the same, therefore constant + static const std::vector Indices + { + 0, 2, 3, + 0, 3, 4, + 0, 4, 5, + 0, 5, 2, + 1, 2, 5, + 1, 5, 4, + 1, 4, 3, + 1, 3, 2 + }; + + RenderableGeometry::updateGeometry(render::GeometryType::Triangles, vertices, Indices); +} + +void RenderableLightVolume::updateGeometry() +{ + if (!_needsUpdate) return; + + _needsUpdate = false; + + // TODO +} + } // namespace entity diff --git a/radiantcore/entity/light/Renderables.h b/radiantcore/entity/light/Renderables.h index 417a3e8943..fde8f8e588 100644 --- a/radiantcore/entity/light/Renderables.h +++ b/radiantcore/entity/light/Renderables.h @@ -11,7 +11,10 @@ void light_draw_box_lines(const Vector3& origin, const Vector3 points[8]); -namespace entity { +namespace entity +{ + +class LightNode; class RenderLightRadiiBox : public OpenGLRenderable { const Vector3& m_origin; @@ -36,6 +39,8 @@ class RenderLightProjection : public OpenGLRenderable { }; // class RenderLightProjection // The small diamond representing at the light's origin +// This is using the Triangle geometry type such that we can see +// the half-transparent (red) overlay when the light is selected class RenderableLightOctagon : public render::RenderableGeometry { @@ -55,54 +60,31 @@ class RenderableLightOctagon : } protected: - void updateGeometry() override + void updateGeometry() override; +}; + +// The wireframe showing the light volume of the light +// which is either a box (point light) or a frustum/cone (projected) +class RenderableLightVolume : + public render::RenderableGeometry +{ +private: + const LightNode& _light; + bool _needsUpdate; + +public: + RenderableLightVolume(const LightNode& light) : + _light(light), + _needsUpdate(true) + {} + + void queueUpdate() { - if (!_needsUpdate) return; - - _needsUpdate = false; - - // Generate the indexed vertex data - static Vector3 Origin(0, 0, 0); - static Vector3 Extents(8, 8, 8); - - // Calculate the light vertices of this bounding box and store them into - Vector3 max(Origin + Extents); - Vector3 min(Origin - Extents); - Vector3 mid(Origin); - - // top, bottom, tleft, tright, bright, bleft - std::vector vertices - { - ArbitraryMeshVertex({ mid[0], mid[1], max[2] }, {1,0,0}, {0,0}), - ArbitraryMeshVertex({ mid[0], mid[1], min[2] }, {1,0,0}, {0,0}), - ArbitraryMeshVertex({ min[0], max[1], mid[2] }, {1,0,0}, {0,0}), - ArbitraryMeshVertex({ max[0], max[1], mid[2] }, {1,0,0}, {0,0}), - ArbitraryMeshVertex({ max[0], min[1], mid[2] }, {1,0,0}, {0,0}), - ArbitraryMeshVertex({ min[0], min[1], mid[2] }, {1,0,0}, {0,0}), - }; - - // Orient the points using the transform - const auto& orientation = _owner.localToWorld(); - for (auto& vertex : vertices) - { - vertex.vertex = orientation * vertex.vertex; - } - - // Indices are always the same, therefore constant - static const std::vector Indices - { - 0, 2, 3, - 0, 3, 4, - 0, 4, 5, - 0, 5, 2, - 1, 2, 5, - 1, 5, 4, - 1, 4, 3, - 1, 3, 2 - }; - - RenderableGeometry::updateGeometry(render::GeometryType::Triangles, vertices, Indices); + _needsUpdate = true; } + +protected: + void updateGeometry() override; }; } // namespace entity