Camera.cpp
Go to the documentation of this file.
1 #include "Camera.hpp"
2 
3 #include "../Defs.hpp"
4 #include "ElementSystem.hpp"
5 
6 namespace iv
7 {
8 
10  cm( inst, this, "Camera", ClientMarker::Status() ),
11  Slot( inst ),
12  ElementRenderer( inst ),
13  viewport_size()
14 {
15  this->cm.inherits( this->Slot::cm, this->ElementRenderer::cm );
16 
17  this->geometry( geometry );
18 
19  auto es = this->instance()->getSystem< ElementSystem >();
20  if( es )
21  es->camera_created( this );
22 }
23 
25 {
26  auto es = this->instance()->getSystem< ElementSystem >();
27  if( es )
28  es->camera_destroyed( this );
29 }
30 
32 {
33  static iv::TableId DebugTable = TableId::create( "Camera" );
34  auto row = view->Table( DebugTable ).Row( this );
35 
36  row.Column( "projection", this->state.projection );
37  row.Column( "pixelizing_projection", this->state.pixelizing_projection );
38  row.Column( "view", this->state.view );
39 }
40 
42 {
43  this->viewport_size = geometry.size;
44 
45  float3 new_size( geometry.size.x / geometry.density, geometry.size.y / geometry.density, 1000 );
46  this->expectedSize.Set( new_size );
47  this->size.Set( new_size );
48 
49  this->state.projection = glm::scale( float4x4( 1 ), float3( 1.0f, -1.0f, 1.0f ) ) // Y inversion
50  * glm::ortho( 0.0f, geometry.size.x / geometry.density, 0.0f, geometry.size.y / geometry.density, 1.0f, -1001.0f );
51 
52  this->state.pixelizing_projection = glm::scale( float4x4( 1 ), float3( 1.0f, -1.0f, 1.0f ) ) // Y inversion
53  * glm::ortho( 0.0f, float( geometry.size.x ), 0.0f, float( geometry.size.y ), -1.0f, 1.0f );
54 }
55 
56 void Camera::render_scene( Elem * view )
57 {
58  if( view )
59  this->state.view = glm::inverse( view->modelTransform.Get() );
60  else
61  this->state.view = iv::float4x4( 1 );
62 
63  this->init_frame();
64  this->cm.log( SRC_INFO, Defs::Log::ElementFirstPass, "Start first pass." );
65  this->first_pass( this );
66  this->RunSecondPasses();
67  this->cm.log( SRC_INFO, Defs::Log::ElementRenderPass, "Start render pass." );
68  this->RunRender( state );
69  this->end_frame();
70 }
71 
73 {
74  return this;
75 }
76 
77 //==================================================================================================
78 //--------------------- math -----------------------------------------------------------------------
79 float3 Camera::WNormalized( float4 in )
80 {
81  if( in.w == 0.0f )
82  return float3( in.x, in.y, in.z );
83  else
84  return float3( in.x / in.w, in.y / in.w, in.z / in.w );
85 }
86 
87 float3 Camera::FromViewportSpaceToCameraSpace( float3 screen_point )
88 {
89  float2 view_size = this->viewport_size;
90 
91  screen_point.y = view_size.y - screen_point.y; // Flip Y coordinate, because natively 3D Y coordinate begins at bottom but we have it on top (to match gui construction).
92 
93  float3 camera_point;
94  camera_point.x = screen_point.x / view_size.x * 2.0f - 1.0f;
95  camera_point.y = screen_point.y / view_size.y * 2.0f - 1.0f;
96  camera_point.z = screen_point.z * 2.0f - 1.0f;
97 
98  return camera_point;
99 }
100 
101 float3 Camera::FromCameraSpaceToViewportSpace( float3 camera_point )
102 {
103  float2 view_size = this->viewport_size;
104 
105  float3 screen_point;
106  screen_point.x = ( camera_point.x + 1.0f ) * 0.5f * view_size.x;
107  screen_point.y = ( camera_point.y + 1.0f ) * 0.5f * view_size.y;
108  screen_point.y = view_size.y - screen_point.y; // Flip Y coordinate, because natively 3D Y coordinate begins at bottom but we have it on top (to match gui construction).
109  screen_point.z = ( camera_point.z + 1.0f ) * 0.5f;
110 
111  return screen_point;
112 }
113 
115 {
116  float4x4 mvp = this->state.projection * this->state.view * model_transform;
117 
118  float4 camera_space = mvp * float4( in.x, in.y, in.z, 1.0 );
119  return this->FromCameraSpaceToViewportSpace( this->WNormalized( camera_space ) );
120 }
121 
123 {
124  float4x4 mvp = this->state.projection * this->state.view * model_transform;
125 
126  float3 camera_space = FromViewportSpaceToCameraSpace( in );
127  float4 local_space = glm::inverse( mvp ) * float4( camera_space.x, camera_space.y, camera_space.z, 1.0f );
128  return this->WNormalized( local_space );
129 }
130 
132 {
133  float4x4 mvp = this->state.projection * this->state.view * model_transform;
134  float4x4 mvp_inv = glm::inverse( mvp );
135 
136  float4 local_lorigin( 0, 0, 0, 1 ); // local origin seen by localy-relative observer
137  float3 camera_lorigin = this->WNormalized( mvp * local_lorigin ); // local origin seen by camera-relative observer
138 
139 
140  float3 camera_in = this->FromViewportSpaceToCameraSpace( float3( in.x, in.y, 0.0 ) ); // input point seen by camera-relative observer
141  float3 camera_move( camera_in.x - camera_lorigin.x, camera_in.y - camera_lorigin.y, 0.0 ); // distance between input point and local origin seen by camera-relative observer
142 
143  // adjust Z
144  camera_move.z = ( -1.0f * mvp_inv[ 0 ][ 2 ] * camera_move.x - mvp_inv[ 1 ][ 2 ] * camera_move.y ) / mvp_inv[ 2 ][ 2 ];
145  camera_in.z = camera_lorigin.z + camera_move.z;
146 
147  //
148  float4 local_in = mvp_inv * float4( camera_in.x, camera_in.y, camera_in.z, 1.0f ); // input point seen by localy-relative observer
149  float3 out = this->WNormalized( local_in );
150  return float2( out.x, out.y );
151 }
152 
153 }