• 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/

  • 相关阅读:
    co模块总结
    Promise总结
    webpack错误Chunk.entry was removed. Use hasRuntime()
    jquery validate用法总结
    node命令行开发
    animation总结
    formData使用总结
    vue-resource发送multipart/form-data数据
    keil中使用Astyle格式化你的代码的方法-keil4 keil5通用
    tcpip入门的网络教程汇总
  • 原文地址:https://www.cnblogs.com/hackpig/p/5811922.html
Copyright © 2020-2023  润新知