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)。
代码如下:
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 SharpGLWinformsApplication1
{ public partial class SharpGLForm : Form
{
private float rotation = 0.0f;
private bool isRotate = false;
private bool isLines = false;
private bool isFrontView = false;
private bool isLeftView = false;
private bool isTopView = false;
private bool isPerspective = true;
private float[] lightPos = new float[] { -, -, , };
private float[] lightSphereColor = new float[] { 1f, 1f, 1f };
private IList<float[]> lightColor = new List<float[]>();
private double[] lookatValue = { , , , , , , , , };
private IList<double[]> viewDefaultPos = new List<double[]>();
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); drawGrid(gl);
DrawCube(ref gl, 1.5f,-1f, -2f, isLines);
drawOneSphere(ref gl,-,-,-,isLines);
if (isRotate)
rotation += 3.0f;
} private void setLightColor(OpenGL gl)
{
gl.Light(OpenGL.GL_LIGHT0, OpenGL.GL_AMBIENT, lightColor[]);
gl.Light(OpenGL.GL_LIGHT0, OpenGL.GL_DIFFUSE, lightColor[]);
gl.Light(OpenGL.GL_LIGHT0, OpenGL.GL_SPECULAR, lightColor[]);
} private void openGLControl_OpenGLInitialized(object sender, EventArgs e)
{
OpenGL gl = openGLControl.OpenGL; //四个视图的缺省位置
viewDefaultPos.Add(new double[] { , , , , , , , , }); //透视
viewDefaultPos.Add(new double[] { , , , , , , , , }); //前视
viewDefaultPos.Add(new double[] { , , , , , , , , }); //左视
viewDefaultPos.Add(new double[] { , , , -, , , , , }); //顶视
lookatValue =(double[])viewDefaultPos[].Clone(); lightColor.Add(new float[] { 1f, 1f, 1f, 1f }); //环境光(ambient light)
lightColor.Add(new float[] { 1f, 1f, 1f, 1f }); //漫射光(diffuse light)
lightColor.Add(new float[] { 1f, 1f, 1f, 1f }); //镜面反射光(specular light) setLightColor(gl);
gl.Light(OpenGL.GL_LIGHT0, OpenGL.GL_POSITION, lightPos); gl.Enable(OpenGL.GL_LIGHTING);
gl.Enable(OpenGL.GL_LIGHT0); gl.ClearColor(, , , );
} private void drawOneSphere(ref OpenGL gl, float xPos, float yPos, float zPos, bool isLine)
{
gl.PushMatrix();
{
gl.Translate(xPos, yPos, zPos);
gl.Color(lightSphereColor);
drawSphere(gl,,,,isLine);
}
gl.PopMatrix();
} private void openGLControl_Resized(object sender, EventArgs e)
{ OpenGL gl = openGLControl.OpenGL;
gl.MatrixMode(OpenGL.GL_PROJECTION);
gl.LoadIdentity();
gl.Perspective(40.0f, (double)Width / (double)Height, 0.01, 100.0); gl.LookAt(lookatValue[], lookatValue[], lookatValue[],
lookatValue[], lookatValue[], lookatValue[],
lookatValue[], lookatValue[], lookatValue[]); gl.MatrixMode(OpenGL.GL_MODELVIEW);
updateLabInfo();
} internal void DrawCube(ref OpenGL Gl, float xPos, float yPos, float zPos, bool isLine)
{
Gl.PushMatrix();
Gl.Translate(xPos, yPos, zPos);
if (isLine)
Gl.Begin(OpenGL.GL_LINE_STRIP);
else
Gl.Begin(OpenGL.GL_POLYGON); /** 顶面 */
Gl.Vertex(0.0f, 0.0f, 0.0f);
Gl.Vertex(0.0f, 0.0f, -1.0f);
Gl.Vertex(-1.0f, 0.0f, -1.0f);
Gl.Vertex(-1.0f, 0.0f, 0.0f); /** 前面 */
Gl.Vertex(0.0f, 0.0f, 0.0f);
Gl.Vertex(-1.0f, 0.0f, 0.0f);
Gl.Vertex(-1.0f, -1.0f, 0.0f);
Gl.Vertex(0.0f, -1.0f, 0.0f); /** 右面 */
Gl.Vertex(0.0f, 0.0f, 0.0f);
Gl.Vertex(0.0f, -1.0f, 0.0f);
Gl.Vertex(0.0f, -1.0f, -1.0f);
Gl.Vertex(0.0f, 0.0f, -1.0f); /** 左面*/
Gl.Vertex(-1.0f, 0.0f, 0.0f);
Gl.Vertex(-1.0f, 0.0f, -1.0f);
Gl.Vertex(-1.0f, -1.0f, -1.0f);
Gl.Vertex(-1.0f, -1.0f, 0.0f); /** 底面 */
Gl.Vertex(0.0f, 0.0f, 0.0f);
Gl.Vertex(0.0f, -1.0f, -1.0f);
Gl.Vertex(-1.0f, -1.0f, -1.0f);
Gl.Vertex(-1.0f, -1.0f, 0.0f); /** 后面 */
Gl.Vertex(0.0f, 0.0f, 0.0f);
Gl.Vertex(-1.0f, 0.0f, -1.0f);
Gl.Vertex(-1.0f, -1.0f, -1.0f);
Gl.Vertex(0.0f, -1.0f, -1.0f);
Gl.End();
Gl.PopMatrix();
} void drawGrid(OpenGL gl)
{
//绘制过程
gl.PushAttrib(OpenGL.GL_CURRENT_BIT); //保存当前属性
gl.PushMatrix(); //压入堆栈
gl.Translate(0f, -2f, 0f);
gl.Color(0f, 0f, 1f); //在X,Z平面上绘制网格
for (float i = -; i <= ; i += )
{
//绘制线
gl.Begin(OpenGL.GL_LINES);
{
if (i == )
gl.Color(0f, 1f, 0f);
else
gl.Color(0f, 0f, 1f); //X轴方向
gl.Vertex(-50f, 0f, i);
gl.Vertex(50f, 0f, i);
//Z轴方向
gl.Vertex(i, 0f, -50f);
gl.Vertex(i, 0f, 50f); }
gl.End();
}
gl.PopMatrix();
gl.PopAttrib();
} void drawSphere(OpenGL gl,double radius,int segx,int segy,bool isLines)
{
gl.PushMatrix();
gl.Translate(2f, 1f, 2f);
var sphere = gl.NewQuadric();
if (isLines)
gl.QuadricDrawStyle(sphere, OpenGL.GL_LINES);
else
gl.QuadricDrawStyle(sphere, OpenGL.GL_QUADS);
gl.QuadricNormals(sphere, OpenGL.GLU_SMOOTH);
gl.QuadricOrientation(sphere, (int)OpenGL.GLU_OUTSIDE);
gl.QuadricTexture(sphere, (int)OpenGL.GLU_FALSE);
gl.Sphere(sphere, radius, segx, segy);
gl.DeleteQuadric(sphere);
gl.PopMatrix();
} private void moveObject(int obj,string keyName)
{
//obj==0移动视图
switch (keyName)
{
case "btnQ":
if (obj == ) ++lookatValue[]; //y
else
++lightPos[];
break;
case "btnE":
if (obj == ) --lookatValue[];
else
--lightPos[];
break;
case "btnW":
if (obj == ) --lookatValue[]; //z
else
--lightPos[];
break;
case "btnS":
if (obj == ) ++lookatValue[];
else
++lightPos[];
break;
case "btnA":
if (obj == ) --lookatValue[]; //X
else
--lightPos[];
break;
case "btnD":
if (obj == ) ++lookatValue[];
else
++lightPos[];
break;
}
} private void rbPerspective_CheckedChanged(object sender, EventArgs e)
{
switch (((RadioButton)sender).Name)
{
case "rbPerspective":
isPerspective = !isPerspective;
isFrontView = false;
isTopView = false;
isLeftView = false;
break;
case "rbLeft":
isLeftView = !isLeftView;
isFrontView = false;
isPerspective = false;
isTopView = false;
break;
case "rbFront":
isFrontView = !isFrontView;
isTopView = false;
isPerspective = false;
isLeftView = false;
break;
case "rbTop":
isTopView = !isTopView;
isPerspective = false;
isLeftView = false;
isFrontView = false;
break;
default:
return;
}
setViewDefaultValue();
openGLControl_Resized(null, null);
} private void cbxRotate_CheckedChanged(object sender, EventArgs e)
{
var cbx=((CheckBox)sender);
switch (cbx.Name)
{
case "cbxRotate":
isRotate = cbx.Checked;
break;
case "cbxLines":
isLines = cbx.Checked;
break;
case "cbxLightOff":
if (!cbx.Checked)
this.openGLControl.OpenGL.Enable(OpenGL.GL_LIGHT0);
else
this.openGLControl.OpenGL.Disable(OpenGL.GL_LIGHT0);
break;
}
} private void SharpGLForm_Load(object sender, EventArgs e)
{
this.cbxLightType.SelectedIndex = ;
updateLabInfo();
} private void updateLabInfo()
{
tbLightPos.Text = string.Format("{0},{1},{2},{3}", lightPos[], lightPos[], lightPos[], lightPos[]);
tbLookAt.Text = string.Format("{0},{1},{2},{3},{4},{5},{6},{7},{8}", lookatValue[], lookatValue[], lookatValue[],
lookatValue[], lookatValue[], lookatValue[], lookatValue[], lookatValue[], lookatValue[]);
} private void rbWhite_CheckedChanged(object sender, EventArgs e)
{
var rad = ((RadioButton)sender);
var lightType = this.cbxLightType.SelectedIndex;
if (rad.Checked)
{
switch (rad.Name)
{
case "rbWhite":
lightColor[lightType][] = 1f;
lightColor[lightType][] = 1f;
lightColor[lightType][] = 1f;
lightColor[lightType][] = 1f;
break;
case "rbRed":
lightColor[lightType][] = 1f;
lightColor[lightType][] = 0f;
lightColor[lightType][] = 0f;
lightColor[lightType][] = 1f;
break;
case "rbGreen":
lightColor[lightType][] = 0f;
lightColor[lightType][] = 1f;
lightColor[lightType][] = 0f;
lightColor[lightType][] = 1f;
break;
case "rbBlue":
lightColor[lightType][] = 0f;
lightColor[lightType][] = 0f;
lightColor[lightType][] = 1f;
lightColor[lightType][] = 1f;
break;
}
setLightColor(openGLControl.OpenGL);
}
} private void cbxLightType_SelectedIndexChanged(object sender, EventArgs e)
{
var lightType = this.cbxLightType.SelectedIndex;
if (lightType >= )
judgeColor(lightColor[lightType]);
} private void judgeColor(float[] color)
{
if (color[] == 1f && color[] == 1f && color[] == 1f && color[] == 1f)
rbWhite.Checked = true;
else if (color[] == 1f && color[] == 0f && color[] == 0f && color[] == 1f)
rbRed.Checked = true;
else if (color[] == 0f && color[] == 1f && color[] == 0f && color[] == 1f)
rbGreen.Checked = true;
else if (color[] == 0f && color[] == 0f && color[] == 1f && color[] == 1f)
rbBlue.Checked = true;
} private void btnQ_Click(object sender, EventArgs e)
{
moveObject(radioButton1.Checked ? : ,((Button)sender).Name);
openGLControl_Resized(null, null);
openGLControl.OpenGL.Light(OpenGL.GL_LIGHT0, OpenGL.GL_POSITION, lightPos);
} private void setViewDefaultValue()
{
if (isPerspective)
{
lookatValue = (double[])viewDefaultPos[].Clone();
}
else if (isFrontView)
{
lookatValue = (double[])viewDefaultPos[].Clone();
}
else if (isLeftView)
{
lookatValue = (double[])viewDefaultPos[].Clone();
}
else if (isTopView)
{
lookatValue = (double[])viewDefaultPos[].Clone();
}
} private void btnDefaultPOS_Click(object sender, EventArgs e)
{
if (radioButton1.Checked)
{
setViewDefaultValue();
}
else
{
lightPos = new float[] { -, -, , };
openGLControl.OpenGL.Light(OpenGL.GL_LIGHT0, OpenGL.GL_POSITION, lightPos);
}
openGLControl_Resized(null, null);
} private void openGLControl_KeyDown(object sender, KeyEventArgs e)
{
string name = string.Empty;
switch (e.KeyCode)
{
case Keys.W:
name = "btnW";
break;
case Keys.A:
name = "btnA";
break;
case Keys.S:
name = "btnS";
break;
case Keys.D:
name = "btnD";
break;
case Keys.Q:
name = "btnQ";
break;
case Keys.E:
name = "btnE";
break;
}
moveObject(radioButton1.Checked ? : , name);
openGLControl_Resized(null, null);
} private void btnSetPos_Click(object sender, EventArgs e)
{
if (radioButton1.Checked)
{
double[] ary = tbLookAt.Text.Split(',').Select(s => Convert.ToDouble(s)).ToArray();
lookatValue = ary;
openGLControl_Resized(null, null);
}
else
{
float[] ary = tbLightPos.Text.Split(',').Select(s => Convert.ToSingle(s)).ToArray();
lightPos = ary;
openGLControl.OpenGL.Light(OpenGL.GL_LIGHT0, OpenGL.GL_POSITION, ary);
} } }
}
有关灯光的代码如下粗体显示部分:
private void setLightColor(OpenGL gl)
{
gl.Light(OpenGL.GL_LIGHT0, OpenGL.GL_AMBIENT, lightColor[]);
gl.Light(OpenGL.GL_LIGHT0, OpenGL.GL_DIFFUSE, lightColor[]);
gl.Light(OpenGL.GL_LIGHT0, OpenGL.GL_SPECULAR, lightColor[]);
} private void openGLControl_OpenGLInitialized(object sender, EventArgs e)
{
OpenGL gl = openGLControl.OpenGL; //四个视图的缺省位置
viewDefaultPos.Add(new double[] { , , , , , , , , }); //透视
viewDefaultPos.Add(new double[] { , , , , , , , , }); //前视
viewDefaultPos.Add(new double[] { , , , , , , , , }); //左视
viewDefaultPos.Add(new double[] { , , , -, , , , , }); //顶视
lookatValue =(double[])viewDefaultPos[].Clone(); lightColor.Add(new float[] { 1f, 1f, 1f, 1f }); //环境光(ambient light)
lightColor.Add(new float[] { 1f, 1f, 1f, 1f }); //漫射光(diffuse light)
lightColor.Add(new float[] { 1f, 1f, 1f, 1f }); //镜面反射光(specular light) setLightColor(gl);
gl.Light(OpenGL.GL_LIGHT0, OpenGL.GL_POSITION, lightPos); gl.Enable(OpenGL.GL_LIGHTING);
gl.Enable(OpenGL.GL_LIGHT0);
gl.ClearColor(, , , );
}
第3,4,5行是创建灯光三个部分 环境光,漫射光,镜面反射光。
第24行是设定灯光的位置。
第26,27是让灯光开,有效。
灯光代码确实比较简单,这段代码其它部分没什么好说的,笔者按界面功能直述其意,朋友们应该很容易懂。
唯一要关注下的是:视图和灯光的参数修改是如何实时生效的。
原创文章,出自"博客园, 猪悟能'S博客" : http://www.cnblogs.com/hackpig/
SharpGL学习笔记(十一) 光源创建的综合例子:光源参数可调节的测试场景的更多相关文章
- ROS学习笔记十一:创建URDF 文件并在RVIZ中查看模型
Unified Robot Description Format,简称为URDF(标准化机器人描述格式),是一种用于描述机器人及其部分结构.关节.自由度等的XML格式文件. 一.创建第一个URDF文件 ...
- 6.6(java学习笔记)文件分割(IO综合例子)
基本思路: 文件分割:将一个文件分割成若干个独立的文件. 设置分割后小文件文件的字节数,然后读取被分割文件, 将对应的字节数写入分割后的小文件中. 使用seek定位下一次读取位置. 文件 ...
- python3.4学习笔记(十一) 列表、数组实例
python3.4学习笔记(十一) 列表.数组实例 #python列表,数组类型要相同,python不需要指定数据类型,可以把各种类型打包进去#python列表可以包含整数,浮点数,字符串,对象#创建 ...
- Go语言学习笔记十一: 切片(slice)
Go语言学习笔记十一: 切片(slice) 切片这个概念我是从python语言中学到的,当时感觉这个东西真的比较好用.不像java语言写起来就比较繁琐.不过我觉得未来java语法也会支持的. 定义切片 ...
- SharpGL学习笔记(七) OpenGL的变换总结
笔者接触OpenGL最大的困难是: 经常调试一份代码时, 屏幕漆黑一片, 也不知道结果对不对,不知道如何是好! 这其实就是关于OpenGL"变换"的基础概念没有掌握好, 以至于对& ...
- InterSystems Ensemble学习笔记(二) Ensemble创建镜像, 实现自动故障转移
系列目录 InterSystems Ensemble学习笔记(一) Ensemble介绍及安装InterSystems Ensemble学习笔记(二) Ensemble创建镜像, 实现自动故障转移 一 ...
- 【opencv学习笔记八】创建TrackBar轨迹条
createTrackbar这个函数我们以后会经常用到,它创建一个可以调整数值的轨迹条,并将轨迹条附加到指定的窗口上,使用起来很方便.首先大家要记住,它往往会和一个回调函数配合起来使用.先看下他的函数 ...
- ensorflow学习笔记四:mnist实例--用简单的神经网络来训练和测试
http://www.cnblogs.com/denny402/p/5852983.html ensorflow学习笔记四:mnist实例--用简单的神经网络来训练和测试 刚开始学习tf时,我们从 ...
- JavaScript权威设计--JavaScript函数(简要学习笔记十一)
1.函数调用的四种方式 第三种:构造函数调用 如果构造函数调用在圆括号内包含一组实参列表,先计算这些实参表达式,然后传入函数内.这和函数调用和方法调用是一致的.但如果构造函数没有形参,JavaScri ...
随机推荐
- linux下重要的网络配置文件
linux下重要的网络配置文件:一; /etc/sysconfig/network 文件内容: NETWORKING=yes <= ...
- $(this).bind("change",itemno_change);
如果是onchange 会出错,超过3个可能就无效.
- Objective-C语法之字符串NSString去掉前后空格或回车符(可以是NSCharacterSet类型的其它字符)
main.m #import <Foundation/Foundation.h> #import "NSString+Trim.h" int main(int argc ...
- 非抢占式RCU实现(二),解释:为什么 RCU_NEXT_SIZE 宏值是4?
参考:2.6.34 一个很奇怪的问题. 没有查找到为什么 RCU_NEXT_SIZE的值为4的原因(包括Documentation),主要是在rcu_state中定义了一个四级的list,感到很有意思 ...
- SSH上传和下载文件
备个份: 一,ssh上传文件 scp file username@hostIP:文件地址 例: [zhangy@BlackGhost ~]$ scp test.sql zhangying@192.16 ...
- ffmpeg把ts文件转m3u8并切片
Linux_x86_64流媒体环境:nginx + EasyDarwin-master 客户端播放器:VLC media player 下载windows下的ffmepg二进制版本,请进网站http: ...
- vue给input file绑定函数获取当前上传的对象
HTML <input type="file" @change="tirggerFile($event)"> JS(vue-methods) tir ...
- innodb分区
当 MySQL的总记录数超过了100万后,性能会大幅下降,可以采用分区方案 分区允许根据指定的规则,跨文件系统分配单个表的多个部分.表的不同部分在不同的位置被存储为单独的表. 1.先看下innodb的 ...
- 将windbg设置为默认调试器命令
前提条件:安装好windbg软件(默认安装位置) 以截取组态王运行系统崩溃为例: 64位系统0.文件更新替换 将Touchvew.exe以及Touchvew.pdb覆盖替换C:\Program Fil ...
- linux 安装 Django 安装
下载源码包:https://www.djangoproject.com/download/ 输入以下命令并安装: tar xzvf Django-X.Y.tar.gz # 解压下载包 cd Djang ...