Cogs.Core
NormalUpdater.cpp
1#include "NormalUpdater.h"
2#include "ClipmapUpdate.h"
3#include "Effects.h"
4#include "RenderContext.h"
5#include "Raster/RasterLevel.h"
6
7#include "Rendering/IGraphicsDevice.h"
8#include "Rendering/IEffects.h"
9#include "Rendering/IContext.h"
10#include "Rendering/IBuffers.h"
11
12#include "Foundation/Logging/Logger.h"
13
14namespace
15{
16 Cogs::Logging::Log logger = Cogs::Logging::getLogger("NormalUpdater");
17}
18
19namespace Cogs
20{
22 {
23 Matrix projectionMatrix;
24 Vector2 oneOverHeightMapSize;
25
26 float heightExaggeration;
27 float postDelta;
28 };
29
31 {
32 Vector2 updateSize;
33 Vector2 origin;
34 };
35}
36
37void Cogs::NormalUpdater::initialize(IGraphicsDevice * device)
38{
39 VertexElement positionElement = { 0, DataFormat::X32Y32_FLOAT, ElementSemantic::Position, 0, InputType::VertexData, 0 };
40 VertexFormatHandle positionFormat = device->getBuffers()->createVertexFormat(&positionElement, 1);
41 vertexBufferHandle = device->getBuffers()->loadVertexBuffer(quadVertices, 6, positionFormat);
42
43 IEffects * effects = device->getEffects();
44
45 LOG_DEBUG(logger, "Loading climpap normal update effect.");
46
47 computeNormalsEffectHandle = Terrain::EffectLoader::loadEffect(effects, "ClipmapComputeNormalsVS", "ClipmapComputeNormalsPS");
48
49 if (!HandleIsValid(computeNormalsEffectHandle)) {
50 LOG_ERROR(logger, "Error loading normal computation effect.");
51
52 return;
53 }
54
55 auto buffers = device->getBuffers();
56
57 computeNormalsLayoutHandle = device->getBuffers()->loadInputLayout(&positionFormat, 1, computeNormalsEffectHandle);
58
59 normalLevelBuffer = buffers->loadBuffer(nullptr, sizeof(NormalLevelParameters), Usage::Dynamic, AccessMode::Write, BindFlags::ConstantBuffer);
60 normalLevelBinding = effects->getConstantBufferBinding(computeNormalsEffectHandle, "NormalLevelParameters");
61
62 normalUpdateBuffer = buffers->loadBuffer(nullptr, sizeof(NormalUpdateParameters), Usage::Dynamic, AccessMode::Write, BindFlags::ConstantBuffer);
63 normalUpdateBinding = effects->getConstantBufferBinding(computeNormalsEffectHandle, "NormalUpdateParameters");
64
65 SamplerState nearestRepeatState = {
70 SamplerState::ComparisonFunction::Never,
71 0,
72 { 0.0f, 0.0f, 0.0f, 0.0f }
73 };
74
75 nearestRepeatStateHandle = device->getTextures()->loadSamplerState(nearestRepeatState);
76 samplerStateBinding = effects->getSamplerStateBinding(computeNormalsEffectHandle, std::string(), 0);
77
78 levelTextureBinding = effects->getTextureBinding(computeNormalsEffectHandle, "heightTexture", 0);
79}
80
81void Cogs::NormalUpdater::updateNormalLevel(RenderContext & context, const WorldOptions & worldOptions, const ClipmapUpdate & clipmapUpdate, ClipmapLevel & normalLevel)
82{
83 // Normals at edges are incorrect, so include a one-post buffer around the update region
84 // when updating normals in order to update normals that were previously at the edge.
85 ClipmapUpdate updateWithBuffer = clipmapUpdate.addBufferWithinLevelNextExtent();
86
87 static std::vector<ClipmapUpdate> normalUpdates;
88
89 normalUpdates.clear();
90
91 ClipmapUpdate::splitUpdateToAvoidWrapping(updateWithBuffer, normalUpdates);
92
93 renderNormals(context, worldOptions, normalUpdates, normalLevel);
94}
95
96void Cogs::NormalUpdater::renderNormals(RenderContext & renderContext, const WorldOptions & worldOptions, const std::vector<ClipmapUpdate> & normalUpdates, ClipmapLevel & normalLevel)
97{
98 if (!normalUpdates.size() || !HandleIsValid(computeNormalsEffectHandle)) return;
99
100 IContext * context = renderContext.context;
101
102 const ClipmapLevel * terrainLevel = normalUpdates[0].getLevel();
103 auto & nextExtent = terrainLevel->nextExtent;
104
105 const float width = static_cast<float>(normalLevel.renderTexture.width);
106 const float height = static_cast<float>(normalLevel.renderTexture.height);
107
108 context->setRenderTarget(normalLevel.renderTexture.renderTarget, DepthStencilHandle::InvalidHandle);
109 context->setViewport(0, 0, width, height);
110
111 context->setEffect(computeNormalsEffectHandle);
112
113 context->setTexture(levelTextureBinding, terrainLevel->renderTexture.handle);
114 context->setSamplerState(samplerStateBinding, nearestRepeatStateHandle);
115
116 const uint32_t strides[] = { 2 * sizeof(float) };
117 context->setVertexBuffers(&vertexBufferHandle, 1, strides, nullptr);
118 context->setInputLayout(computeNormalsLayoutHandle);
119
120 context->setConstantBuffer(normalLevelBinding, normalLevelBuffer);
121 context->setConstantBuffer(normalUpdateBinding, normalUpdateBuffer);
122
123 {
124 MappedBuffer<NormalLevelParameters> levelParameters(context, normalLevelBuffer, MapMode::WriteDiscard);
125
126 if (levelParameters) {
127 levelParameters->heightExaggeration = worldOptions.heightExaggeration;
128
129 levelParameters->projectionMatrix = glm::ortho<float>(0, static_cast<float>(nextExtent.east - nextExtent.west), 0, static_cast<float>(nextExtent.north - nextExtent.south), -1.0f, 1.0f);
130
131 levelParameters->oneOverHeightMapSize = Vector2(
132 1.0f / (float) (terrainLevel->nextExtent.east - terrainLevel->nextExtent.west + 1),
133 1.0f / (float) (terrainLevel->nextExtent.north - terrainLevel->nextExtent.south + 1));
134
135 levelParameters->postDelta = static_cast<float>(terrainLevel->rasterLevel->getPostDeltaLongitude() * worldOptions.worldScale.x);
136 }
137 }
138
139 const int clipmapSize = terrainLevel->nextExtent.east - terrainLevel->nextExtent.west + 1;
140
141 for (size_t i = 0; i < normalUpdates.size(); ++i) {
142 const ClipmapUpdate & normalUpdate = normalUpdates[i];
143
144 const int west = (terrainLevel->origin.x + (normalUpdate.getWest() - terrainLevel->nextExtent.west)) % clipmapSize;
145 const int south = (terrainLevel->origin.y + (normalUpdate.getSouth() - terrainLevel->nextExtent.south)) % clipmapSize;
146
147 {
148 MappedBuffer<NormalUpdateParameters> updateParameters(context, normalUpdateBuffer, MapMode::WriteDiscard);
149
150 if (updateParameters) {
151 updateParameters->origin = Vector2(static_cast<float>(west), static_cast<float>(south));
152 updateParameters->updateSize = Vector2(static_cast<float>(normalUpdate.getWidth()), static_cast<float>(normalUpdate.getHeight()));
153 }
154 }
155
156 context->draw(PrimitiveType::TriangleList, 0, 6);
157 }
158}
Log implementation class.
Definition: LogManager.h:139
bool HandleIsValid(const ResourceHandle_t< T > &handle)
Check if the given resource is valid, that is not equal to NoHandle or InvalidHandle.
constexpr Log getLogger(const char(&name)[LEN]) noexcept
Definition: LogManager.h:180
Contains all Cogs related functionality.
Definition: FieldSetter.h:23
@ VertexData
Per vertex data.
@ Position
Position semantic.
@ Write
The buffer can be mapped and written to by the CPU after creation.
Definition: Flags.h:50
@ ConstantBuffer
The buffer can be bound as input to effects as a constant buffer.
Definition: Flags.h:72
static const Handle_t InvalidHandle
Represents an invalid handle.
Definition: Common.h:80
@ WriteDiscard
Write access. When unmapping the graphics system will discard the old contents of the resource.
Definition: Flags.h:103
@ TriangleList
List of triangles.
Definition: Common.h:116
@ Wrap
Texture coordinates automatically wrap around to [0, 1] range.
Definition: SamplerState.h:19
@ MinMagMipPoint
Point sampling for both minification and magnification.
Definition: SamplerState.h:33
@ Dynamic
Buffer will be loaded and modified with some frequency.
Definition: Flags.h:30