diff options
Diffstat (limited to 'game/scenary')
| -rw-r--r-- | game/scenary/foliage.cpp | 143 | ||||
| -rw-r--r-- | game/scenary/foliage.h | 29 | ||||
| -rw-r--r-- | game/scenary/illuminator.cpp | 71 | ||||
| -rw-r--r-- | game/scenary/illuminator.h | 44 | ||||
| -rw-r--r-- | game/scenary/light.cpp | 4 | ||||
| -rw-r--r-- | game/scenary/light.h | 7 | ||||
| -rw-r--r-- | game/scenary/plant.cpp | 2 | ||||
| -rw-r--r-- | game/scenary/plant.h | 2 |
8 files changed, 176 insertions, 126 deletions
diff --git a/game/scenary/foliage.cpp b/game/scenary/foliage.cpp index 159a078..f27ac26 100644 --- a/game/scenary/foliage.cpp +++ b/game/scenary/foliage.cpp @@ -1,7 +1,34 @@ #include "foliage.h" +#include "gfx/frustum.h" +#include "gfx/gl/billboardPainter.h" #include "gfx/gl/sceneShader.h" #include "gfx/gl/shadowMapper.h" -#include "gfx/gl/vertexArrayObject.h" +#include "gfx/gl/shadowStenciller.h" +#include "util.h" +#include <location.h> + +static_assert(std::is_constructible_v<Foliage>); +constexpr float OBJECT_BILLBOARD_DIVISOR = 64; +constexpr float BILLBOARD_ANGLE_TOLERANCE = 250.F; // Radians per mm size +constexpr float ASSUMED_VIEWPORT = 1440; +constexpr float OVER_SAMPLE_MULTIPLIER = 2; // Use mesh until billboard 1/2 of rendered size + +namespace { + GLsizei + billboardTextureSizeForObject(RelativeDistance objectSize) + { + return static_cast<GLsizei>(std::pow(2, std::ceil(std::log2(objectSize / OBJECT_BILLBOARD_DIVISOR)))); + } +} + +std::weak_ptr<glVertexArray> Foliage::commonInstanceVAO, Foliage::commonInstancePointVAO; + +std::any +Foliage::createAt(const Location & position) const +{ + return std::make_shared<InstanceVertices<InstanceVertex>::InstanceProxy>( + instances.acquire(locationData->acquire(position))); +} bool Foliage::persist(Persistence::PersistenceStore & store) @@ -13,43 +40,117 @@ void Foliage::postLoad() { texture = getTexture(); - bodyMesh->configureVAO(instanceVAO) - .addAttribs<LocationVertex, &LocationVertex::rotation, &LocationVertex::position>( - instances.bufferName(), 1); - VertexArrayObject {instancePointVAO}.addAttribs<LocationVertex, &LocationVertex::position, &LocationVertex::yaw>( - instances.bufferName()); + glDebugScope _ {0}; + if (createIfRequired(instanceVAO, commonInstanceVAO)) { + bodyMesh->configureVAO(*instanceVAO, 0).addAttribs<InstanceVertex, &InstanceVertex::location>(1); + } + if (createIfRequired(instancePointVAO, commonInstancePointVAO)) { + instancePointVAO->configure().addAttribs<InstanceVertex, &InstanceVertex::location>(0); + } + const auto & size = bodyMesh->getDimensions().size; + billboardSize = billboardTextureSizeForObject(size); + ShadowStenciller::configureStencilTexture(shadowStencil, {billboardSize, billboardSize}); + BillboardPainter::configureBillBoardTextures(billboard, {billboardSize, billboardSize}); + useMeshClipDist = (ASSUMED_VIEWPORT * OVER_SAMPLE_MULTIPLIER * size) / static_cast<RelativeDistance>(billboardSize); } void -Foliage::updateStencil(const ShadowStenciller & ss) const +Foliage::updateStencil(const ShadowStenciller & shadowStenciller) const +{ + if (instancePartitions.second.second != instancePartitions.second.first + && glm::distance(shadowStenciller.getLightDirection(), shadowStencilDir) + > BILLBOARD_ANGLE_TOLERANCE / bodyMesh->getDimensions().size) { + shadowStenciller.renderStencil(shadowStencil, *bodyMesh, texture); + } +} + +void +Foliage::updateBillboard(const BillboardPainter & bbp) const +{ + if (instancePartitions.first != instancePartitions.second.first + && std::abs(bbp.getAngle() - billboardAngle) > BILLBOARD_ANGLE_TOLERANCE / bodyMesh->getDimensions().size) { + bbp.renderBillBoard(billboard, *bodyMesh, texture); + billboardAngle = bbp.getAngle(); + } +} + +void +Foliage::preFrame(const Frustum & frustum, const Frustum & lighting) { if (instances.size() > 0) { - ss.renderStencil(shadowStencil, *bodyMesh, texture); + const auto & dims = bodyMesh->getDimensions(); + instancePartitions = instances.partition( + [&frustum, &dims](const auto & instance) { + return frustum.contains(instance.location->position.xyz() + dims.centre, dims.size); + }, + [&frustum, this](const auto & instance) { + return distance(frustum.getPosition(), instance.location->position.xyz()) < useMeshClipDist; + }, + [&lighting, &dims](const auto & instance) { + return lighting.contains(instance.location->position.xyz() + dims.centre, dims.size); + }); + // In view frustum / Outside view frustum / + // Close to view / Far from view / Casts shadow into view / No shadow in view / } } void Foliage::render(const SceneShader & shader, const Frustum &) const { - if (const auto count = instances.size()) { - shader.basicInst.use(); - if (texture) { - texture->bind(); + if (instancePartitions.first) { + glDebugScope _ {*instanceVAO}; + std::ignore = instances.size(); + if (const auto count = instancePartitions.first - instancePartitions.second.first) { + glDebugScope _ {0, "Billboard"}; + const auto dimensions = bodyMesh->getDimensions(); + shader.billboard.use(dimensions.size, dimensions.centre); + billboard[0].bind(0); + billboard[1].bind(1); + billboard[2].bind(2); + glBindVertexArray(*instancePointVAO); + instancePointVAO->useBuffer(0, instances); + glDrawArrays(GL_POINTS, static_cast<GLint>(instancePartitions.second.first), static_cast<GLsizei>(count)); + glBindVertexArray(0); + } + if (const auto count = instancePartitions.second.first) { + glDebugScope _ {0, "Mesh"}; + shader.basicInst.use(); + if (texture) { + texture->bind(0); + } + instanceVAO->useBuffer(1, instances); + bodyMesh->drawInstanced(*instanceVAO, static_cast<GLsizei>(count)); } - bodyMesh->DrawInstanced(instanceVAO, static_cast<GLsizei>(count)); } } void Foliage::shadows(const ShadowMapper & mapper, const Frustum &) const { - if (const auto count = instances.size()) { - const auto dimensions = bodyMesh->getDimensions(); - mapper.stencilShadowProgram.use(dimensions.centre, dimensions.size); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D_ARRAY, shadowStencil); - glBindVertexArray(instancePointVAO); - glDrawArrays(GL_POINTS, 0, static_cast<GLsizei>(count)); - glBindVertexArray(0); + if (instancePartitions.second.second) { + glDebugScope _ {*instanceVAO}; + std::ignore = instances.size(); + if (const auto count = instancePartitions.second.second - instancePartitions.second.first) { + glDebugScope _ {0, "Billboard"}; + const auto dimensions = bodyMesh->getDimensions(); + mapper.stencilShadowProgram.use(dimensions.centre, dimensions.size); + shadowStencil.bind(0); + glBindVertexArray(*instancePointVAO); + instancePointVAO->useBuffer(0, instances); + glDrawArrays(GL_POINTS, static_cast<GLint>(instancePartitions.second.first), static_cast<GLsizei>(count)); + glBindVertexArray(0); + } + if (const auto count = instancePartitions.second.first) { + glDebugScope _ {0, "Mesh"}; + if (texture) { + texture->bind(3); + mapper.dynamicPointInstWithTextures.use(); + } + else { + mapper.dynamicPointInst.use(); + } + instanceVAO->useBuffer(1, instances); + bodyMesh->drawInstanced(*instanceVAO, static_cast<GLsizei>(count)); + } } } diff --git a/game/scenary/foliage.h b/game/scenary/foliage.h index 71bc734..f424ffc 100644 --- a/game/scenary/foliage.h +++ b/game/scenary/foliage.h @@ -2,7 +2,6 @@ #include "assetFactory/asset.h" #include "gfx/gl/instanceVertices.h" -#include "gfx/gl/shadowStenciller.h" #include "gfx/models/texture.h" #include "gfx/renderable.h" @@ -13,24 +12,36 @@ class Location; class Foliage : public Asset, public Renderable, public StdTypeDefs<Foliage> { Mesh::Ptr bodyMesh; Texture::Ptr texture; - glVertexArray instanceVAO; - glVertexArray instancePointVAO; + std::shared_ptr<glVertexArray> instanceVAO, instancePointVAO; + static std::weak_ptr<glVertexArray> commonInstanceVAO, commonInstancePointVAO; public: - struct LocationVertex { - glm::mat3 rotation; - float yaw; - GlobalPosition3D position; + [[nodiscard]] std::any createAt(const Location &) const override; + + struct InstanceVertex { + CommonLocationInstance location; + // float scale; + // something colorBias; }; - mutable InstanceVertices<LocationVertex> instances; + mutable InstanceVertices<InstanceVertex> instances; + void preFrame(const Frustum &, const Frustum &) override; void render(const SceneShader &, const Frustum &) const override; void shadows(const ShadowMapper &, const Frustum &) const override; void updateStencil(const ShadowStenciller &) const override; - glTexture shadowStencil = ShadowStenciller::createStencilTexture(256, 256); + void updateBillboard(const BillboardPainter &) const override; protected: friend Persistence::SelectionPtrBase<std::shared_ptr<Foliage>>; bool persist(Persistence::PersistenceStore & store) override; void postLoad() override; + GLsizei billboardSize {}; + RelativeDistance useMeshClipDist {}; + mutable Direction2D shadowStencilDir {std::numeric_limits<Direction2D::value_type>::infinity()}; + glTexture<GL_TEXTURE_2D_ARRAY> shadowStencil; + mutable Angle billboardAngle = std::numeric_limits<Angle>::infinity(); + glTextures<GL_TEXTURE_2D_ARRAY, 3> billboard; + +private: + InstanceVertices<InstanceVertex>::PartitionResult instancePartitions; }; diff --git a/game/scenary/illuminator.cpp b/game/scenary/illuminator.cpp index f1a02b2..7f0c7c2 100644 --- a/game/scenary/illuminator.cpp +++ b/game/scenary/illuminator.cpp @@ -1,19 +1,18 @@ #include "illuminator.h" #include "gfx/gl/sceneShader.h" -#include "gfx/gl/vertexArrayObject.h" #include "gfx/models/texture.h" // IWYU pragma: keep +#include "util.h" +#include <location.h> -bool -Illuminator::SpotLight::persist(Persistence::PersistenceStore & store) -{ - return STORE_TYPE && STORE_MEMBER(position) && STORE_MEMBER(direction) && STORE_MEMBER(colour) && STORE_MEMBER(kq) - && STORE_MEMBER(arc); -} +static_assert(std::is_constructible_v<Illuminator>); -bool -Illuminator::PointLight::persist(Persistence::PersistenceStore & store) +std::weak_ptr<glVertexArray> Illuminator::commonInstanceVAO; + +std::any +Illuminator::createAt(const Location & position) const { - return STORE_TYPE && STORE_MEMBER(position) && STORE_MEMBER(colour) && STORE_MEMBER(kq); + return std::make_shared<InstanceVertices<InstanceVertex>::InstanceProxy>( + instances.acquire(locationData->acquire(position))); } bool @@ -31,30 +30,9 @@ Illuminator::postLoad() throw std::logic_error {"Illuminator has no lights"}; } texture = getTexture(); - bodyMesh->configureVAO(instanceVAO) - .addAttribs<LocationVertex, &LocationVertex::first, &LocationVertex::second>(instances.bufferName(), 1); - if (!spotLight.empty()) { - instancesSpotLightVAO.emplace(); - VertexArrayObject {*instancesSpotLightVAO} - .addAttribs<SpotLightVertex, &SpotLightVertex::position, &SpotLightVertex::direction, - &SpotLightVertex::colour, &SpotLightVertex::kq, &SpotLightVertex::arc>( - instancesSpotLight.bufferName(), 0) - .addAttribs<LocationVertex, &LocationVertex::first, &LocationVertex::second>(instances.bufferName(), 1); - std::transform( - spotLight.begin(), spotLight.end(), std::back_inserter(spotLightInstances), [this](const auto & s) { - return instancesSpotLight.acquire(*s); - }); - } - if (!pointLight.empty()) { - instancesPointLightVAO.emplace(); - VertexArrayObject {*instancesPointLightVAO} - .addAttribs<PointLightVertex, &PointLightVertex::position, &PointLightVertex::colour, - &PointLightVertex::kq>(instancesPointLight.bufferName(), 0) - .addAttribs<LocationVertex, &LocationVertex::first, &LocationVertex::second>(instances.bufferName(), 1); - std::transform( - pointLight.begin(), pointLight.end(), std::back_inserter(pointLightInstances), [this](const auto & s) { - return instancesPointLight.acquire(*s); - }); + glDebugScope _ {0}; + if (createIfRequired(instanceVAO, commonInstanceVAO)) { + bodyMesh->configureVAO(*instanceVAO, 0).addAttribs<InstanceVertex, &InstanceVertex::location>(1); } } @@ -62,29 +40,12 @@ void Illuminator::render(const SceneShader & shader, const Frustum &) const { if (const auto count = instances.size()) { + glDebugScope _ {*instanceVAO}; shader.basicInst.use(); if (texture) { - texture->bind(); + texture->bind(0); } - bodyMesh->DrawInstanced(instanceVAO, static_cast<GLsizei>(count)); - } -} - -void -Illuminator::lights(const SceneShader & shader) const -{ - if (const auto count = instances.size()) { - if (const auto scount = instancesSpotLight.size()) { - shader.spotLightInst.use(); - glBindVertexArray(*instancesSpotLightVAO); - glDrawArraysInstanced(GL_POINTS, 0, static_cast<GLsizei>(scount), static_cast<GLsizei>(count)); - } - if (const auto pcount = instancesPointLight.size()) { - shader.pointLightInst.use(); - glBindVertexArray(*instancesPointLightVAO); - glDrawArraysInstanced(GL_POINTS, 0, static_cast<GLsizei>(pcount), static_cast<GLsizei>(count)); - } - - glBindVertexArray(0); + instanceVAO->useBuffer(1, instances); + bodyMesh->drawInstanced(*instanceVAO, static_cast<GLsizei>(count)); } } diff --git a/game/scenary/illuminator.h b/game/scenary/illuminator.h index 47ce337..2373812 100644 --- a/game/scenary/illuminator.h +++ b/game/scenary/illuminator.h @@ -1,6 +1,7 @@ #pragma once #include "assetFactory/asset.h" +#include "game/mixins/lights.h" #include "gfx/gl/instanceVertices.h" #include "gfx/models/texture.h" #include "gfx/renderable.h" @@ -8,53 +9,24 @@ class SceneShader; class Location; -class Illuminator : public Asset, public Renderable, public StdTypeDefs<Illuminator> { +class Illuminator : public Asset, public Renderable, public AssetLights, public StdTypeDefs<Illuminator> { Mesh::Ptr bodyMesh; Texture::Ptr texture; - glVertexArray instanceVAO; - std::optional<glVertexArray> instancesSpotLightVAO, instancesPointLightVAO; + std::shared_ptr<glVertexArray> instanceVAO; + static std::weak_ptr<glVertexArray> commonInstanceVAO; public: - struct LightCommonVertex { - RelativePosition3D position; - RGB colour; - RelativeDistance kq; - }; - - struct SpotLightVertex : LightCommonVertex { - Direction3D direction; - Angle arc; - }; - - struct PointLightVertex : LightCommonVertex { }; + [[nodiscard]] std::any createAt(const Location &) const override; - struct SpotLight : Persistence::Persistable, SpotLightVertex, StdTypeDefs<SpotLight> { - private: - friend Persistence::SelectionPtrBase<std::shared_ptr<SpotLight>>; - bool persist(Persistence::PersistenceStore & store) override; + struct InstanceVertex { + CommonLocationInstance location; }; - struct PointLight : Persistence::Persistable, PointLightVertex, StdTypeDefs<PointLight> { - private: - friend Persistence::SelectionPtrBase<std::shared_ptr<PointLight>>; - bool persist(Persistence::PersistenceStore & store) override; - }; - -public: - using LocationVertex = std::pair<glm::mat3, GlobalPosition3D>; - mutable InstanceVertices<LocationVertex> instances; - mutable InstanceVertices<SpotLightVertex> instancesSpotLight; - mutable InstanceVertices<PointLightVertex> instancesPointLight; + mutable InstanceVertices<InstanceVertex> instances; void render(const SceneShader &, const Frustum &) const override; - void lights(const SceneShader &) const override; protected: friend Persistence::SelectionPtrBase<std::shared_ptr<Illuminator>>; bool persist(Persistence::PersistenceStore & store) override; void postLoad() override; - - std::vector<SpotLight::Ptr> spotLight; - std::vector<PointLight::Ptr> pointLight; - std::vector<InstanceVertices<SpotLightVertex>::InstanceProxy> spotLightInstances; - std::vector<InstanceVertices<PointLightVertex>::InstanceProxy> pointLightInstances; }; diff --git a/game/scenary/light.cpp b/game/scenary/light.cpp index 6207497..455d5b5 100644 --- a/game/scenary/light.cpp +++ b/game/scenary/light.cpp @@ -2,6 +2,8 @@ #include "location.h" Light::Light(std::shared_ptr<const Illuminator> type, const Location & position) : - type {std::move(type)}, location {this->type->instances.acquire(position.getRotationTransform(), position.pos)} + type {std::move(type)}, + instance {this->type->instances.acquire(Renderable::commonLocationData.lock()->acquire(position))} { + lightsEnable(this->type, instance->location.index); } diff --git a/game/scenary/light.h b/game/scenary/light.h index 0b19535..0b9320c 100644 --- a/game/scenary/light.h +++ b/game/scenary/light.h @@ -5,15 +5,18 @@ class Location; -class Light : public WorldObject { +class Light : public WorldObject, public InstanceLights { std::shared_ptr<const Illuminator> type; - InstanceVertices<Illuminator::LocationVertex>::InstanceProxy location; + InstanceVertices<Illuminator::InstanceVertex>::InstanceProxy instance; void tick(TickDuration) override { } + std::vector<InstanceVertices<SpotLightVertex>::InstanceProxy> spotLightInstances; + std::vector<InstanceVertices<PointLightVertex>::InstanceProxy> pointLightInstances; + public: Light(std::shared_ptr<const Illuminator> type, const Location & position); }; diff --git a/game/scenary/plant.cpp b/game/scenary/plant.cpp index 2006225..b0e7d16 100644 --- a/game/scenary/plant.cpp +++ b/game/scenary/plant.cpp @@ -3,6 +3,6 @@ Plant::Plant(std::shared_ptr<const Foliage> type, const Location & position) : type {std::move(type)}, - location {this->type->instances.acquire(position.getRotationTransform(), position.rot.y, position.pos)} + instance {this->type->instances.acquire(Renderable::commonLocationData.lock()->acquire(position))} { } diff --git a/game/scenary/plant.h b/game/scenary/plant.h index 77c9ff7..cc690c5 100644 --- a/game/scenary/plant.h +++ b/game/scenary/plant.h @@ -7,7 +7,7 @@ class Location; class Plant : public WorldObject { std::shared_ptr<const Foliage> type; - InstanceVertices<Foliage::LocationVertex>::InstanceProxy location; + InstanceVertices<Foliage::InstanceVertex>::InstanceProxy instance; void tick(TickDuration) override |
