SharpGL学习笔记(十一) 光源创建的综合例子:光源参数可调节的测试场景

 

灯光的测试例子:光源参数可以调节的测试场景

 

先看一下测试场景和效果。

场景中可以切换视图, 以方便观察三维体和灯光的位置。环境光,漫射光,镜面反射光都可以在四种颜色间切换。

灯光位置和摄像机位置(LookAt)可以输入数值或者点动调节,也可以按键盘的QEWASD六个键进行调节。

你还会注意到:球体对光的效果要敏感柔和些,而那个六面体BOX看来效果不好。这是因为灯光对顶点发生作用。在程序里面,球休的顶点数量有20*10,而BOX只有4*6个,而且还重合了一些顶点。

这一点,在3dsmax的全局光照里面表现很明显,做为墙壁的box顶点数量越大,计算出来光照效果越好

勘误:box在创建的时候没有指定法线,这个也是重要原因,请参考例子SharpGL学习笔记(十五) 纹理映射 ,那里的box指定了法线,效果就很好了。(2016/9/4)

还有,界面上灯光位置是 -1,5,1,1  前三个是x,y,z, 后面的一个1不是坐标,它取值0或者1,表示灯光是定向光源(directonal),还是定位光源(positional)。

 

代码如下:

  1 using System;
  2 using System.Collections.Generic;
  3 using System.ComponentModel;
  4 using System.Data;
  5 using System.Drawing;
  6 using System.Linq;
  7 using System.Text;
  8 using System.Windows.Forms;
  9 using SharpGL;
 10 
 11 namespace SharpGLWinformsApplication1
 12 {
 13 
 14     public partial class SharpGLForm : Form
 15     {
 16         private float rotation = 0.0f;
 17         private bool isRotate = false;
 18         private bool isLines = false;
 19         private bool isFrontView = false;
 20         private bool isLeftView = false;
 21         private bool isTopView = false;
 22         private bool isPerspective = true;
 23         private float[] lightPos = new float[] { -1, -3, 1, 1 };
 24         private float[] lightSphereColor = new float[] { 1f, 1f, 1f };
 25         private IList<float[]> lightColor = new List<float[]>();
 26         private double[] lookatValue = { 1, 1, 2, 0, 0, 0, 0, 1, 0 };
 27         private IList<double[]> viewDefaultPos = new List<double[]>();
 28         public SharpGLForm()
 29         {
 30             InitializeComponent();
 31         }
 32 
 33         private void openGLControl_OpenGLDraw(object sender, PaintEventArgs e)
 34         {
 35             OpenGL gl = openGLControl.OpenGL;
 36             gl.Clear(OpenGL.GL_COLOR_BUFFER_BIT | OpenGL.GL_DEPTH_BUFFER_BIT);
 37             gl.LoadIdentity();
 38             gl.Rotate(rotation, 0.0f, 1.0f, 0.0f);
 39 
 40             drawGrid(gl);
 41             DrawCube(ref gl, 1.5f,-1f, -2f, isLines);
 42             drawOneSphere(ref gl,-3,-2,-4,isLines);
 43             if (isRotate)
 44                 rotation += 3.0f;
 45         }
 46 
 47         private void setLightColor(OpenGL gl)
 48         {
 49             gl.Light(OpenGL.GL_LIGHT0, OpenGL.GL_AMBIENT, lightColor[0]);
 50             gl.Light(OpenGL.GL_LIGHT0, OpenGL.GL_DIFFUSE, lightColor[1]);
 51             gl.Light(OpenGL.GL_LIGHT0, OpenGL.GL_SPECULAR, lightColor[2]);
 52         }
 53 
 54         private void openGLControl_OpenGLInitialized(object sender, EventArgs e)
 55         {
 56             OpenGL gl = openGLControl.OpenGL;
 57 
 58             //四个视图的缺省位置
 59             viewDefaultPos.Add(new double[] { 1, 1, 2, 0, 0, 0, 0, 1, 0 });     //透视
 60             viewDefaultPos.Add(new double[] { 0, 0, 2, 0, 0, 0, 0, 1, 0 });     //前视 
 61             viewDefaultPos.Add(new double[] { 5, 0, 0, 0, 0, 0, 0, 1, 0 });     //左视
 62             viewDefaultPos.Add(new double[] { 0, 13, 0, -1, 0, 0, 0, 1, 0 });   //顶视
 63             lookatValue =(double[])viewDefaultPos[0].Clone();
 64 
 65             lightColor.Add(new float[] { 1f, 1f, 1f, 1f });  //环境光(ambient light)
 66             lightColor.Add(new float[] { 1f, 1f, 1f, 1f });  //漫射光(diffuse light)
 67             lightColor.Add(new float[] { 1f, 1f, 1f, 1f });  //镜面反射光(specular light)
 68 
 69             setLightColor(gl);
 70             gl.Light(OpenGL.GL_LIGHT0, OpenGL.GL_POSITION, lightPos);
 71             
 72             gl.Enable(OpenGL.GL_LIGHTING);
 73             gl.Enable(OpenGL.GL_LIGHT0);
 74 
 75             gl.ClearColor(0, 0, 0, 0);
 76         }
 77 
 78         private void drawOneSphere(ref OpenGL gl, float xPos, float yPos, float zPos, bool isLine)
 79         {
 80             gl.PushMatrix();
 81             {
 82                 gl.Translate(xPos, yPos, zPos);
 83                 gl.Color(lightSphereColor);
 84                 drawSphere(gl,1,20,10,isLine);
 85             }
 86             gl.PopMatrix();
 87         }
 88 
 89         private void openGLControl_Resized(object sender, EventArgs e)
 90         {
 91 
 92             OpenGL gl = openGLControl.OpenGL;
 93             gl.MatrixMode(OpenGL.GL_PROJECTION);
 94             gl.LoadIdentity();
 95             gl.Perspective(40.0f, (double)Width / (double)Height, 0.01, 100.0);
 96 
 97 
 98             gl.LookAt(lookatValue[0], lookatValue[1], lookatValue[2],
 99                 lookatValue[3], lookatValue[4], lookatValue[5],
100                 lookatValue[6], lookatValue[7], lookatValue[8]);
101             
102             gl.MatrixMode(OpenGL.GL_MODELVIEW);
103             updateLabInfo();
104         }
105 
106         internal void DrawCube(ref OpenGL Gl, float xPos, float yPos, float zPos, bool isLine)
107         {
108             Gl.PushMatrix();
109             Gl.Translate(xPos, yPos, zPos);
110             if (isLine)
111                 Gl.Begin(OpenGL.GL_LINE_STRIP);
112             else
113                 Gl.Begin(OpenGL.GL_POLYGON);
114 
115             /** 顶面 */
116             Gl.Vertex(0.0f, 0.0f, 0.0f);
117             Gl.Vertex(0.0f, 0.0f, -1.0f);
118             Gl.Vertex(-1.0f, 0.0f, -1.0f);
119             Gl.Vertex(-1.0f, 0.0f, 0.0f);
120 
121             /** 前面 */
122             Gl.Vertex(0.0f, 0.0f, 0.0f);
123             Gl.Vertex(-1.0f, 0.0f, 0.0f);
124             Gl.Vertex(-1.0f, -1.0f, 0.0f);
125             Gl.Vertex(0.0f, -1.0f, 0.0f);
126 
127             /** 右面 */
128             Gl.Vertex(0.0f, 0.0f, 0.0f);
129             Gl.Vertex(0.0f, -1.0f, 0.0f);
130             Gl.Vertex(0.0f, -1.0f, -1.0f);
131             Gl.Vertex(0.0f, 0.0f, -1.0f);
132 
133             /** 左面*/
134             Gl.Vertex(-1.0f, 0.0f, 0.0f);
135             Gl.Vertex(-1.0f, 0.0f, -1.0f);
136             Gl.Vertex(-1.0f, -1.0f, -1.0f);
137             Gl.Vertex(-1.0f, -1.0f, 0.0f);
138 
139             /** 底面 */
140             Gl.Vertex(0.0f, 0.0f, 0.0f);
141             Gl.Vertex(0.0f, -1.0f, -1.0f);
142             Gl.Vertex(-1.0f, -1.0f, -1.0f);
143             Gl.Vertex(-1.0f, -1.0f, 0.0f);
144 
145 
146             /** 后面 */
147             Gl.Vertex(0.0f, 0.0f, 0.0f);
148             Gl.Vertex(-1.0f, 0.0f, -1.0f);
149             Gl.Vertex(-1.0f, -1.0f, -1.0f);
150             Gl.Vertex(0.0f, -1.0f, -1.0f);
151             Gl.End();
152             Gl.PopMatrix();
153         }
154 
155         void drawGrid(OpenGL gl)
156         {
157             //绘制过程
158             gl.PushAttrib(OpenGL.GL_CURRENT_BIT);  //保存当前属性
159             gl.PushMatrix();                        //压入堆栈
160             gl.Translate(0f, -2f, 0f);
161             gl.Color(0f, 0f, 1f);
162 
163             //在X,Z平面上绘制网格
164             for (float i = -50; i <= 50; i += 1)
165             {
166                 //绘制线
167                 gl.Begin(OpenGL.GL_LINES);
168                 {
169                     if (i == 0)
170                         gl.Color(0f, 1f, 0f);
171                     else
172                         gl.Color(0f, 0f, 1f);
173 
174                     //X轴方向
175                     gl.Vertex(-50f, 0f, i);
176                     gl.Vertex(50f, 0f, i);
177                     //Z轴方向 
178                     gl.Vertex(i, 0f, -50f);
179                     gl.Vertex(i, 0f, 50f);
180 
181                 }
182                 gl.End();
183             }
184             gl.PopMatrix();
185             gl.PopAttrib();
186         }
187 
188       
189         void drawSphere(OpenGL gl,double radius,int segx,int segy,bool isLines)
190         {
191             gl.PushMatrix();
192             gl.Translate(2f, 1f, 2f);
193             var sphere = gl.NewQuadric();
194             if (isLines)
195                 gl.QuadricDrawStyle(sphere, OpenGL.GL_LINES);
196             else
197                 gl.QuadricDrawStyle(sphere, OpenGL.GL_QUADS);
198             gl.QuadricNormals(sphere, OpenGL.GLU_SMOOTH);
199             gl.QuadricOrientation(sphere, (int)OpenGL.GLU_OUTSIDE);
200             gl.QuadricTexture(sphere, (int)OpenGL.GLU_FALSE);
201             gl.Sphere(sphere, radius, segx, segy);
202             gl.DeleteQuadric(sphere);
203             gl.PopMatrix();
204         }
205 
206         private void moveObject(int obj,string keyName)
207         {
208             //obj==0移动视图
209             switch (keyName)
210             {
211                 case "btnQ":
212                     if (obj == 0) ++lookatValue[1];   //y
213                     else
214                         ++lightPos[1];
215                     break;
216                 case "btnE":
217                     if (obj == 0) --lookatValue[1];
218                     else
219                         --lightPos[1];
220                     break;
221                 case "btnW":
222                     if (obj == 0) --lookatValue[2];   //z
223                     else
224                        --lightPos[2];
225                     break;
226                 case "btnS":
227                     if (obj == 0)  ++lookatValue[2];
228                     else
229                         ++lightPos[2];
230                     break;
231                 case "btnA":
232                     if (obj == 0) --lookatValue[0];  //X
233                     else
234                        --lightPos[0];
235                     break;
236                 case "btnD":
237                     if (obj == 0)  ++lookatValue[0];
238                     else
239                         ++lightPos[0];
240                     break;
241             }
242         }
243 
244         private void rbPerspective_CheckedChanged(object sender, EventArgs e)
245         {
246             switch (((RadioButton)sender).Name)
247             {
248                 case "rbPerspective":
249                     isPerspective = !isPerspective;
250                     isFrontView = false;
251                     isTopView = false;
252                     isLeftView = false;
253                     break;
254                 case "rbLeft":
255                      isLeftView = !isLeftView;
256                     isFrontView = false;
257                     isPerspective = false;
258                     isTopView = false;
259                     break;
260                 case "rbFront":
261                      isFrontView = !isFrontView;
262                     isTopView = false;
263                     isPerspective = false;
264                     isLeftView = false;
265                     break;
266                 case "rbTop":
267                      isTopView = !isTopView;
268                     isPerspective = false;
269                     isLeftView = false;
270                     isFrontView = false;
271                     break;
272                 default:
273                     return;
274             }
275             setViewDefaultValue();
276             openGLControl_Resized(null, null);
277         }
278 
279         private void cbxRotate_CheckedChanged(object sender, EventArgs e)
280         {
281             var cbx=((CheckBox)sender);
282             switch (cbx.Name)
283             {
284                 case "cbxRotate":
285                     isRotate = cbx.Checked;
286                     break;
287                 case "cbxLines":
288                     isLines = cbx.Checked;
289                     break;
290                 case "cbxLightOff":
291                     if (!cbx.Checked)
292                         this.openGLControl.OpenGL.Enable(OpenGL.GL_LIGHT0);
293                     else
294                         this.openGLControl.OpenGL.Disable(OpenGL.GL_LIGHT0);
295                     break;
296             }
297         }
298 
299         private void SharpGLForm_Load(object sender, EventArgs e)
300         {
301             this.cbxLightType.SelectedIndex = 0;
302             updateLabInfo();
303         }
304 
305         private void updateLabInfo()
306         {
307             tbLightPos.Text = string.Format("{0},{1},{2},{3}", lightPos[0], lightPos[1], lightPos[2], lightPos[3]);
308             tbLookAt.Text = string.Format("{0},{1},{2},{3},{4},{5},{6},{7},{8}", lookatValue[0], lookatValue[1], lookatValue[2],
309                 lookatValue[3], lookatValue[4], lookatValue[5], lookatValue[6], lookatValue[7], lookatValue[8]);
310         }
311 
312         private void rbWhite_CheckedChanged(object sender, EventArgs e)
313         {
314             var rad = ((RadioButton)sender);
315             var lightType = this.cbxLightType.SelectedIndex;
316             if (rad.Checked)
317             {
318                 switch (rad.Name)
319                 {
320                     case "rbWhite":
321                         lightColor[lightType][0] = 1f;
322                         lightColor[lightType][1] = 1f;
323                         lightColor[lightType][2] = 1f;
324                         lightColor[lightType][3] = 1f;
325                         break;
326                     case "rbRed":
327                         lightColor[lightType][0] = 1f;
328                         lightColor[lightType][1] = 0f;
329                         lightColor[lightType][2] = 0f;
330                         lightColor[lightType][3] = 1f;
331                         break;
332                     case "rbGreen":
333                         lightColor[lightType][0] = 0f;
334                         lightColor[lightType][1] = 1f;
335                         lightColor[lightType][2] = 0f;
336                         lightColor[lightType][3] = 1f;
337                         break;
338                     case "rbBlue":
339                         lightColor[lightType][0] = 0f;
340                         lightColor[lightType][1] = 0f;
341                         lightColor[lightType][2] = 1f;
342                         lightColor[lightType][3] = 1f;
343                         break;
344                 }
345                 setLightColor(openGLControl.OpenGL);
346             }
347         }
348 
349         private void cbxLightType_SelectedIndexChanged(object sender, EventArgs e)
350         {
351             var lightType = this.cbxLightType.SelectedIndex;
352             if (lightType >= 0)
353                 judgeColor(lightColor[lightType]);
354         }
355 
356         private void judgeColor(float[] color)
357         {
358             if (color[0] == 1f && color[1] == 1f && color[2] == 1f && color[3] == 1f)
359                 rbWhite.Checked = true;
360             else if (color[0] == 1f && color[1] == 0f && color[2] == 0f && color[3] == 1f)
361                 rbRed.Checked = true;
362             else if (color[0] == 0f && color[1] == 1f && color[2] == 0f && color[3] == 1f)
363                 rbGreen.Checked = true;
364             else if (color[0] == 0f && color[1] == 0f && color[2] == 1f && color[3] == 1f)
365                 rbBlue.Checked = true;   
366         }
367 
368         private void btnQ_Click(object sender, EventArgs e)
369         {
370             moveObject(radioButton1.Checked ? 0 : 1,((Button)sender).Name);
371             openGLControl_Resized(null, null);
372             openGLControl.OpenGL.Light(OpenGL.GL_LIGHT0, OpenGL.GL_POSITION, lightPos);
373         }
374 
375         private void setViewDefaultValue()
376         {
377             if (isPerspective)
378             {
379                 lookatValue = (double[])viewDefaultPos[0].Clone();
380             }
381             else if (isFrontView)
382             {
383                 lookatValue = (double[])viewDefaultPos[1].Clone();
384             }
385             else if (isLeftView)
386             {
387                 lookatValue = (double[])viewDefaultPos[2].Clone();
388             }
389             else if (isTopView)
390             {
391                 lookatValue = (double[])viewDefaultPos[3].Clone();
392             }
393         }
394 
395         private void btnDefaultPOS_Click(object sender, EventArgs e)
396         {
397             if (radioButton1.Checked)
398             {
399                 setViewDefaultValue();
400             }
401             else
402             {
403                 lightPos = new float[] { -1, -3, 1, 1 };
404                 openGLControl.OpenGL.Light(OpenGL.GL_LIGHT0, OpenGL.GL_POSITION, lightPos);
405             }
406             openGLControl_Resized(null, null); 
407         }
408 
409         private void openGLControl_KeyDown(object sender, KeyEventArgs e)
410         {
411             string name = string.Empty;
412             switch (e.KeyCode)
413             {
414                 case Keys.W:
415                     name = "btnW";
416                     break;
417                 case Keys.A:
418                     name = "btnA";
419                     break;
420                 case Keys.S:
421                     name = "btnS";
422                     break;
423                 case Keys.D:
424                     name = "btnD";
425                     break;
426                 case Keys.Q:
427                     name = "btnQ";
428                     break;
429                 case Keys.E:
430                     name = "btnE";
431                     break;
432             }
433             moveObject(radioButton1.Checked ? 0 : 1, name);
434             openGLControl_Resized(null, null);
435         }
436 
437         private void btnSetPos_Click(object sender, EventArgs e)
438         {
439             if (radioButton1.Checked)
440             {
441                 double[] ary = tbLookAt.Text.Split(',').Select(s => Convert.ToDouble(s)).ToArray();
442                 lookatValue = ary;
443                 openGLControl_Resized(null, null); 
444             }
445             else
446             {
447                 float[] ary = tbLightPos.Text.Split(',').Select(s => Convert.ToSingle(s)).ToArray();
448                 lightPos = ary;
449                 openGLControl.OpenGL.Light(OpenGL.GL_LIGHT0, OpenGL.GL_POSITION, ary);
450             }
451            
452         }
453 
454        
455     }
456 }

 

