8 #include <Engine/Data/EnvironmentTexture.hpp>
10 #include <stb/stb_image.h>
11 #include <stb/stb_image_write.h>
13 #include <Core/Asset/Camera.hpp>
14 #include <Core/Geometry/MeshPrimitives.hpp>
15 #include <Core/Math/Math.hpp>
16 #include <Core/Resources/Resources.hpp>
18 #include <Engine/Data/Mesh.hpp>
19 #include <Engine/Data/ShaderProgram.hpp>
20 #include <Engine/Data/ShaderProgramManager.hpp>
21 #include <Engine/Data/Texture.hpp>
22 #include <Engine/Data/ViewingParameters.hpp>
23 #include <Engine/RadiumEngine.hpp>
24 #include <Engine/Scene/CameraManager.hpp>
26 #include <tinyEXR/tinyexr.h>
35 void flip_horizontally( T* img,
size_t w,
size_t h,
size_t c ) {
36 #pragma omp parallel for firstprivate( img )
37 for (
int r = 0; r < int( h ); ++r ) {
38 auto limg = img + r * ( w * c );
39 for (
int l = 0; l < int( w ) / 2; ++l ) {
40 T* from = limg + ( l * c );
41 T* to = limg + ( w - ( l + 1 ) ) * c;
42 for (
int e = 0; e < int( c ); ++e ) {
43 std::swap( *( from + e ), *( to + e ) );
66 static HDRIMAGE* open( std::string fileName ) {
67 FILE* fptr = fopen( fileName.c_str(),
"rb" );
68 if (
nullptr == fptr ) {
69 std::cerr <<
"could not open " << fileName << std::endl;
72 int width, height, color, swap;
73 if ( !readHeader( fptr, width, height, color, swap ) ) {
74 std::cerr <<
"bad header " << fileName << std::endl;
78 HDRPIXEL* pixels =
new HDRPIXEL[width * height];
79 for (
int i = 0; i < width * height; ++i ) {
80 float* ptr = &( pixels[i].r );
81 if ( !readFloat( fptr, ptr, swap ) ) {
82 std::cerr <<
"could not read pixel " << i << std::endl;
85 if ( !readFloat( fptr, ptr + 1, swap ) ) {
86 std::cerr <<
"could not read pixel " << i << std::endl;
88 if ( !readFloat( fptr, ptr + 2, swap ) ) {
89 std::cerr <<
"could not read pixel " << i << std::endl;
93 HDRIMAGE* ret =
new HDRIMAGE;
100 static bool readFloat( FILE* fptr,
float* n,
int swap ) {
102 if ( fread( n, 4, 1, fptr ) != 1 )
return false;
104 unsigned char* cptr = (
unsigned char*)n;
105 std::swap( cptr[0], cptr[3] );
106 std::swap( cptr[1], cptr[2] );
112 static bool readHeader( FILE* fptr,
int& width,
int& height,
int& color,
int& swap ) {
115 if ( NULL == fgets( buf, 32, fptr ) )
return false;
117 if ( 0 == strncmp(
"PF", buf, 2 ) )
119 else if ( 0 == strncmp(
"Pf", buf, 2 ) )
124 if ( NULL == fgets( buf, 32, fptr ) )
return false;
127 width = strtol( buf, &endptr, 10 );
128 if ( endptr == buf )
return false;
129 height = strtol( endptr, (
char**)NULL, 10 );
131 if ( NULL == fgets( buf, 32, fptr ) )
return false;
132 if ( endptr == buf )
return false;
133 float aspect = strtof( buf, &endptr );
143 using namespace Ra::Core;
148 m_skyData { nullptr, nullptr, nullptr, nullptr, nullptr, nullptr },
149 m_isSkyBox( isSkybox ) {
150 m_type = ( mapName.find(
';' ) != mapName.npos ) ? EnvironmentTexture::EnvMapType::ENVMAP_CUBE
151 : EnvironmentTexture::EnvMapType::ENVMAP_PFM;
152 if ( m_type == EnvironmentTexture::EnvMapType::ENVMAP_PFM ) {
153 auto ext = mapName.substr( mapName.size() - 3 );
154 if ( ext !=
"pfm" ) { m_type = EnvironmentTexture::EnvMapType::ENVMAP_LATLON; }
159 void EnvironmentTexture::initializeTexture() {
161 case EnvMapType::ENVMAP_PFM:
162 setupTexturesFromPfm();
164 case EnvMapType::ENVMAP_CUBE:
165 setupTexturesFromCube();
167 case EnvMapType::ENVMAP_LATLON:
168 setupTexturesFromSphericalEquiRectangular();
171 LOG( logERROR ) <<
"EnvironmentTexture::initializeTexture(): unkown EnvMapType";
186 GL_LINEAR_MIPMAP_LINEAR,
188 (
void**)( m_skyData ) };
189 m_skyTexture = std::make_unique<Ra::Engine::Data::Texture>( params );
193 Aabb aabb( Vector3 { -1_ra, -1_ra, -1_ra }, Vector3 { 1_ra, 1_ra, 1_ra } );
194 Geometry::TriangleMesh skyMesh = Geometry::makeSharpBox( aabb );
195 m_displayMesh = std::make_unique<Ra::Engine::Data::Mesh>(
"skyBox" );
196 m_displayMesh->loadGeometry( std::move( skyMesh ) );
200 void EnvironmentTexture::setupTexturesFromPfm() {
201 PfmReader::HDRIMAGE* img = PfmReader::open( m_name.c_str() );
202 m_width = img->width / 3;
203 m_height = img->height / 4;
205 for (
int imgIdx = 0; imgIdx < 6; ++imgIdx ) {
206 m_skyData[imgIdx] =
new float[m_width * m_height * 4];
209 #pragma omp parallel for
210 for (
int imgIdx = 0; imgIdx < 6; ++imgIdx ) {
215 xOffset = 1 * m_width;
216 yOffset = 0 * m_height;
219 xOffset = 1 * m_width;
220 yOffset = 2 * m_height;
223 xOffset = 1 * m_width;
224 yOffset = 3 * m_height;
227 xOffset = 1 * m_width;
228 yOffset = 1 * m_height;
231 xOffset = 0 * m_width;
232 yOffset = 2 * m_height;
235 xOffset = 2 * m_width;
236 yOffset = 2 * m_height;
243 for (
size_t i = 0; i < m_height; ++i ) {
244 for (
size_t j = 0; j < m_width; ++j ) {
245 if ( imgIdx == 1 || imgIdx == 4 || imgIdx == 5 ) {
246 m_skyData[imgIdx][4 * ( ( m_height - 1 - i ) * m_width + j ) + 0] =
247 img->pixels[( i + yOffset ) * img->width + j + xOffset].r;
248 m_skyData[imgIdx][4 * ( ( m_height - 1 - i ) * m_width + j ) + 1] =
249 img->pixels[( i + yOffset ) * img->width + j + xOffset].g;
250 m_skyData[imgIdx][4 * ( ( m_height - 1 - i ) * m_width + j ) + 2] =
251 img->pixels[( i + yOffset ) * img->width + j + xOffset].b;
252 m_skyData[imgIdx][4 * ( ( m_height - 1 - i ) * m_width + j ) + 3] = 1.f;
257 [4 * ( ( m_width - 1 - j ) * m_height + m_height - 1 - i ) + 0] =
258 img->pixels[( i + yOffset ) * img->width + j + xOffset].r;
260 [4 * ( ( m_width - 1 - j ) * m_height + m_height - 1 - i ) + 1] =
261 img->pixels[( i + yOffset ) * img->width + j + xOffset].g;
263 [4 * ( ( m_width - 1 - j ) * m_height + m_height - 1 - i ) + 2] =
264 img->pixels[( i + yOffset ) * img->width + j + xOffset].b;
266 [4 * ( ( m_width - 1 - j ) * m_height + m_height - 1 - i ) + 3] =
271 m_skyData[imgIdx][4 * ( i * m_width + m_width - 1 - j ) + 0] =
272 img->pixels[( i + yOffset ) * img->width + j + xOffset].r;
273 m_skyData[imgIdx][4 * ( i * m_width + m_width - 1 - j ) + 1] =
274 img->pixels[( i + yOffset ) * img->width + j + xOffset].g;
275 m_skyData[imgIdx][4 * ( i * m_width + m_width - 1 - j ) + 2] =
276 img->pixels[( i + yOffset ) * img->width + j + xOffset].b;
277 m_skyData[imgIdx][4 * ( i * m_width + m_width - 1 - j ) + 3] = 1.f;
281 m_skyData[imgIdx][4 * ( j * m_width + i ) + 0] =
282 img->pixels[( i + yOffset ) * img->width + j + xOffset].r;
283 m_skyData[imgIdx][4 * ( j * m_width + i ) + 1] =
284 img->pixels[( i + yOffset ) * img->width + j + xOffset].g;
285 m_skyData[imgIdx][4 * ( j * m_width + i ) + 2] =
286 img->pixels[( i + yOffset ) * img->width + j + xOffset].b;
287 m_skyData[imgIdx][4 * ( j * m_width + i ) + 3] = 1.f;
295 for (
int imgIdx = 0; imgIdx < 6; ++imgIdx ) {
296 flip_horizontally( m_skyData[imgIdx], m_width, m_height, 4 );
299 delete[] img->pixels;
303 void EnvironmentTexture::setupTexturesFromCube() {
304 std::stringstream imgs( m_name );
306 while ( getline( imgs, imgname,
';' ) ) {
308 bool flipV {
false };
310 if ( ( imgname.find(
"posx" ) != imgname.npos ) ||
311 ( imgname.find(
"-X-plux" ) != imgname.npos ) ) {
315 if ( ( imgname.find(
"negx" ) != imgname.npos ) ||
316 ( imgname.find(
"-X-minux" ) != imgname.npos ) ) {
320 if ( ( imgname.find(
"posy" ) != imgname.npos ) ||
321 ( imgname.find(
"-Y-plux" ) != imgname.npos ) ) {
326 if ( ( imgname.find(
"negy" ) != imgname.npos ) ||
327 ( imgname.find(
"-Y-minux" ) != imgname.npos ) ) {
332 if ( ( imgname.find(
"posz" ) != imgname.npos ) ||
333 ( imgname.find(
"-Z-plux" ) != imgname.npos ) ) {
337 if ( ( imgname.find(
"negz" ) != imgname.npos ) ||
338 ( imgname.find(
"-Z-minux" ) != imgname.npos ) ) {
345 stbi_set_flip_vertically_on_load( flipV );
347 auto loaded = stbi_loadf( imgname.c_str(), &w, &h, &n, 0 );
349 LOG( logERROR ) <<
"EnvironmentTexture::setupTexturesFromCube : unable to load "
354 m_skyData[imgIdx] =
new float[m_width * m_height * 4];
356 for (
int l = 0; l < int( m_height ); ++l ) {
357 for (
int c = 0; c < int( m_width ); ++c ) {
358 auto is = ( l * m_width + c );
359 auto id = flipV ? is : ( l * m_width + ( m_width - c - 1 ) );
360 m_skyData[imgIdx][
id * 4 + 0] = loaded[is * n + 0];
361 m_skyData[imgIdx][
id * 4 + 1] = loaded[is * n + 1];
362 m_skyData[imgIdx][
id * 4 + 2] = loaded[is * n + 2];
363 m_skyData[imgIdx][
id * 4 + 3] = 0;
366 stbi_image_free( loaded );
370 void EnvironmentTexture::setupTexturesFromSphericalEquiRectangular() {
371 auto ext = m_name.substr( m_name.size() - 3 );
372 float* latlonPix {
nullptr };
374 if ( ext ==
"exr" ) {
375 const char* err {
nullptr };
377 int ret = LoadEXR( &latlonPix, &w, &h, m_name.c_str(), &err );
379 if ( ret != TINYEXR_SUCCESS ) {
381 std::cerr <<
"EnvironmentTexture -- Error reading " << m_name <<
" : " << err
383 FreeEXRErrorMessage( err );
388 stbi_set_flip_vertically_on_load(
false );
390 latlonPix = stbi_loadf( m_name.c_str(), &w, &h, &n, 4 );
393 while ( textureSize < h ) {
400 Vector3 bases[6][3] = { { { -1, 0, 0 }, { 0, 1, 0 }, { 0, 0, -1 } },
401 { { 1, 0, 0 }, { 0, -1, 0 }, { 0, 0, -1 } },
402 { { 0, 0, 1 }, { 1, 0, 0 }, { 0, 1, 0 } },
403 { { 0, 0, -1 }, { 1, 0, 0 }, { 0, -1, 0 } },
404 { { 0, 1, 0 }, { 1, 0, 0 }, { 0, 0, -1 } },
405 { { 0, -1, 0 }, { -1, 0, 0 }, { 0, 0, -1 } } };
406 auto sphericalPhi = [](
const Vector3& d ) {
407 Scalar p = std::atan2( d.x(), d.y() );
408 return ( p < 0 ) ? ( p + 2 * M_PI ) : p;
410 auto sphericalTheta = [](
const Vector3& d ) {
return std::acos( d.z() ); };
412 for (
int imgIdx = 0; imgIdx < 6; ++imgIdx ) {
414 m_skyData[imgIdx] =
new float[textureSize * textureSize * 4];
417 Scalar duv = 2_ra / textureSize;
419 #pragma omp parallel for firstprivate( duv )
420 for (
int imgIdx = 0; imgIdx < 6; ++imgIdx ) {
422 for (
int i = 0; i < textureSize; i++ ) {
423 Scalar u = -1 + i * duv;
424 for (
int j = 0; j < textureSize; j++ ) {
425 Scalar v = -1 + j * duv;
426 Vector3 d = bases[imgIdx][0] + u * bases[imgIdx][1] + v * bases[imgIdx][2];
428 Vector2 st { w * sphericalPhi( d ) / ( 2 * M_PI ), h * sphericalTheta( d ) / M_PI };
431 int s = int( st.x() );
432 int t = int( st.y() );
433 int cu = int( ( u / 2 + 0.5 ) * textureSize );
434 int cv = int( ( v / 2 + 0.5 ) * textureSize );
436 m_skyData[imgIdx][4 * ( cv * textureSize + cu ) + 0] =
437 latlonPix[4 * ( t * w + s ) + 0];
438 m_skyData[imgIdx][4 * ( cv * textureSize + cu ) + 1] =
439 latlonPix[4 * ( t * w + s ) + 1];
440 m_skyData[imgIdx][4 * ( cv * textureSize + cu ) + 2] =
441 latlonPix[4 * ( t * w + s ) + 2];
442 m_skyData[imgIdx][4 * ( cv * textureSize + cu ) + 3] = 1;
447 for (
int imgIdx = 0; imgIdx < 6; ++imgIdx ) {
448 flip_horizontally( m_skyData[imgIdx], textureSize, textureSize, 4 );
452 m_width = m_height = textureSize;
455 void EnvironmentTexture::computeSHMatrices() {
456 for (
int i = 0; i < 9; i++ ) {
457 for (
int j = 0; j < 3; j++ ) {
458 m_shcoefs[i][j] = 0.f;
463 constexpr Scalar dtheta = 0.005_ra;
464 constexpr Scalar dphi = 0.005_ra;
465 for ( Scalar theta = 0_ra; theta < M_PI; theta += dtheta ) {
466 for ( Scalar phi = 0_ra; phi < 2_ra * M_PI; phi += dphi ) {
467 Scalar x = std::sin( theta ) * std::cos( phi );
468 Scalar y = std::sin( theta ) * std::sin( phi );
469 Scalar z = std::cos( theta );
470 float* thePixel = getPixel( x, y, z );
471 updateCoeffs( thePixel, -x, y, z, std::sin( theta ) * dtheta * dphi );
477 void EnvironmentTexture::updateCoeffs(
float* hdr,
float x,
float y,
float z,
float domega ) {
483 for (
int col = 0; col < 3; col++ ) {
488 m_shcoefs[0][col] += hdr[col] * c * domega;
492 m_shcoefs[1][col] += hdr[col] * ( c * y ) * domega;
493 m_shcoefs[2][col] += hdr[col] * ( c * z ) * domega;
494 m_shcoefs[3][col] += hdr[col] * ( c * x ) * domega;
500 m_shcoefs[4][col] += hdr[col] * ( c * x * y ) * domega;
501 m_shcoefs[5][col] += hdr[col] * ( c * y * z ) * domega;
502 m_shcoefs[7][col] += hdr[col] * ( c * x * z ) * domega;
506 m_shcoefs[6][col] += hdr[col] * ( c * ( 3 * z * z - 1 ) ) * domega;
510 m_shcoefs[8][col] += hdr[col] * ( c * ( x * x - y * y ) ) * domega;
514 void EnvironmentTexture::tomatrix(
void ) {
517 constexpr
float c1 = 0.429043f, c2 = 0.511664f, c3 = 0.743125f, c4 = 0.886227f, c5 = 0.247708f;
519 for ( col = 0; col < 3; col++ ) {
520 m_shMatrices[col] = ( Ra::Core::Matrix4() << c1 * m_shcoefs[8][col],
521 c1 * m_shcoefs[4][col],
522 c1 * m_shcoefs[7][col],
523 c2 * m_shcoefs[3][col],
525 c1 * m_shcoefs[4][col],
526 -c1 * m_shcoefs[8][col],
527 c1 * m_shcoefs[5][col],
528 c2 * m_shcoefs[1][col],
530 c1 * m_shcoefs[7][col],
531 c1 * m_shcoefs[5][col],
532 c3 * m_shcoefs[6][col],
533 c2 * m_shcoefs[2][col],
535 c2 * m_shcoefs[3][col],
536 c2 * m_shcoefs[1][col],
537 c2 * m_shcoefs[2][col],
538 c4 * m_shcoefs[0][col] - c5 * m_shcoefs[6][col] )
543 float* EnvironmentTexture::getPixel(
float x,
float y,
float z ) {
544 auto ma = std::abs( x );
545 int axis = ( x > 0 );
546 auto tc = axis ? z : -z;
548 if ( std::abs( y ) > ma ) {
550 axis = 2 + ( y < 0 );
552 sc = ( axis == 2 ) ? -z : z;
554 if ( std::abs( z ) > ma ) {
556 axis = 4 + ( z < 0 );
557 tc = ( axis == 4 ) ? -x : x;
560 auto s = 0.5_ra * ( 1_ra + sc / ma );
561 auto t = 0.5_ra * ( 1_ra + tc / ma );
562 int is = int( s * m_width );
563 int it = int( t * m_height );
564 return &( m_skyData[axis][4 * ( ( m_height - 1 - is ) * m_width + it )] );
568 if ( m_shtexture !=
nullptr ) {
return m_shtexture.get(); }
570 size_t ambientWidth = 1024;
571 auto thepixels =
new unsigned char[4 * ambientWidth * ambientWidth];
572 #pragma omp parallel for
573 for (
int i = 0; i < int( ambientWidth ); i++ ) {
574 for (
int j = 0; j < int( ambientWidth ); j++ ) {
579 v = ( ambientWidth / 2.0_ra - j ) /
580 ( ambientWidth / 2.0_ra );
581 u = ( ambientWidth / 2.0_ra - i ) /
582 ( ambientWidth / 2.0_ra );
583 r = sqrt( u * u + v * v );
585 thepixels[4 * ( j * ambientWidth + i ) + 0] = 0;
586 thepixels[4 * ( j * ambientWidth + i ) + 1] = 0;
587 thepixels[4 * ( j * ambientWidth + i ) + 2] = 0;
588 thepixels[4 * ( j * ambientWidth + i ) + 3] = 255;
592 Scalar theta = M_PI * r;
593 Scalar phi = atan2( v, u );
595 Scalar x = std::sin( theta ) * std::cos( phi );
596 Scalar y = std::sin( theta ) * std::sin( phi );
597 Scalar z = std::cos( theta );
600 Ra::Core::Vector4 normal( x, y, z, 1_ra );
601 const Ra::Core::Vector4 lcolor { normal.dot( m_shMatrices[0] * normal ),
602 normal.dot( m_shMatrices[1] * normal ),
603 normal.dot( m_shMatrices[2] * normal ),
608 auto clpfnct = []( Scalar value ) {
return std::clamp( value, 0_ra, 1_ra ); };
610 color.unaryExpr( clpfnct );
611 thepixels[4 * ( j * ambientWidth + i ) + 0] =
612 static_cast<unsigned char>( color[0] * 255 );
613 thepixels[4 * ( j * ambientWidth + i ) + 1] =
614 static_cast<unsigned char>( color[1] * 255 );
615 thepixels[4 * ( j * ambientWidth + i ) + 2] =
616 static_cast<unsigned char>( color[2] * 255 );
617 thepixels[4 * ( j * ambientWidth + i ) + 3] = 255;
634 m_shtexture = std::make_unique<Ra::Engine::Data::Texture>( params );
635 return m_shtexture.get();
639 auto tex = getSHImage();
640 auto flnm = std::string(
"../" ) + filename;
641 stbi_write_png( flnm.c_str(), tex->width(), tex->height(), 4, tex->texels(), 0 );
645 return m_shMatrices[channel];
651 auto shaderMngr = Ra::Engine::RadiumEngine::getInstance()->getShaderProgramManager();
652 const std::string vertexShaderSource {
"#include \"TransformStructs.glsl\"\n"
653 "layout (location = 0) in vec3 in_position;\n"
654 "out vec3 incidentDirection;\n"
655 "uniform Transform transform;\n"
658 " mat4 mvp = transform.proj * transform.view;\n"
659 " gl_Position = mvp*vec4(in_position, 1.0);\n"
660 " incidentDirection = in_position;\n"
662 const std::string fragmentShadersource {
663 "layout (location = 0) out vec4 outColor;\n"
664 "in vec3 incidentDirection;\n"
665 "uniform samplerCube skyTexture;\n"
666 "uniform float strength;\n"
669 " vec3 envColor = texture(skyTexture, normalize(incidentDirection)).rgb;\n"
670 " outColor =vec4(strength*envColor, 1);\n"
673 config.
addShaderSource( Ra::Engine::Data::ShaderType::ShaderType_VERTEX,
674 vertexShaderSource );
675 config.addShaderSource( Ra::Engine::Data::ShaderType::ShaderType_FRAGMENT,
676 fragmentShadersource );
677 auto added = shaderMngr->addShaderProgram( config );
678 if ( added ) { m_skyShader = added.value(); }
683 m_displayMesh->updateGL();
684 m_skyTexture->initializeGL();
685 glEnable( GL_TEXTURE_CUBE_MAP_SEAMLESS );
695 auto skyparams = viewParams;
696 Ra::Core::Matrix3 t = Ra::Core::Transform { skyparams.viewMatrix }.linear();
697 skyparams.viewMatrix.setIdentity();
698 skyparams.viewMatrix.topLeftCorner<3, 3>() = t;
700 Ra::Engine::RadiumEngine::getInstance()->getSystem(
"DefaultCameraManager" ) );
703 std::clamp( cam->getZoomFactor() * cam->getFOV(), 0.001_ra, Math::Pi - 0.1_ra );
704 skyparams.projMatrix =
707 m_skyShader->
setUniform(
"transform.proj", skyparams.projMatrix );
708 m_skyShader->
setUniform(
"transform.view", skyparams.viewMatrix );
709 m_skyTexture->bind( 0 );
711 m_skyShader->
setUniform(
"strength", m_environmentStrength );
712 GLboolean depthEnabled;
713 glGetBooleanv( GL_DEPTH_WRITEMASK, &depthEnabled );
714 glDepthMask( GL_FALSE );
715 m_displayMesh->render( m_skyShader );
716 glDepthMask( depthEnabled );
721 m_environmentStrength = s;
725 return m_environmentStrength;
729 return m_skyTexture.get();
static Core::Matrix4 perspective(Scalar a, Scalar y, Scalar n, Scalar f)
static ColorBase linearRGBTosRGB(const ColorBase &lrgb)
convert the color expressed in linear RGB color space to sRGB
Ra::Engine::Data::Texture * getEnvironmentTexture()
void render(const Ra::Engine::Data::ViewingParameters &viewParams)
Render the envmap as a textured cube. This method does nothing if the envmap is not a skybox.
const Ra::Core::Matrix4 & getShMatrix(int channel)
Return the SH Matrix corresponding to the given color channel. The SH matrix is computed according to...
void saveShProjection(const std::string &filename)
Saves the spherical image representing the SH-encoded envmap.
EnvironmentTexture(const std::string &mapName, bool isSkybox=false)
Construct an envmap from a file. Supported image component of the envmap are the following.
void updateGL()
Update the OpenGL state of the envmap : texture, skybox and shaders if needed.
float getStrength() const
Get the multiplicative factor which defined the power of the light source.
void setStrength(float s)
Set the multiplicative factor which defined the power of the light source.
void addShaderSource(ShaderType type, const std::string &source)
void setUniform(const char *name, const T &value) const
Uniform setters.
Ra::Core::Asset::Camera * getActiveCamera()
Get the pointer on the active camera data.
the set of viewing parameters extracted from the camera and given to the renderer