筆者學到光源這一節,遇到的問題就比較多了,收集了一些如下所述:
- (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/