SharpGL學習筆記(十二) 光源例子:解決光源場景中的常見問題


 

筆者學到光源這一節,遇到的問題就比較多了,收集了一些如下所述:

  • (1) 導入的3ds模型,如果沒有材質光照效果很奇怪.
    如下圖
  •  

  • (2) 導入的3ds模型,有材質,燈光效果發暗,材質偏色,效果也很奇怪.

    下圖中是有燈光的,但效果慘不忍睹.
  •  

  • (3) 場景引入燈光后,場景中的物體的顏色就全部消失了,即合引入顏色材質,效果也是怪怪的.

    如下圖中的柵格,它原本應該是藍色的.
  •  

  • (4) 場景中有物體引入材質后,整個場景的顏色就變得很奇怪

    下圖中球體引入材質后,整個場景的顏色就變得很奇怪了.
  • (5) 導入的3ds模型,貼圖顏色失真。

  • 下圖中的茶壺,柱體,地板的貼圖分別對應上圖材質圖片,可以看到經過紋理映射后,貼圖顏色失真。
    這種問題並不是光源的問題,但是我也在這里一並列出來。

  •  

     

像這些問題,因為不好形容,網上也找不到合適的答案.群里的高手們也不屑回答這些菜鳥問題,因此只好自力更生了.

 

