SharpGL学习笔记(十三) 光源例子:环绕二次曲面球体的光源
这是根据徐明亮《OpenGL游戏编程》书上光灯一节的一个例子改编的.
从这个例子可以学习到二次曲面的参数设置,程序中提供了两个画球的函数,一个是用三角形画出来的,一个是二次曲面构成的.
你会发现,跟三角形版本不同,二次曲面要做一些设定,否则画出来的球体无法接受光照.
先上代码:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using SharpGL; namespace light2
{
/// <summary>
/// 原创文章,出自"博客园, 猪悟能'S博客" : http://www.cnblogs.com/hackpig/
/// </summary>
public partial class SharpGLForm : 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[] lightPosG = new float[] { 0f, 0f, 2f, 1f };
float[] lightPosB = new float[] { 0f, 0f, 2f, 1f }; //3个光源漫射光
float[] diffLightR = { 1f, 0f, 0f, 1f };
float[] diffLightG = { 0f, 1f, 0f, 1f };
float[] diffLightB = { 0f, 0f, 1f, 1f }; //定义3个光源我镜面光
float[] specLightR = { 1f, 0f, 0f, 1f };
float[] specLightG = { 0f, 1f, 0f, 1f };
float[] specLightB = { 0f, 0f, 1f, 1f }; //默认的光源, 灰色光源,用于默认照明
float[] defDiffLight = new float[] { 0.8f, 0.8f, 0.8f, 1f };
float[] defSpecLight = new float[] { 1f, 1f, 1f, 1f };
float[] defLightPos = new float[] { 0f, 0f, 10f, 1f }; public SharpGLForm()
{
InitializeComponent();
} private void openGLControl_OpenGLDraw(object sender, PaintEventArgs e)
{
OpenGL gl = openGLControl.OpenGL;
gl.Clear(OpenGL.GL_COLOR_BUFFER_BIT | OpenGL.GL_DEPTH_BUFFER_BIT);
gl.LoadIdentity();
gl.Rotate(rotation, 0.0f, 1.0f, 0.0f); draw(gl);
rotation += 3.0f; update(gl);
} void update(OpenGL gl)
{
gl.Enable(OpenGL.GL_LIGHT1);
m_bReadX += ;
m_bReadY += ;
gl.Enable(OpenGL.GL_LIGHT2);
m_bGreenX += ;
m_bGreenY += ;
gl.Enable(OpenGL.GL_LIGHT3);
m_bBlueX += ;
m_bBlueY += ;
} void draw(OpenGL gl)
{
gl.PushMatrix();
//旋转红光
gl.Rotate(m_bReadX, 1f, 0f, 0f);
gl.Rotate(m_bReadY, 0f, 1f, 0f);
//设置红光的位置
gl.Light(OpenGL.GL_LIGHT1, OpenGL.GL_POSITION, lightPosR);
//绘制光球
gl.Translate(lightPosR[], lightPosR[], lightPosR[]);
gl.Color(1f, 0f, 0f);
gl.PushAttrib(OpenGL.GL_LIGHTING_BIT);
gl.Disable(OpenGL.GL_LIGHTING);
drawSphere(gl,lightPosR[], lightPosR[], lightPosR[],0.2f,,,false);
gl.Enable(OpenGL.GL_LIGHTING);
gl.PopAttrib();
gl.PopMatrix(); gl.PushMatrix();
//旋转绿光
gl.Rotate(m_bGreenX, 1f, 0f, 0f);
gl.Rotate(m_bGreenY, 0f, 1f, 0f);
//设置绿光的位置
gl.Light(OpenGL.GL_LIGHT2, OpenGL.GL_POSITION, lightPosG);
//绘制光球
gl.Translate(lightPosG[], lightPosG[], lightPosG[]);
gl.Color(0f, 1f, 0f);
gl.PushAttrib(OpenGL.GL_LIGHTING_BIT);
gl.Disable(OpenGL.GL_LIGHTING);
drawSphere(gl, lightPosG[], lightPosG[], lightPosG[], 0.2f, , ,false);
gl.Enable(OpenGL.GL_LIGHTING);
gl.PopAttrib();
gl.PopMatrix(); gl.PushMatrix();
//旋转蓝光
gl.Rotate(m_bBlueX, 1f, 0f, 0f);
gl.Rotate(m_bBlueY, 0f, 1f, 0f);
//设置蓝光的位置
gl.Light(OpenGL.GL_LIGHT3, OpenGL.GL_POSITION, lightPosB);
//绘制光球
gl.Translate(lightPosB[], lightPosB[], lightPosB[]);
gl.Color(0f, 0f, 1f);
gl.PushAttrib(OpenGL.GL_LIGHTING_BIT);
gl.Disable(OpenGL.GL_LIGHTING);
drawSphere(gl, lightPosB[], lightPosB[], lightPosB[], 0.2f, , ,false);
gl.Enable(OpenGL.GL_LIGHTING);
gl.PopAttrib();
gl.PopMatrix(); //绘制球体
gl.PushMatrix();
gl.Rotate(rotation, 1f, 0f, 0f);
gl.Rotate(rotation, 0f, 1f, 0f);
gl.Rotate(rotation, 0f, 0f, 1f);
drawSphere(gl, , , , , , ,false); gl.PopMatrix(); gl.Flush(); } //二次曲面球体
void drawSphere(OpenGL gl,float x,float y,float z, double radius, int segx, int segy, bool isLines)
{
gl.PushMatrix();
gl.Translate(x, y, z);
var sphere = gl.NewQuadric();
if (isLines)
gl.QuadricDrawStyle(sphere, OpenGL.GL_LINES);
else
gl.QuadricDrawStyle(sphere, OpenGL.GL_QUADS);
gl.QuadricNormals(sphere, OpenGL.GLU_NONE); //GLU_NONE,GLU_FLAT,GLU_SMOOTH
gl.QuadricOrientation(sphere, (int)OpenGL.GLU_OUTSIDE); //GLU_OUTSIDE,GLU_INSIDE
gl.QuadricTexture(sphere, (int)OpenGL.GLU_FALSE); //GL_TRUE,GLU_FALSE
gl.Sphere(sphere, radius, segx, segy);
gl.DeleteQuadric(sphere);
gl.PopMatrix();
} //球心坐标为(x,y,z),球的半径为radius,M,N分别表示球体的横纵向被分成多少份
void drawSphere1(OpenGL gl, float xx, float yy, float zz, float radius, float M, float N,bool isLines)
{
const float PI = 3.1415926f;
float step_z = (float)Math.PI / M;
float step_xy = * PI / N;
float[] x = new float[] { , , , };
float[] y = new float[] { , , , };
float[] z = new float[] { , , , }; float angle_z = 0.0f;
float angle_xy = 0.0f;
int i = , j = ;
gl.Begin(OpenGL.GL_QUADS);
for (i = ; i < M; i++)
{
angle_z = i * step_z;
for (j = ; j < N; j++)
{
angle_xy = j * step_xy; x[] = (float)(radius * Math.Sin(angle_z) * Math.Cos(angle_xy));
y[] = (float)(radius * Math.Sin(angle_z) * Math.Sin(angle_xy));
z[] = (float)(radius * Math.Cos(angle_z)); x[] = (float)(radius * Math.Sin(angle_z + step_z) * Math.Cos(angle_xy));
y[] = (float)(radius * Math.Sin(angle_z + step_z) * Math.Sin(angle_xy));
z[] = (float)(radius * Math.Cos(angle_z + step_z)); x[] = (float)(radius * Math.Sin(angle_z + step_z) * Math.Cos(angle_xy + step_xy));
y[] = (float)(radius * Math.Sin(angle_z + step_z) * Math.Sin(angle_xy + step_xy));
z[] = (float)(radius * Math.Cos(angle_z + step_z)); x[] = (float)(radius * Math.Sin(angle_z) * Math.Cos(angle_xy + step_xy));
y[] = (float)(radius * Math.Sin(angle_z) * Math.Sin(angle_xy + step_xy));
z[] = (float)(radius * Math.Cos(angle_z)); for (int k = ; k < ; k++)
{
gl.Vertex(xx + x[k], yy + y[k], zz + z[k]);
}
}
}
gl.End();
} private void openGLControl_OpenGLInitialized(object sender, EventArgs e)
{
OpenGL gl = openGLControl.OpenGL;
setLight(gl);
//gl.Enable(OpenGL.GL_NORMALIZE);
gl.ClearColor(, , , );
} private void setLight(OpenGL gl)
{
//0号灯光,默认灯光
gl.Light(OpenGL.GL_LIGHT0, OpenGL.GL_DIFFUSE, defDiffLight);
gl.Light(OpenGL.GL_LIGHT0, OpenGL.GL_SPECULAR, defSpecLight);
gl.Light(OpenGL.GL_LIGHT0, OpenGL.GL_POSITION, defLightPos); //1号灯光
gl.Light(OpenGL.GL_LIGHT1, OpenGL.GL_DIFFUSE, diffLightR);
gl.Light(OpenGL.GL_LIGHT1, OpenGL.GL_SPECULAR, specLightR);
gl.Light(OpenGL.GL_LIGHT1, OpenGL.GL_POSITION, lightPosR); //2号灯光
gl.Light(OpenGL.GL_LIGHT2, OpenGL.GL_DIFFUSE, diffLightG);
gl.Light(OpenGL.GL_LIGHT2, OpenGL.GL_SPECULAR, specLightG);
gl.Light(OpenGL.GL_LIGHT2, OpenGL.GL_POSITION, lightPosG); //3号灯光
gl.Light(OpenGL.GL_LIGHT3, OpenGL.GL_DIFFUSE, diffLightB);
gl.Light(OpenGL.GL_LIGHT3, OpenGL.GL_SPECULAR, specLightB);
gl.Light(OpenGL.GL_LIGHT3, OpenGL.GL_POSITION, lightPosB); gl.Enable(OpenGL.GL_LIGHTING);
gl.Enable(OpenGL.GL_LIGHT0); //启用默认光源 } private void openGLControl_Resized(object sender, EventArgs e)
{
OpenGL gl = openGLControl.OpenGL;
gl.MatrixMode(OpenGL.GL_PROJECTION);
gl.LoadIdentity();
gl.Perspective(70.0f, (double)Width / (double)Height, 0.01, 100.0);
gl.LookAt(-, , -, , , , , , );
gl.MatrixMode(OpenGL.GL_MODELVIEW);
} }
}
截取了一帧的效果如下图:
有三个光球围绕球体旋转,三组光分别为红,绿,蓝,因此它们的组合可以在球面上生成所有可能的颜色效果.
函数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/
SharpGL学习笔记(十三) 光源例子:环绕二次曲面球体的光源的更多相关文章
- SharpGL学习笔记(十一) 光源创建的综合例子:光源参数可调节的测试场景
灯光的测试例子:光源参数可以调节的测试场景 先看一下测试场景和效果. 场景中可以切换视图, 以方便观察三维体和灯光的位置.环境光,漫射光,镜面反射光都可以在四种颜色间切换. 灯光位置和摄像机位置(Lo ...
- java之jvm学习笔记十三(jvm基本结构)
java之jvm学习笔记十三(jvm基本结构) 这一节,主要来学习jvm的基本结构,也就是概述.说是概述,内容很多,而且概念量也很大,不过关于概念方面,你不用担心,我完全有信心,让概念在你的脑子里变成 ...
- SharpGL学习笔记(七) OpenGL的变换总结
笔者接触OpenGL最大的困难是: 经常调试一份代码时, 屏幕漆黑一片, 也不知道结果对不对,不知道如何是好! 这其实就是关于OpenGL"变换"的基础概念没有掌握好, 以至于对& ...
- python3.4学习笔记(十三) 网络爬虫实例代码,使用pyspider抓取多牛投资吧里面的文章信息,抓取政府网新闻内容
python3.4学习笔记(十三) 网络爬虫实例代码,使用pyspider抓取多牛投资吧里面的文章信息PySpider:一个国人编写的强大的网络爬虫系统并带有强大的WebUI,采用Python语言编写 ...
- Go语言学习笔记十三: Map集合
Go语言学习笔记十三: Map集合 Map在每种语言中基本都有,Java中是属于集合类Map,其包括HashMap, TreeMap等.而Python语言直接就属于一种类型,写法上比Java还简单. ...
- SharpGL学习笔记(六) 裁剪变换
在OpenGL中,除了视景体定义的6个裁剪平面(上下左右前后)外, 用户还可以定义一个或者多个附加的裁剪平面,以去掉场景中无关的目标. 附加平面裁剪函数原型如下: ClipPlane(OpenGL.G ...
- Vue学习笔记十三:Vue+Bootstrap+vue-resource从接口获取数据库数据
目录 前言 SpringBoot提供后端接口 Entity类 JPA操作接口 配置文件 数据库表自动映射,添加数据 写提供数据的接口 跨域问题 前端修改 效果图 待续 前言 Vue学习笔记九的列表案例 ...
- SharpGL学习笔记(十二) 光源例子:解决光源场景中的常见问题
笔者学到光源这一节,遇到的问题就比较多了,收集了一些如下所述: (1) 导入的3ds模型,如果没有材质光照效果很奇怪.如下图 (2) 导入的3ds模型,有材质,灯光效果发暗,材质偏色,效果也很奇怪. ...
- SharpGL学习笔记(八) 矩阵堆栈和变换的综合例子: 机器人
我们先引入关于"矩阵堆栈"的官方说法: OpenGL的矩阵堆栈指的就是内存中专门用来存放矩阵数据的某块特殊区域.实际上,在创建.装入.相乘模型变换和投影变换矩阵时,都已用到堆栈操作 ...
随机推荐
- MFC中混合使用Duilib制作界面
因为公司项目最近入了MFC的这个大坑,用MFC做UI做了一段时间,感觉不是很方便,开发效率有点慢. 看了c++里面做界面的类库,感觉Duilib比较符合做界面的需求,而且很多大公司也在使用Duilib ...
- SSAS:OLE DB 错误: OLE DB 或 ODBC 错误 : Login failed for user 'NT Service\MSSQLServerOLAPService'
问题描述 按照微软官方教程尝试使用SSAS做OLAP时,出现如下错误信息: Severity Code Description Project File Line Suppression State ...
- 查询修改linux 打开文件句柄数量
查询系统支持最大可打开文件句柄数量: #vi /proc/sys/fs/file-max 查询当前连接用户最大可打开文件句柄数量: #ulimit -a 修改当前连接用户最大可打开文件句柄数量: #u ...
- 控制反转(Ioc)和依赖注入(DI)
控制反转IOC, 全称 “Inversion of Control”.依赖注入DI, 全称 “Dependency Injection”. 面向的问题:软件开发中,为了降低模块间.类间的耦合度,提倡基 ...
- windows下配置nginx+php
[转] http://www.cnblogs.com/fengyuqing/p/php_nginx.html 1.首先需要准备的应用程序包. nginx:nginx/Windows-1.0.4 php ...
- netty ByteBuf分析
1.Heap Buffer(堆缓冲区) 2.Direct Buffer(直接缓冲区) 3.Composite Buffer(复合缓冲区) 4.PooledByteBuf 池缓冲 readerInex ...
- win7 or win8 系统访问2003系统上的数据库很慢
解决方式, 执行当前命令即可 netsh interface tcp set global autotuninglevel=disabled
- 如何克隆kvm虚拟机
关于如何使用kvm虚拟化技术创建虚拟机,这里有一系列博客讲的已经非常清楚了,这里不再赘述,不过其中有些小坑可能需要大家注意: 0. 写在创建虚拟机之前(即教程的系列三之前) 1. 确认防火墙是否关闭, ...
- "浅谈Android"第一篇:Android系统简介
近来,看了一本书,名字叫做<第一行代码>,是CSDN一名博主写的,一本Android入门级的书,比较适合新手.看了书之后,有感而发,想来进行Android开发已经有一年多了,但欠缺系统化的 ...
- ASP.NET HTTP模拟提交通用类 GET POST
用法: WebRequestSugar ws = new WebRequestSugar(); //可选参数 //ws.SetAccept //ws.SetContentType //ws.SetC ...