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 ...
随机推荐
- MySQL binlog日志操作详解
MySQL的二进制日志可以说是MySQL最重要的日志了,它记录了所有的DDL和DML(除了数据查询语句)语句,以事件形式记录,还包含语句所执行的消耗的时间,MySQL的二进制日志是事务安全型的. bi ...
- Process和Thread在指定CPU运行
最近帮朋友写了一个多线程程序,他那边一运行多线程就出错,我这边却没有任何问题,找了好久才找到解决方法,原来是CPU的问题,有朋友遇到同样的问题,可以一起参考 //进程与指定cpu绑定 SetProce ...
- 由于PADT伪造攻击带来的大面积掉线原因分析
今天一早接到一个客户电话,说他有一个交换机下面的用户,大面积和上线下线. 由于之有已建议用户在主干换了普通VLAN交换机.所以这次出现问题概率较小,只在一条支路的交换机下面. 下面我对这个情况的发生做 ...
- OpenGL中各种坐标系的理解
转载:https://blog.csdn.net/meegomeego/article/details/8686816 OPENGL坐标系可分为:世界坐标系和当前绘图坐标系. 世界坐标系以屏幕中心为原 ...
- ASP.NET程序也能像WinForm程序一样运行[转载]
阅读目录 开始 操作方式 支持的ASP.NET程序类别 它也是个HTTP服务器 支持远程机器访问 不受限于Windows防火墙 尊重每个人的操作习惯 内置多标签浏览器支持 启动参数及配置文件 支持 . ...
- GCT之数学公式(微积分)
- VIM复制粘贴大全[转]
用vim这么久 了,始终也不知道怎么在vim中使用系统粘贴板,通常要在网上复制一段代码都是先gedit打开文件,中键粘贴后关闭,然后再用vim打开编辑,真的不 爽:上次论坛上有人问到了怎么在vim中使 ...
- 使用T4模板调用Sqlserver链接生成自己的模板
<#@ template debug="false" hostspecific="false" language="C#" #> ...
- apache+tomcat集群部署笔记
前提条件 安装gcc,gcc-c++两个编译器 yum install gcc yum install gcc-c++ 接下来开始安装集群相关环境: 1.下载apr,apr-util,pcre,apa ...
- Android数据库升级、降级、创建(onCreate() onUpgrade() onDowngrade())的注意点
以下内容可以作为面试官在面试的时候的问题,感觉比较好,是比较常用的知识点,可以用来考察基础是否扎实. 也可以程序猿学习.开发中的注意点.因为稍微不注意,就有可能导致数据库不能用. DBAdapter. ...