root/OpenSceneGraph/trunk/examples/osgspotlight/osgspotlight.cpp @ 12295

Revision 12295, 9.3 kB (checked in by robert, 4 years ago)

From Paul Martz, "To summarize the fix: OpenGL eye coords are negative outside Cartesian quadrant 1. As a result, the center of projection is eye coord (0,0), which (when used as st tex coords) looks up the lower left corner of the texture. However, in projective texturing, you usually want eye coord (0,0) to look up the center of the texture. Accomplishing this mapping requires not just a lookat and perspective transform, but also a translate and scale."

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/* OpenSceneGraph example, osgspotlight.
2*
3*  Permission is hereby granted, free of charge, to any person obtaining a copy
4*  of this software and associated documentation files (the "Software"), to deal
5*  in the Software without restriction, including without limitation the rights
6*  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7*  copies of the Software, and to permit persons to whom the Software is
8*  furnished to do so, subject to the following conditions:
9*
10*  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
11*  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
12*  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
13*  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
14*  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
15*  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
16*  THE SOFTWARE.
17*/
18
19#include <osg/Notify>
20#include <osg/MatrixTransform>
21#include <osg/ShapeDrawable>
22#include <osg/PositionAttitudeTransform>
23#include <osg/Geometry>
24#include <osg/Texture2D>
25#include <osg/Geode>
26#include <osg/LightSource>
27#include <osg/TexGenNode>
28
29#include <osgUtil/Optimizer>
30
31#include <osgDB/Registry>
32#include <osgDB/ReadFile>
33
34#include <osgViewer/Viewer>
35
36
37// for the grid data..
38#include "../osghangglide/terrain_coords.h"
39
40
41osg::Image* createSpotLightImage(const osg::Vec4& centerColour, const osg::Vec4& backgroudColour, unsigned int size, float power)
42{
43    osg::Image* image = new osg::Image;
44    image->allocateImage(size,size,1,
45                         GL_RGBA,GL_UNSIGNED_BYTE);
46     
47     
48    float mid = (float(size)-1)*0.5f;
49    float div = 2.0f/float(size);
50    for(unsigned int r=0;r<size;++r)
51    {
52        unsigned char* ptr = image->data(0,r,0);
53        for(unsigned int c=0;c<size;++c)
54        {
55            float dx = (float(c) - mid)*div;
56            float dy = (float(r) - mid)*div;
57            float r = powf(1.0f-sqrtf(dx*dx+dy*dy),power);
58            if (r<0.0f) r=0.0f;
59            osg::Vec4 color = centerColour*r+backgroudColour*(1.0f-r);
60            *ptr++ = (unsigned char)((color[0])*255.0f);
61            *ptr++ = (unsigned char)((color[1])*255.0f);
62            *ptr++ = (unsigned char)((color[2])*255.0f);
63            *ptr++ = (unsigned char)((color[3])*255.0f);
64        }
65    }
66    return image;
67
68    //return osgDB::readImageFile("spot.dds");
69}
70
71osg::StateSet* createSpotLightDecoratorState(unsigned int lightNum, unsigned int textureUnit)
72{
73    osg::StateSet* stateset = new osg::StateSet;
74   
75    stateset->setMode(GL_LIGHT0+lightNum, osg::StateAttribute::ON);
76
77    osg::Vec4 centerColour(1.0f,1.0f,1.0f,1.0f);
78    osg::Vec4 ambientColour(0.05f,0.05f,0.05f,1.0f);
79
80    // set up spot light texture
81    osg::Texture2D* texture = new osg::Texture2D();
82    texture->setImage(createSpotLightImage(centerColour, ambientColour, 64, 1.0));
83    texture->setBorderColor(osg::Vec4(ambientColour));
84    texture->setWrap(osg::Texture::WRAP_S,osg::Texture::CLAMP_TO_BORDER);
85    texture->setWrap(osg::Texture::WRAP_T,osg::Texture::CLAMP_TO_BORDER);
86    texture->setWrap(osg::Texture::WRAP_R,osg::Texture::CLAMP_TO_BORDER);
87   
88    stateset->setTextureAttributeAndModes(textureUnit, texture, osg::StateAttribute::ON);
89   
90    // set up tex gens
91    stateset->setTextureMode(textureUnit, GL_TEXTURE_GEN_S, osg::StateAttribute::ON);
92    stateset->setTextureMode(textureUnit, GL_TEXTURE_GEN_T, osg::StateAttribute::ON);
93    stateset->setTextureMode(textureUnit, GL_TEXTURE_GEN_R, osg::StateAttribute::ON);
94    stateset->setTextureMode(textureUnit, GL_TEXTURE_GEN_Q, osg::StateAttribute::ON);
95   
96    return stateset;
97}
98
99
100osg::Node* createSpotLightNode(const osg::Vec3& position, const osg::Vec3& direction, float angle, unsigned int lightNum, unsigned int textureUnit)
101{
102    osg::Group* group = new osg::Group;
103   
104    // create light source.
105    osg::LightSource* lightsource = new osg::LightSource;
106    osg::Light* light = lightsource->getLight();
107    light->setLightNum(lightNum);
108    light->setPosition(osg::Vec4(position,1.0f));
109    light->setAmbient(osg::Vec4(0.00f,0.00f,0.05f,1.0f));
110    light->setDiffuse(osg::Vec4(1.0f,1.0f,1.0f,1.0f));
111    group->addChild(lightsource);
112   
113    // create tex gen.
114   
115    osg::Vec3 up(0.0f,0.0f,1.0f);
116    up = (direction ^ up) ^ direction;
117    up.normalize();
118   
119    osg::TexGenNode* texgenNode = new osg::TexGenNode;
120    texgenNode->setTextureUnit(textureUnit);
121    osg::TexGen* texgen = texgenNode->getTexGen();
122    texgen->setMode(osg::TexGen::EYE_LINEAR);
123    texgen->setPlanesFromMatrix(osg::Matrixd::lookAt(position, position+direction, up)*
124                                osg::Matrixd::perspective(angle,1.0,0.1,100)*
125                                osg::Matrixd::translate(1.0,1.0,1.0)*
126                                osg::Matrixd::scale(0.5,0.5,0.5));
127
128   
129    group->addChild(texgenNode);
130   
131    return group;
132   
133}
134
135
136osg::AnimationPath* createAnimationPath(const osg::Vec3& center,float radius,double looptime)
137{
138    // set up the animation path
139    osg::AnimationPath* animationPath = new osg::AnimationPath;
140    animationPath->setLoopMode(osg::AnimationPath::LOOP);
141   
142    int numSamples = 40;
143    float yaw = 0.0f;
144    float yaw_delta = 2.0f*osg::PI/((float)numSamples-1.0f);
145    float roll = osg::inDegrees(30.0f);
146   
147    double time=0.0f;
148    double time_delta = looptime/(double)numSamples;
149    for(int i=0;i<numSamples;++i)
150    {
151        osg::Vec3 position(center+osg::Vec3(sinf(yaw)*radius,cosf(yaw)*radius,0.0f));
152        osg::Quat rotation(osg::Quat(roll,osg::Vec3(0.0,1.0,0.0))*osg::Quat(-(yaw+osg::inDegrees(90.0f)),osg::Vec3(0.0,0.0,1.0)));
153       
154        animationPath->insert(time,osg::AnimationPath::ControlPoint(position,rotation));
155
156        yaw += yaw_delta;
157        time += time_delta;
158
159    }
160    return animationPath;   
161}
162
163osg::Node* createBase(const osg::Vec3& center,float radius)
164{
165
166    osg::Geode* geode = new osg::Geode;
167   
168    // set up the texture of the base.
169    osg::StateSet* stateset = new osg::StateSet();
170    osg::Image* image = osgDB::readImageFile("Images/lz.rgb");
171    if (image)
172    {
173        osg::Texture2D* texture = new osg::Texture2D;
174        texture->setImage(image);
175        stateset->setTextureAttributeAndModes(0,texture,osg::StateAttribute::ON);
176    }
177   
178    geode->setStateSet( stateset );
179
180
181    osg::HeightField* grid = new osg::HeightField;
182    grid->allocate(38,39);
183    grid->setOrigin(center+osg::Vec3(-radius,-radius,0.0f));
184    grid->setXInterval(radius*2.0f/(float)(38-1));
185    grid->setYInterval(radius*2.0f/(float)(39-1));
186   
187    float minHeight = FLT_MAX;
188    float maxHeight = -FLT_MAX;
189
190
191    unsigned int r;
192    for(r=0;r<39;++r)
193    {
194        for(unsigned int c=0;c<38;++c)
195        {
196            float h = vertex[r+c*39][2];
197            if (h>maxHeight) maxHeight=h;
198            if (h<minHeight) minHeight=h;
199        }
200    }
201   
202    float hieghtScale = radius*0.5f/(maxHeight-minHeight);
203    float hieghtOffset = -(minHeight+maxHeight)*0.5f;
204
205    for(r=0;r<39;++r)
206    {
207        for(unsigned int c=0;c<38;++c)
208        {
209            float h = vertex[r+c*39][2];
210            grid->setHeight(c,r,(h+hieghtOffset)*hieghtScale);
211        }
212    }
213   
214    geode->addDrawable(new osg::ShapeDrawable(grid));
215     
216    osg::Group* group = new osg::Group;
217    group->addChild(geode);
218     
219    return group;
220
221}
222
223osg::Node* createMovingModel(const osg::Vec3& center, float radius)
224{
225    float animationLength = 10.0f;
226
227    osg::AnimationPath* animationPath = createAnimationPath(center,radius,animationLength);
228
229    osg::Group* model = new osg::Group;
230 
231    osg::Node* cessna = osgDB::readNodeFile("cessna.osg");
232    if (cessna)
233    {
234        const osg::BoundingSphere& bs = cessna->getBound();
235
236        float size = radius/bs.radius()*0.3f;
237        osg::MatrixTransform* positioned = new osg::MatrixTransform;
238        positioned->setDataVariance(osg::Object::STATIC);
239        positioned->setMatrix(osg::Matrix::translate(-bs.center())*
240                              osg::Matrix::scale(size,size,size)*
241                              osg::Matrix::rotate(osg::inDegrees(180.0f),0.0f,0.0f,2.0f));
242   
243        positioned->addChild(cessna);
244   
245        osg::MatrixTransform* xform = new osg::MatrixTransform;
246        xform->setUpdateCallback(new osg::AnimationPathCallback(animationPath,0.0f,2.0));
247        xform->addChild(positioned);
248
249        xform->addChild(createSpotLightNode(osg::Vec3(0.0f,0.0f,0.0f), osg::Vec3(0.0f,1.0f,-1.0f), 60.0f, 0, 1));
250
251        model->addChild(xform);
252    }
253   
254    return model;
255}
256
257
258
259
260osg::Node* createModel()
261{
262    osg::Vec3 center(0.0f,0.0f,0.0f);
263    float radius = 100.0f;
264    osg::Vec3 lightPosition(center+osg::Vec3(0.0f,0.0f,radius));
265
266    // the shadower model
267    osg::Node* shadower = createMovingModel(center,radius*0.5f);
268
269    // the shadowed model
270    osg::Node* shadowed = createBase(center-osg::Vec3(0.0f,0.0f,radius*0.1),radius);
271
272    // combine the models together to create one which has the shadower and the shadowed with the required callback.
273    osg::Group* root = new osg::Group;
274   
275    root->setStateSet(createSpotLightDecoratorState(0,1));
276
277    root->addChild(shadower);
278    root->addChild(shadowed);
279
280    return root;
281}
282
283
284int main(int, char **)
285{
286    // construct the viewer.
287    osgViewer::Viewer viewer;
288   
289    // add the spoit light model to the viewer
290    viewer.setSceneData( createModel() );
291   
292    // run the viewer main frame loop.
293    return viewer.run();
294}
Note: See TracBrowser for help on using the browser.