openGL+VS2010的例程--喷泉池注释版(三维)

时间:2022-09-10 17:12:20

openGL+VS2010的例程--喷泉池注释版(三维)

效果图如上:

功能:按“m”“t”“u”3个按键,可以控制运行状态。

步骤:略。

实际代码如下:

main.c

  1 /**********************************************************************
  2 
  3   Fountain
  4 
  5   June, 7th, 2000
  6 
  7   This tutorial was written by Philipp Crocoll
  8   Contact: 
  9     philipp.crocoll@web.de
 10     www.codecolony.de
 11 
 12   Every comment would be appreciated.
 13 
 14   If you want to use parts of any code of mine:
 15     let me know and
 16     use it!
 17 
 18   The used texture water.bmp is from www.freetextures.com
 19 
 20 ***********************************************************************
 21 
 22 
 23   ESC    : Exit
 24   m        : turn the movement up/down on/off
 25   t        : turn the turning around the fountain on/off
 26   u        : turn the updating of the scene on/off
 27 
 28 **********************************************************************/
 29    
 30 #pragma comment ( lib , "glaux.lib" )
 31 
 32 #include <GL\glut.h>        //includes gl.h and glu.h
 33 #include <GL\glaux.h>        //load the texture
 34 #include <stdlib.h>            //random function
 35 #include <math.h>            //sine and cosine functions
 36 
 37 #define PI 3.1415265359
 38 #define RandomFactor 2.0    //cannot be variable, because it is only use in InitFountain(),
 39                             //zero for perfect physical
 40 
 41 GLint ListNum;  //The number of the diplay list
 42 
 43 GLfloat OuterRadius = 1.2;
 44 GLfloat InnerRadius = 1.0;
 45 GLint NumOfVerticesStone = 16;    //only a quarter of the finally used vertices
 46 GLfloat StoneHeight = 0.5;
 47 GLfloat WaterHeight = 0.45;
 48 
 49 GLint Turned = 0;
 50 bool DoTurn = true;
 51 bool DoMoveUp = true;
 52 bool DoUpdateScene = true;
 53 GLfloat MoveUp = 0.8;
 54 GLfloat ChangeMoveUp = 0.01;
 55 
 56 //The variables for the fountain are below
 57 
 58 
 59 
 60 ////////////////////////////////////////////////////////////////////////////////
 61 
 62 
 63 struct SVertex
 64 {
 65     GLfloat x,y,z;
 66 };
 67 
 68 //It's not the best style to put classes into the main file, 
 69 //but here it is easier for you and me!
 70 class CDrop
 71 {
 72 private:
 73     GLfloat time;  //How many steps the drop was "outside", when it falls into the water, time is set back to 0
 74     SVertex ConstantSpeed;  //See the doc for explanation of the physics
 75     GLfloat AccFactor;
 76 public:
 77     void SetConstantSpeed (SVertex NewSpeed);
 78     void SetAccFactor(GLfloat NewAccFactor);
 79     void SetTime(GLfloat NewTime);
 80     void GetNewPosition(SVertex * PositionVertex);  //increments time, gets the new position
 81 };
 82 
 83 void CDrop::SetConstantSpeed(SVertex NewSpeed)
 84 {
 85     ConstantSpeed = NewSpeed;
 86 }
 87 
 88 void CDrop::SetAccFactor (GLfloat NewAccFactor)
 89 {
 90     AccFactor = NewAccFactor;
 91 }
 92 
 93 void CDrop::SetTime(GLfloat NewTime)
 94 {
 95     time = NewTime;
 96 }
 97 
 98 void CDrop::GetNewPosition(SVertex * PositionVertex)
 99 {
100     SVertex Position;
101     time += 0.2;
102     Position.x = ConstantSpeed.x * time;
103     Position.y = ConstantSpeed.y * time - AccFactor * time * time;
104     Position.z = ConstantSpeed.z * time;
105     PositionVertex->x = Position.x;
106     PositionVertex->y = Position.y + WaterHeight;
107     PositionVertex->z = Position.z;
108     if (Position.y < 0.0) 
109     {
110         /*the drop has fallen into the water. The problem is now, that we cannot
111         set time to 0.0, because if there are more "DropsPerRay" than "TimeNeeded" (See InitFountain())
112         several drops would be seen as one. Check it out.
113         */
114         time = time - int(time);
115         if (time > 0.0) time -= 0.2;
116     }
117         
118 }
119 
120 ////////////////////////////////////////////////////////////////////////////////
121 
122 CDrop * FountainDrops;
123 SVertex * FountainVertices;
124 GLint Steps = 3;   //a fountain has several steps, each with its own height
125 GLint RaysPerStep = 4;  
126 GLint DropsPerRay = 10;
127 GLint DropsComplete = Steps * RaysPerStep * DropsPerRay;
128 GLfloat AngleOfDeepestStep =60;
129 GLfloat AccFactor = 0.016;
130 
131 ////////////////////////////////////////////////////////////////////////////////
132 
133 void CreateList(void)
134 {    
135     GLuint ID;
136     _AUX_RGBImageRec *Image;
137     glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
138     glGenTextures(1,&ID); //开辟一个纹理内存,内存指向ID
139     glBindTexture( GL_TEXTURE_2D, ID);//将创建的纹理内存指向的内容绑定到纹理对象GL_TEXTURE_2D上,经过这句代码后,以后对
140                                             //GL_TEXTURE_2D的操作的任何操作都同时对应与它所绑定的纹理对象
141     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,GL_REPEAT); // s方向,即x轴方向,重复
142     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,GL_REPEAT); //t方向,即y轴方向,重复
143     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,GL_NEAREST); //当所显示的纹理比加载进来的纹理大时,采用GL_LINEAR的方法来处理
144     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,GL_NEAREST); //当所显示的纹理比加载进来的纹理小时,采用GL_LINEAR的方法来处理
145     glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL); // 贴图模式:光照无效
146     Image = auxDIBImageLoadA( "water.bmp" );
147     gluBuild2DMipmaps(    GL_TEXTURE_2D, 3, 
148                         Image->sizeX,
149                         Image->sizeY,
150                         GL_RGB,
151                         GL_UNSIGNED_BYTE,
152                         Image->data);
153     delete Image;
154     SVertex * Vertices = new SVertex[NumOfVerticesStone*4];  //allocate mem for the required vertices 保存石头围的总块数的4个顶点
155     ListNum = glGenLists(1);
156     GLint i;
157     for (i = 0; i<NumOfVerticesStone; i++)
158     {
159         Vertices[i].x = cos(2.0 * PI / NumOfVerticesStone * i) * OuterRadius;
160         Vertices[i].y = StoneHeight;  //Top
161         Vertices[i].z = sin(2.0 * PI / NumOfVerticesStone * i) * OuterRadius;
162     }
163     for (i = 0; i<NumOfVerticesStone; i++)
164     {
165         Vertices[i + NumOfVerticesStone*1].x = cos(2.0 * PI / NumOfVerticesStone * i) * InnerRadius;
166         Vertices[i + NumOfVerticesStone*1].y = StoneHeight;  //Top
167         Vertices[i + NumOfVerticesStone*1].z = sin(2.0 * PI / NumOfVerticesStone * i) * InnerRadius;
168     }    
169     for (i = 0; i<NumOfVerticesStone; i++)
170     {
171         Vertices[i + NumOfVerticesStone*2].x = cos(2.0 * PI / NumOfVerticesStone * i) * OuterRadius;
172         Vertices[i + NumOfVerticesStone*2].y = 0.0;  //Bottom
173         Vertices[i + NumOfVerticesStone*2].z = sin(2.0 * PI / NumOfVerticesStone * i) * OuterRadius;
174     }
175     for (i = 0; i<NumOfVerticesStone; i++)
176     {
177         Vertices[i + NumOfVerticesStone*3].x = cos(2.0 * PI / NumOfVerticesStone * i) * InnerRadius;
178         Vertices[i + NumOfVerticesStone*3].y = 0.0;  //Bottom
179         Vertices[i + NumOfVerticesStone*3].z = sin(2.0 * PI / NumOfVerticesStone * i) * InnerRadius;
180     }
181     glNewList(ListNum, GL_COMPILE);
182     
183         glBegin(GL_QUADS);
184         //ground quad: // 用于衬托的四方形地板
185         glColor3f(0.6,0.6,0.6);
186         glVertex3f(-OuterRadius*1.3,0.0,OuterRadius*1.3);
187         glVertex3f(-OuterRadius*1.3,0.0,-OuterRadius*1.3);
188         glVertex3f(OuterRadius*1.3,0.0,-OuterRadius*1.3);
189         glVertex3f(OuterRadius*1.3,0.0,OuterRadius*1.3);
190         //stone:  // 用于围绕的石头
191         for (int j = 1; j < 3; j++)
192         {
193             if (j == 1) glColor3f(0.8,0.4,0.4);
194             if (j == 2) glColor3f(0.4,0.2,0.2);
195             for (i = 0; i<NumOfVerticesStone-1; i++) // 石头围的外侧壁和顶层。石围块的总个数。
196             {
197                 glVertex3fv(&Vertices[i+NumOfVerticesStone*j].x);
198                 glVertex3fv(&Vertices[i].x);
199                 glVertex3fv(&Vertices[i+1].x);
200 
201                 glVertex3fv(&Vertices[i+NumOfVerticesStone*j+1].x);
202             }
203             glVertex3fv(&Vertices[i+NumOfVerticesStone*j].x);
204             glVertex3fv(&Vertices[i].x);
205             glVertex3fv(&Vertices[0].x);
206             glVertex3fv(&Vertices[NumOfVerticesStone*j].x);
207         }
208         glColor3f(0.4,0.2,0.2);
209         for (i = 0; i<NumOfVerticesStone-1; i++) // 石头围的内侧壁
210         {
211             glVertex3fv(&Vertices[i+NumOfVerticesStone*3].x);
212             glVertex3fv(&Vertices[i+NumOfVerticesStone].x);
213             glVertex3fv(&Vertices[i+NumOfVerticesStone+1].x);
214             glVertex3fv(&Vertices[i+NumOfVerticesStone*3+1].x);
215         }
216         glVertex3fv(&Vertices[i+NumOfVerticesStone*3].x);
217         glVertex3fv(&Vertices[i+NumOfVerticesStone].x);
218         glVertex3fv(&Vertices[NumOfVerticesStone].x);
219         glVertex3fv(&Vertices[NumOfVerticesStone*3].x);
220 
221         glEnd();
222 
223         //The "water":
224         glTranslatef(0.0,WaterHeight - StoneHeight, 0.0); // 从石头围的高度下降到水面的高度
225         glBindTexture(GL_TEXTURE_2D, ID);
226         glEnable(GL_TEXTURE_2D);
227         glBegin(GL_POLYGON);
228         for (i = 0; i<NumOfVerticesStone; i++) // 白色的水波圈
229         {
230             glTexCoord2f(    0.5+cos(i/GLfloat(NumOfVerticesStone)*360.0*PI/180.0)/2.0,
231                             0.5-sin(i/GLfloat(NumOfVerticesStone)*360.0*PI/180.0)/2.0);
232 
233             glVertex3fv(&Vertices[i+NumOfVerticesStone].x);
234         }
235         
236         glEnd();
237         glDisable(GL_TEXTURE_2D);
238         
239     glEndList();
240 }
241 
242 GLfloat GetRandomFloat(GLfloat range)
243 {
244     return (GLfloat)rand() / (GLfloat)RAND_MAX * range * RandomFactor; 
245 }
246 
247 void InitFountain(void)
248 {
249     //This function needn't be and isn't speed optimized
250     FountainDrops = new CDrop [ DropsComplete ]; //  掉落物
251     FountainVertices = new SVertex [ DropsComplete ]; // 最高点
252     SVertex NewSpeed;
253     GLfloat DropAccFactor; //different from AccFactor because of the random change // 随机数
254     GLfloat TimeNeeded;
255     GLfloat StepAngle; //Angle, which the ray gets out of the fountain with // 喷泉的向下射线
256     GLfloat RayAngle;    //Angle you see when you look down on the fountain
257     GLint i,j,k;
258     for (k = 0; k <Steps; k++)
259     {
260         for (j = 0; j < RaysPerStep; j++)
261         {
262             for (i = 0; i < DropsPerRay; i++)
263             {
264                 DropAccFactor = AccFactor + GetRandomFloat(0.0005);
265                 StepAngle = AngleOfDeepestStep + (90.0-AngleOfDeepestStep) 
266                         * GLfloat(k) / (Steps-1) + GetRandomFloat(0.2+0.8*(Steps-k-1)/(Steps-1));
267                 //This is the speed caused by the step:
268                 NewSpeed.x = cos ( StepAngle * PI / 180.0) * (0.2+0.04*k);
269                 NewSpeed.y = sin ( StepAngle * PI / 180.0) * (0.2+0.04*k);
270                 //This is the speed caused by the ray:    
271                 RayAngle = (GLfloat)j / (GLfloat)RaysPerStep * 360.0;
272                 //for the next computations "NewSpeed.x" is the radius. Care! Dont swap the two
273                 //lines, because the second one changes NewSpeed.x!
274                 NewSpeed.z = NewSpeed.x * sin ( RayAngle * PI /180.0);
275                 NewSpeed.x = NewSpeed.x * cos ( RayAngle * PI /180.0);            
276                 //Calculate how many steps are required, that a drop comes out and falls down again
277                 TimeNeeded = NewSpeed.y/ DropAccFactor;
278                 FountainDrops[i+j*DropsPerRay+k*DropsPerRay*RaysPerStep].SetConstantSpeed ( NewSpeed );
279                 FountainDrops[i+j*DropsPerRay+k*DropsPerRay*RaysPerStep].SetAccFactor (DropAccFactor);
280                 FountainDrops[i+j*DropsPerRay+k*DropsPerRay*RaysPerStep].SetTime(TimeNeeded * i / DropsPerRay);
281             }
282         }
283     }
284 
285 
286     //Tell OGL that we'll use the vertex array function
287     glEnableClientState(GL_VERTEX_ARRAY); // 开启顶点数组
288     //Pass the date position
289     glVertexPointer(    3,            //x,y,z-components
290                         GL_FLOAT,    //data type of SVertex
291                         0,            //the vertices are tightly packed
292                         FountainVertices);
293                         
294 }
295 
296 
297 void DrawFountain(void)
298 {
299     glColor4f(0.8,0.8,0.8,0.8);
300     if (DoUpdateScene)
301     for (int i = 0; i < DropsComplete; i++)
302     {
303         FountainDrops[i].GetNewPosition(&FountainVertices[i]);
304     }
305     glDrawArrays(    GL_POINTS,
306                     0,
307                     DropsComplete);
308 
309 }
310 
311 static long long times = 0;
312 void Display(void)
313 {
314      times++; // 延迟
315      if(times>1000000)
316          times =0;
317      if(times% 1000000== 0)
318      {
319  
320     if (DoTurn) Turned += 2;
321     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
322     glLoadIdentity();    //Load a new modelview matrix -> we can apply new transformations
323     glTranslatef(0.0,0.0,-5.0);    
324     //glRotatef(90.0,1.0,0.0,0.0);    //Enable this line to look down on the fountain
325     glRotatef((GLfloat)Turned,0.0,1.0,0.0);
326     if (DoMoveUp)
327     {
328         MoveUp += ChangeMoveUp;
329         if (MoveUp>= 1.5 || MoveUp<=0.8) ChangeMoveUp = -ChangeMoveUp;
330     }
331     glTranslatef(0.0,-MoveUp,0.0);    
332     glPushMatrix();
333         glCallList(ListNum);
334     glPopMatrix();
335         DrawFountain();
336     glFlush();            //Finish rendering
337     glutSwapBuffers();    //Swap the buffers ->make the result of rendering visible
338      
339      }// timeout
340 }
341 void Reshape(int x, int y)
342 {
343     if (y == 0 || x == 0) return;  //Nothing is visible then, so return
344     //Set a new projection matrix
345     glMatrixMode(GL_PROJECTION);  
346     glLoadIdentity();
347     //Angle of view:40 degrees
348     //Near clipping plane distance: 0.5
349     //Far clipping plane distance: 20.0
350     gluPerspective(40.0,(GLdouble)x/(GLdouble)y,0.5,20.0);
351     glMatrixMode(GL_MODELVIEW);
352     glViewport(0,0,x,y);  //Use the whole window for rendering
353     //Adjust point size to window size
354     glPointSize(GLfloat(x)/200.0);
355 }
356 void KeyDown(unsigned char key, int x, int y)
357 {    
358     switch(key)
359     {
360     case 27:    //ESC
361         exit(0);
362         break;
363     case 't':
364         DoTurn = !DoTurn;
365         break;
366     case 'm':
367         DoMoveUp = !DoMoveUp;
368         break;
369     case 'u':
370         DoUpdateScene = !DoUpdateScene;
371         break;
372     }
373 }
374 
375 int main(int argc, char **argv)
376 {    
377     //Initialize GLUT
378     glutInit(&argc, argv);
379     //Lets use doublebuffering, RGB(A)-mode and a depth buffer
380     glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
381     glutInitWindowSize(300,300);
382     //Create a window with rendering context and everything else we need
383     glutCreateWindow("Fountain");  // 喷泉
384     //Init some state variables:
385     glEnable(GL_DEPTH_TEST);
386     glClearColor(0.1,0.1,0.1,0.0); // 背景颜色
387 
388     glHint(GL_POINT_SMOOTH,GL_NICEST); //告诉opengl以显示效果为重,速度不重要 (+)
389 
390     glEnable(GL_POINT_SMOOTH);  // 开启点平滑
391     glEnable(GL_BLEND);   // 混合,在做透明效果时,必须要启用 
392 
393     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); //  表示用1.0减去源颜色的alpha值来作为因子。
394     glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);    //also try GL_LINE GL_FILL 用于控制多边形的显示方式
395     //Init the foundtain
396     InitFountain();
397     //Create the display list
398     CreateList();
399     
400     //Assign the event-handling routines
401     glutDisplayFunc(Display);
402     glutReshapeFunc(Reshape);
403     glutKeyboardFunc(KeyDown);
404     glutIdleFunc(Display);  //If there is no msg, we have to repaint
405     //Let GLUT get the msgs and tell us the ones we need
406     glutMainLoop();
407     return 0;
408 }

原始代码来源:  www.codecolony.de