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/

时间: 2024-10-17 16:43:04

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

13、事例十三:光源例子:环绕二次曲面球体的光源(二)

namespace sharpGLTest13 { public partial class Form1 : Form { private float rotation = 0.0f; float m_bReadX, m_bReadY; float m_bGreenX, m_bGreenY; float m_bBlueX, m_bBlueY; //3个光源位置 float[] lightPosR = new float[] { 0f, 0f, 2f, 1f }; float[] lightPos

SharpGL学习笔记(七) OpenGL的变换总结

笔者接触OpenGL最大的困难是: 经常调试一份代码时, 屏幕漆黑一片, 也不知道结果对不对,不知道如何是好! 这其实就是关于OpenGL"变换"的基础概念没有掌握好, 以至于对"将三维体正确的显示在屏幕上指定位置"这样的操作都无法完成. OpenGL变换包括计算机图形学中最基本的三维变换,即几何变换.投影变换.裁剪变换.视口变换,以及针对OpenGL的特殊变换概念理解和用法,如相机模拟.矩阵堆栈等,这些基础是开始真正走进三维世界无法绕过的基础. 所以笔者在前面花了

java之jvm学习笔记十三(jvm基本结构)

java之jvm学习笔记十三(jvm基本结构) 这一节,主要来学习jvm的基本结构,也就是概述.说是概述,内容很多,而且概念量也很大,不过关于概念方面,你不用担心,我完全有信心,让概念在你的脑子里变成图形,所以只要你有耐心,仔细,认真,并发挥你的想象力,这一章之后你会充满自信.当然,不是说看完本章,就对jvm了解了,jvm要学习的知识实在是非常的多.在你看完本节之后,后续我们还会来学jvm的细节,但是如果你在学习完本节的前提下去学习,再学习其他jvm的细节会事半功倍. 为了让你每一个知识点都有迹

【Unity 3D】学习笔记三十二:游戏元素——游戏光源

游戏光源 在3D游戏中,光源是一个非常具有特色的游戏组件.用来提升游戏画面质感的.如果没有加入光源,游戏场景可能就会显得很昏暗.在unity中提供了三种不同的光源类型:点光源,聚光灯,平行光. 点光源 顾名思义,点光源是从一个点向周围散发出光的光源,就像电灯一样.创建点光源在hierarchy视图中点击create--point light: 创建完以后,点击点光源对象,在右侧inspector视图中可以看到点光源的所有信息: type:光源的类型.有point(点光源),directional

Swift学习笔记十三:继承

一个类可以继承(inherit)另一个类的方法(methods),属性(property)和其它特性 一.基本语法 class Human{ var name :String init(){ name = "human" println(name) } func description(){ println("name:\(name)") } } class Student:Human{ var score = 0 init(){ super.init() name

laravel3学习笔记(十三)

原作者博客:ieqi.net ==================================================================================================== 类的自动载入 使用 PHP 自身的 include 或者 require 族的函数载入重用代码一般情况下很难帮助我们更好的组织工程代码,对于此,从便捷和性能的方面考虑, Laravel3 为我们提供了类的自动载入功能.自动载入可以让我们在需要的时候才载入所需要的类文件

Go语言学习笔记十三: Map集合

Go语言学习笔记十三: Map集合 Map在每种语言中基本都有,Java中是属于集合类Map,其包括HashMap, TreeMap等.而Python语言直接就属于一种类型,写法上比Java还简单. Go语言中Map的写法比Java简单些,比Python繁琐. 定义Map var x map[string]string x : = make(map[string]string) 写法上有些奇怪,map为关键字,右侧中括号内部为key的类型,中括号外部为value的类型.一般情况下使用逗号或者冒号

[傅里叶变换及其应用学习笔记] 十三. 分布的傅里叶变换

这份是本人的学习笔记,课程为网易公开课上的斯坦福大学公开课:傅里叶变换及其应用. 分布傅里叶变换的定义 在傅里叶变换领域中,测试函数$\varphi$选择了速降函数(Schwartz Functions).与之对应的分布$T$通常被称为缓增分布(Tempered Distributions). $<T,\varphi>$ 上式表示了,给定测试函数$\varphi$,分布$T$对测试函数$\varphi$进行作用,得到的结果为一个数值,该过程也被称为匹配(Pair).这种作用是通过积分来实现的.

西门子PLC学习笔记十三-(算术运算指令与控制指令)

今天在写一篇PLC的学习笔记,本篇将介绍PLC最基本的运算指令与控制指令,本篇将直接上截图. 1.基本算数运算指令 1)整数运算 2)长整数运算 3)实数运算 . STL编程示例(16位整数的算术运算) L IW10 //将输入字IW10装入累加器1的低字 L MW12 //将累加器1低字中的内容装入到累加器2的低字 //将存储字MW12装入累加器1的低字 +I //将累加器2低字和累加器1低字相加,结果保存到累加器1的低字中 +68 //将累加器1的低字中的内容加上常数68,结果保存到累加器1