SLProject  4.2.000
A platform independent 3D computer graphics framework for desktop OS, Android, iOS and online in web browsers
SLLightDirect.cpp
Go to the documentation of this file.
1 /**
2  * \file SLLightDirect.cpp
3  * \date July 2016
4  * \authors Marcus Hudritsch
5  * \copyright http://opensource.org/licenses/GPL-3.0
6  * \remarks Please use clangformat to format the code. See more code style on
7  * https://github.com/cpvrlab/SLProject4/wiki/SLProject-Coding-Style
8 */
9 
10 #include <SLArrow.h>
11 #include <SLLightDirect.h>
12 #include <SLRay.h>
13 #include <SLScene.h>
14 #include <SLSceneView.h>
15 #include <SLShadowMap.h>
16 #include <SLSphere.h>
17 #include <SLSpheric.h>
18 
19 //-----------------------------------------------------------------------------
20 /**
21  * @brief Construct a new SLLightDirect::SLLightDirect object
22  * @details It is important that during instantiation NO OpenGL functions (gl*)
23  * get called because this constructor will be most probably called in a parallel
24  * thread from within a SLScene::assemble function. All objects that get rendered
25  * have to do their OpenGL initialization when they are used the first time
26  * during rendering in the main thread.
27  * @param assetMgr AssetManager that will own the light mesh
28  * @param s SLScene pointer
29  * @param arrowLength Length of the arrow visualization mesh
30  * @param hasMesh Boolean if a mesh should be created and shown
31  * @param doCascadedShadows Boolean for doing cascaded shadow mapping
32  */
34  SLScene* s,
35  SLfloat arrowLength,
36  SLbool hasMesh,
37  SLbool doCascadedShadows)
38 
39  : SLNode("LightDirect Node"),
40  _arrowRadius(arrowLength * 0.1f),
41  _arrowLength(arrowLength),
42  _doSunPowerAdaptation(false),
43  _sunLightPowerMin(0),
44  _sunLightColorLUT(nullptr, CLUT_DAYLIGHT),
45  _doCascadedShadows(doCascadedShadows)
46 {
47  if (hasMesh)
48  {
49  SLMaterial* mat = new SLMaterial(assetMgr,
50  "LightDirect Mesh Mat",
53  addMesh(new SLArrow(assetMgr,
56  _arrowLength * 0.3f,
57  _arrowRadius * 2.0f,
58  16,
59  "LightDirect Mesh",
60  mat));
61  _castsShadows = false;
62  }
63 
64  init(s);
65 }
66 //-----------------------------------------------------------------------------
67 /**
68  * @brief Construct a new SLLightDirect::SLLightDirect object
69  * @remarks It is important that during instantiation NO OpenGL functions (gl*)
70  * get called because this constructor will be most probably called in a parallel
71  * thread from within an SLScene::registerAssetsToLoad or SLScene::assemble
72  * function. All objects that get rendered have to do their OpenGL initialization
73  * when they are used the first time during rendering in the main thread.
74  * @param assetMgr AssetManager that will own the light mesh
75  * @param s SLScene pointer
76  * @param posx Light position x
77  * @param posy Light position y
78  * @param posz Light position z
79  * @param arrowLength Length of the arrow visualization mesh
80  * @param ambiPower Ambient light power
81  * @param diffPower Diffuse light power
82  * @param specPower Specular light power
83  * @param hasMesh Boolean if a mesh should be created and shown
84  * @param doCascadedShadows Boolean for doing cascaded shadow mapping
85  */
87  SLScene* s,
88  SLfloat posx,
89  SLfloat posy,
90  SLfloat posz,
91  SLfloat arrowLength,
92  SLfloat ambiPower,
93  SLfloat diffPower,
94  SLfloat specPower,
95  SLbool hasMesh,
96  SLbool doCascadedShadows)
97  : SLNode("Directional Light"),
98  SLLight(ambiPower, diffPower, specPower),
99  _arrowRadius(arrowLength * 0.1f),
100  _arrowLength(arrowLength),
101  _doSunPowerAdaptation(false),
102  _sunLightPowerMin(0),
103  _sunLightColorLUT(nullptr, CLUT_DAYLIGHT),
104  _doCascadedShadows(doCascadedShadows)
105 {
106  translate(posx, posy, posz, TS_object);
107 
108  if (hasMesh)
109  {
110  SLMaterial* mat = new SLMaterial(assetMgr,
111  "LightDirect Mesh Mat",
114  addMesh(new SLArrow(assetMgr,
115  _arrowRadius,
116  _arrowLength,
117  _arrowLength * 0.3f,
118  _arrowRadius * 2.0f,
119  16,
120  "LightDirect Mesh",
121  mat));
122  }
123  init(s);
124 }
125 //-----------------------------------------------------------------------------
127 {
128  delete _shadowMap;
129 
130  // Clear the color LUT that is also an OpenGL texture
132 }
133 //-----------------------------------------------------------------------------
134 /*!
135  * SLLightDirect::init sets the light id, the light states & creates an emissive
136  * material.
137 */
139 {
140  // Check if OpenGL lights are available
141  if (s->lights().size() >= SL_MAX_LIGHTS)
142  SL_EXIT_MSG("Max. NO. of lights is exceeded!");
143 
144  // Add the light to the lights array of the scene
145  if (_id == -1)
146  {
147  _id = (SLint)s->lights().size();
148  s->lights().push_back(this);
149  }
150 
151  // Set emissive light material to the lights diffuse color
152  if (_mesh)
153  if (_mesh->mat())
155 }
156 //-----------------------------------------------------------------------------
157 /*!
158 SLLightDirect::hitRec calls the recursive node intersection.
159 */
161 {
162  // do not intersect shadow rays
163  if (ray->type == SHADOW) return false;
164 
165  // only allow intersection with primary rays (no lights in reflections)
166  if (ray->type != PRIMARY) return false;
167 
168  // call the intersection routine of the node
169  return SLNode::hitRec(ray);
170 }
171 //-----------------------------------------------------------------------------
172 //! SLLightDirect::statsRec updates the statistic parameters
174 {
175  stats.numBytes += sizeof(SLLightDirect);
176  SLNode::statsRec(stats);
177 }
178 //-----------------------------------------------------------------------------
179 
180 /*!
181 SLLightDirect::drawMeshes sets the light states and calls then the drawMeshes
182 method of its node.
183 */
185 {
186  if (_id != -1)
187  {
188  // Set emissive light material to the lights diffuse color
189  if (_mesh)
190  if (_mesh->mat())
192 
193  // now draw the meshes of the node
195 
196  // Draw the volume affected by the shadow map
197  if (_createsShadows && _isOn && sv->s()->singleNodeSelected() == this)
198  {
199  if (sv->camera() != _shadowMap->camera())
201  _shadowMap->drawRays();
202  }
203  }
204 }
205 //-----------------------------------------------------------------------------
206 /*! Creates an fixed sized standard shadow map for a directional light.
207  * \param clipNear The light frustums near clipping distance
208  * \param clipFar The light frustums near clipping distance
209  * \param size Width and height of the orthographic light frustum
210  * \param texSize Shadow texture map size
211  */
212 void SLLightDirect::createShadowMap(float clipNear,
213  float clipFar,
214  SLVec2f size,
215  SLVec2i texSize)
216 {
217  if (!_shadowMap)
218  delete _shadowMap;
219 
220  _shadowMap = new SLShadowMap(this,
221  clipNear,
222  clipFar,
223  size,
224  texSize);
225 }
226 //-----------------------------------------------------------------------------
227 /*! Creates an automatic sized and cascaded shadow map for the directional light.
228  * \param camera Pointer to the camera for witch the shadow map gets sized
229  * \param texSize Shadow texture map size (equal for all cascades)
230  * \param numCascades NO. of cascades shadow maps
231  */
233  SLVec2i texSize,
234  int numCascades)
235 {
236  if (!_shadowMap)
237  delete _shadowMap;
238 
239  _doCascadedShadows = true;
240  _shadowMap = new SLShadowMap(this,
241  camera,
242  texSize,
243  numCascades);
244 }
245 //-----------------------------------------------------------------------------
246 /*! SLLightDirect::shadowTest returns 0.0 if the hit point is completely shaded
247 and 1.0 if it is 100% lighted. A directional light can not generate soft shadows.
248 */
249 SLfloat SLLightDirect::shadowTest(SLRay* ray, // ray of hit point
250  const SLVec3f& L, // vector from hit point to light
251  SLfloat lightDist, // distance to light
252  SLNode* root3D)
253 {
254  // define shadow ray and shoot
255  SLRay shadowRay(lightDist, L, ray);
256  root3D->hitRec(&shadowRay);
257 
258  if (shadowRay.length < lightDist)
259  {
260  // Handle shadow value of transparent materials
261  if (shadowRay.hitMesh->mat()->hasAlpha())
262  {
263  shadowRay.hitMesh->preShade(&shadowRay);
264  SLfloat shadowTransp = Utils::abs(shadowRay.dir.dot(shadowRay.hitNormal));
265  return shadowTransp * shadowRay.hitMesh->mat()->kt();
266  }
267  else
268  return 0.0f;
269  }
270  else
271  return 1.0f;
272 }
273 //-----------------------------------------------------------------------------
274 /*!
275 SLLightDirect::shadowTestMC returns 0.0 if the hit point is completely shaded
276 and 1.0 if it is 100% lighted. A directional light can not generate soft shadows.
277 */
278 SLfloat SLLightDirect::shadowTestMC(SLRay* ray, // ray of hit point
279  const SLVec3f& L, // vector from hit point to light
280  SLfloat lightDist, // distance to light
281  SLNode* root3D)
282 {
283  // define shadow ray and shoot
284  SLRay shadowRay(lightDist, L, ray);
285  root3D->hitRec(&shadowRay);
286 
287  if (shadowRay.length < lightDist)
288  {
289  // Handle shadow value of transparent materials
290  if (shadowRay.hitMesh->mat()->hasAlpha())
291  {
292  shadowRay.hitMesh->preShade(&shadowRay);
293  SLfloat shadowTransp = Utils::abs(shadowRay.dir.dot(shadowRay.hitNormal));
294  return shadowTransp * shadowRay.hitMesh->mat()->kt();
295  }
296  else
297  return 0.0f;
298  }
299  else
300  return 1.0f;
301 }
302 //-----------------------------------------------------------------------------
303 //! Calculates the sunlight color depending on the zenith angle
304 /*! If the angle is 0 it return 1 and _sunLightPowerMin at 90 degrees or more.
305  This can be used to the downscale the directional light to simulate the reduced
306  power of the sun. The color is take from a color ramp that is white at 0 degree
307  zenith angle.
308  */
310 {
311  SLVec3f toSunDirWS = -forwardOS();
312 
313  // The sun power is equal to the cosine of the sun zenith angle
314  SLfloat cosZenithAngle = std::max(toSunDirWS.dot(SLVec3f::AXISY),
316 
317  // The color is take from a color ramp that is white at 0 degree zenith
318  SLCol4f sunColor = _sunLightColorLUT.getTexelf(cosZenithAngle, 0);
319 
320  return sunColor * standardPower * cosZenithAngle;
321 }
322 //-----------------------------------------------------------------------------
323 //! Returns the product of the ambient light color and the ambient light power
325 {
326  return _ambientColor * _ambientPower;
327 }
328 //-----------------------------------------------------------------------------
329 //! Returns the product of the diffuse light color and the diffuse light power
330 /*! If the directional light is the sun the color and the power is depending
331  from the zenith angle of the sun. At noon it is high and bright and at sunrise
332  and sunset it is low and reddish.
333  */
335 {
338  else
339  return _diffuseColor * _diffusePower;
340 }
341 //-----------------------------------------------------------------------------
342 //! Returns the product of the specular light color and the specular light power
343 /*! If the directional light is the sun the color and the power is depending
344  from the zenith angle of the sun. At noon it is high and bright and at sunrise
345  and sunset it is low and reddish.
346  */
348 {
351  else
353 }
354 //-----------------------------------------------------------------------------
356 {
357  // Check if no shadow map was created at load time
358  if (!_shadowMap)
359  {
360  this->createShadowMap();
361  }
362  _shadowMap->renderShadows(sv, root);
363 }
364 //-----------------------------------------------------------------------------
float SLfloat
Definition: SL.h:173
bool SLbool
Definition: SL.h:175
#define SL_EXIT_MSG(message)
Definition: SL.h:240
int SLint
Definition: SL.h:170
@ TS_object
Definition: SLEnums.h:210
static const SLint SL_MAX_LIGHTS
max. number of used lights
Definition: SLGLState.h:49
@ SHADOW
Definition: SLRay.h:26
@ PRIMARY
Definition: SLRay.h:23
@ CLUT_DAYLIGHT
daylight from sunrise to sunset with noon in the middle
Definition: SLTexColorLUT.h:35
SLArrow is creates an arrow mesh based on its SLRevolver methods.
Definition: SLArrow.h:27
Toplevel holder of the assets meshes, materials, textures and shaders.
Active or visible camera node class.
Definition: SLCamera.h:54
void deleteData(SLbool deleteAlsoOnGPU)
Delete all data (CVImages and GPU textures)
SLCol4f getTexelf(SLfloat u, SLfloat v, SLuint imgIndex=0)
SLGLTexture::getTexelf returns a pixel color from u & v texture coordinates.
SLbool _doSunPowerAdaptation
Flag for sun power scaling.
~SLLightDirect() override
SLCol4f ambient() override
Returns the product of the ambient light color and the ambient light power.
SLLightDirect(SLAssetManager *assetMgr, SLScene *s, SLfloat arrowLength=0.5f, SLbool hasMesh=true, SLbool doCascadedShadows=false)
Construct a new SLLightDirect::SLLightDirect object.
SLfloat _sunLightPowerMin
Min. zenith power scale factor for sun.
SLfloat shadowTest(SLRay *ray, const SLVec3f &L, SLfloat lightDist, SLNode *root3D) override
SLCol4f specular() override
Returns the product of the specular light color and the specular light power.
bool hitRec(SLRay *ray) override
void renderShadowMap(SLSceneView *sv, SLNode *root) override
SLLight::renderShadowMap renders the shadow map of the light.
SLCol4f diffuse() override
Returns the product of the diffuse light color and the diffuse light power.
SLfloat _arrowLength
Length of direction line.
void createShadowMap(float clipNear=0.1f, float clipFar=20.0f, SLVec2f size=SLVec2f(8, 8), SLVec2i texSize=SLVec2i(1024, 1024)) override
SLfloat _arrowRadius
The sphere lights radius.
void drawMesh(SLSceneView *sv) override
SLCol4f calculateSunLight(SLfloat standardPower)
Calculates the sunlight color depending on the zenith angle.
SLfloat shadowTestMC(SLRay *ray, const SLVec3f &L, SLfloat lightDist, SLNode *root3D) override
bool _doCascadedShadows
Cascaded shadow.
void init(SLScene *s)
SLTexColorLUT _sunLightColorLUT
Sun light color LUT.
void createShadowMapAutoSize(SLCamera *camera, SLVec2i texSize=SLVec2i(1024, 1024), int numCascades=4) override
void statsRec(SLNodeStats &stats) override
SLLightDirect::statsRec updates the statistic parameters.
Abstract Light class for OpenGL light sources.
Definition: SLLight.h:61
SLint _id
OpenGL light number (0-7)
Definition: SLLight.h:208
SLCol4f _ambientColor
Ambient light color (RGB 0-1)
Definition: SLLight.h:210
SLShadowMap * _shadowMap
Used for shadow mapping.
Definition: SLLight.h:224
SLfloat _diffusePower
Diffuse light power (0-N)
Definition: SLLight.h:213
SLbool _isOn
Flag if light is on or off.
Definition: SLLight.h:209
SLfloat _specularPower
Specular light power (0-N)
Definition: SLLight.h:215
SLCol4f diffuseColor()
Definition: SLLight.h:136
SLCol4f _diffuseColor
Diffuse light color (RGB 0-1)
Definition: SLLight.h:212
SLfloat _ambientPower
Ambient light power (0-N)
Definition: SLLight.h:211
SLbool _createsShadows
flag if light creates shadows or not
Definition: SLLight.h:223
SLCol4f _specularColor
Specular light color (RGB 0-1)
Definition: SLLight.h:214
Defines a standard CG material with textures and a shader program.
Definition: SLMaterial.h:56
SLbool hasAlpha()
Returns true if there is any transparency in diffuse alpha or textures.
Definition: SLMaterial.h:125
void kt(SLfloat kt)
Definition: SLMaterial.h:190
void emissive(const SLCol4f &emis)
Definition: SLMaterial.h:174
SLMaterial * mat() const
Definition: SLMesh.h:177
virtual void preShade(SLRay *ray)
Definition: SLMesh.cpp:1470
SLNode represents a node in a hierarchical scene graph.
Definition: SLNode.h:147
virtual void drawMesh(SLSceneView *sv)
Draws the single mesh.
Definition: SLNode.cpp:176
SLVec3f forwardOS() const
Definition: SLNode.h:477
bool _castsShadows
flag if meshes of node should cast shadows
Definition: SLNode.h:357
virtual void addMesh(SLMesh *mesh)
Definition: SLNode.cpp:157
virtual void statsRec(SLNodeStats &stats)
Definition: SLNode.cpp:479
SLMesh * _mesh
pointer to a single mesh
Definition: SLNode.h:346
virtual bool hitRec(SLRay *ray)
Definition: SLNode.cpp:508
void translate(const SLVec3f &vec, SLTransformSpace relativeTo=TS_object)
Definition: SLNode.cpp:906
Ray class with ray and intersection properties.
Definition: SLRay.h:40
SLRayType type
PRIMARY, REFLECTED, REFRACTED, SHADOW.
Definition: SLRay.h:92
SLMesh * hitMesh
Points to the intersected mesh.
Definition: SLRay.h:106
SLVec3f dir
Direction vector of ray in WS.
Definition: SLRay.h:76
SLfloat length
length from origin to an intersection
Definition: SLRay.h:77
SLVec3f hitNormal
Surface normal at intersection point.
Definition: SLRay.h:111
The SLScene class represents the top level instance holding the scene structure.
Definition: SLScene.h:47
SLVLight & lights()
Definition: SLScene.h:107
SLNode * singleNodeSelected()
Returns the node if only one is selected. See also SLMesh::selectNodeMesh.
Definition: SLScene.h:116
SceneView class represents a dynamic real time 3D view onto the scene.
Definition: SLSceneView.h:69
void camera(SLCamera *camera)
Definition: SLSceneView.h:145
SLScene * s()
Definition: SLSceneView.h:167
Class for standard and cascaded shadow mapping.
Definition: SLShadowMap.h:39
void drawFrustum()
SLShadowMap::drawFrustum draws the volume affected by the shadow map.
void renderShadows(SLSceneView *sv, SLNode *root)
void drawRays()
SLCamera * camera()
Definition: SLShadowMap.h:90
static SLVec3 AXISY
Definition: SLVec3.h:298
T dot(const SLVec3 &v) const
Definition: SLVec3.h:117
static SLVec4 BLACK
Definition: SLVec4.h:213
T abs(T a)
Definition: Utils.h:249
Struct for scene graph statistics.
Definition: SLNode.h:37
SLuint numBytes
NO. of bytes allocated.
Definition: SLNode.h:39