source: OGRE/trunk/ogrenew/OgreMain/src/OgreLight.cpp @ 657

Revision 657, 18.8 KB checked in by mattausch, 19 years ago (diff)

added ogre dependencies and patched ogre sources

Line 
1/*
2-----------------------------------------------------------------------------
3This source file is part of OGRE
4    (Object-oriented Graphics Rendering Engine)
5For the latest info, see http://www.ogre3d.org/
6
7Copyright (c) 2000-2005 The OGRE Team
8Also see acknowledgements in Readme.html
9
10This program is free software; you can redistribute it and/or modify it under
11the terms of the GNU Lesser General Public License as published by the Free Software
12Foundation; either version 2 of the License, or (at your option) any later
13version.
14
15This program is distributed in the hope that it will be useful, but WITHOUT
16ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
18
19You should have received a copy of the GNU Lesser General Public License along with
20this program; if not, write to the Free Software Foundation, Inc., 59 Temple
21Place - Suite 330, Boston, MA 02111-1307, USA, or go to
22http://www.gnu.org/copyleft/lesser.txt.
23-----------------------------------------------------------------------------
24*/
25#include "OgreStableHeaders.h"
26#include "OgreLight.h"
27
28#include "OgreException.h"
29#include "OgreSceneNode.h"
30#include "OgreCamera.h"
31
32
33namespace Ogre {
34    String Light::msMovableType = "Light";
35
36    //-----------------------------------------------------------------------
37    Light::Light()
38    {
39        // Default to point light, white diffuse light, linear attenuation, fair range
40        mLightType = LT_POINT;
41        mDiffuse = ColourValue::White;
42        mSpecular = ColourValue::Black;
43        mRange = 5000;
44        mAttenuationConst = 1.0f;
45        mAttenuationLinear = 0.0f;
46        mAttenuationQuad = 0.0f;
47
48        // Center in world, direction irrelevant but set anyway
49        mPosition = mDerivedPosition = Vector3::ZERO;
50        mDirection = mDerivedPosition = Vector3::UNIT_Z;
51        mParentNode = NULL;
52
53        mLocalTransformDirty = false;
54
55    }
56    //-----------------------------------------------------------------------
57    Light::Light(const String& name)
58    {
59        mName = name;
60
61        // Default to point light, white diffuse light, linear attenuation, fair range
62        mLightType = LT_POINT;
63        mDiffuse = ColourValue::White;
64        mSpecular = ColourValue::Black;
65        mRange = 100000;
66        mAttenuationConst = 1.0f;
67        mAttenuationLinear = 0.0f;
68        mAttenuationQuad = 0.0f;
69
70        // Center in world, direction irrelevant but set anyway
71        mPosition = Vector3::ZERO;
72        mDirection = Vector3::UNIT_Z;
73
74        // Default some spot values
75        mSpotInner = Degree(30.0f);
76        mSpotOuter = Degree(40.0f);
77        mSpotFalloff = 1.0f;
78        mParentNode = NULL;
79
80
81    }
82    //-----------------------------------------------------------------------
83    Light::~Light()
84    {
85    }
86    //-----------------------------------------------------------------------
87    const String& Light::getName(void) const
88    {
89        return mName;
90
91    }
92    //-----------------------------------------------------------------------
93    void Light::setType(LightTypes type)
94    {
95        mLightType = type;
96    }
97    //-----------------------------------------------------------------------
98    Light::LightTypes Light::getType(void) const
99    {
100        return mLightType;
101    }
102    //-----------------------------------------------------------------------
103    void Light::setPosition(Real x, Real y, Real z)
104    {
105        mPosition.x = x;
106        mPosition.y = y;
107        mPosition.z = z;
108        mLocalTransformDirty = true;
109
110    }
111    //-----------------------------------------------------------------------
112    void Light::setPosition(const Vector3& vec)
113    {
114        mPosition = vec;
115        mLocalTransformDirty = true;
116    }
117    //-----------------------------------------------------------------------
118    const Vector3& Light::getPosition(void) const
119    {
120        return mPosition;
121    }
122    //-----------------------------------------------------------------------
123    void Light::setDirection(Real x, Real y, Real z)
124    {
125        mDirection.x = x;
126        mDirection.y = y;
127        mDirection.z = z;
128        mLocalTransformDirty = true;
129    }
130    //-----------------------------------------------------------------------
131    void Light::setDirection(const Vector3& vec)
132    {
133        mDirection = vec;
134        mLocalTransformDirty = true;
135    }
136    //-----------------------------------------------------------------------
137    const Vector3& Light::getDirection(void) const
138    {
139        return mDirection;
140    }
141    //-----------------------------------------------------------------------
142    void Light::setSpotlightRange(const Radian& innerAngle, const Radian& outerAngle, Real falloff)
143    {
144
145        if (mLightType != LT_SPOTLIGHT)
146            OGRE_EXCEPT(9999,
147                "setSpotlightRange is only valid for spotlights.",
148                "Light::setSpotlightRange");
149
150        mSpotInner =innerAngle;
151        mSpotOuter = outerAngle;
152        mSpotFalloff = falloff;
153    }
154    //-----------------------------------------------------------------------
155    const Radian& Light::getSpotlightInnerAngle(void) const
156    {
157        return mSpotInner;
158    }
159    //-----------------------------------------------------------------------
160    const Radian& Light::getSpotlightOuterAngle(void) const
161    {
162        return mSpotOuter;
163    }
164    //-----------------------------------------------------------------------
165    Real Light::getSpotlightFalloff(void) const
166    {
167        return mSpotFalloff;
168    }
169    //-----------------------------------------------------------------------
170    void Light::setDiffuseColour(Real red, Real green, Real blue)
171    {
172        mDiffuse.r = red;
173        mDiffuse.b = blue;
174        mDiffuse.g = green;
175    }
176    //-----------------------------------------------------------------------
177    void Light::setDiffuseColour(const ColourValue& colour)
178    {
179        mDiffuse = colour;
180    }
181    //-----------------------------------------------------------------------
182    const ColourValue& Light::getDiffuseColour(void) const
183    {
184        return mDiffuse;
185    }
186    //-----------------------------------------------------------------------
187    void Light::setSpecularColour(Real red, Real green, Real blue)
188    {
189        mSpecular.r = red;
190        mSpecular.b = blue;
191        mSpecular.g = green;
192    }
193    //-----------------------------------------------------------------------
194    void Light::setSpecularColour(const ColourValue& colour)
195    {
196        mSpecular = colour;
197    }
198    //-----------------------------------------------------------------------
199    const ColourValue& Light::getSpecularColour(void) const
200    {
201        return mSpecular;
202    }
203    //-----------------------------------------------------------------------
204    void Light::setAttenuation(Real range, Real constant,
205                        Real linear, Real quadratic)
206    {
207        mRange = range;
208        mAttenuationConst = constant;
209        mAttenuationLinear = linear;
210        mAttenuationQuad = quadratic;
211    }
212    //-----------------------------------------------------------------------
213    Real Light::getAttenuationRange(void) const
214    {
215        return mRange;
216    }
217    //-----------------------------------------------------------------------
218    Real Light::getAttenuationConstant(void) const
219    {
220        return mAttenuationConst;
221    }
222    //-----------------------------------------------------------------------
223    Real Light::getAttenuationLinear(void) const
224    {
225        return mAttenuationLinear;
226    }
227    //-----------------------------------------------------------------------
228    Real Light::getAttenuationQuadric(void) const
229    {
230        return mAttenuationQuad;
231    }
232    //-----------------------------------------------------------------------
233    void Light::update(void) const
234    {
235        if (mParentNode)
236        {
237            if (!(mParentNode->_getDerivedOrientation() == mLastParentOrientation &&
238                mParentNode->_getDerivedPosition() == mLastParentPosition)
239                || mLocalTransformDirty)
240            {
241                // Ok, we're out of date with SceneNode we're attached to
242                mLastParentOrientation = mParentNode->_getDerivedOrientation();
243                mLastParentPosition = mParentNode->_getDerivedPosition();
244                mDerivedDirection = mLastParentOrientation * mDirection;
245                mDerivedPosition = (mLastParentOrientation * mPosition) + mLastParentPosition;
246            }
247        }
248        else
249        {
250            mDerivedPosition = mPosition;
251            mDerivedDirection = mDirection;
252        }
253
254        mLocalTransformDirty = false;
255
256    }
257    //-----------------------------------------------------------------------
258    void Light::_notifyCurrentCamera(Camera* cam)
259    {
260        // Do nothing
261    }
262    //-----------------------------------------------------------------------
263    const AxisAlignedBox& Light::getBoundingBox(void) const
264    {
265        // Null, lights are not visible
266        static AxisAlignedBox box;
267        return box;
268    }
269    //-----------------------------------------------------------------------
270    void Light::_updateRenderQueue(RenderQueue* queue)
271    {
272        // Do nothing
273    }
274    //-----------------------------------------------------------------------
275    const String& Light::getMovableType(void) const
276    {
277        return msMovableType;
278    }
279    //-----------------------------------------------------------------------
280    const Vector3& Light::getDerivedPosition(void) const
281    {
282        update();
283        return mDerivedPosition;
284    }
285    //-----------------------------------------------------------------------
286    const Vector3& Light::getDerivedDirection(void) const
287    {
288        update();
289        return mDerivedDirection;
290    }
291    //-----------------------------------------------------------------------
292    void Light::setVisible(bool visible)
293    {
294        MovableObject::setVisible(visible);
295    }
296    //-----------------------------------------------------------------------
297        Vector4 Light::getAs4DVector(void) const
298        {
299                Vector4 ret;
300        if (mLightType == Light::LT_DIRECTIONAL)
301        {
302            ret = -(getDerivedDirection()); // negate direction as 'position'
303            ret.w = 0.0; // infinite distance
304        }       
305                else
306        {
307            ret = getDerivedPosition();
308            ret.w = 1.0;
309        }
310                return ret;
311        }
312    //-----------------------------------------------------------------------
313    const PlaneBoundedVolume& Light::_getNearClipVolume(const Camera* const cam) const
314    {
315        // First check if the light is close to the near plane, since
316        // in this case we have to build a degenerate clip volume
317        mNearClipVolume.planes.clear();
318        mNearClipVolume.outside = Plane::NEGATIVE_SIDE;
319
320        Real n = cam->getNearClipDistance();
321        // Homogenous position
322        Vector4 lightPos = getAs4DVector();
323        // 3D version (not the same as _getDerivedPosition, is -direction for
324        // directional lights)
325        Vector3 lightPos3 = Vector3(lightPos.x, lightPos.y, lightPos.z);
326
327        // Get eye-space light position
328        // use 4D vector so directional lights still work
329        Vector4 eyeSpaceLight = cam->getViewMatrix() * lightPos;
330        // Find distance to light, project onto -Z axis
331        Real d = eyeSpaceLight.dotProduct(
332            Vector4(0, 0, -1, -n) );
333        #define THRESHOLD 1e-6
334        if (d > THRESHOLD || d < -THRESHOLD)
335        {
336            // light is not too close to the near plane
337            // First find the worldspace positions of the corners of the viewport
338            const Vector3 *corner = cam->getWorldSpaceCorners();
339            int winding = (d < 0) ^ cam->isReflected() ? +1 : -1;
340            // Iterate over world points and form side planes
341            Vector3 normal;
342            Vector3 lightDir;
343            for (unsigned int i = 0; i < 4; ++i)
344            {
345                // Figure out light dir
346                lightDir = lightPos3 - (corner[i] * lightPos.w);
347                // Cross with anticlockwise corner, therefore normal points in
348                normal = (corner[i] - corner[(i+winding)%4])
349                    .crossProduct(lightDir);
350                normal.normalise();
351                mNearClipVolume.planes.push_back(Plane(normal, corner[i]));
352            }
353
354            // Now do the near plane plane
355            normal = cam->getFrustumPlane(FRUSTUM_PLANE_NEAR).normal;
356            if (d < 0)
357            {
358                // Behind near plane
359                normal = -normal;
360            }
361            // HACK: There bug in Camera::getDerivedPosition() which should be
362            // take reflection into account.
363            Vector3 cameraPos = cam->getDerivedPosition();
364            if (cam->isReflected())
365            {
366                // Camera is reflected, used the reflect of
367                // derived position as world position
368                cameraPos = cam->getReflectionMatrix() * cameraPos;
369            }
370            mNearClipVolume.planes.push_back(Plane(normal, cameraPos));
371
372            // Finally, for a point/spot light we can add a sixth plane
373            // This prevents false positives from behind the light
374            if (mLightType != LT_DIRECTIONAL)
375            {
376                // Direction from light perpendicular to near plane
377                mNearClipVolume.planes.push_back(Plane(-normal, lightPos3));
378            }
379        }
380        else
381        {
382            // light is close to being on the near plane
383            // degenerate volume including the entire scene
384            // we will always require light / dark caps
385            mNearClipVolume.planes.push_back(Plane(Vector3::UNIT_Z, -n));
386            mNearClipVolume.planes.push_back(Plane(-Vector3::UNIT_Z, n));
387        }
388
389        return mNearClipVolume;
390    }
391    //-----------------------------------------------------------------------
392    const PlaneBoundedVolumeList& Light::_getFrustumClipVolumes(const Camera* const cam) const
393    {
394
395        // Homogenous light position
396        Vector4 lightPos = getAs4DVector();
397        // 3D version (not the same as _getDerivedPosition, is -direction for
398        // directional lights)
399        Vector3 lightPos3 = Vector3(lightPos.x, lightPos.y, lightPos.z);
400
401        const Vector3 *clockwiseVerts[4];
402
403        // Get worldspace frustum corners
404        const Vector3* corners = cam->getWorldSpaceCorners();
405        int winding = cam->isReflected() ? +1 : -1;
406
407        bool infiniteViewDistance = (cam->getFarClipDistance() == 0);
408
409        mFrustumClipVolumes.clear();
410        for (unsigned short n = 0; n < 6; ++n)
411        {
412            // Skip far plane if infinite view frustum
413            if (infiniteViewDistance && n == FRUSTUM_PLANE_FAR)
414                continue;
415
416            const Plane& plane = cam->getFrustumPlane(n);
417            Vector4 planeVec(plane.normal.x, plane.normal.y, plane.normal.z, plane.d);
418            // planes face inwards, we need to know if light is on negative side
419            Real d = planeVec.dotProduct(lightPos);
420            if (d < -1e-06)
421            {
422                // Ok, this is a valid one
423                // clockwise verts mean we can cross-product and always get normals
424                // facing into the volume we create
425
426                mFrustumClipVolumes.push_back(PlaneBoundedVolume());
427                PlaneBoundedVolume& vol = mFrustumClipVolumes.back();
428                switch(n)
429                {
430                case(FRUSTUM_PLANE_NEAR):
431                    clockwiseVerts[0] = corners + 3;
432                    clockwiseVerts[1] = corners + 2;
433                    clockwiseVerts[2] = corners + 1;
434                    clockwiseVerts[3] = corners + 0;
435                    break;
436                case(FRUSTUM_PLANE_FAR):
437                    clockwiseVerts[0] = corners + 7;
438                    clockwiseVerts[1] = corners + 6;
439                    clockwiseVerts[2] = corners + 5;
440                    clockwiseVerts[3] = corners + 4;
441                    break;
442                case(FRUSTUM_PLANE_LEFT):
443                    clockwiseVerts[0] = corners + 2;
444                    clockwiseVerts[1] = corners + 6;
445                    clockwiseVerts[2] = corners + 5;
446                    clockwiseVerts[3] = corners + 1;
447                    break;
448                case(FRUSTUM_PLANE_RIGHT):
449                    clockwiseVerts[0] = corners + 7;
450                    clockwiseVerts[1] = corners + 3;
451                    clockwiseVerts[2] = corners + 0;
452                    clockwiseVerts[3] = corners + 4;
453                    break;
454                case(FRUSTUM_PLANE_TOP):
455                    clockwiseVerts[0] = corners + 0;
456                    clockwiseVerts[1] = corners + 1;
457                    clockwiseVerts[2] = corners + 5;
458                    clockwiseVerts[3] = corners + 4;
459                    break;
460                case(FRUSTUM_PLANE_BOTTOM):
461                    clockwiseVerts[0] = corners + 7;
462                    clockwiseVerts[1] = corners + 6;
463                    clockwiseVerts[2] = corners + 2;
464                    clockwiseVerts[3] = corners + 3;
465                    break;
466                };
467
468                // Build a volume
469                // Iterate over world points and form side planes
470                Vector3 normal;
471                Vector3 lightDir;
472                for (unsigned int i = 0; i < 4; ++i)
473                {
474                    // Figure out light dir
475                    lightDir = lightPos3 - (*(clockwiseVerts[i]) * lightPos.w);
476                    Vector3 edgeDir = *(clockwiseVerts[i]) - *(clockwiseVerts[(i+winding)%4]);
477                    // Cross with anticlockwise corner, therefore normal points in
478                    normal = edgeDir.crossProduct(lightDir);
479                    normal.normalise();
480                    vol.planes.push_back(Plane(normal, *(clockwiseVerts[i])));
481                }
482
483                // Now do the near plane (this is the plane of the side we're
484                // talking about, with the normal inverted (d is already interpreted as -ve)
485                vol.planes.push_back( Plane(-plane.normal, plane.d) );
486
487                // Finally, for a point/spot light we can add a sixth plane
488                // This prevents false positives from behind the light
489                if (mLightType != LT_DIRECTIONAL)
490                {
491                    // re-use our own plane normal
492                    vol.planes.push_back(Plane(plane.normal, lightPos3));
493                }
494            }
495        }
496
497        return mFrustumClipVolumes;
498    }
499
500
501
502
503} // Namespace
Note: See TracBrowser for help on using the repository browser.