燈光的測試例子:光源參數可以調節的測試場景 先看一下測試場景和效果。 場景中可以切換視圖, 以方便觀察三維體和燈光的位置。環境光,漫射光,鏡面反射光都可以在四種顏色間切換。 燈光位置和攝像機位置(LookAt)可以輸入數值或者點動調節,也可以按鍵盤的QEWASD六個鍵進行調節。 你還會註意到:球體對 ...
燈光的測試例子:光源參數可以調節的測試場景
先看一下測試場景和效果。
場景中可以切換視圖, 以方便觀察三維體和燈光的位置。環境光,漫射光,鏡面反射光都可以在四種顏色間切換。
燈光位置和攝像機位置(LookAt)可以輸入數值或者點動調節,也可以按鍵盤的QEWASD六個鍵進行調節。
你還會註意到:球體對光的效果要敏感柔和些,而那個六面體BOX看來效果不好。這是因為燈光對頂點發生作用。在程式裡面,球休的頂點數量有20*10,而BOX只有4*6個,而且還重合了一些頂點。
這一點,在3dsmax的全局光照裡面表現很明顯,做為牆壁的box頂點數量越大,計算出來光照效果越好。
還有,界面上燈光位置是 -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 }