• SharpGL学习笔记(十三) 光源例子:环绕二次曲面球体的光源


    这是根据徐明亮《OpenGL游戏编程》书上光灯一节的一个例子改编的.

    从这个例子可以学习到二次曲面的参数设置,程序中提供了两个画球的函数,一个是用三角形画出来的,一个是二次曲面构成的.

    你会发现,跟三角形版本不同,二次曲面要做一些设定,否则画出来的球体无法接受光照.

    先上代码:

      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 light2
     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;
     19         float m_bReadX, m_bReadY;
     20         float m_bGreenX, m_bGreenY;
     21         float m_bBlueX, m_bBlueY;
     22 
     23         //3个光源位置
     24         float[] lightPosR = new float[] { 0f, 0f, 2f, 1f };
     25         float[] lightPosG = new float[] { 0f, 0f, 2f, 1f };
     26         float[] lightPosB = new float[] { 0f, 0f, 2f, 1f };
     27 
     28         //3个光源漫射光
     29         float[] diffLightR = { 1f, 0f, 0f, 1f };
     30         float[] diffLightG = { 0f, 1f, 0f, 1f };
     31         float[] diffLightB = { 0f, 0f, 1f, 1f };
     32 
     33         //定义3个光源我镜面光
     34         float[] specLightR = { 1f, 0f, 0f, 1f };
     35         float[] specLightG = { 0f, 1f, 0f, 1f };
     36         float[] specLightB = { 0f, 0f, 1f, 1f };
     37 
     38         //默认的光源, 灰色光源,用于默认照明
     39         float[] defDiffLight = new float[] { 0.8f, 0.8f, 0.8f, 1f };
     40         float[] defSpecLight = new float[] { 1f, 1f, 1f, 1f };
     41         float[] defLightPos = new float[] { 0f, 0f, 10f, 1f };
     42 
     43 
     44 
     45         public SharpGLForm()
     46         {
     47             InitializeComponent();
     48         }
     49 
     50         private void openGLControl_OpenGLDraw(object sender, PaintEventArgs e)
     51         {
     52             OpenGL gl = openGLControl.OpenGL;
     53             gl.Clear(OpenGL.GL_COLOR_BUFFER_BIT | OpenGL.GL_DEPTH_BUFFER_BIT);
     54             gl.LoadIdentity();
     55             gl.Rotate(rotation, 0.0f, 1.0f, 0.0f);
     56 
     57             draw(gl);
     58             rotation += 3.0f;
     59 
     60             update(gl);
     61         }
     62 
     63         void update(OpenGL gl)
     64         {
     65             gl.Enable(OpenGL.GL_LIGHT1);
     66             m_bReadX += 16;
     67             m_bReadY += 12;
     68             gl.Enable(OpenGL.GL_LIGHT2);
     69             m_bGreenX += 10;
     70             m_bGreenY += 6;
     71             gl.Enable(OpenGL.GL_LIGHT3);
     72             m_bBlueX += 2;
     73             m_bBlueY += 4;
     74         }
     75 
     76         void draw(OpenGL gl)
     77         {
     78             gl.PushMatrix();
     79             //旋转红光
     80             gl.Rotate(m_bReadX, 1f, 0f, 0f);
     81             gl.Rotate(m_bReadY, 0f, 1f, 0f);
     82             //设置红光的位置
     83             gl.Light(OpenGL.GL_LIGHT1, OpenGL.GL_POSITION, lightPosR);   
     84             //绘制光球
     85             gl.Translate(lightPosR[0], lightPosR[1], lightPosR[2]);
     86             gl.Color(1f, 0f, 0f);
     87             gl.PushAttrib(OpenGL.GL_LIGHTING_BIT);
     88             gl.Disable(OpenGL.GL_LIGHTING);
     89             drawSphere(gl,lightPosR[0], lightPosR[1], lightPosR[2],0.2f,10,10,false);
     90             gl.Enable(OpenGL.GL_LIGHTING);
     91             gl.PopAttrib();
     92             gl.PopMatrix();
     93 
     94 
     95             gl.PushMatrix();
     96             //旋转绿光
     97             gl.Rotate(m_bGreenX, 1f, 0f, 0f);
     98             gl.Rotate(m_bGreenY, 0f, 1f, 0f);
     99             //设置绿光的位置
    100             gl.Light(OpenGL.GL_LIGHT2, OpenGL.GL_POSITION, lightPosG);
    101             //绘制光球
    102             gl.Translate(lightPosG[0], lightPosG[1], lightPosG[2]);
    103             gl.Color(0f, 1f, 0f);
    104             gl.PushAttrib(OpenGL.GL_LIGHTING_BIT);
    105             gl.Disable(OpenGL.GL_LIGHTING);
    106             drawSphere(gl, lightPosG[0], lightPosG[1], lightPosG[2], 0.2f, 10, 10 ,false);
    107             gl.Enable(OpenGL.GL_LIGHTING);
    108             gl.PopAttrib();
    109             gl.PopMatrix();
    110 
    111 
    112             gl.PushMatrix();
    113             //旋转蓝光
    114             gl.Rotate(m_bBlueX, 1f, 0f, 0f);
    115             gl.Rotate(m_bBlueY, 0f, 1f, 0f);
    116             //设置蓝光的位置
    117             gl.Light(OpenGL.GL_LIGHT3, OpenGL.GL_POSITION, lightPosB);
    118             //绘制光球
    119             gl.Translate(lightPosB[0], lightPosB[1], lightPosB[2]);
    120             gl.Color(0f, 0f, 1f);
    121             gl.PushAttrib(OpenGL.GL_LIGHTING_BIT);
    122             gl.Disable(OpenGL.GL_LIGHTING);
    123             drawSphere(gl, lightPosB[0], lightPosB[1], lightPosB[2], 0.2f, 10, 10,false);
    124             gl.Enable(OpenGL.GL_LIGHTING);
    125             gl.PopAttrib();
    126             gl.PopMatrix();
    127 
    128 
    129             //绘制球体
    130             gl.PushMatrix();
    131             gl.Rotate(rotation, 1f, 0f, 0f);
    132             gl.Rotate(rotation, 0f, 1f, 0f);
    133             gl.Rotate(rotation, 0f, 0f, 1f);
    134             drawSphere(gl, 0, 0, 0, 3, 40, 40,false);
    135 
    136             gl.PopMatrix();
    137 
    138             gl.Flush();
    139 
    140         }
    141 
    142         //二次曲面球体
    143         void drawSphere(OpenGL gl,float x,float y,float z, double radius, int segx, int segy, bool isLines)
    144         {
    145             gl.PushMatrix();
    146             gl.Translate(x, y, z);
    147             var sphere = gl.NewQuadric();
    148             if (isLines)
    149                 gl.QuadricDrawStyle(sphere, OpenGL.GL_LINES);
    150             else
    151                 gl.QuadricDrawStyle(sphere, OpenGL.GL_QUADS);
    152             gl.QuadricNormals(sphere, OpenGL.GLU_NONE);   //GLU_NONE,GLU_FLAT,GLU_SMOOTH
    153             gl.QuadricOrientation(sphere, (int)OpenGL.GLU_OUTSIDE);  //GLU_OUTSIDE,GLU_INSIDE
    154             gl.QuadricTexture(sphere, (int)OpenGL.GLU_FALSE);  //GL_TRUE,GLU_FALSE
    155             gl.Sphere(sphere, radius, segx, segy);
    156             gl.DeleteQuadric(sphere);
    157             gl.PopMatrix();
    158         }
    159 
    160         //球心坐标为(x,y,z),球的半径为radius,M,N分别表示球体的横纵向被分成多少份
    161         void drawSphere1(OpenGL gl, float xx, float yy, float zz, float radius, float M, float N,bool isLines)
    162         {
    163             const float PI = 3.1415926f;
    164             float step_z = (float)Math.PI / M;
    165             float step_xy = 2 * PI / N;
    166             float[] x = new float[4] { 0, 0, 0, 0 };
    167             float[] y = new float[4] { 0, 0, 0, 0 };
    168             float[] z = new float[4] { 0, 0, 0, 0 };
    169 
    170             float angle_z = 0.0f;
    171             float angle_xy = 0.0f;
    172             int i = 0, j = 0;
    173             gl.Begin(OpenGL.GL_QUADS);
    174             for (i = 0; i < M; i++)
    175             {
    176                 angle_z = i * step_z;
    177                 for (j = 0; j < N; j++)
    178                 {
    179                     angle_xy = j * step_xy;
    180 
    181                     x[0] = (float)(radius * Math.Sin(angle_z) * Math.Cos(angle_xy));
    182                     y[0] = (float)(radius * Math.Sin(angle_z) * Math.Sin(angle_xy));
    183                     z[0] = (float)(radius * Math.Cos(angle_z));
    184 
    185                     x[1] = (float)(radius * Math.Sin(angle_z + step_z) * Math.Cos(angle_xy));
    186                     y[1] = (float)(radius * Math.Sin(angle_z + step_z) * Math.Sin(angle_xy));
    187                     z[1] = (float)(radius * Math.Cos(angle_z + step_z));
    188 
    189                     x[2] = (float)(radius * Math.Sin(angle_z + step_z) * Math.Cos(angle_xy + step_xy));
    190                     y[2] = (float)(radius * Math.Sin(angle_z + step_z) * Math.Sin(angle_xy + step_xy));
    191                     z[2] = (float)(radius * Math.Cos(angle_z + step_z));
    192 
    193                     x[3] = (float)(radius * Math.Sin(angle_z) * Math.Cos(angle_xy + step_xy));
    194                     y[3] = (float)(radius * Math.Sin(angle_z) * Math.Sin(angle_xy + step_xy));
    195                     z[3] = (float)(radius * Math.Cos(angle_z));
    196 
    197                     for (int k = 0; k < 4; k++)
    198                     {
    199                         gl.Vertex(xx + x[k], yy + y[k], zz + z[k]);
    200                     }
    201                 }
    202             }
    203             gl.End();
    204         }
    205 
    206         private void openGLControl_OpenGLInitialized(object sender, EventArgs e)
    207         {
    208             OpenGL gl = openGLControl.OpenGL;
    209             setLight(gl);
    210             //gl.Enable(OpenGL.GL_NORMALIZE);
    211             gl.ClearColor(0, 0, 0, 0);
    212         }
    213 
    214         private void setLight(OpenGL gl)
    215         {
    216             //0号灯光,默认灯光
    217             gl.Light(OpenGL.GL_LIGHT0, OpenGL.GL_DIFFUSE, defDiffLight);
    218             gl.Light(OpenGL.GL_LIGHT0, OpenGL.GL_SPECULAR, defSpecLight);
    219             gl.Light(OpenGL.GL_LIGHT0, OpenGL.GL_POSITION, defLightPos);
    220 
    221             //1号灯光
    222             gl.Light(OpenGL.GL_LIGHT1, OpenGL.GL_DIFFUSE, diffLightR);
    223             gl.Light(OpenGL.GL_LIGHT1, OpenGL.GL_SPECULAR, specLightR);
    224             gl.Light(OpenGL.GL_LIGHT1, OpenGL.GL_POSITION, lightPosR);
    225 
    226             //2号灯光
    227             gl.Light(OpenGL.GL_LIGHT2, OpenGL.GL_DIFFUSE, diffLightG);
    228             gl.Light(OpenGL.GL_LIGHT2, OpenGL.GL_SPECULAR, specLightG);
    229             gl.Light(OpenGL.GL_LIGHT2, OpenGL.GL_POSITION, lightPosG);
    230 
    231             //3号灯光
    232             gl.Light(OpenGL.GL_LIGHT3, OpenGL.GL_DIFFUSE, diffLightB);
    233             gl.Light(OpenGL.GL_LIGHT3, OpenGL.GL_SPECULAR, specLightB);
    234             gl.Light(OpenGL.GL_LIGHT3, OpenGL.GL_POSITION, lightPosB);
    235 
    236             gl.Enable(OpenGL.GL_LIGHTING);
    237             gl.Enable(OpenGL.GL_LIGHT0);  //启用默认光源
    238 
    239         }
    240 
    241         private void openGLControl_Resized(object sender, EventArgs e)
    242         {
    243             OpenGL gl = openGLControl.OpenGL;
    244             gl.MatrixMode(OpenGL.GL_PROJECTION);
    245             gl.LoadIdentity();
    246             gl.Perspective(70.0f, (double)Width / (double)Height, 0.01, 100.0);
    247             gl.LookAt(-5, 5, -5, 0, 0, 0, 0, 1, 0);
    248             gl.MatrixMode(OpenGL.GL_MODELVIEW);
    249         }
    250         
    251     }
    252 }

    截取了一帧的效果如下图:

    有三个光球围绕球体旋转,三组光分别为红,绿,蓝,因此它们的组合可以在球面上生成所有可能的颜色效果.

    函数drawSphere是二次曲面球体,函数drawSphere1是三角形构成的球体.

    下面我们研究一下二次曲面的几个关键的需要注意的设置函数:

    (1) QuadricDrawStyle(IntPtr quadObject, uint drawStyle);

    第一个参数是二次方程对象状态的指针,第二个参数的枚举值如下表:

    常量 描述
    GLU_FILL 二次方程对象画成实体
    GLU_LINE 二次方程对象画成线框
    GLU_POINT 二次方程对象画成一组顶点的集合
    GLU_SILHOUETTE 类似于线框,但相邻的多边形的边不被绘制。

    (2) QuadricNormals(IntPtr quadricObject, uint normals);

    这个函数指定二次方程对象如何生成法线。第二个参数可以是:GLU_NONE不生成法线,GLU_FLAT扁平法线,GLU_SMOOTH平滑法线。

    (3) QuadricOrientation(IntPtr quadricObject, int orientation);

    这个函数可以指定法线的朝向,指向外面还是只想里面。orientation可以是GLU_OUTSIDE或者是GLU_INSIDE这两个值。OpenGL默认是以GL_CCW逆时针为正方向的

    (4) QuadricTexture(IntPtr quadricObject, int textureCoords);

    这个函数可以指定二次方程表面的纹理坐标,textureCoords这个参数可以是GL_TRUE或者GL_FALSE.当为球体和圆柱体生成纹理坐标时,纹理是对称地环绕在球体和圆柱体的表面的。如果应用到圆盘上,那么纹理的中心就是圆盘的中心,然后以线性插值的方式扩展到圆盘的边界。

    读者可以尝试改变这些函数的参数,会发现受光效果是不同的.

    也可以尝试用drawSphere1()函数替换掉drawSphere()函数,它是不需要做任何设定,就有很好的效果.

    本节源代码下载

    原创文章,出自"博客园, 猪悟能'S博客" : http://www.cnblogs.com/hackpig/

  • 相关阅读:
    年报统计系统—基本信息模块的目标文档
    用户分析
    第一周第三天
    第一周第二天
    第一周第一天
    学习进度条第三周
    学习进度表第二周
    四则运算2
    构建之法阅读笔记 01
    软件工程概论学习进度表第一周
  • 原文地址:https://www.cnblogs.com/hackpig/p/5825865.html
Copyright © 2020-2023  润新知