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

Revision 692, 24.5 KB checked in by mattausch, 18 years ago (diff)

adding ogre 1.2 and dependencies

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#include "OgreSceneManager.h"
32
33namespace Ogre {
34    //-----------------------------------------------------------------------
35    Light::Light()
36                : mLightType(LT_POINT),
37          mPosition(Vector3::ZERO),
38          mDiffuse(ColourValue::White),
39          mSpecular(ColourValue::Black),
40          mDirection(Vector3::UNIT_Z),
41                  mSpotOuter(Degree(40.0f)),
42          mSpotInner(Degree(30.0f)),
43          mSpotFalloff(1.0f),
44                  mRange(100000),
45                  mAttenuationConst(1.0f),
46                  mAttenuationLinear(0.0f),
47          mAttenuationQuad(0.0f),
48                  mPowerScale(1.0f),
49          mDerivedPosition(Vector3::ZERO),
50          mDerivedDirection(Vector3::UNIT_Z)
51    {
52        // Default to point light, white diffuse light, linear attenuation, fair range
53
54        mParentNode = NULL;
55        mLocalTransformDirty = false;
56
57    }
58    //-----------------------------------------------------------------------
59        Light::Light(const String& name) : MovableObject(name),
60        mLightType(LT_POINT),
61        mPosition(Vector3::ZERO),
62        mDiffuse(ColourValue::White),
63        mSpecular(ColourValue::Black),
64        mDirection(Vector3::UNIT_Z),
65                mSpotOuter(Degree(40.0f)),
66        mSpotInner(Degree(30.0f)),
67        mSpotFalloff(1.0f),
68                mRange(100000),
69                mAttenuationConst(1.0f),
70                mAttenuationLinear(0.0f),
71        mAttenuationQuad(0.0f),
72                mPowerScale(1.0f),
73        mDerivedPosition(Vector3::ZERO),
74        mDerivedDirection(Vector3::UNIT_Z)
75    {
76
77        mParentNode = NULL;
78
79    }
80    //-----------------------------------------------------------------------
81    Light::~Light()
82    {
83    }
84    //-----------------------------------------------------------------------
85    void Light::setType(LightTypes type)
86    {
87        mLightType = type;
88    }
89    //-----------------------------------------------------------------------
90    Light::LightTypes Light::getType(void) const
91    {
92        return mLightType;
93    }
94    //-----------------------------------------------------------------------
95    void Light::setPosition(Real x, Real y, Real z)
96    {
97        mPosition.x = x;
98        mPosition.y = y;
99        mPosition.z = z;
100        mLocalTransformDirty = true;
101
102    }
103    //-----------------------------------------------------------------------
104    void Light::setPosition(const Vector3& vec)
105    {
106        mPosition = vec;
107        mLocalTransformDirty = true;
108    }
109    //-----------------------------------------------------------------------
110    const Vector3& Light::getPosition(void) const
111    {
112        return mPosition;
113    }
114    //-----------------------------------------------------------------------
115    void Light::setDirection(Real x, Real y, Real z)
116    {
117        mDirection.x = x;
118        mDirection.y = y;
119        mDirection.z = z;
120        mLocalTransformDirty = true;
121    }
122    //-----------------------------------------------------------------------
123    void Light::setDirection(const Vector3& vec)
124    {
125        mDirection = vec;
126        mLocalTransformDirty = true;
127    }
128    //-----------------------------------------------------------------------
129    const Vector3& Light::getDirection(void) const
130    {
131        return mDirection;
132    }
133    //-----------------------------------------------------------------------
134    void Light::setSpotlightRange(const Radian& innerAngle, const Radian& outerAngle, Real falloff)
135    {
136
137        if (mLightType != LT_SPOTLIGHT)
138            OGRE_EXCEPT(9999,
139                "setSpotlightRange is only valid for spotlights.",
140                "Light::setSpotlightRange");
141
142        mSpotInner =innerAngle;
143        mSpotOuter = outerAngle;
144        mSpotFalloff = falloff;
145    }
146        //-----------------------------------------------------------------------
147        void Light::setSpotlightInnerAngle(const Radian& val)
148        {
149                mSpotInner = val;
150        }
151        //-----------------------------------------------------------------------
152        void Light::setSpotlightOuterAngle(const Radian& val)
153        {
154                mSpotOuter = val;
155        }
156        //-----------------------------------------------------------------------
157        void Light::setSpotlightFalloff(Real val)
158        {
159                mSpotFalloff = val;
160        }
161    //-----------------------------------------------------------------------
162    const Radian& Light::getSpotlightInnerAngle(void) const
163    {
164        return mSpotInner;
165    }
166    //-----------------------------------------------------------------------
167    const Radian& Light::getSpotlightOuterAngle(void) const
168    {
169        return mSpotOuter;
170    }
171    //-----------------------------------------------------------------------
172    Real Light::getSpotlightFalloff(void) const
173    {
174        return mSpotFalloff;
175    }
176    //-----------------------------------------------------------------------
177    void Light::setDiffuseColour(Real red, Real green, Real blue)
178    {
179        mDiffuse.r = red;
180        mDiffuse.b = blue;
181        mDiffuse.g = green;
182    }
183    //-----------------------------------------------------------------------
184    void Light::setDiffuseColour(const ColourValue& colour)
185    {
186        mDiffuse = colour;
187    }
188    //-----------------------------------------------------------------------
189    const ColourValue& Light::getDiffuseColour(void) const
190    {
191        return mDiffuse;
192    }
193    //-----------------------------------------------------------------------
194    void Light::setSpecularColour(Real red, Real green, Real blue)
195    {
196        mSpecular.r = red;
197        mSpecular.b = blue;
198        mSpecular.g = green;
199    }
200    //-----------------------------------------------------------------------
201    void Light::setSpecularColour(const ColourValue& colour)
202    {
203        mSpecular = colour;
204    }
205    //-----------------------------------------------------------------------
206    const ColourValue& Light::getSpecularColour(void) const
207    {
208        return mSpecular;
209    }
210    //-----------------------------------------------------------------------
211    void Light::setAttenuation(Real range, Real constant,
212                        Real linear, Real quadratic)
213    {
214        mRange = range;
215        mAttenuationConst = constant;
216        mAttenuationLinear = linear;
217        mAttenuationQuad = quadratic;
218    }
219    //-----------------------------------------------------------------------
220    Real Light::getAttenuationRange(void) const
221    {
222        return mRange;
223    }
224    //-----------------------------------------------------------------------
225    Real Light::getAttenuationConstant(void) const
226    {
227        return mAttenuationConst;
228    }
229    //-----------------------------------------------------------------------
230    Real Light::getAttenuationLinear(void) const
231    {
232        return mAttenuationLinear;
233    }
234    //-----------------------------------------------------------------------
235    Real Light::getAttenuationQuadric(void) const
236    {
237        return mAttenuationQuad;
238    }
239    //-----------------------------------------------------------------------
240        void Light::setPowerScale(Real power)
241        {
242                mPowerScale = power;
243        }
244    //-----------------------------------------------------------------------
245        Real Light::getPowerScale(void) const
246        {
247                return mPowerScale;
248        }
249    //-----------------------------------------------------------------------
250    void Light::update(void) const
251    {
252        if (mParentNode)
253        {
254            if (!(mParentNode->_getDerivedOrientation() == mLastParentOrientation &&
255                mParentNode->_getDerivedPosition() == mLastParentPosition)
256                || mLocalTransformDirty)
257            {
258                // Ok, we're out of date with SceneNode we're attached to
259                mLastParentOrientation = mParentNode->_getDerivedOrientation();
260                mLastParentPosition = mParentNode->_getDerivedPosition();
261                mDerivedDirection = mLastParentOrientation * mDirection;
262                mDerivedPosition = (mLastParentOrientation * mPosition) + mLastParentPosition;
263            }
264        }
265        else
266        {
267            mDerivedPosition = mPosition;
268            mDerivedDirection = mDirection;
269        }
270
271        mLocalTransformDirty = false;
272
273    }
274    //-----------------------------------------------------------------------
275    const AxisAlignedBox& Light::getBoundingBox(void) const
276    {
277        // Null, lights are not visible
278        static AxisAlignedBox box;
279        return box;
280    }
281    //-----------------------------------------------------------------------
282    void Light::_updateRenderQueue(RenderQueue* queue)
283    {
284        // Do nothing
285    }
286    //-----------------------------------------------------------------------
287    const String& Light::getMovableType(void) const
288    {
289                return LightFactory::FACTORY_TYPE_NAME;
290    }
291    //-----------------------------------------------------------------------
292    const Vector3& Light::getDerivedPosition(void) const
293    {
294        update();
295        return mDerivedPosition;
296    }
297    //-----------------------------------------------------------------------
298    const Vector3& Light::getDerivedDirection(void) const
299    {
300        update();
301        return mDerivedDirection;
302    }
303    //-----------------------------------------------------------------------
304    void Light::setVisible(bool visible)
305    {
306        MovableObject::setVisible(visible);
307    }
308    //-----------------------------------------------------------------------
309        Vector4 Light::getAs4DVector(void) const
310        {
311                Vector4 ret;
312        if (mLightType == Light::LT_DIRECTIONAL)
313        {
314            ret = -(getDerivedDirection()); // negate direction as 'position'
315            ret.w = 0.0; // infinite distance
316        }       
317                else
318        {
319            ret = getDerivedPosition();
320            ret.w = 1.0;
321        }
322                return ret;
323        }
324    //-----------------------------------------------------------------------
325    const PlaneBoundedVolume& Light::_getNearClipVolume(const Camera* const cam) const
326    {
327        // First check if the light is close to the near plane, since
328        // in this case we have to build a degenerate clip volume
329        mNearClipVolume.planes.clear();
330        mNearClipVolume.outside = Plane::NEGATIVE_SIDE;
331
332        Real n = cam->getNearClipDistance();
333        // Homogenous position
334        Vector4 lightPos = getAs4DVector();
335        // 3D version (not the same as _getDerivedPosition, is -direction for
336        // directional lights)
337        Vector3 lightPos3 = Vector3(lightPos.x, lightPos.y, lightPos.z);
338
339        // Get eye-space light position
340        // use 4D vector so directional lights still work
341        Vector4 eyeSpaceLight = cam->getViewMatrix() * lightPos;
342        // Find distance to light, project onto -Z axis
343        Real d = eyeSpaceLight.dotProduct(
344            Vector4(0, 0, -1, -n) );
345        #define THRESHOLD 1e-6
346        if (d > THRESHOLD || d < -THRESHOLD)
347        {
348            // light is not too close to the near plane
349            // First find the worldspace positions of the corners of the viewport
350            const Vector3 *corner = cam->getWorldSpaceCorners();
351            int winding = (d < 0) ^ cam->isReflected() ? +1 : -1;
352            // Iterate over world points and form side planes
353            Vector3 normal;
354            Vector3 lightDir;
355            for (unsigned int i = 0; i < 4; ++i)
356            {
357                // Figure out light dir
358                lightDir = lightPos3 - (corner[i] * lightPos.w);
359                // Cross with anticlockwise corner, therefore normal points in
360                normal = (corner[i] - corner[(i+winding)%4])
361                    .crossProduct(lightDir);
362                normal.normalise();
363                mNearClipVolume.planes.push_back(Plane(normal, corner[i]));
364            }
365
366            // Now do the near plane plane
367            normal = cam->getFrustumPlane(FRUSTUM_PLANE_NEAR).normal;
368            if (d < 0)
369            {
370                // Behind near plane
371                normal = -normal;
372            }
373            const Vector3& cameraPos = cam->getDerivedPosition();
374            mNearClipVolume.planes.push_back(Plane(normal, cameraPos));
375
376            // Finally, for a point/spot light we can add a sixth plane
377            // This prevents false positives from behind the light
378            if (mLightType != LT_DIRECTIONAL)
379            {
380                // Direction from light perpendicular to near plane
381                mNearClipVolume.planes.push_back(Plane(-normal, lightPos3));
382            }
383        }
384        else
385        {
386            // light is close to being on the near plane
387            // degenerate volume including the entire scene
388            // we will always require light / dark caps
389            mNearClipVolume.planes.push_back(Plane(Vector3::UNIT_Z, -n));
390            mNearClipVolume.planes.push_back(Plane(-Vector3::UNIT_Z, n));
391        }
392
393        return mNearClipVolume;
394    }
395    //-----------------------------------------------------------------------
396    const PlaneBoundedVolumeList& Light::_getFrustumClipVolumes(const Camera* const cam) const
397    {
398
399        // Homogenous light position
400        Vector4 lightPos = getAs4DVector();
401        // 3D version (not the same as _getDerivedPosition, is -direction for
402        // directional lights)
403        Vector3 lightPos3 = Vector3(lightPos.x, lightPos.y, lightPos.z);
404
405        const Vector3 *clockwiseVerts[4];
406
407        // Get worldspace frustum corners
408        const Vector3* corners = cam->getWorldSpaceCorners();
409        int winding = cam->isReflected() ? +1 : -1;
410
411        bool infiniteViewDistance = (cam->getFarClipDistance() == 0);
412
413        mFrustumClipVolumes.clear();
414        for (unsigned short n = 0; n < 6; ++n)
415        {
416            // Skip far plane if infinite view frustum
417            if (infiniteViewDistance && n == FRUSTUM_PLANE_FAR)
418                continue;
419
420            const Plane& plane = cam->getFrustumPlane(n);
421            Vector4 planeVec(plane.normal.x, plane.normal.y, plane.normal.z, plane.d);
422            // planes face inwards, we need to know if light is on negative side
423            Real d = planeVec.dotProduct(lightPos);
424            if (d < -1e-06)
425            {
426                // Ok, this is a valid one
427                // clockwise verts mean we can cross-product and always get normals
428                // facing into the volume we create
429
430                mFrustumClipVolumes.push_back(PlaneBoundedVolume());
431                PlaneBoundedVolume& vol = mFrustumClipVolumes.back();
432                switch(n)
433                {
434                case(FRUSTUM_PLANE_NEAR):
435                    clockwiseVerts[0] = corners + 3;
436                    clockwiseVerts[1] = corners + 2;
437                    clockwiseVerts[2] = corners + 1;
438                    clockwiseVerts[3] = corners + 0;
439                    break;
440                case(FRUSTUM_PLANE_FAR):
441                    clockwiseVerts[0] = corners + 7;
442                    clockwiseVerts[1] = corners + 6;
443                    clockwiseVerts[2] = corners + 5;
444                    clockwiseVerts[3] = corners + 4;
445                    break;
446                case(FRUSTUM_PLANE_LEFT):
447                    clockwiseVerts[0] = corners + 2;
448                    clockwiseVerts[1] = corners + 6;
449                    clockwiseVerts[2] = corners + 5;
450                    clockwiseVerts[3] = corners + 1;
451                    break;
452                case(FRUSTUM_PLANE_RIGHT):
453                    clockwiseVerts[0] = corners + 7;
454                    clockwiseVerts[1] = corners + 3;
455                    clockwiseVerts[2] = corners + 0;
456                    clockwiseVerts[3] = corners + 4;
457                    break;
458                case(FRUSTUM_PLANE_TOP):
459                    clockwiseVerts[0] = corners + 0;
460                    clockwiseVerts[1] = corners + 1;
461                    clockwiseVerts[2] = corners + 5;
462                    clockwiseVerts[3] = corners + 4;
463                    break;
464                case(FRUSTUM_PLANE_BOTTOM):
465                    clockwiseVerts[0] = corners + 7;
466                    clockwiseVerts[1] = corners + 6;
467                    clockwiseVerts[2] = corners + 2;
468                    clockwiseVerts[3] = corners + 3;
469                    break;
470                };
471
472                // Build a volume
473                // Iterate over world points and form side planes
474                Vector3 normal;
475                Vector3 lightDir;
476                for (unsigned int i = 0; i < 4; ++i)
477                {
478                    // Figure out light dir
479                    lightDir = lightPos3 - (*(clockwiseVerts[i]) * lightPos.w);
480                    Vector3 edgeDir = *(clockwiseVerts[i]) - *(clockwiseVerts[(i+winding)%4]);
481                    // Cross with anticlockwise corner, therefore normal points in
482                    normal = edgeDir.crossProduct(lightDir);
483                    normal.normalise();
484                    vol.planes.push_back(Plane(normal, *(clockwiseVerts[i])));
485                }
486
487                // Now do the near plane (this is the plane of the side we're
488                // talking about, with the normal inverted (d is already interpreted as -ve)
489                vol.planes.push_back( Plane(-plane.normal, plane.d) );
490
491                // Finally, for a point/spot light we can add a sixth plane
492                // This prevents false positives from behind the light
493                if (mLightType != LT_DIRECTIONAL)
494                {
495                    // re-use our own plane normal
496                    vol.planes.push_back(Plane(plane.normal, lightPos3));
497                }
498            }
499        }
500
501        return mFrustumClipVolumes;
502    }
503        //-----------------------------------------------------------------------
504        uint32 Light::getTypeFlags(void) const
505        {
506                return SceneManager::LIGHT_TYPE_MASK;
507        }
508        //-----------------------------------------------------------------------
509        const String& Light::getAnimableDictionaryName(void) const
510        {
511                return LightFactory::FACTORY_TYPE_NAME;
512        }
513        //-----------------------------------------------------------------------
514        void Light::initialiseAnimableDictionary(StringVector& vec) const
515        {
516                vec.push_back("diffuseColour");
517                vec.push_back("specularColour");
518                vec.push_back("attenuation");
519                vec.push_back("spotlightInner");
520                vec.push_back("spotlightOuter");
521                vec.push_back("spotlightFalloff");
522
523        }
524        //-----------------------------------------------------------------------
525        class LightDiffuseColourValue : public AnimableValue
526        {
527        protected:
528                Light* mLight;
529        public:
530                LightDiffuseColourValue(Light* l) :AnimableValue(COLOUR)
531                { mLight = l; }
532                void setValue(const ColourValue& val)
533                {
534                        mLight->setDiffuseColour(val);
535                }
536                void applyDeltaValue(const ColourValue& val)
537                {
538                        setValue(mLight->getDiffuseColour() + val);
539                }
540                void setCurrentStateAsBaseValue(void)
541                {
542                        setAsBaseValue(mLight->getDiffuseColour());
543                }
544
545        };
546        //-----------------------------------------------------------------------
547        class LightSpecularColourValue : public AnimableValue
548        {
549        protected:
550                Light* mLight;
551        public:
552                LightSpecularColourValue(Light* l) :AnimableValue(COLOUR)
553                { mLight = l; }
554                void setValue(const ColourValue& val)
555                {
556                        mLight->setSpecularColour(val);
557                }
558                void applyDeltaValue(const ColourValue& val)
559                {
560                        setValue(mLight->getSpecularColour() + val);
561                }
562                void setCurrentStateAsBaseValue(void)
563                {
564                        setAsBaseValue(mLight->getSpecularColour());
565                }
566
567        };
568        //-----------------------------------------------------------------------
569        class LightAttenuationValue : public AnimableValue
570        {
571        protected:
572                Light* mLight;
573        public:
574                LightAttenuationValue(Light* l) :AnimableValue(VECTOR4)
575                { mLight = l; }
576                void setValue(const Vector4& val)
577                {
578                        mLight->setAttenuation(val.x, val.y, val.z, val.w);
579                }
580                void applyDeltaValue(const Vector4& val)
581                {
582                        setValue(mLight->getAs4DVector() + val);
583                }
584                void setCurrentStateAsBaseValue(void)
585                {
586                        setAsBaseValue(mLight->getAs4DVector());
587                }
588
589        };
590        //-----------------------------------------------------------------------
591        class LightSpotlightInnerValue : public AnimableValue
592        {
593        protected:
594                Light* mLight;
595        public:
596                LightSpotlightInnerValue(Light* l) :AnimableValue(REAL)
597                { mLight = l; }
598                void setValue(Real val)
599                {
600                        mLight->setSpotlightInnerAngle(Radian(val));
601                }
602                void applyDeltaValue(const Real& val)
603                {
604                        setValue(mLight->getSpotlightInnerAngle().valueRadians() + val);
605                }
606                void setCurrentStateAsBaseValue(void)
607                {
608                        setAsBaseValue(mLight->getSpotlightInnerAngle().valueRadians());
609                }
610
611        };
612        //-----------------------------------------------------------------------
613        class LightSpotlightOuterValue : public AnimableValue
614        {
615        protected:
616                Light* mLight;
617        public:
618                LightSpotlightOuterValue(Light* l) :AnimableValue(REAL)
619                { mLight = l; }
620                void setValue(Real val)
621                {
622                        mLight->setSpotlightOuterAngle(Radian(val));
623                }
624                void applyDeltaValue(const Real& val)
625                {
626                        setValue(mLight->getSpotlightOuterAngle().valueRadians() + val);
627                }
628                void setCurrentStateAsBaseValue(void)
629                {
630                        setAsBaseValue(mLight->getSpotlightOuterAngle().valueRadians());
631                }
632
633        };
634        //-----------------------------------------------------------------------
635        class LightSpotlightFalloffValue : public AnimableValue
636        {
637        protected:
638                Light* mLight;
639        public:
640                LightSpotlightFalloffValue(Light* l) :AnimableValue(REAL)
641                { mLight = l; }
642                void setValue(Real val)
643                {
644                        mLight->setSpotlightFalloff(val);
645                }
646                void applyDeltaValue(const Real& val)
647                {
648                        setValue(mLight->getSpotlightFalloff() + val);
649                }
650                void setCurrentStateAsBaseValue(void)
651                {
652                        setAsBaseValue(mLight->getSpotlightFalloff());
653                }
654
655        };
656        //-----------------------------------------------------------------------
657        AnimableValuePtr Light::createAnimableValue(const String& valueName)
658        {
659                if (valueName == "diffuseColour")
660                {
661                        return AnimableValuePtr(
662                                new LightDiffuseColourValue(this));
663                }
664                else if(valueName == "specularColour")
665                {
666                        return AnimableValuePtr(
667                                new LightSpecularColourValue(this));
668                }
669                else if (valueName == "attenuation")
670                {
671                        return AnimableValuePtr(
672                                new LightAttenuationValue(this));
673                }
674                else if (valueName == "spotlightInner")
675                {
676                        return AnimableValuePtr(
677                                new LightSpotlightInnerValue(this));
678                }
679                else if (valueName == "spotlightOuter")
680                {
681                        return AnimableValuePtr(
682                                new LightSpotlightOuterValue(this));
683                }
684                else if (valueName == "spotlightFalloff")
685                {
686                        return AnimableValuePtr(
687                                new LightSpotlightFalloffValue(this));
688                }
689                else
690                {
691                        return MovableObject::createAnimableValue(valueName);
692                }
693        }
694        //-----------------------------------------------------------------------
695        //-----------------------------------------------------------------------
696        String LightFactory::FACTORY_TYPE_NAME = "Light";
697        //-----------------------------------------------------------------------
698        const String& LightFactory::getType(void) const
699        {
700                return FACTORY_TYPE_NAME;
701        }
702        //-----------------------------------------------------------------------
703        MovableObject* LightFactory::createInstanceImpl( const String& name,
704                const NameValuePairList* params)
705        {
706
707                return new Light(name);
708
709        }
710        //-----------------------------------------------------------------------
711        void LightFactory::destroyInstance( MovableObject* obj)
712        {
713                delete obj;
714        }
715
716
717
718
719} // Namespace
Note: See TracBrowser for help on using the repository browser.