SLProject  4.2.000
A platform independent 3D computer graphics framework for desktop OS, Android, iOS and online in web browsers
SLLightRect.cpp
Go to the documentation of this file.
1 /**
2  * \file SLLightRect.cpp
3  * \authors Marcus Hudritsch
4  * \date July 2014
5  * \authors Marcus Hudritsch
6  * \copyright http://opensource.org/licenses/GPL-3.0
7  * \remarks Please use clangformat to format the code. See more code style on
8  * https://github.com/cpvrlab/SLProject4/wiki/SLProject-Coding-Style
9 */
10 
11 #include <SLLightRect.h>
12 #include <SLPolygon.h>
13 #include <SLRay.h>
14 #include <SLScene.h>
15 #include <SLSceneView.h>
16 #include <SLShadowMap.h>
17 
18 extern SLfloat rnd01();
19 
20 //-----------------------------------------------------------------------------
21 /**
22  * @brief Construct a new SLLightRect::SLLightRect object
23  * @remarks It is important that during instantiation NO OpenGL functions (gl*)
24  * get called because this constructor will be most probably called in a parallel
25  * thread from within an SLScene::registerAssetsToLoad or SLScene::assemble
26  * function. All objects that get rendered have to do their OpenGL initialization
27  * when they are used the first time during rendering in the main thread.
28  * @param assetMgr AssetManager that will own the light mesh
29  * @param s SLScene pointer
30  * @param w Width of the light rectangle
31  * @param h Height if the light rectangle
32  * @param hasMesh Boolean if a mesh should be created and shown
33  */
35  SLScene* s,
36  SLfloat w,
37  SLfloat h,
38  SLbool hasMesh) : SLNode("LightRect Node")
39 {
40  width(w);
41  height(h);
42  _castsShadows = false;
43  _samples.set(1, 1);
44 
45  // make sample number even
46  if (_samples.x % 2 == 0) _samples.x++;
47  if (_samples.y % 2 == 0) _samples.y++;
48 
49  spotCutOffDEG(90.0f);
50  spotExponent(1.0);
51 
52  if (hasMesh)
53  {
54  SLMaterial* mat = new SLMaterial(assetMgr,
55  "LightRect Mesh Mat",
58  addMesh(new SLPolygon(assetMgr, w, h, "LightRect Mesh", mat));
59  _castsShadows = false;
60  }
61  init(s);
62 }
63 //-----------------------------------------------------------------------------
65 {
66  delete _shadowMap;
67 }
68 //-----------------------------------------------------------------------------
69 /*!
70 SLLightRect::init sets the light id, the light states & creates an
71 emissive mat.
72 */
74 {
75  // Check if OpenGL lights are available
76  if (s->lights().size() >= SL_MAX_LIGHTS)
77  SL_EXIT_MSG("Max. NO. of lights is exceeded!");
78 
79  // Add the light to the lights vector of the scene
80  if (_id == -1)
81  {
82  _id = (SLint)s->lights().size();
83  s->lights().push_back(this);
84  }
85 
86  // Set emissive light material to the lights diffuse color
87  if (_mesh)
88  if (_mesh->mat())
90 }
91 //-----------------------------------------------------------------------------
92 /*!
93 SLLightRect::hitRec calls the nodes intersection code.
94 */
95 SLbool
97 {
98  // do not intersect shadow rays
99  if (ray->type == SHADOW) return false;
100 
101  // only allow intersection with primary rays (no lights in reflections)
102  // if (ray->type!=PRIMARY) return false;
103 
104  // call the intersection routine of the node
105  return SLNode::hitRec(ray);
106 }
107 //-----------------------------------------------------------------------------
108 //! SLLightSpot::statsRec updates the statistic parameters
110 {
111  stats.numBytes += sizeof(SLLightRect);
112  SLNode::statsRec(stats);
113 }
114 //-----------------------------------------------------------------------------
115 /*!
116 SLLightRect::drawMeshes sets the light states and calls then the drawMeshes
117 method of its node.
118 */
120 {
121  if (_id != -1)
122  {
123  // Set emissive light material to the lights diffuse color
124  if (_mesh)
125  {
126  if (_mesh->mat())
128  }
129 
130  // now draw the meshes of the node
132 
133  // Draw the volume affected by the shadow map
134  if (_createsShadows && _isOn && sv->s()->singleNodeSelected() == this)
135  {
137  _shadowMap->drawRays();
138  }
139  }
140 }
141 //-----------------------------------------------------------------------------
142 /*!
143 SLLightRect::shadowTest returns 0.0 if the hit point is completely shaded and
144 1.0 if it is 100% lighted. A return value inbetween is calculate by the ratio
145 of the shadow rays not blocked to the total number of casted shadow rays.
146 */
147 SLfloat SLLightRect::shadowTest(SLRay* ray, // ray of hit point
148  const SLVec3f& L, // vector from hit point to light
149  const SLfloat lightDist, // distance to light
150  SLNode* root3D)
151 {
152  if (_samples.x == 1 && _samples.y == 1)
153  {
154  // define shadow ray
155  SLRay shadowRay(lightDist, L, ray);
156 
157  root3D->hitRec(&shadowRay);
158 
159  return (shadowRay.length < lightDist) ? 0.0f : 1.0f;
160  }
161  else // do light sampling for soft shadows
162  {
163  SLfloat dw = (SLfloat)_width / (SLfloat)_samples.x; // width of a sample cell
164  SLfloat dl = (SLfloat)_height / (SLfloat)_samples.y; // length of a sample cell
165  SLint x = 0, y = 0, hx = _samples.x / 2, hy = _samples.y / 2;
167  SLVbool isSampled;
168  SLbool importantPointsAreLighting = true;
169  SLfloat lighted = 0.0f; // return value
170  SLfloat invSamples = 1.0f / (SLfloat)(samples);
171  SLVec3f SP; // vector hit point to sample point in world coords
172 
173  isSampled.resize((SLuint)samples);
174 
175  for (y = 0; y < _samples.y; ++y)
176  {
177  for (x = 0; x < _samples.x; ++x)
178  {
179  SLint iSP = y * _samples.x + x;
180  isSampled[(SLuint)iSP] = false;
181  }
182  }
183 
184  /*
185  Important sample points (X) on a 7 by 5 rectangular light.
186  If all of them are lighting the hit point the sample points
187  in between (O) are not tested anymore.
188 
189  0 1 2 3 4 5 6
190  +---+---+---+---+---+---+---+
191  0 | X | . | . | X | . | . | X |
192  +---+---+---+---+---+---+---+
193  1 | . | . | . | . | . | . | . |
194  +---+---+---+---+---+---+---+
195  2 | X | . | . | X | . | . | X |
196  +---+---+---+---+---+---+---+
197  3 | . | . | . | . | . | . | . |
198  +---+---+---+---+---+---+---+
199  4 | X | . | . | X | . | . | X |
200  +---+---+---+---+---+---+---+
201  */
202 
203  // Double loop for the important sample points
204  for (y = -hy; y <= hy; y += hy)
205  {
206  for (x = -hx; x <= hx; x += hx)
207  {
208  SLint iSP = (y + hy) * _samples.x + x + hx;
209  isSampled[(SLuint)iSP] = true;
210 
211  SP.set(updateAndGetWM().multVec(SLVec3f(x * dw, y * dl, 0)) - ray->hitPoint);
212  SLfloat SPDist = SP.length();
213  SP.normalize();
214  SLRay shadowRay(SPDist, SP, ray);
215 
216  root3D->hitRec(&shadowRay);
217 
218  if (shadowRay.length >= SPDist - FLT_EPSILON)
219  lighted += invSamples; // sum up the light
220  else
221  importantPointsAreLighting = false;
222  }
223  }
224 
225  if (importantPointsAreLighting)
226  lighted = 1.0f;
227  else
228  { // Double loop for the sample points in between
229  for (y = -hy; y <= hy; ++y)
230  {
231  for (x = -hx; x <= hx; ++x)
232  {
233  SLint iSP = (y + hy) * _samples.x + x + hx;
234  if (!isSampled[(SLuint)iSP])
235  {
236  SP.set(updateAndGetWM().multVec(SLVec3f(x * dw, y * dl, 0)) - ray->hitPoint);
237  SLfloat SPDist = SP.length();
238  SP.normalize();
239  SLRay shadowRay(SPDist, SP, ray);
240 
241  root3D->hitRec(&shadowRay);
242 
243  // sum up the light
244  if (shadowRay.length >= SPDist - FLT_EPSILON)
245  lighted += invSamples;
246  }
247  }
248  }
249  }
250  return lighted;
251  }
252 }
253 //-----------------------------------------------------------------------------
254 /*!
255 SLLightRect::shadowTestMC returns 0.0 if the hit point is shaded and 1.0 if it
256 lighted. Only one shadow sample is tested for path tracing.
257 */
258 SLfloat SLLightRect::shadowTestMC(SLRay* ray, // ray of hit point
259  const SLVec3f& L, // vector from hit point to light
260  const SLfloat lightDist, // distance to light
261  SLNode* root3D)
262 {
263  SLfloat rndX = rnd01();
264  SLfloat rndY = rnd01();
265 
266  // Sample point in object space
267  SLVec3f spOS(SLVec3f(rndX * _width - _width * 0.5f,
268  rndY * _height - _height * 0.5f,
269  0.0f));
270 
271  // Sample point in world space
272  SLVec3f spWS(updateAndGetWM().multVec(spOS) - ray->hitPoint);
273 
274  SLfloat spDistWS = spWS.length();
275  spWS.normalize();
276  SLRay shadowRay(spDistWS, spWS, ray);
277 
278  root3D->hitRec(&shadowRay);
279 
280  return (shadowRay.length < spDistWS) ? 0.0f : 1.0f;
281 }
282 //-----------------------------------------------------------------------------
283 /*! Creates an fixed sized standard shadow map for a rectangular light.
284  * \param lightClipNear The light frustums near clipping distance
285  * \param lightClipFar The light frustums near clipping distance
286  * \param size Ignored for rectangular lights
287  * \param texSize Shadow texture map size
288  */
289 void SLLightRect::createShadowMap(float lightClipNear,
290  float lightClipFar,
291  SLVec2f size,
292  SLVec2i texSize)
293 {
294  if (!_shadowMap)
295  delete _shadowMap;
296 
297  _shadowMap = new SLShadowMap(this,
298  lightClipNear,
299  lightClipFar,
300  size,
301  texSize);
302 }
303 //-----------------------------------------------------------------------------
304 /*! Creates an automatic sized shadow map for the rectangular light.
305  * \param camera Pointer to the camera for witch the shadow map gets sized
306  * \param texSize Shadow texture map size (equal for all cascades)
307  * \param numCascades This value is ignored (default 0)
308  */
310  SLVec2i texSize,
311  int numCascades)
312 {
313  (void)numCascades;
314  if (!_shadowMap)
315  delete _shadowMap;
316 
317  _shadowMap = new SLShadowMap(this,
318  camera,
319  texSize,
320  0);
321 }
322 //-----------------------------------------------------------------------------
323 void SLLightRect::samples(const SLVec2i samples)
324 {
325  assert(samples.x % 2 == 1 && samples.y % 2 == 1);
326  _samples = samples;
327 }
328 //-----------------------------------------------------------------------------
329 void SLLightRect::samplesXY(const SLint x, const SLint y)
330 {
331  assert(x % 2 == 1 && y % 2 == 1);
332  _samples.set(x, y);
333 }
334 //-----------------------------------------------------------------------------
float SLfloat
Definition: SL.h:173
unsigned int SLuint
Definition: SL.h:171
bool SLbool
Definition: SL.h:175
vector< SLbool > SLVbool
Definition: SL.h:189
#define SL_EXIT_MSG(message)
Definition: SL.h:240
int SLint
Definition: SL.h:170
typedef void(SL_STDCALL *cbOnImGuiBuild)(SLScene *s
Callback function typedef for ImGui build function.
static const SLint SL_MAX_LIGHTS
max. number of used lights
Definition: SLGLState.h:49
SLfloat rnd01()
Definition: SLRay.cpp:39
@ SHADOW
Definition: SLRay.h:26
SLVec3< SLfloat > SLVec3f
Definition: SLVec3.h:318
Toplevel holder of the assets meshes, materials, textures and shaders.
Active or visible camera node class.
Definition: SLCamera.h:54
SLint _id
OpenGL light number (0-7)
Definition: SLLight.h:208
SLShadowMap * _shadowMap
Used for shadow mapping.
Definition: SLLight.h:224
SLfloat spotCutOffDEG() const
Definition: SLLight.h:140
SLbool _isOn
Flag if light is on or off.
Definition: SLLight.h:209
SLCol4f diffuseColor()
Definition: SLLight.h:136
SLbool _createsShadows
flag if light creates shadows or not
Definition: SLLight.h:223
SLfloat spotExponent() const
Definition: SLLight.h:142
SLfloat shadowTest(SLRay *ray, const SLVec3f &L, SLfloat lightDist, SLNode *root3D) override
void init(SLScene *s)
Definition: SLLightRect.cpp:73
SLfloat width() const
Definition: SLLightRect.h:84
SLfloat height() const
Definition: SLLightRect.h:85
void statsRec(SLNodeStats &stats) override
SLLightSpot::statsRec updates the statistic parameters.
SLLightRect(SLAssetManager *assetMgr, SLScene *s, SLfloat width=1, SLfloat height=1, SLbool hasMesh=true)
Construct a new SLLightRect::SLLightRect object.
Definition: SLLightRect.cpp:34
SLfloat shadowTestMC(SLRay *ray, const SLVec3f &L, SLfloat lightDist, SLNode *root3D) override
void samples(SLVec2i samples)
SLVec2i _samples
Uneven NO. of samples in x and y dir.
Definition: SLLightRect.h:105
void drawMesh(SLSceneView *sv) override
void createShadowMapAutoSize(SLCamera *camera, SLVec2i texSize=SLVec2i(1024, 1024), int numCascades=0) override
~SLLightRect() override
Definition: SLLightRect.cpp:64
SLfloat _width
Width of square light in x direction.
Definition: SLLightRect.h:101
SLfloat _height
Lenght of square light in y direction.
Definition: SLLightRect.h:102
void samplesXY(SLint x, SLint y)
bool hitRec(SLRay *ray) override
Definition: SLLightRect.cpp:96
void createShadowMap(float lightClipNear=0.1f, float lightClipFar=20.0f, SLVec2f size=SLVec2f(8, 8), SLVec2i texSize=SLVec2i(1024, 1024)) override
SLCol4f diffuse() override
Returns normally _diffuseColor * _diffusePower.
Definition: SLLightRect.h:89
SLVec3< T > multVec(SLVec3< T > v) const
Definition: SLMat4.h:576
Defines a standard CG material with textures and a shader program.
Definition: SLMaterial.h:56
void emissive(const SLCol4f &emis)
Definition: SLMaterial.h:174
SLMaterial * mat() const
Definition: SLMesh.h:177
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
const SLMat4f & updateAndGetWM() const
Definition: SLNode.cpp:703
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
SLPolygon creates a convex polyon mesh.
Definition: SLPolygon.h:29
Ray class with ray and intersection properties.
Definition: SLRay.h:40
SLRayType type
PRIMARY, REFLECTED, REFRACTED, SHADOW.
Definition: SLRay.h:92
SLfloat length
length from origin to an intersection
Definition: SLRay.h:77
SLVec3f hitPoint
Point of intersection.
Definition: SLRay.h:110
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
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 drawRays()
T y
Definition: SLVec2.h:30
T x
Definition: SLVec2.h:30
void set(const T X, const T Y)
Definition: SLVec2.h:40
SLVec3 & normalize()
Definition: SLVec3.h:124
T length() const
Definition: SLVec3.h:122
void set(const T X, const T Y, const T Z)
Definition: SLVec3.h:59
static SLVec4 BLACK
Definition: SLVec4.h:213
Struct for scene graph statistics.
Definition: SLNode.h:37
SLuint numBytes
NO. of bytes allocated.
Definition: SLNode.h:39