我先上一段演示場景的代碼:

 

  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     /// <summary>
 14     /// 原創文章,出自"博客園, 豬悟能'S博客" : http://www.cnblogs.com/hackpig/
 15     /// </summary>
 16     public partial class SharpGLForm : Form
 17     {
 18         private float rotation = 0.0f,rotation2=0f,rotation3=0f;
 19         SharpGL.SceneGraph.Assets.Texture textureBox = new SharpGL.SceneGraph.Assets.Texture();
 20 
 21         float[] fLightPosition = new float[4] { 16f, 9f, -18f, 0f };// 光源位置 
 22         float[] fLightAmbient = new float[4] { 1f, 1f, 1f, 0f };// 環境光參數 
 23         float[] fLightDiffuse = new float[4] { 1f, 1f, 1f,0f };// 漫射光參數
 24 
 25         float[] fLightPosition2 = new float[4] { -7f, 5f, 2f, 0f };// 光源位置 
 26         float[] fLightAmbient2 = new float[4] { 0f, 0f, 1f, 0f };// 環境光參數 
 27         float[] fLightDiffuse2 = new float[4] { 0f, 0f, 1f, 0f };// 漫射光參數
 28 
 29         bool f1 = false;
 30 
 31         public SharpGLForm()
 32         {
 33             InitializeComponent();
 34         }
 35 
 36         private void openGLControl_OpenGLDraw(object sender, PaintEventArgs e)
 37         {
 38             OpenGL gl = openGLControl.OpenGL;
 39             gl.Clear(OpenGL.GL_COLOR_BUFFER_BIT | OpenGL.GL_DEPTH_BUFFER_BIT);
 40             gl.LoadIdentity();
 41             gl.Rotate(rotation3, 0, 1, 0);
 42             drawGrid(gl);
 43             drawLightPT(gl);
 44             drawLightPT2(gl);
 45             drawTextrueBox(gl, 1, 0, 2);
 46             drawSphere(gl, 2, 20, 20, false);
 47 
 48             moveLightA(gl);
 49             rotation3+=0.1f;
 50         }
 51 
 52        
 53         private void moveLightA(OpenGL gl)
 54         {
 55             if (!f1)
 56                 --fLightPosition[0];
 57             else
 58                 ++fLightPosition[0];
 59             if (fLightPosition[0] > 15f)
 60             {
 61                 f1 = !f1;
 62             }
 63             else if (fLightPosition[0] < -25f)
 64             {
 65                 f1 = !f1;
 66             }
 67             gl.Light(OpenGL.GL_LIGHT0, OpenGL.GL_POSITION, fLightPosition);//光源位置 
 68         }
 69 
 70       
 71 
 72         private void drawLightPT(OpenGL gl)
 73         {
 74             gl.PushMatrix();
 75             {
 76                 gl.Disable(OpenGL.GL_TEXTURE_2D);
 77                 gl.Color(0f,1f, 1f);
 78                 gl.Scale(0.2, 0.2, 0.2);
 79                 gl.Translate(fLightPosition[0]-5 , fLightPosition[1]+5, fLightPosition[2]); 
 80                 drawBox(gl, 0, 0, 0);
 81             }
 82             gl.PopMatrix();
 83         }
 84 
 85         private void drawLightPT2(OpenGL gl)
 86         {
 87             
 88             rotation2+=4f;
 89             gl.PushMatrix();
 90             {
 91                 gl.LoadIdentity();
 92                 gl.Disable(OpenGL.GL_TEXTURE_2D);
 93                 gl.Color(0f, 1f, 1f);
 94                 gl.Scale(0.2, 0.2, 0.2);
 95                 gl.Rotate(rotation2, 0, 1, 0);
 96                 gl.Translate(-28 , 8 , 5);
 97                
 98                 drawBox(gl, 0, 0, 0);
 99             }
100             gl.PopMatrix();
101         }
102 
103         private void drawTextrueBox(OpenGL gl, float xPos, float yPos, float zPos)
104         {
105             rotation += 3.0f;
106             gl.PushMatrix();
107             {
108                 textureBox.Bind(gl);
109                 gl.Enable(OpenGL.GL_TEXTURE_2D);
110                 gl.Rotate(rotation, 0, 1, 0);
111                 gl.Translate(-1, 2, -5);
112                 gl.Scale(3, 3, 3);
113                 drawBox(gl,xPos, yPos, zPos);
114             }
115             gl.PopMatrix();
116         }
117 
118         private void drawBox(OpenGL gl, float xPos, float yPos, float zPos)
119         {          
120             gl.PushMatrix();
121             gl.Translate(xPos, yPos, zPos);
122            
123             gl.Begin(OpenGL.GL_QUADS);
124 
125             //
126             gl.TexCoord(0, 0); gl.Vertex(0, 0, 0);
127             gl.TexCoord(1, 0); gl.Vertex(-1, 0, 0);
128             gl.TexCoord(1, 1); gl.Vertex(-1, -1, 0);
129             gl.TexCoord(0, 1); gl.Vertex(0, -1, 0);
130 
131             //
132             gl.TexCoord(0, 0); gl.Vertex(0, 0, 0);
133             gl.TexCoord(1, 0); gl.Vertex(0, 0, -1);
134             gl.TexCoord(1, 1); gl.Vertex(-1, 0, -1);
135             gl.TexCoord(0, 1); gl.Vertex(-1, 0, 0);
136 
137             //
138             gl.TexCoord(0, 0); gl.Vertex(-1, 0, 0);
139             gl.TexCoord(1, 0); gl.Vertex(-1, 0, -1);
140             gl.TexCoord(1, 1); gl.Vertex(-1, -1, -1);
141             gl.TexCoord(0, 1); gl.Vertex(-1, -1, 0);
142 
143             //
144             gl.TexCoord(0, 0); gl.Vertex(0, 0, 0);
145             gl.TexCoord(1, 0); gl.Vertex(0, 0, -1);
146             gl.TexCoord(1, 1); gl.Vertex(0, -1, -1);
147             gl.TexCoord(0, 1); gl.Vertex(0, -1, 0);
148 
149             //
150             gl.TexCoord(0, 0); gl.Vertex(0, 0, -1);
151             gl.TexCoord(1, 0); gl.Vertex(-1, 0, -1);
152             gl.TexCoord(1, 1); gl.Vertex(-1, -1, -1);
153             gl.TexCoord(0, 1); gl.Vertex(0, -1, -1);
154 
155             //
156             gl.TexCoord(0, 0); gl.Vertex(0, -1, 0);
157             gl.TexCoord(1, 0); gl.Vertex(0, -1, -1);
158             gl.TexCoord(1, 1); gl.Vertex(-1, -1, -1);
159             gl.TexCoord(0, 1); gl.Vertex(-1, -1, 0);
160 
161 
162             gl.End();
163             gl.PopMatrix();
164 
165         }
166 
167         void drawSphere(OpenGL gl, double radius, int segx, int segy, bool isLines)
168         {
169            
170             gl.PushMatrix();
171  gl.Disable(OpenGL.GL_TEXTURE_2D); 172             gl.Translate(-7f, -1f, 2f);
173             var sphere = gl.NewQuadric();
174         
175             if (isLines)
176                 gl.QuadricDrawStyle(sphere, OpenGL.GL_LINES);
177             else
178                 gl.QuadricDrawStyle(sphere, OpenGL.GL_QUADS);
179             gl.QuadricNormals(sphere, OpenGL.GLU_SMOOTH);
180             gl.QuadricOrientation(sphere, (int)OpenGL.GLU_OUTSIDE);
181             gl.QuadricTexture(sphere, (int)OpenGL.GLU_FALSE);
182             gl.Sphere(sphere, radius, segx, segy);
183             gl.DeleteQuadric(sphere);
184             gl.PopMatrix();
185             
186         }
187 
188 
189      
190 
191         void drawGrid(OpenGL gl)
192         {
193             //關閉紋理和光照
194  gl.Disable(OpenGL.GL_TEXTURE_2D); 195  gl.Disable(OpenGL.GL_LIGHTING); 196 
197             //繪制過程
198             gl.PushAttrib(OpenGL.GL_CURRENT_BIT);  //保存當前屬性
199             gl.PushMatrix();                        //壓入堆棧
200             gl.Translate(0f, -2f, 0f);
201             gl.Color(0f, 0f, 1f);
202 
203             //在X,Z平面上繪制網格
204             for (float i = -50; i <= 50; i += 1)
205             {
206                 //繪制線
207                 gl.Begin(OpenGL.GL_LINES);
208                 {
209                     if (i == 0)
210                         gl.Color(0f, 1f, 0f);
211                     else
212                         gl.Color(0f, 0f, 1f);
213 
214                     //X軸方向
215                     gl.Vertex(-50f, 0f, i);
216                     gl.Vertex(50f, 0f, i);
217                     //Z軸方向 
218                     gl.Vertex(i, 0f, -50f);
219                     gl.Vertex(i, 0f, 50f);
220 
221                 }
222                 gl.End();
223             }
224             gl.PopMatrix();
225             gl.PopAttrib();
226             gl.Enable(OpenGL.GL_LIGHTING);
227         }
228 
229         private void openGLControl_OpenGLInitialized(object sender, EventArgs e)
230         {
231             OpenGL gl = openGLControl.OpenGL;
232             textureBox.Create(gl, "image.bmp");
233 
234             gl.Light(OpenGL.GL_LIGHT0, OpenGL.GL_AMBIENT, fLightAmbient);//環境光源 
235             gl.Light(OpenGL.GL_LIGHT0, OpenGL.GL_DIFFUSE, fLightDiffuse);//漫射光源 
236             gl.Light(OpenGL.GL_LIGHT0, OpenGL.GL_POSITION, fLightPosition);//光源位置 
237 
238             gl.Light(OpenGL.GL_LIGHT1, OpenGL.GL_AMBIENT, fLightAmbient2);//環境光源 
239             gl.Light(OpenGL.GL_LIGHT1, OpenGL.GL_DIFFUSE, fLightDiffuse2);//漫射光源 
240             gl.Light(OpenGL.GL_LIGHT1, OpenGL.GL_POSITION, fLightPosition2);//光源位置 
241 
242             gl.Enable(OpenGL.GL_LIGHTING);//開啟光照 
243             gl.Enable(OpenGL.GL_LIGHT0);
244             gl.Enable(OpenGL.GL_LIGHT1);
245 
246  gl.Enable(OpenGL.GL_NORMALIZE); 247             gl.ClearColor(0, 0, 0, 0);
248             
249         }
250 
251         private void openGLControl_Resized(object sender, EventArgs e)
252         {
253             OpenGL gl = openGLControl.OpenGL;
254             gl.MatrixMode(OpenGL.GL_PROJECTION);
255             gl.LoadIdentity();
256             gl.Perspective(60.0f, (double)Width / (double)Height, 0.01, 100.0);
257             gl.LookAt(-2, 3, -7, -2, 0, 0, 0, 1, 0);
258             gl.MatrixMode(OpenGL.GL_MODELVIEW);
259         }
260 
261 
262        
263     }
264 }

 

