Cogs.Core
ClipmapDepthQuery.cpp
1#include "ClipmapDepthQuery.h"
2#include "ClipmapRenderer.h"
3
4#include "Foundation/Logging/Logger.h"
5
6#include "Rendering/IBuffers.h"
7#include "Rendering/IContext.h"
8
9namespace
10{
11 Cogs::Logging::Log logger = Cogs::Logging::getLogger("ClipmapDepthQuery");
12}
13
14Cogs::ClipmapDepthQuery::ClipmapDepthQuery()
15 : device(nullptr),
16 clipmapRenderer(nullptr)
17{
18
19}
20
21void Cogs::ClipmapDepthQuery::initialize(IGraphicsDevice * device, ClipmapRenderer * clipmapRenderer)
22{
23 this->device = device;
24 this->clipmapRenderer = clipmapRenderer;
25
26 const size_t queryBufferSize = clipmapRenderer->depthQuerySize * clipmapRenderer->depthQuerySize * sizeof(float) * 4;
27
28 this->queryReadBackBuffer = device->getBuffers()->loadBuffer(nullptr, queryBufferSize * 4, Usage::Staging, AccessMode::Read, 0);
29}
30
31Cogs::ClipmapDepthQuery::~ClipmapDepthQuery()
32{
33 if (!device) return;
34
35 auto buffers = device->getBuffers();
36
37 if (HandleIsValid(queryReadBackBuffer)) {
38 buffers->releaseBuffer(queryReadBackBuffer);
39 }
40}
41
42void Cogs::ClipmapDepthQuery::readBack()
43{
44 IContext * context = this->device->getImmediateContext();
45 for (auto & data : clipmapRenderer->raypickDepthData) {
46 context->setRenderTarget(data.depthRenderHandle, data.depthTargetHandle);
47 context->readColorBuffer(data.readbackBufferHandle, 0, 0, data.width, data.height, Framebuffer::Front);
48 }
49
50 context->setRenderTarget(clipmapRenderer->depthQueryRenderHandle, clipmapRenderer->depthQueryTargetHandle);
51 context->readColorBuffer(queryReadBackBuffer, 0, 0, clipmapRenderer->depthQuerySize, clipmapRenderer->depthQuerySize, Framebuffer::Front);
53 hasReadBack = clipmapRenderer->raypickDepthData[0].depthRenderInitialized && clipmapRenderer->depthQueryRenderInitialized;
54}
55
56bool Cogs::ClipmapDepthQuery::getPositions(const Vector2 * mousePositions, const Matrix & inverseViewProjection, const size_t numPositions, Vector4 * worldPos, bool * positionValid, int rayPickId)
57{
58 if (rayPickId < 0 || rayPickId >= static_cast<int>(clipmapRenderer->raypickDepthData.size())) {
59 LOG_ERROR(logger, "Invalid ray pick id: %d", rayPickId);
60 return false;
61 }
62
63 auto & depthData = clipmapRenderer->raypickDepthData[rayPickId];
64 if (!device || !HandleIsValid(depthData.readbackBufferHandle) || !hasReadBack) return false;
65
66 IContext * context = this->device->getImmediateContext();
67
68 MappedBuffer<float> data(context, depthData.readbackBufferHandle, MapMode::Read);
69
70 if (!data) return false;
71
72 bool anyValid = false;
73 const int width = depthData.width;
74 const int height = depthData.height;
75
76 bool flip = device->getType() == GraphicsDeviceType::Direct3D11 ? true : false;
77
78 const int rowPitch = data.getStride() ? data.getStride() / sizeof(float) : width;
79
80 for (size_t i = 0; i < numPositions; ++i) {
81 const float screenX = mousePositions[i][0] * width;
82 const float screenY = (flip ? (1.0f - mousePositions[i][1]) : mousePositions[i][1]) * height;
83
84 const int screenIndexX = static_cast<int>(screenX);
85 const int screenIndexY = static_cast<int>(screenY);
86
87 if ((screenIndexX < 0 || screenIndexX >= width) || (screenIndexY < 0 || screenIndexY >= height)) {
88 LOG_WARNING(logger, "Readback positions outside of buffer dimensions.");
89
90 return false;
91 }
92
93 const float depth = data[screenIndexY * rowPitch + screenIndexX];
94 float clearDepth = 1.0;
95 if(clipmapRenderer->reverseDepth)
96 clearDepth = 0.0f;
97
98 if (depth != clearDepth) {
99 // Reconstruct the projected, normalized screen position from the positions
100 // and the queried depth.
101 const float x = (mousePositions[i][0] - 0.5f) * 2.0f;
102 const float y = (mousePositions[i][1] - 0.5f) * 2.0f;
103
104 const Vector4 screenPos(x, y, depth, 1);
105
106 worldPos[i] = inverseViewProjection * screenPos;
107
108 if (worldPos[i][3] != 0) {
109 // Renormalize to get world position.
110 worldPos[i] /= worldPos[i][3];
111 positionValid[i] = true;
112 anyValid = true;
113 } else {
114 positionValid[i] = false;
115 }
116 } else {
117 positionValid[i] = false;
118 }
119 }
120
121 return anyValid;
122}
123
124float Cogs::ClipmapDepthQuery::getNearestTerrainSample(const Matrix & inverseProjection)
125{
126 if (!device || !HandleIsValid(queryReadBackBuffer)) return 0.0f;
127
128 IContext * context = this->device->getImmediateContext();
129
130 const MappedBuffer<float> data(context, queryReadBackBuffer, MapMode::Read);
131
132 if (!data) return 0.0f;
133
134 float min = std::numeric_limits<float>::max();
135 float minX = 0.0f;
136 float minY = 0.0f;
137
138 auto size = clipmapRenderer->depthQuerySize;
139 const int sampleSize = 4; //RGBA
140 const int rowPitch = data.getStride() ? data.getStride() / (sizeof(float) * sampleSize) : size;
141
142 for (int y = 0; y < size; ++y) {
143 for (int x = 0; x < size; ++x) {
144 int sampleIndex = (y * rowPitch + x) * sampleSize;
145
146 const float depth = data[sampleIndex];
147 float clearDepth = 1.0;
148 if(clipmapRenderer->reverseDepth)
149 clearDepth = 0.0f;
150
151 if (depth != clearDepth) {
152 const float xPos = data[sampleIndex + 1];
153 const float yPos = data[sampleIndex + 2];
154
155 if(clipmapRenderer->reverseDepth){
156 if (depth > min) {
157 min = depth;
158 minX = xPos;
159 minY = yPos;
160 }
161 }
162 else{
163 if (depth < min) {
164 min = depth;
165 minX = xPos;
166 minY = yPos;
167 }
168 }
169 }
170 }
171 }
172
173 const Vector4 screenPos(minX, minY, min, 1);
174 Vector4 viewPos;
175
176 viewPos = inverseProjection * screenPos;
177
178 if (viewPos[3] != 0) {
179 viewPos /= viewPos[3];
180
181 return -viewPos[2];
182 }
183
184 return 0;
185}
186
187float Cogs::ClipmapDepthQuery::getNearestTerrainSample2(const Matrix & inverseProjection, const Matrix & viewMatrix)
188{
189 if (!device || !HandleIsValid(queryReadBackBuffer)) return 0.0f;
190
191 IContext * context = this->device->getImmediateContext();
192
193 const MappedBuffer<float> data(context, queryReadBackBuffer, MapMode::Read);
194
195 if (!data) return 0.0f;
196
197 float min = std::numeric_limits<float>::max();
198 float minX = 0.0f;
199 float minY = 0.0f;
200
201 auto size = clipmapRenderer->depthQuerySize;
202 const int sampleSize = 4; //RGBA
203 const int rowPitch = data.getStride() ? data.getStride() / (sizeof(float) * sampleSize) : size;
204
205 for (int y = 0; y < size; ++y) {
206 for (int x = 0; x < size; ++x) {
207 int sampleIndex = (y * rowPitch + x) * sampleSize;
208
209 float depth = data[sampleIndex];
210 float clearDepth = 1.0;
211 if(clipmapRenderer->reverseDepth)
212 clearDepth = 0.0f;
213
214 if (depth != clearDepth) {
215 const float xPos = data[sampleIndex + 1];
216 const float yPos = data[sampleIndex + 2];
217
218 if(clipmapRenderer->reverseDepth){
219 if (depth > min) {
220 min = depth;
221 minX = xPos;
222 minY = yPos;
223 }
224 }
225 else{
226 if (depth < min) {
227 min = depth;
228 minX = xPos;
229 minY = yPos;
230 }
231 }
232 }
233 }
234 }
235
236 const Vector4 screenPos(minX, minY, min, 1);
237 Vector4 viewPos;
238
239 viewPos = inverseProjection * screenPos;
240
241 float ret = 0.0f;
242
243 if (viewPos[3]) {
244 viewPos /= viewPos[3];
245 ret = -viewPos[2];
246 }
247
248 if (prevViewPos[3]) {
249 prevViewPos = viewMatrix * glm::inverse(prevViewMatrix) * prevViewPos;
250 ret = std::min(ret, -prevViewPos[2]);
251 }
252
253 prevViewPos = viewPos;
254 prevViewMatrix = viewMatrix;
255
256 return ret;
257}
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
@ Direct3D11
Graphics device using the Direct3D 11 API.
@ Read
The buffer can be mapped and read from by the CPU after creation.
Definition: Flags.h:48
float getNearestTerrainSample(const Matrix &inverseProjection)
Returns the nearest sample in the query readback buffer.
float getNearestTerrainSample2(const Matrix &inverseProjection, const Matrix &viewMatrix)
Returns the nearest sample in the query readback buffer for two frames.
@ Front
Front buffer.
Definition: Common.h:152
static const Handle_t NoHandle
Represents a handle to nothing.
Definition: Common.h:77
Represents a graphics device context which can receive rendering commands.
Definition: IContext.h:43
Provides RAII style mapping of a buffer resource.
Definition: IBuffers.h:160
@ Staging
Definition: Flags.h:33