0032121: Draw Harness, ViewerTest - implement -reset option for vlight command
[occt.git] / src / OpenGl / OpenGl_ShadowMap.cxx
1 // Copyright (c) 2021 OPEN CASCADE SAS
2 //
3 // This file is part of Open CASCADE Technology software library.
4 //
5 // This library is free software; you can redistribute it and/or modify it under
6 // the terms of the GNU Lesser General Public License version 2.1 as published
7 // by the Free Software Foundation, with special exception defined in the file
8 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
9 // distribution for complete text of the license and disclaimer of any warranty.
10 //
11 // Alternatively, this file may be used under the terms of Open CASCADE
12 // commercial license or contractual agreement.
13
14 #include <OpenGl_ShadowMap.hxx>
15
16 #include <OpenGl_ArbFBO.hxx>
17 #include <OpenGl_FrameBuffer.hxx>
18 #include <OpenGl_ShaderManager.hxx>
19 #include <Graphic3d_Camera.hxx>
20 #include <Graphic3d_CView.hxx>
21 #include <Message.hxx>
22 #include <Message_Messenger.hxx>
23
24 IMPLEMENT_STANDARD_RTTIEXT(OpenGl_ShadowMap, OpenGl_NamedResource)
25
26 // =======================================================================
27 // function : OpenGl_ShadowMap
28 // purpose  :
29 // =======================================================================
30 OpenGl_ShadowMap::OpenGl_ShadowMap()
31 : OpenGl_NamedResource ("shadow_map"),
32   myShadowMapFbo (new OpenGl_FrameBuffer()),
33   myShadowCamera (new Graphic3d_Camera()),
34   myShadowMapBias (0.0f)
35 {
36   //
37 }
38
39 // =======================================================================
40 // function : Release
41 // purpose  :
42 // =======================================================================
43 void OpenGl_ShadowMap::Release (OpenGl_Context* theCtx)
44 {
45   myShadowMapFbo->Release (theCtx);
46 }
47
48 // =======================================================================
49 // function : ~OpenGl_ShadowMap
50 // purpose  :
51 // =======================================================================
52 OpenGl_ShadowMap::~OpenGl_ShadowMap()
53 {
54   Release (NULL);
55 }
56
57 // =======================================================================
58 // function : EstimatedDataSize
59 // purpose  :
60 // =======================================================================
61 Standard_Size OpenGl_ShadowMap::EstimatedDataSize() const
62 {
63   return myShadowMapFbo->EstimatedDataSize();
64 }
65
66 // =======================================================================
67 // function : IsValid
68 // purpose  :
69 // =======================================================================
70 bool OpenGl_ShadowMap::IsValid() const
71 {
72   return myShadowMapFbo->IsValid();
73 }
74
75 // =======================================================================
76 // function : Texture
77 // purpose  :
78 // =======================================================================
79 const Handle(OpenGl_Texture)& OpenGl_ShadowMap::Texture() const
80 {
81   return myShadowMapFbo->DepthStencilTexture();
82 }
83
84 // =======================================================================
85 // function : UpdateCamera
86 // purpose  :
87 // =======================================================================
88 bool OpenGl_ShadowMap::UpdateCamera (const Graphic3d_CView& theView,
89                                      const gp_XYZ* theOrigin)
90 {
91   const Bnd_Box aMinMaxBox  = theOrigin == NULL ? theView.MinMaxValues (false) : Bnd_Box(); // applicative min max boundaries
92   const Bnd_Box aGraphicBox = theOrigin == NULL ? theView.MinMaxValues (true)  : Bnd_Box(); // real graphical boundaries (not accounting infinite flag)
93
94   switch (myShadowLight->Type())
95   {
96     case Graphic3d_TypeOfLightSource_Ambient:
97     {
98       return false; // not applicable
99     }
100     case Graphic3d_TypeOfLightSource_Directional:
101     {
102       if (theOrigin != NULL)
103       {
104         Graphic3d_Mat4d aTrans;
105         aTrans.Translate (Graphic3d_Vec3d (theOrigin->X(), theOrigin->Y(), theOrigin->Z()));
106         Graphic3d_Mat4d anOrientMat = myShadowCamera->OrientationMatrix() * aTrans;
107         myLightMatrix = myShadowCamera->ProjectionMatrixF() * Graphic3d_Mat4 (anOrientMat);
108         return true;
109       }
110
111       Graphic3d_Vec4d aDir (myShadowLight->Direction().X(), myShadowLight->Direction().Y(), myShadowLight->Direction().Z(), 0.0);
112       if (myShadowLight->IsHeadlight())
113       {
114         Graphic3d_Mat4d anOrientInv;
115         theView.Camera()->OrientationMatrix().Inverted (anOrientInv);
116         aDir = anOrientInv * aDir;
117       }
118       myShadowCamera->SetZeroToOneDepth (theView.Camera()->IsZeroToOneDepth());
119       myShadowCamera->SetProjectionType (Graphic3d_Camera::Projection_Orthographic);
120       myShadowCamera->SetDirection (gp_Dir (aDir.x(), aDir.y(), aDir.z()));
121       myShadowCamera->SetUp (!myShadowCamera->Direction().IsParallel (gp::DY(), Precision::Angular())
122                             ? gp::DY()
123                             : gp::DX());
124       myShadowCamera->OrthogonalizeUp();
125
126       // Fitting entire scene to the light might produce a shadow map of too low resolution.
127       // More reliable approach would be putting a center to a current eye position and limiting maximum range,
128       // so that shadow range will be limited to some reasonable distance from current eye.
129       if (myShadowCamera->FitMinMax (aMinMaxBox, 10.0 * Precision::Confusion(), false))
130       {
131         myShadowCamera->SetScale (Max (myShadowCamera->ViewDimensions().X() * 1.1, myShadowCamera->ViewDimensions().Y() * 1.1)); // add margin
132       }
133       myShadowCamera->ZFitAll (1.0, aMinMaxBox, aGraphicBox);
134       myLightMatrix = myShadowCamera->ProjectionMatrixF() * myShadowCamera->OrientationMatrixF();
135       return true;
136     }
137     case Graphic3d_TypeOfLightSource_Positional:
138     {
139       // render into cubemap shadowmap texture
140       return false; // not implemented
141     }
142     case Graphic3d_TypeOfLightSource_Spot:
143     {
144       //myShadowCamera->SetProjectionType (Graphic3d_Camera::Projection_Perspective);
145       //myShadowCamera->SetEye (theCastShadowLight->Position());
146       return false; // not implemented
147     }
148   }
149   return false;
150 }
151
152 // =======================================================================
153 // function : Release
154 // purpose  :
155 // =======================================================================
156 void OpenGl_ShadowMapArray::Release (OpenGl_Context* theCtx)
157 {
158   for (Standard_Integer anIter = Lower(); anIter <= Upper(); ++anIter)
159   {
160     if (const Handle(OpenGl_ShadowMap)& aShadow = ChangeValue (anIter))
161     {
162       aShadow->Release (theCtx);
163     }
164   }
165 }
166
167 // =======================================================================
168 // function : EstimatedDataSize
169 // purpose  :
170 // =======================================================================
171 Standard_Size OpenGl_ShadowMapArray::EstimatedDataSize() const
172 {
173   Standard_Size aSize = 0;
174   for (Standard_Integer anIter = Lower(); anIter <= Upper(); ++anIter)
175   {
176     if (const Handle(OpenGl_ShadowMap)& aShadow = Value (anIter))
177     {
178       aSize += aShadow->EstimatedDataSize();
179     }
180   }
181   return aSize;
182 }