效果如下圖:

場景中有兩個光源,一個在X方向左右運行,一個繞點點在轉圈.

Box上了材質貼圖,球體沒有材質.

從效果上看,已經解決了開頭所述的問題(3),(4),我們提下關鍵點在哪里:

1. 第194,195行必須有,否則畫柵格時會受到場景中的燈光,或者材質設定的影響,柵格原來顏色就沒有了.

  這個其實就是因為OpenGL是個狀態機,其它部分代碼改變了某些狀態,畫柵格時就會繼承改變.

2. 同樣原道理,第171行必須關閉紋理,否會受到Box材質設置狀態的影響,球就不會是白色的了.

3. 第246行必須有,它用來自動歸一化法線方向,因為光照效果由頂點和法線方向決定.

  這就是問題(1),(2)之所以有問題的原因.

  而導入的3ds模型,其畫三角形的函數中也需要注意Normal()函數的向量值有沒有方向問題.
  下圖是修正了法線后的光照效果,可以看到是正常的.

   

4.  對於問題5,因為在檢查了燈光與貼圖后都是正常的, 所以問題只會在出現在貼圖的時候。

     經檢測,是在導入3ds模形的代碼中,關於讀取貼圖的一個函數Build2DMipmaps()中,把RGB換BGR即可。

     GL.Build2DMipmaps(OpenGL.GL_TEXTURE_2D, 3, image.Width, image.Height, OpenGL.GL_BGR, OpenGL.GL_UNSIGNED_BYTE, bitmapdata.Scan0);

      可以看到,效果正常了。

      

 

5. 最后一個困繞筆者的問題是物體旋轉中心點的問題.這個話題跟燈光無關,在這個場景中恰好碰到了這個問題,發現原來是知識上的一個盲點.

  演示場景中,你會看到Box並不是繞世界坐標系的原點(綠色線的交匯點)在轉,而是沿指定位置為軸心在轉.

  是繞世界坐標原點轉,還是繞你指定的坐標為軸轉動,關鍵在於你是先Translate(),還是先Rotate().  讀者可以參考下演示代碼,然后自己嘗試一下就知道了.

 

 

本節源代碼下載

 

原創文章,出自"博客園, 豬悟能'S博客" : http://www.cnblogs.com/hackpig/

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM