Cogs.Core
ReflectionComponent.cpp
1#include "ReflectionComponent.h"
2
3#include "Context.h"
4
5#include "Renderer/IRenderer.h"
6
7#include "Components/Core/RenderComponent.h"
8#include "Components/Core/SceneComponent.h"
9
10#include "Systems/Core/CameraSystem.h"
11#include "Systems/Core/TransformSystem.h"
12
13#include "Types.h"
14
15using namespace Cogs::Reflection;
16
17void Cogs::Core::ReflectionComponent::registerType()
18{
19 Field fields [] = {
20 Field(Name("position"), &ReflectionComponent::position),
21 Field(Name("normal"), &ReflectionComponent::normal),
22 };
23
24 Method methods [] = {
25 Method(Name("postUpdate"), &ReflectionComponent::postUpdate),
26 Method(Name("initialize"), &ReflectionComponent::initialize),
27 };
28
29 DynamicComponent::registerDerivedType<ReflectionComponent>().setFields(fields).setMethods(methods);
30}
31
32void Cogs::Core::ReflectionComponent::initialize(Context * context)
33{
34 this->context = context;
35}
36
37namespace
38{
39 const float offset = 0.01f;
40
41 glm::vec4 cameraSpacePlane(const glm::mat4 & viewMatrix, glm::vec3 position, glm::vec3 normal, float s)
42 {
43 const glm::vec3 offsetPos = position + normal * offset;
44
45 const glm::vec3 cPos = glm::vec3(viewMatrix * glm::vec4(offsetPos, 1.0f));
46 const glm::vec3 cNormal = glm::normalize(glm::vec3(viewMatrix * glm::vec4(normal, 0.0))) * s;
47
48 return glm::vec4(cNormal, -glm::dot(cPos, cNormal));
49 }
50
57 glm::mat4 calculateOblique(const glm::mat4 & projectionMatrix, glm::vec4 clipPlane)
58 {
59 // Calculate the clip-space corner point opposite the clipping plane
60 // as (sign(clipPlane.x), sign(clipPlane.y), 1, 1) and
61 // transform it into camera space by multiplying it
62 // by the inverse of the projection matrix
63 glm::vec4 q = glm::inverse(projectionMatrix) * glm::vec4(
64 glm::sign(clipPlane.x),
65 glm::sign(clipPlane.y),
66 1.0f,
67 1.0f);
68
69 glm::vec4 c = clipPlane * (2.0f / (glm::dot(clipPlane, q)));
70
71 glm::mat4 output = projectionMatrix;
72
73 output[0][2] = c.x - projectionMatrix[0][3];
74 output[1][2] = c.y - projectionMatrix[1][3];
75 output[2][2] = c.z - projectionMatrix[2][3];
76 output[3][2] = c.w - projectionMatrix[3][3];
77
78 return output;
79 }
80
81 glm::mat4 calculateReflectionPlane(glm::vec4 plane)
82 {
83 glm::mat4 r(1.0f);
84
85 r[0][0] = 1 - 2 * plane.x * plane.x;
86 r[0][1] = -2 * plane.x * plane.y;
87 r[0][2] = -2 * plane.x * plane.z;
88 r[0][3] = 0.0f;
89
90 r[1][0] = -2 * plane.x * plane.y;
91 r[1][1] = 1 - 2 * plane.y * plane.y;
92 r[1][2] = -2 * plane.z * plane.y;
93 r[1][3] = 0.0f;
94
95 r[2][0] = -2 * plane.x * plane.z;
96 r[2][1] = -2 * plane.y * plane.z;
97 r[2][2] = 1 - 2 * plane.z * plane.z;
98 r[2][3] = 0.0f;
99
100 r[3][0] = -2 * plane.w * plane.x;
101 r[3][1] = -2 * plane.w * plane.y;
102 r[3][2] = -2 * plane.w * plane.z;
103 r[3][3] = 1.0f;
104
105 return r;
106 }
107}
108
109void Cogs::Core::ReflectionComponent::postUpdate()
110{
111 if (!context || !texture) return;
112
113 const CameraComponent* parentCamera = nullptr;
114 auto parent = getComponent<SceneComponent>()->parent;
115 if (auto * parentContainer = parent.resolve(); parentContainer) {
116 parentCamera = parentContainer->getComponent<CameraComponent>();
117 }
118 if (!parentCamera) {
119 parentCamera = context->cameraSystem->getMainCamera();
120 }
121 const auto & parentCameraData = context->cameraSystem->getData(parentCamera);
122
123
124
125 auto cameraComponent = getComponent<CameraComponent>();
126 cameraComponent->enableClippingPlaneAdjustment = false;
127 cameraComponent->renderTexture = texture;
128
129 auto & cameraData = context->cameraSystem->getData(cameraComponent);
130 cameraData.passOptions = &passOptions;
131
132 cameraData.layerMask = cameraData.layerMask & ~(RenderLayers::Ocean | RenderLayers::Annotations | RenderLayers::Overlay);
133
134 const float d = -glm::dot(normal, position) - offset;
135 const glm::vec4 reflectionPlane(normal, d);
136
137 bool below = glm::dot(reflectionPlane, cameraData.inverseViewMatrix[3]) < 0.f;
138
139 const auto reflectionMatrix = below ? glm::mat4() : calculateReflectionPlane(reflectionPlane);
140
141 cameraData.viewportSize = cameraComponent->viewportSize;
142 cameraData.viewportOrigin = cameraComponent->viewportOrigin;
143 cameraData.viewMatrix = cameraData.viewMatrix * reflectionMatrix;
144 cameraData.inverseViewMatrix = glm::inverse(cameraData.viewMatrix);
145 cameraData.reflection = true;
146 cameraData.flipWindingOrder = !below;
147
148 const glm::vec4 clipPlane = cameraSpacePlane(cameraData.viewMatrix, glm::vec3(0.0f), normal, 1.0f);
149
150 cameraData.rawProjectionMatrix = calculateOblique(parentCameraData.rawProjectionMatrix, clipPlane);
151 cameraData.projectionMatrix = context->renderer->getProjectionMatrix(cameraData.rawProjectionMatrix);
152 cameraData.viewProjection = cameraData.projectionMatrix * cameraData.viewMatrix;
153 cameraData.inverseViewProjectionMatrix = glm::inverse(cameraData.viewProjection);
154 cameraData.frustum = Geometry::calculateFrustum<Geometry::Frustum, glm::mat4>(cameraData.viewProjection);
155 cameraData.renderPass = RenderPass::Reflection;
156
157 cameraData.discardThreshold = parentCameraData.discardThreshold;
158 cameraData.keepThreshold = parentCameraData.keepThreshold;
159}
Field definition describing a single data member of a data structure.
Definition: Field.h:70
Simple method definition.
Definition: Method.h:72
Contains reflection support.
Definition: Component.h:11
Represents an unique name.
Definition: Name.h:70