你的位置:首页 > ASP.net教程

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


 

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

 

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

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

灯光位置和摄像机位置(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       else113         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           else172             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       else197         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];  //y213           else214             ++lightPos[1];215           break;216         case "btnE":217           if (obj == 0) --lookatValue[1];218           else219             --lightPos[1];220           break;221         case "btnW":222           if (obj == 0) --lookatValue[2];  //z223           else224            --lightPos[2];225           break;226         case "btnS":227           if (obj == 0) ++lookatValue[2];228           else229             ++lightPos[2];230           break;231         case "btnA":232           if (obj == 0) --lookatValue[0]; //X233           else234            --lightPos[0];235           break;236         case "btnD":237           if (obj == 0) ++lookatValue[0];238           else239             ++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           else294             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       else402       {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       else446       {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/