有关灯光的代码如下粗体显示部分:

 1   private void setLightColor(OpenGL gl)
 2         {
 3             gl.Light(OpenGL.GL_LIGHT0, OpenGL.GL_AMBIENT, lightColor[0]);
 4             gl.Light(OpenGL.GL_LIGHT0, OpenGL.GL_DIFFUSE, lightColor[1]);
 5             gl.Light(OpenGL.GL_LIGHT0, OpenGL.GL_SPECULAR, lightColor[2]);
 6         }
 7 
 8         private void openGLControl_OpenGLInitialized(object sender, EventArgs e)
 9         {
10             OpenGL gl = openGLControl.OpenGL;
11 
12             //四个视图的缺省位置
13             viewDefaultPos.Add(new double[] { 1, 1, 2, 0, 0, 0, 0, 1, 0 });     //透视
14             viewDefaultPos.Add(new double[] { 0, 0, 2, 0, 0, 0, 0, 1, 0 });     //前视 
15             viewDefaultPos.Add(new double[] { 5, 0, 0, 0, 0, 0, 0, 1, 0 });     //左视
16             viewDefaultPos.Add(new double[] { 0, 13, 0, -1, 0, 0, 0, 1, 0 });   //顶视
17             lookatValue =(double[])viewDefaultPos[0].Clone();
18 
19             lightColor.Add(new float[] { 1f, 1f, 1f, 1f });  //环境光(ambient light)
20             lightColor.Add(new float[] { 1f, 1f, 1f, 1f });  //漫射光(diffuse light)
21             lightColor.Add(new float[] { 1f, 1f, 1f, 1f });  //镜面反射光(specular light)
22 
23             setLightColor(gl);
24             gl.Light(OpenGL.GL_LIGHT0, OpenGL.GL_POSITION, lightPos);
25             
26             gl.Enable(OpenGL.GL_LIGHTING);
27             gl.Enable(OpenGL.GL_LIGHT0);
28 
29             gl.ClearColor(0, 0, 0, 0);
30         }

 

第3,4,5行是创建灯光三个部分 环境光,漫射光,镜面反射光。

第24行是设定灯光的位置。

第26,27是让灯光开,有效。

 

灯光代码确实比较简单,这段代码其它部分没什么好说的,笔者按界面功能直述其意,朋友们应该很容易懂。

唯一要关注下的是:视图和灯光的参数修改是如何实时生效的。

 

 

本节源代码下载

 

原创文章,出自"博客园, 猪悟能'S博客" : http://www.cnblogs.com/hackpig/

 

posted @ 2016-08-26 23:01  猪悟能  阅读(2510)  评论(5编辑  收藏  举报