2#include <glm/gtc/type_ptr.hpp>
3#include <glm/gtx/quaternion.hpp>
5#include "CameraArraySystem.h"
6#include "Foundation/Logging/Logger.h"
7#include "Utilities/Math.h"
9#include "Resources/Texture.h"
10#include "Rendering/ICapabilities.h"
18 bool updateViewBuffer(
Context* context,
19 std::vector<ViewBufferEntry>& viewBuffer,
20 const glm::mat4& worldFromBase,
21 const std::vector<glm::mat4>& projections,
22 const std::vector<glm::mat4>& transforms,
23 const size_t numViews,
24 const float overrideNearValue,
25 const float overrideFarValue,
26 const bool overrideProjectionNearAndFar)
29 if (projections.size() != numViews || transforms.size() != numViews) {
33 viewBuffer.resize(numViews);
34 for (
size_t i = 0; i < numViews; i++) {
44 if (overrideProjectionNearAndFar && overrideNearValue>0.0 && overrideNearValue < overrideFarValue) {
47 glm::mat4 IP = glm::inverse(projections[i]);
48 glm::vec4 lb = IP * glm::vec4(-1, -1, -1.0, 1);
49 glm::vec4 rt = IP * glm::vec4(1, 1, -1.0, 1);
53 float slb = -overrideNearValue / lb.z;
54 float srt = -overrideNearValue / rt.z;
55 float left = lb.x * slb;
56 float bottom = lb.y * slb;
57 float right = rt.x * srt;
58 float top = rt.y * srt;
60 glm::mat4 P = glm::frustum(left, right, bottom, top, overrideNearValue, overrideFarValue);
61 entry.clipFromView = P;
65 entry.worldFromView = worldFromBase * transforms[i];
66 entry.viewFromClip = glm::inverse(entry.clipFromView);
67 entry.viewFromWorld = glm::inverse(entry.worldFromView);
68 entry.clipFromWorld = entry.clipFromView * entry.viewFromWorld;
75 bool makeCameraEncloseViews(
Context* context,
78 std::span<ViewBufferEntry> viewBuffer,
79 const uint32_t height,
80 const float debugFrustumSqueeze,
81 const bool moveCameraBack,
82 const bool updateNearAndFar,
83 const bool overrideViewportResolution)
85 const size_t numViews = viewBuffer.size();
98 refCamPos = glm::vec3(viewBuffer[0].worldFromView[3]);
99 refCamRot = glm::quat_cast(glm::mat3(viewBuffer[0].worldFromView));
102 refCamPos = 0.5f * (glm::vec3(viewBuffer[0].worldFromView[3]) +
103 glm::vec3(viewBuffer[1].worldFromView[3]));
104 refCamRot = glm::shortMix(glm::quat_cast(glm::mat3(viewBuffer[0].worldFromView)),
105 glm::quat_cast(glm::mat3(viewBuffer[1].worldFromView)), 0.5f);
109 refCamTrComp.
position = glm::vec3(0.f);
110 refCamTrComp.
coordinates = context->transformSystem->worldFromEngineCoords(refCamPos);
113 context->transformSystem->updateLocalToWorldTransform(refCamTrComp,
true);
117 if (moveCameraBack) {
119 const glm::mat4 camViewFromWorld = glm::inverse(context->transformSystem->getLocalToWorld(&refCamTrComp));
120 for (
size_t i = 0; i < numViews; i++) {
122 const glm::mat4 camViewFromViewClip = camViewFromWorld * viewBuffer[i].worldFromView * viewBuffer[i].viewFromClip;
124 for (
size_t c = 0; c < 4; c++) {
125 const float x = ((c >> 0) & 1) ? -1.f : 1.f;
126 const float y = ((c >> 1) & 1) ? -1.f : 1.f;
128 const glm::vec3 a = euclidean(camViewFromViewClip * glm::vec4(x, y, -1.f, 1.f));
129 const glm::vec3 b = euclidean(camViewFromViewClip * glm::vec4(x, y, 1.f, 1.f));
140 if (
float qz = (b.x * a.z - a.x * b.z) / (b.x - a.x); std::isfinite(qz) && qz < back) {
144 if (
float qz = (b.y * a.z - a.y * b.z) / (b.y - a.y); std::isfinite(qz) && qz < back) {
150 glm::vec3 newPosEngine = euclidean(context->transformSystem->getLocalToWorld(&refCamTrComp) * glm::vec4(0.f, 0.f, -back, 1.f));
151 glm::dvec3 newPosWorld = context->transformSystem->worldFromEngineCoords(newPosEngine);
154 context->transformSystem->updateLocalToWorldTransform(refCamTrComp,
true);
162 float nearDist = std::numeric_limits<float>::max();
164 const glm::mat4 camViewFromWorld = glm::inverse(context->transformSystem->getLocalToWorld(&refCamTrComp));
165 for (
size_t i = 0; i < numViews; i++) {
168 const glm::mat4 camViewFromViewClip = camViewFromWorld * viewBuffer[i].worldFromView * viewBuffer[i].viewFromClip;
170 for (
size_t c = 0; c < 8; c++) {
172 const glm::vec4 h = camViewFromViewClip * glm::vec4(((c >> 0) & 1) ? -1.f : 1.f,
173 ((c >> 1) & 1) ? -1.f : 1.f,
174 ((c >> 2) & 1) ? -1.f : 1.f,
176 const glm::vec3 p = (1.f / h.w) * glm::vec3(h);
179 const glm::vec3 pp = glm::vec3(std::abs(p.x),
181 std::max(1e-3f, -p.z));
182 nearDist = std::min(nearDist, pp.z);
183 farDist = std::max(farDist, pp.z);
184 xAngle = std::max(xAngle, std::atan2(pp.x, pp.z));
185 yAngle = std::max(yAngle, std::atan2(pp.y, pp.z));
190 const float aspect = glm::tan(0.5f * xAngle) / glm::tan(0.5f * yAngle);
194 refCamComp.
fieldOfView = 2.0f * glm::clamp(1.f - debugFrustumSqueeze, 0.1f, 1.f) * yAngle;
198 if (updateNearAndFar) {
208 if (overrideViewportResolution) {
215 context->cameraSystem->updateProjection(context, refCamComp);
221 assert(camArrData.textureMode == CameraArrayData::TextureMode::None);
224 if (colorTex && (colorTex->description.target == Cogs::ResourceDimensions::Texture2DArray || colorTex->description.target == Cogs::ResourceDimensions::Texture2DMSArray)) {
226 width = colorTex->description.width;
227 height = colorTex->description.height;
229 camArrData.numViews = colorTex->description.layers;
230 camArrData.textureMode = CameraArrayData::TextureMode::TextureArray;
236 camArrData.depthMode = CameraArrayData::DepthMode::Create;
241 if (colorTex->description.target == Cogs::ResourceDimensions::Texture2DArray || colorTex->description.target == Cogs::ResourceDimensions::Texture2DMSArray) {
242 if ((depthTex->description.width == width) &&
243 (depthTex->description.height == height) &&
244 (depthTex->description.layers == camArrData.numViews))
246 camArrData.depthMode = CameraArrayData::DepthMode::Provided;
260 if (camArrData.textureMode != CameraArrayData::TextureMode::None || camArrComp.
colorTextures.empty()) {
264 camArrData.numViews =
static_cast<uint32_t
>(camArrComp.
colorTextures.size());
266 camArrData.depthMode = CameraArrayData::DepthMode::None;
269 camArrData.depthMode = CameraArrayData::DepthMode::Create;
273 camArrData.depthMode = CameraArrayData::DepthMode::Provided;
278 for (
size_t i = 0; i < camArrData.numViews; i++) {
282 if (!(colorTex && (colorTex->description.target == Cogs::ResourceDimensions::Texture2D || colorTex->description.target == Cogs::ResourceDimensions::RenderBuffer))) {
286 width = colorTex->description.width;
287 height = colorTex->description.height;
289 else if ((colorTex->description.width != width) || (colorTex->description.height != height)) {
292 camArrData.colorTextures.push_back(colorTexHandle);
294 if (camArrData.depthMode == CameraArrayData::DepthMode::Provided) {
298 (depthTex->description.target == Cogs::ResourceDimensions::Texture2D || depthTex->description.target == Cogs::ResourceDimensions::RenderBuffer) &&
299 (depthTex->description.width == width) &&
300 (depthTex->description.height == height))
302 camArrData.depthTextures.push_back(depthTexHandle);
307 camArrData.textureMode = CameraArrayData::TextureMode::ArrayOfTextures;
309 if ((camArrData.depthMode == CameraArrayData::DepthMode::Provided) && (camArrData.colorTextures.size() != camArrData.depthTextures.size())) {
310 camArrData.depthMode = CameraArrayData::DepthMode::None;
324 if (!camArrTrComp)
continue;
326 const glm::mat4 worldFromBase =
context->transformSystem->getLocalToWorld(camArrTrComp);
329 camArrData.textureMode = CameraArrayData::TextureMode::None;
330 camArrData.depthMode = CameraArrayData::DepthMode::None;
331 camArrData.colorTextures.clear();
332 camArrData.depthTextures.clear();
337 tryValidateTextureArraySetup(camArrComp, camArrData, width, height);
338 tryValidateArrayOfTexturesSetup(camArrComp, camArrData, width, height);
343 if (camArrData.textureMode != CameraArrayData::TextureMode::None) {
344 assert(0 < camArrData.numViews);
349 if (camArrData.numViews <= 2) {
353 camArrData.viewBuffer,
366 *refCamComp, *refCamTrComp,
367 camArrData.viewBuffer,
376 camArrData.camData = camData;
379 camArrData.camData.viewportOrigin = { 0, 0 };
380 camArrData.camData.viewportSize.x =
static_cast<float>(width);
381 camArrData.camData.viewportSize.y =
static_cast<float>(height);
395 camArrData.textureMode = CameraArrayData::TextureMode::None;
void setChanged()
Sets the component to the ComponentFlags::Changed state with carry.
ComponentType * getComponent() const
ComponentHandle getComponentHandle() const
Multi-view: Render a set of related views into array texture layers.
bool enableDepth
Rendering should use a depth buffer, either backed by a provided texture or a buffer created by the r...
std::vector< glm::mat4 > projections
One projection matrix per layer.
std::vector< TextureHandle > colorTextures
The color render texture to output the rendered scene from the camera to.
bool updateReferenceCamera
Update reference camera using the view projection and transform matrices.
bool moveCameraBack
Find intersection of frustum edges and Z axis and back camera back, tries to minimize field-of-view o...
bool overrideProjectionNearAndFar
If true, override near and far values embedded in the provided projection matrix with overrideNearVal...
float overrideNearValue
Near-value to use when overrideNearAndFar is enabled.
float overrideFarValue
Far-value to use when overrideNearAndFar is enabled.
std::vector< TextureHandle > depthTextures
The depth render texture to output the rendered scene from the camera to. Optional.
bool updateNearAndFar
When updating the reference camera, also update near and far.
bool updateViewportResolution
When updating the reference camera, use texture dimension to set camera viewport resolution.
std::vector< glm::mat4 > transforms
One affine transform matrix per layer.
float debugFrustumSqueeze
Debug variable to squeeze the frustum to be smaller than required, as a help to debug culling.
WeakEntityPtr referenceCamera
Reference camera to pull data from.
float fieldOfView
Vertical field of view, given in radians.
bool enableClippingPlaneAdjustment
If automatic adjustment of the clipping planes should be performed to fit as much of the scene as pos...
glm::vec2 viewportSize
Size of the viewport covered by this instance, given in pixels.
std::string renderPipeline
Render pipeline to apply when rendering to texture. Defaults to the built-in forward rendering pipeli...
glm::vec2 viewportOrigin
Origin of the viewport covered by this instance, given in screen units from the lower left.
Context * context
Pointer to the Context instance the system lives in.
void update()
Updates the system state to that of the current frame.
ComponentPool< ComponentType > pool
Pool of components managed by the system.
A Context instance contains all the services, systems and runtime components needed to use Cogs.
class IRenderer * renderer
Renderer.
virtual glm::mat4 getViewFromViewportMatrix(const glm::mat4 inverseProjectionMatrix)=0
Get an adjusted inverse projection matrix mainly used in post processing.
virtual glm::mat4 getProjectionMatrix(const glm::mat4 projectionMatrix)=0
Get an adjusted projection matrix used to render.
Log implementation class.
Contains the Engine, Renderer, resource managers and other systems needed to run Cogs....
std::shared_ptr< ComponentModel::Entity > EntityPtr
Smart pointer for Entity access.
constexpr Log getLogger(const char(&name)[LEN]) noexcept
Contains data describing a Camera instance and its derived data structured such as matrix data and vi...
ResourceType * resolve() const
Resolve the handle, returning a pointer to the actual resource.
Texture resources contain raster bitmap data to use for texturing.