opengl:OpenGL基础篇



本人水平有限如有问题请以文章形式提出大家可以讨论吗...

[OPENGL如何用]
OPENGL编程类似C编程实际接口就是C所以熟悉C是必要
般编程可用到库包括:
OPENGL实用库:以glu开头
OPENGL辅助库:以aux开头
Windows专用库:以wgl开头
Win32API:无专用前缀

OPENGL中有115个核心可以在任何OPENGL平台上使用
OPENGL实用库比上面这115个提供高级
OPENGL辅助库本来是提供初学者入门不保证在任何平台使用
但恰好可以在WIN32下使用所以本讲座将大量引用

WIN32下OPENGL编程有两个方便途径:
1使用辅助库
2使用C基于消息驱动编程
显然1要简单入门从这里开始吧

[用的前准备]
1
首先你需要下列*.lib包含在你工程中:
opengl32.lib glu32.lib glaux.lib
本讲座所有例子“将”在VC5下调试通过所以从
project->ting->link->general->object/libary modules
中加入上面 3个*.lib
(这些LIBVC4以上版本已经自带加入即可不用在 4处搜寻文件)

2
另外在你运行路径下或\\win95\\system\\下你需要些*.dll动态连接库
opengl32.dll glu32.dll rxddi.dll mga.drv

如果谁需要上述文件跟我打个招呼
别跟我说要Visual C 5.0 呦




[编程入门]
这里我将给出个小例子让大家熟悉用辅助库编程结构:


// GLOS.H
//////////////////////////////////////////////////////////
// This is an OS specic header file
//判别操作系统基本头文件


# <windows.h>


// disable data conversion warnings


#pragma warning(disable : 4244) // MIPS
#pragma warning(disable : 4136) // X86
#pragma warning(disable : 4051) // ALPHA
//////////////////////////////////////////////////////////
//opengl.cpp
//主
# "glos.h"
# <GL/gl.h>
# <GL/glaux.h>
# "windows.h"


void (void)
{
/*化:*/
auxInitDisplayMode(AUX_SINGLE|AUX_RGBA);
//窗口显示单缓存Cache和RGB(彩色)模式
auxInitPosition(0,0,500,500);
//大小x=500 y=500 (00)是屏幕左上点
auxInitWindow("sample1");
//窗口参数是标题
glClearColor(0.0,0.0,0.0,0.0);
//将窗口清为黑色
glClear(GL_COLOR_BUFFER_BIT);
//将颜色缓存Cache清为glClearColor命令所设置颜色
//即背景色


/*绘图*/
glColor3f(1.0,0.0,0.0);
//选颜色(RGB)参数0<x<1这里就是红色
glRectf(-0.5,-0.5,0.5,0.5);
//画个方块


glFlush;
//强制绘图不驻留缓存Cache
_sleep(1000);
//windows显示1秒(单位是毫秒)
}
//end of sample
根据注释应该看出功能:显示红色方块(2D)秒钟
结构不外乎:
化 + 绘图 + 其它功能,现在不用过分追究细节知道是干什么就可以乐好吗?
我想结束本节前让大家实现第个3D例子很简单而且好看但是我们必须被迫不得不多学些东东:


1.OPENGL、变量命名准则


变量:
前缀 类型 对应C变量
b 8-bit  signed char
s 16-bit  
i 32-bit  long
f 32-bit float float
d 64-bit float double
ub 8-bit unsigned  unsigned char
us 16-bit unsigned  unsigned 
ui 32-bit unsigned  unsigned long
例如1.0f实际就是1.0般写成1.0f看上去好辨认


:
参数类型作为后缀
例如:glVertex2i(2,4)表明是opengl基本(gl-)
是绘点(-Vertex-)
是两个整型参数(-2i)
将来对掐头去尾就知道它是干什么


2.CALLBACK
些用来让系统系统要它们例如显示、接受键盘输入...
你就好比擂积木样把它们列在主化后(顺序般无关紧要)
系统会自动执行它们例如:
void CALLBACK display(void)中你写好乐想画什么东东然后主中使用auxMainLoop(display);就可以让这个东东直显示乐很类似VC中OnPa


3.OPENGL基本库绘图思路方法


glBegin(类型);
glColor3f(...);
glVertex(...)
glColor3f(...);
glVertex(...);
...
glEnd;


先由“类型”指定画什么平面:
GL_POINTS 单个顶点集
GL_LINES 多组线2个点条线
GL_GL_POLYGON 单个简单填充凸多边形
GL_TRAINGLES 多组 3角型3个点个 3角
..用到在说吧(自己可以在VC HELP INDEX中查找)
//////////////////////////////////////////////////////
//sample.cpp


# "glos.h"
# <GL/gl.h>
# <GL/glaux.h>
# "windows.h"


void myinit(void);
void CALLBACK display(void);
void CALLBACK reshape(GLsizei w,GLsizei h);
//这里不用管reshape只是个用于窗口改变大小时处理
//和绘图无关后面会讲到
//这里重点是display,请注意绘图思路方法
void myinit(void)
{
/*化:*/
auxInitDisplayMode(AUX_SINGLE|AUX_RGBA);
//窗口显示单缓存Cache和RGB(彩色)模式
auxInitPosition(0,0,500,500);


//大小x=500 y=500 (00)是屏幕左上点
auxInitWindow("sample1");
//窗口参数是标题
glClearColor(0.0,0.0,0.0,0.0);
//将窗口清为黑色
glClear(GL_COLOR_BUFFER_BIT);
//将颜色缓存Cache清为glClearColor命令所设置颜色
//即背景色
}


void CALLBACK reshape(GLsizei w,GLsizei h)
{
glViewport(0,0,w,h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity;
(w<=h)
glOrtho(-20.0,20.0,-20.0*(GLfloat)h/(GLfloat)w,
20.0*(GLfloat)h/(GLfloat)w,-50.0,50.0);

glOrtho(-20.0*(GLfloat)h/(GLfloat)w,
20.0*(GLfloat)h/(GLfloat)w,-20.0,20.0,-50.0,50.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity;
}

void CALLBACK display(void)
{
glBegin(GL_TRIANGLE_STRIP);//画连续填充多个 3角
glColor3f(1.0,0.0,0.0);
glVertex3f(15.0,0.0,0.0);
glColor3f(0.0,1.0,0.0);
glVertex3f(-15.0,0.0,0.0);
glColor3f(0.0,0.0,1.0);
glVertex3f(0.0,15.0,15.0);
//第个 3角

glColor3f(0.0,1.0,1.0);
glVertex3f(10.0,15.0,-15.0);
//第 2个 3角

glColor3f(1.0,1.0,0.0);
glVertex3f(15.0,0.0,0.0);
//第 3个 3角

glEnd;
glFlush;
}


void (void)
{
myinit;
auxReshapeFunc(reshape);
auxMainLoop(display);
}
//end of sample
所谓连续填充就是1、2、3点组成 3角1
2、3、4点组成 3角2...
这里共画乐3个向连接彩色 3角组成乐个由 3个彩色平面围成空心 3角椎...enjoy it




上回书说道有个reshape需要进步讲解这个功能是对用户改变窗口大小操作进行些重绘动作(类似VC中OnResize)其中用到了些变换概念我希望大家已经具备初步计算机图形学知识这将有利于这部分理解如果还没有也没关系我尽量讲解通俗些对于3D绘图把其中3D坐标写成齐次坐标系后是4*4矩阵形式(详细…………………………………………………………
可以参阅相关文献后面也会讲到)任何投影、旋转...操作都可以看成是矩阵相乘操作矩阵操作----这个概念定要形成!!
例如在2D中普通旋转变换可以写成:
|cosθ sinθ 0 |
[x' y' 1]=[x y 1] |-sinθ cosθ 0 |
|0 0 1 |
3D中道理完全个3D图形显示包括下面步骤:
1.视点变换(将相机放在合适地方对准3D景物)
2.模型变换(将3D物体放在合适地方)
3.投影变换(将相机镜头调整使3D景物投影在2D胶片上)
4.视口变换(决定胶片大小)
其中1、2并没有本质区别



里面有几个关键性:


 几何变换
1.
void glTranslated(
GLdouble x,
GLdouble y,
GLdouble z
);
void glTranslatef(
GLfloat x,
GLfloat y,
GLfloat z
);
目标沿X Y Z轴平移 x y z


2.
void glRotated(
GLdouble angle,
GLdouble x,
GLdouble y,
GLdouble z
);
void glRotatef(
GLfloat angle,
GLfloat x,
GLfloat y,
GLfloat z
);
目标分别以X Y Z轴为轴逆时针旋转 x y z


3.
void glScaled(
GLdouble x,
GLdouble y,
GLdouble z
);
void glScalef(
GLfloat x,
GLfloat y,
GLfloat z
);
目标在X Y Z 方向缩放,缩放因子为 x y z


2 投影变换


1.正射投影(即没有“近大远小”)
void glOrtho(GLdouble left,GLdouble right,GLdouble bottom,GLdouble top,
GLdouble near,GLdouble far)
创建个平行视景体(矩阵)即投射线是平行线把第个矩形
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
视景投影到第 2个矩形视景上并用这个矩阵乘以当前矩阵以完成变换
近景第个矩形左上角 3维空间坐标(left,bottom,-near)右下角 3维空间坐标(right,top,-near);
远景第 2个矩形左上角 3维空间坐标(left,bottom,-far),右下角 3维空间坐标(right,top,-far);


2.透射投影(“近大远小”)
void glFrustum(
GLdouble left,
GLdouble right,
GLdouble bottom,
GLdouble top,
GLdouble znear,
GLdouble zfar
);
创建个型如棱台视景体其近截取面由left right bottom top znear
确定远截取面由从视点投影近截取面到Z轴zfar位置决定


3 视口变换
void glViewport(GL x,GL y,GLsize width,GLsize height);
这个定义个视口x和y是视口在屏幕窗口坐标系中左上坐标
缺省是(00)width height是宽和高
注意使用中视口长宽比例调整会导致图象变形因此reshape
要检测窗口尺寸修正视口大小保证图象不变形


附:
void glMatrixMode(GLenum mode );
把当前矩阵转换为指定矩阵类型


这 3个利用见例子中中文介绍说明:
////////////////////////////////////////////////////////////
//sample.cpp
# "glos.h"
# <GL/gl.h>
# <GL/glaux.h>
# "windows.h"
void myinit(void);
void CALLBACK display(void);
void CALLBACK reshape(GLsizei w,GLsizei h);
/////////////////////////////////////////////////////////////
void myinit(void)
{
/*化:*/
auxInitDisplayMode(AUX_SINGLE|AUX_RGBA);


//窗口显示单缓存Cache和RGB(彩色)模式
auxInitPosition(0,0,500,500);
//大小x=500 y=500 (00)是屏幕左上点
auxInitWindow("sample1");
//窗口参数是标题
glClearColor(0.0,0.0,0.0,0.0);
//将窗口清为黑色
glClear(GL_COLOR_BUFFER_BIT);
//将颜色缓存Cache清为glClearColor命令所设置颜色
//即背景色
}
//////////////////////////////////////////////////
void CALLBACK reshape(GLsizei w,GLsizei h)
{
//设定视口X Y方向不要大于500单位
(w<=500&&h<=500)
glViewport(0,0,w,h);
(w>500&&h<=500)
glViewport(0,0,500,h);
(w<=500&&h>500)
glViewport(0,0,w,500);
(w>500&&h>500)
glViewport(0,0,500,500);


//进入世界坐标系准备变换
//必要步骤化变换矩阵步骤: 1确定类型 2清成单位阵
glMatrixMode(GL_PROJECTION);
glLoadIdentity;


//定义个合适视景体
(w<=h)
glOrtho(-20.0,20.0,-20.0*(GLfloat)h/(GLfloat)w,
20.0*(GLfloat)h/(GLfloat)w,-50.0,50.0);

glOrtho(-20.0*(GLfloat)h/(GLfloat)w,
20.0*(GLfloat)h/(GLfloat)w,-20.0,20.0,-50.0,50.0);


//把变换结果返回视点坐标系
glMatrixMode(GL_MODELVIEW);
glLoadIdentity;
}
//////////////////////////////////////
//画 3棱锥功能同上
void draw(void)
{
glBegin(GL_TRIANGLE_STRIP);
glColor3f(1.0,0.0,0.0);
glVertex3f(15.0,0.0,0.0);
glColor3f(0.0,1.0,0.0);
glVertex3f(-15.0,0.0,0.0);
glColor3f(0.0,0.0,1.0);
glVertex3f(0.0,15.0,15.0);
//
glColor3f(0.0,1.0,1.0);
glVertex3f(10.0,15.0,-15.0);
//
glColor3f(1.0,1.0,0.0);
glVertex3f(15.0,0.0,0.0);
//
glEnd;
}
////////////////////////////////////////
void CALLBACK display(void)
{
//按上个例子中思路方法画第个 3棱锥
glClearColor(0.0,0.0,0.0,1.0);
glClear(GL_COLOR_BUFFER_BIT);
glLoadIdentity;
glTranslatef(0.0,0.0,-25.0);
draw;


//开始画第 2个 3棱锥
//变换开始清变换矩阵为单位阵
glLoadIdentity;
//先沿X Y Z平移-5 -10 -4屏幕上看就是向左下移动
//Z方向由于是平行投影没有“近大远小”所以看不出效果
glTranslatef(-5.0,-10.0,-4.0);
//再沿Z轴转90度
glRotatef(90,0.0,0.0,1.0);
draw;


//绘图工作完成强制绘图结束
glFlush;
}


void (void)
{
myinit;
auxReshapeFunc(reshape);
auxMainLoop(display);
}


//sample ends here
/////////////////////
如果大家运行下就知道上述作用无非是把物体移动、转动、变形缩放、透视...
我想有了前3讲OPENGL基本原理已经如此了它就是提供了个标准计算机图形学所使用数学模型到显示接口只要具备图形学知识掌握OPENGL API使用绘图很EASY啦基础部分已经完毕慢慢再来谈高级绘图功能如:纹理、光源、动画...
真诚希望大家提提意见和高论 :)





前面 3篇文章已经把OPENGL编程基本结构描述完毕以后会在这个基础上逐渐深化不断增添新内容篇是讲述键盘操作和动画基础(实际还差远哪)只是个简单能由用户控制动画让物体前后移动左右旋转是我们自己个QUAKE!当然这个版本谁买谁上当呵呵
这篇个目就是加深前面对于CALLBACK认识以及对于变换直观解释任何变换你都可以从屏幕上通过自己操作看出来:
我只把和以前变化部分标记中文解释


////////////////////////////////////////////////////
//sample.cpp
# "glos.h"
# <GL/gl.h>
# <GL/glaux.h>
# "windows.h"


void myinit(void);
void CALLBACK display(void);
void CALLBACK reshape(GLsizei w,GLsizei h);


//注意到乐吗?这里新加乐4个CALLBACK
//类似display reshape也由主它们
//实现对键盘输入响应
void CALLBACK left(void);//按 LEFT
void CALLBACK right(void);//按 RIGHT
void CALLBACK up(void);//按 UP
void CALLBACK down(void);//按 DOWN


//两个全局变量z_motion用来控制物体远近
//rotate用来控制物体旋转
  z_motion=0,rotate=0;


void myinit(void)
{
auxInitDisplayMode(AUX_SINGLE|AUX_RGBA);
auxInitPosition(0,0,500,500);
auxInitWindow("sample1");
glClearColor(0.0,0.0,0.0,0.0);
glClear(GL_COLOR_BUFFER_BIT);
}


void CALLBACK reshape(GLsizei w,GLsizei h)
{
(w<=500&&h<=500)
glViewport(0,0,w,h);
(w>500&&h<=500)
glViewport(0,0,500,h);
(w<=500&&h>500)
glViewport(0,0,w,500);
(w>500&&h>500)
glViewport(0,0,500,500);



glMatrixMode(GL_PROJECTION);
glLoadIdentity;
///*(w<=h)
// glOrtho(-20.0,20.0,-20.0*(GLfloat)h/(GLfloat)w,
// 20.0*(GLfloat)h/(GLfloat)w,-50.0,50.0);
//
// glOrtho(-20.0*(GLfloat)h/(GLfloat)w,
// 20.0*(GLfloat)h/(GLfloat)w,-20.0,20.0,-50.0,50.0);
//*/
/************************************************************/
//这里我们换种投影思路方法:透射投影有立体感
//取代上次平行投影前4个参数是控制第个截取面
//left right top bottom然后两个参数控制近截取面


//Z坐标远截取面Z作标声名如下:
//void glFrustum(GLdouble left,GLdouble right,
// GLdouble bottom,GLdouble top,
// GLdouble near,GLdouble far);
/************************************************************/
glFrustum(-20.0,20.0,-20.0,20.0,10.0,50.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity;
}


void draw(void)
{
glBegin(GL_TRIANGLE_STRIP);
glColor3f(1.0,0.0,0.0);
glVertex3f(15.0,0.0,0.0);
glColor3f(0.0,1.0,0.0);
glVertex3f(-15.0,0.0,0.0);
glColor3f(0.0,0.0,1.0);
glVertex3f(0.0,15.0,15.0);
//
glColor3f(0.0,1.0,1.0);
glVertex3f(10.0,15.0,-15.0);
//
glColor3f(1.0,1.0,0.0);
glVertex3f(15.0,0.0,0.0);
//
glEnd;
}


void CALLBACK display(void)
{
glClearColor(0.0,0.0,0.0,1.0);
glClear(GL_COLOR_BUFFER_BIT);


//glPushMatrix;
glLoadIdentity;


//根据z_motion rotate两个参数确定变换具体数值:
//z_motion改变时物体从原Z坐标-25平移z_motion个单位
glTranslatef(0.0,0.0,-25.0+z_motion);
//rotate改变时物体延Y轴(上下方向)旋转5*rotate度
glRotatef(rotate*5.0,0.0,1.0,0.0);


draw;
//glPopMatrix;


glFlush;
}
void CALLBACK left(void)
{
//每当按下LEFTrotate数值 +1
//以下都类似
rotate;
}
void CALLBACK right(void)
{
rotate--;
}
void CALLBACK up(void)
{
z_motion;
}
void CALLBACK down(void)
{
z_motion--;
}
void (void)
{
myinit;


//用辅助库把left right up down
//设为标准键盘输入处理
auxKeyFunc(AUX_LEFT,left);
auxKeyFunc(AUX_RIGHT,right);
auxKeyFunc(AUX_UP,up);
auxKeyFunc(AUX_DOWN,down);


auxReshapeFunc(reshape);
auxMainLoop(display);
}
//end of sample
////////////////////////////////////////////////////
如果运行这个会发现有较明显闪烁感这是单缓存Cache模式造成以后会讲到动画应采用双缓存Cache模式这样可以避免闪烁





这回可能是OPENGL最简单内容:颜色
 RGB模式
般来讲实现彩色是用RGB 3基色来调配这就是
RGB模式我们前面直用这种思路方法
(例如:
glColor3f(1.0,0.0,0.0);
glVertex3f(0.0,0.0,0/0);
绘制个红色点)
void glColor3{b s i f d ub us ui}(TYPE r,TYPE g, TYPE b);
void glColor4{b s i f d ub us ui}(TYPE r,TYPE g, TYPE b,TYPE a);
void glColor3{b s i f d ub us ui}v(TYPE *v);
void glColor4{b s i f d ub us ui}v(TYPE *v);
{}内是任选种数值精度(看前面介绍);
参数a是表征透明度Alpha值
后两个带v后缀表明他们参数是向量(详细使用看本篇例子)
以glColor3f为例其参数取值范围-1.0--1.0其它数值类型
自动把参数均匀影射到这个区间例如:

后缀 类型 MIN MIN映射 MAX MAX映射
b 1整数 -128 -1.0 127 1.0

2 颜色索引模式
使用
void glIndex{s i f d}(TYPE c);
void glIndex{s i f d}(TYPE *c);
来从颜色索引表中选取颜色设置当前颜色索引值(调色板号)大于
总数时取模

前面所有例子都是RGB模式所以这里给出个颜色索引例子:

//sample.cpp
//////////////////////////////
# "glos.h"
# <GL/gl.h>
# <GL/glaux.h>
# "windows.h"
void myinit(void);
void InitPalette(void);
void CALLBACK display(void);
void CALLBACK reshape(GLsizei w,GLsizei h);


void myinit(void)
{
auxInitDisplayMode(AUX_SINGLE|AUX_INDEX);
auxInitPosition(0,0,500,500);
auxInitWindow("sample1");
glClearColor(0.0,0.0,0.0,0.0);
glClear(GL_COLOR_BUFFER_BIT);
glShadeModel(GL_FLAT);//GL_FLAT填色模式
}


void CALLBACK reshape(GLsizei w,GLsizei h)
{
(w<=500&&h<=500)
glViewport(0,0,w,h);
(w>500&&h<=500)
glViewport(0,0,500,h);
(w<=500&&h>500)
glViewport(0,0,w,500);
(w>500&&h>500)
glViewport(0,0,500,500);



glMatrixMode(GL_PROJECTION);
glLoadIdentity;
(w<=h)
glOrtho(-20.0,20.0,-20.0*(GLfloat)h/(GLfloat)w,
20.0*(GLfloat)h/(GLfloat)w,-50.0,50.0);

glOrtho(-20.0*(GLfloat)h/(GLfloat)w,
20.0*(GLfloat)h/(GLfloat)w,-20.0,20.0,-50.0,50.0);


glMatrixMode(GL_MODELVIEW);
glLoadIdentity;
}


void draw(void)
{
GL n;


//首先给定 3角扇坐标信息
GLfloat pp[8][2]={{7.0,-7.0},{0.0,-10.0},{-7.0,-7.0},{-10.0,0.0},
{-7.0,7.0},{0.0,10.0},{7.0,7.0},{10.0,0.0}};


//先画前两个点然后用循环读取前面向量()信息绘制
//完整图形
glBegin(GL_TRIANGLE_FAN);
glVertex2f(0.0,0.0);
glVertex2f(10.0,0.0);
for(n=0;n<8;n)
{


//每次从颜色查找表中找出新颜色然后以这个颜色绘制 3角扇


//注意glVertex2fv中v后缀使用以前没有碰到过v后缀代表
//参数是个向量()
glIndexi(n+1);
glVertex2fv(pp[n]);
}
glEnd;
}


void InitPalette(void)
{
//这是本例子关键化颜色查找表这里共定义
//乐8种颜色是从蓝到青渐进
GL i;
 GLfloat rgb[3]={{0.0,0.0,0.2},{0.0,0.0,0.4},{0.0,0.0,0.6},
{0.0,0.0,1.0},{0.0,0.2,1.0},{0.0,0.4,1.0},{0.0,0.8,1.0},{0.0,1.0,1.0}};


//简单辅助库设置系统调色板把刚才8个颜色定为全部
//颜色索引内容
for(i=0;i<8;i)
auxSetOneColor(i+1,rgb[0],rgb[1],rgb[2]);
}


void CALLBACK display(void)
{
//首先自定义InitPalette化调色板
InitPalette;
glClearColor(0.0,0.0,0.0,1.0);
glClear(GL_COLOR_BUFFER_BIT);


glLoadIdentity;
draw;
glFlush;
}


void (void)
{
myinit;
auxReshapeFunc(reshape);
auxMainLoop(display);
}
//end of sample
下次将介绍OPENGL光照和材质效果个步入3D阶梯
大家快来呀 ......





这部分是最重要部分前面只是基础这里会介绍光照处理、明暗处理、光源
设置、材质定义以及相关计算机图形学概念
般来说产生3D图象步骤:
1 建模
2 将几何模型经变换投影到2D透视图
3 确定场景所有可见面进行消隐
4 计算场景颜色
我们已经再前面介绍乐1 2 两步
消隐是OPENGL工作我们不必关心
所以4就是这里重点


()光照
分为:反射、透射光
1 简单光照模型
简单光照模型只考虑物体表面反射光视觉影响假定物体表面光滑不透明而且由理想材料构成环境假设为白光照明
般反射光分为:环境反射、漫反射和镜面反射3个分量


环境反射光(Ambient Light):入射光均匀从周围环境入射至表面并个方向等量反射
漫反射光(Dfuse Light):特定光源在物体表面反射光中那些向各个方向均匀反射
镜面反射光(Specular Light):朝定方向反射光例如光源在金属球上产生高光(Highlight)
详细可参阅大学物理呵呵


介绍下重要:
(1)
void glLight{}[v](GLenum light,GLenum pname,TYPE param)
设置光源特性


light是名字例如:GL_LIGHT0,GL_LIGHT1...GL_LIGHT7


pname 缺省值 介绍说明
GL_AMBIENT 0,0,0,1 RGBA模式环境光
GL_DIFFUSE 1,1,1,1 RGBA模式漫反射光
GL_SPECULAR 1,1,1,1 RGBA模式镜面光
GL_POSTION 1,0,1,0 光源位置齐次坐标
GL_SPOT_DIRECTION 0,0,-1 点光源聚光方向矢量(x,y,z,w)
GL_SPOT_EXPONENT 0 点光源聚光指数
GL_SPOT_CUTOFF 180 点光源聚光发散半角
GL_CONSTANT_ATTENUATION 1 常数衰减因子
GL_LINER_ATTENUATION 0 线性衰减因子
GL_QUADRATIC_ATTENUATION 0 平方衰减因子
介绍说明:GL_DIFFUSE GL_SPECULAR缺省值只用于GL_LIGHT0,
其他光源GL_DIFFUSE GL_SPECULAR缺省值为:(0.0,0.0,0.0,1.0)


!!!我可能前面忘说了!!!
TYPE就是{}中那些参数类型例如:i就是f就是float
v是可选表明可以作为参数定义组光源
(2)启用光照/关闭光源
void glEnable(GLenum cap)
void glDisable(GLenum cap)
例如使光源有效:
glEnable(GL_LIGHT0);


下面给出简单光照例子:
/////////////////////////////////////////
//sample.cpp


# "glos.h"
# <GL/gl.h>
# <GL/glaux.h>
# "windows.h"


void myinit(void);
void CALLBACK display(void);
void CALLBACK reshape(GLsizei w,GLsizei h);



void myinit(void)
{
auxInitDisplayMode(AUX_SINGLE|AUX_RGBA);
auxInitPosition(0,0,500,500);
auxInitWindow("sample1");
glClearColor(0.0,0.0,0.0,0.0);
glClear(GL_COLOR_BUFFER_BIT);


//glShadeModel用来确定颜色填充模式缺省GL_SMOOTH效果较好但计算
//量大如果你加上下面这句那么填色是按照几何模型平面填充计算量
//大大减小但是效果不好看
// glShadeModel(GL_FLAT);


//定义个光源位置坐标
GLfloat light_position={1.0,1.0,1.0,0.0};
glLightfv(GL_LIGHT0,GL_POSITION,light_position);


//定义光源漫反射颜色(兰色)以及环境光(红色)如果你上机试试这个
//就可以看出光源效果如果没条件可以想象下:在淡淡红色
//背景光下受光照部分呈现纯蓝色而背光部分呈现红色
//你还可以更详细按照上面表格指定其他属性这里其他就用缺省
GLfloat light_dfuse={0.0,0.0,1.0,1.0};
glLightfv(GL_LIGHT0,GL_DIFFUSE,light_dfuse);
GLfloat light_ambient={1.0,0.0,0.0,1.0};
glLightfv(GL_LIGHT0,GL_AMBIENT,light_ambient);



//有关GL_LIGHTING 介绍说明:
//If enabled, use the current lighting parameters to compute the
//vertex color or index. If disabled, associate the current color
//or index with each vertex. 如果Enabled使用当前光照参数计算每个
//点颜色你可以试试去掉这句那么缺省白色漫反射光源会代替你
//灰色光源你将看见个白色没有立体感
glEnable(GL_LIGHTING);


glEnable(GL_LIGHT0);


//有关GL_LESS介绍说明
//Passes  the incoming z value is less than the stored z value.
//This is the default value.
//用glEnable(GL_DEPTH_TEST)激活深度比较然后定义如果z坐标小于buffer中
//值(当前点z较小更靠近观察点)则显示实际就是消隐
glDepthFunc(GL_LESS);
glEnable(GL_DEPTH_TEST);
}


void CALLBACK reshape(GLsizei w,GLsizei h)
{
glViewport(0,0,w,h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity;
(w<=h)
glOrtho(-2.0,2.0,-2.0*(GLfloat)h/(GLfloat)w,
2.0*(GLfloat)h/(GLfloat)w,-10.0,10.0);

glOrtho(-2.0*(GLfloat)h/(GLfloat)w,
2.0*(GLfloat)h/(GLfloat)w,-2.0,2.0,-10.0,10.0);


glMatrixMode(GL_MODELVIEW);
glLoadIdentity;
}


void draw(void)
{
//辅助库个实心圆球半径1.0
auxSolidSphere(1.0);
}


void CALLBACK display(void)
{
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);


glLoadIdentity;
draw;
glFlush;
}


void (void)
{
myinit;


auxReshapeFunc(reshape);
auxMainLoop(display);
}
//end of sample
/////////////////////////////////////////////





紧接上这回讲材质:
OPENGL通过材料对R、G、B近似反光率来近似定义材料颜色
也分为环境、漫反射、镜面反射成分他们决定材料对环境光、漫反射光和
镜面反射光反射程度将材料特性和光源特性结合就是观察最终显示
效果例如红色塑料球大部分是红色在光源形成高光处则出现光源
特性颜色很EASY不是么?


材质定义:
void glMaterial{}[v](GLenum face,GLenum pname,TYPE param);
其中:
face:可以是GL_FRONT、GL_BACK、GL_FRONT_AND_BACK,它表明当前材质应用
到物体个表面上
pname介绍说明特定材质属性(很类似上次光源定义):


pname 缺省值 介绍说明


GL_AMBIENT 0.2,0.2,0.2,1.0 材质环境反射光
GL_DIFFUSE 0.8,0.8,0.8,1.0 材质漫反射光
GL_AMBIENT_AND_DIFFUSE 材质环境光和漫反射光颜色
GL_SPECULAR 0.0,0.0.0.0,1.0 材质镜面反射光
GL_SHINESS 0.0 镜面指数(光照度)
GL_EMISSION 0.0,0.0,0.0,1.0 材质辐射颜色
GL_COLOR_INDEXES 0,1,1 材质环境光、漫反射光和镜面
反射光颜色
请看下面材质简单例子:
////////////////////////////////////////////////////////////////////////
//sample.cpp
# "glos.h"
# <GL/gl.h>
# <GL/glaux.h>
# "windows.h"
void myinit(void);
void CALLBACK display(void);
void CALLBACK reshape(GLsizei w,GLsizei h);



void myinit(void)
{
auxInitDisplayMode(AUX_SINGLE|AUX_RGBA);
auxInitPosition(0,0,500,500);
auxInitWindow("sample1");
glClearColor(0.0,0.0,0.0,0.0);
glClear(GL_COLOR_BUFFER_BIT);
// glShadeModel(GL_FLAT);


//首先定义个材质定义思路方法非常类似前面讲到光源定义
GLfloat mat_ambient={0.8,0.8,0.8,1.0};
//定义 紫色 漫反射特性
GLfloat mat_dfuse={0.8,0.0,0.8,1.0};
//定义 亮紫色 镜面反射特性
GLfloat mat_specular={1.0,0.0,1.0,1.0};
//定义镜面反射光亮度
GLfloat mat_shininess={50.0};
//将以上材质定义应用
glMaterialfv(GL_FRONT,GL_AMBIENT,mat_ambient);
glMaterialfv(GL_FRONT,GL_DIFFUSE,mat_dfuse);
glMaterialfv(GL_FRONT,GL_SPECULAR,mat_specular);
glMaterialfv(GL_FRONT,GL_SHININESS,mat_shininess);


//这里我们简化光源以显示材质效果
//这里我们只指定光源位置其他默认:白色光源
//你也可以加入光源定义看看光源和材质合成效果
//正是它们能够合成才能产生比真实生活中多效果这也正是
//3D技术吸引人魅力所在
GLfloat light_position={1.0,1.0,1.0,0.0};
glLightfv(GL_LIGHT0,GL_POSITION,light_position);
// GLfloat light_dfuse={0.0,0.0,1.0,1.0};
// glLightfv(GL_LIGHT0,GL_DIFFUSE,light_dfuse);


//将光源设置应用
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);


//着色消隐
//*******其实说白乐这就是大名鼎鼎 Z-BUFFER 呀************//
glDepthFunc(GL_LESS);
glEnable(GL_DEPTH_TEST);
}


void CALLBACK reshape(GLsizei w,GLsizei h)
{
glViewport(0,0,w,h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity;
(w<=h)
glOrtho(-2.0,2.0,-2.0*(GLfloat)h/(GLfloat)w,
2.0*(GLfloat)h/(GLfloat)w,-10.0,10.0);

glOrtho(-2.0*(GLfloat)h/(GLfloat)w,
2.0*(GLfloat)h/(GLfloat)w,-2.0,2.0,-10.0,10.0);


glMatrixMode(GL_MODELVIEW);
glLoadIdentity;
}


void draw(void)
{
auxSolidSphere(1.0);
}


void CALLBACK display(void)
{
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);


glLoadIdentity;
draw;
glFlush;
}
void (void)
{
myinit;


auxReshapeFunc(reshape);
auxMainLoop(display);
}
//end of sample


////////////////////////////////////////////////////


通过以上例子我们会看到材质定义实现和光源效果是就我们日常感觉定义材质更加符合人们习惯而光源使用白光这里我们看到个紫色其高光部分呈现亮紫色


作为比较下面我们给出个12个彩色球例子大家可以看出各种光源、材质应用效果起比较
给出例子的前介绍两个:
void glPushMatrix;
void glPopMatrix;
我前面已经讲过所有几何投影变换都是矩阵相乘结果如果你希望保持坐标点就要用到这两个重要:矩阵入栈和矩阵出栈
你可以这样理解为了在左上角画个球你先保存当前矩阵glPushMatrix(入栈)然后把坐标平移到左上角然后auxSolidSphere(1.0)个半径1.0这时再glPopMatrix(矩阵出栈)就又回到原始坐标点这时球就在左上角乐这个很长但实际上部分统统是重复画12个球工作所以也比较好理解
//////////////////////////////////////////////////////////////////
//sample.cpp
# "glos.h"
# <GL/gl.h>
# <GL/glaux.h>
# "windows.h"
void myinit(void);
void CALLBACK display(void);
void CALLBACK reshape(GLsizei w,GLsizei h);



void myinit(void)
{
auxInitDisplayMode(AUX_SINGLE|AUX_RGBA);
auxInitPosition(0,0,500,500);
auxInitWindow("sample1");
glClearColor(0.0,0.1,0.1,0.0);
glClear(GL_COLOR_BUFFER_BIT);
// glShadeModel(GL_FLAT);


//首先定义光源
GLfloat light_ambient={0.0,0.0,0.0,1.0};
GLfloat light_dfuse={1.0,1.0,1.0,1.0};
GLfloat light_specular={1.0,1.0,1.0,1.0};
GLfloat light_position={0.0,3.0,2.0,0.0};
GLfloat Imodel_ambient={0.4,0.4,0.4,1.0};


//应用光源
glLightfv(GL_LIGHT0,GL_AMBIENT,light_ambient);
glLightfv(GL_LIGHT0,GL_POSITION,light_position);
glLightfv(GL_LIGHT0,GL_DIFFUSE,light_dfuse);


glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);


//化Z BUFFER
glDepthFunc(GL_LESS);
glEnable(GL_DEPTH_TEST);
}


void CALLBACK reshape(GLsizei w,GLsizei h)
{
glViewport(0,0,w,h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity;
(w<=h)
glOrtho(-6.0,6.0,-6.0*(GLfloat)h/(GLfloat)w,
6.0*(GLfloat)h/(GLfloat)w,-10.0,10.0);

glOrtho(-6.0*(GLfloat)h/(GLfloat)w,
6.0*(GLfloat)h/(GLfloat)w,-6.0,6.0,-10.0,10.0);


glMatrixMode(GL_MODELVIEW);
glLoadIdentity;
}


void draw(void)
{
auxSolidSphere(1.0);
}


void CALLBACK display(void)
{
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);


//建立材质数据库
GLfloat no_mat={0.0,0.0,0.0,1.0};
GLfloat mat_ambient={0.7,0.7,0.7,1.0};
GLfloat mat_ambient_color={0.8,0.8,0.2,1.0};
GLfloat mat_dfuse={0.1,0.5,0.8,1.0};
GLfloat mat_specular={1.0,1.0,1.0,1.0};
GLfloat no_shininess={0.0};
GLfloat low_shininess={5.0};
GLfloat high_shininess={100.0};
GLfloat mat_emission={0.3,0.2,0.2,0.0};
//////////////////////////////////////////////////////////
//1-1 仅有漫反射光无环境光和镜面光
glPushMatrix;
glTranslatef(-3.75,3.0,0.0);
glMaterialfv(GL_FRONT,GL_AMBIENT,no_mat);
glMaterialfv(GL_FRONT,GL_DIFFUSE,mat_dfuse);
glMaterialfv(GL_FRONT,GL_SPECULAR,no_mat);
glMaterialfv(GL_FRONT,GL_SHININESS,no_shininess);
glMaterialfv(GL_FRONT,GL_EMISSION,no_mat);
draw;
glPopMatrix;


//1-2 有漫反射光并且有低高光无环境光
glPushMatrix;
glTranslatef(-1.25,3.0,0.0);
glMaterialfv(GL_FRONT,GL_AMBIENT,no_mat);
glMaterialfv(GL_FRONT,GL_DIFFUSE,mat_dfuse);
glMaterialfv(GL_FRONT,GL_SPECULAR,mat_specular);
glMaterialfv(GL_FRONT,GL_SHININESS,low_shininess);
glMaterialfv(GL_FRONT,GL_EMISSION,no_mat);
draw;
glPopMatrix;


//1-3 有漫反射光和镜面光很亮高光无环境光
glPushMatrix;
glTranslatef(1.25,3.0,0.0);
glMaterialfv(GL_FRONT,GL_AMBIENT,no_mat);
glMaterialfv(GL_FRONT,GL_DIFFUSE,mat_dfuse);
glMaterialfv(GL_FRONT,GL_SPECULAR,mat_specular);
glMaterialfv(GL_FRONT,GL_SHININESS,high_shininess);
glMaterialfv(GL_FRONT,GL_EMISSION,no_mat);
draw;
glPopMatrix;


//1-4 有漫反射光和辐射光无环境光和镜面反射光
glPushMatrix;
glTranslatef(3.75,3.0,0.0);
glMaterialfv(GL_FRONT,GL_AMBIENT,no_mat);
glMaterialfv(GL_FRONT,GL_DIFFUSE,mat_dfuse);
glMaterialfv(GL_FRONT,GL_SPECULAR,no_mat);
glMaterialfv(GL_FRONT,GL_SHININESS,no_shininess);
glMaterialfv(GL_FRONT,GL_EMISSION,mat_emission);
draw;
glPopMatrix;
//////////////////////////////////////////////////////////////
//2-1 有漫反射光和环境光无镜面反射光
glPushMatrix;
glTranslatef(-3.75,0.0,0.0);
glMaterialfv(GL_FRONT,GL_AMBIENT,mat_ambient);
glMaterialfv(GL_FRONT,GL_DIFFUSE,mat_dfuse);
glMaterialfv(GL_FRONT,GL_SPECULAR,no_mat);
glMaterialfv(GL_FRONT,GL_SHININESS,no_shininess);
glMaterialfv(GL_FRONT,GL_EMISSION,no_mat);


draw;
glPopMatrix;


//2-2 有漫反射光、环境光和镜面光而且有低高光
glPushMatrix;
glTranslatef(-1.25,0.0,0.0);
glMaterialfv(GL_FRONT,GL_AMBIENT,mat_ambient);
glMaterialfv(GL_FRONT,GL_DIFFUSE,mat_dfuse);
glMaterialfv(GL_FRONT,GL_SPECULAR,mat_specular);
glMaterialfv(GL_FRONT,GL_SHININESS,low_shininess);
glMaterialfv(GL_FRONT,GL_EMISSION,no_mat);
draw;
glPopMatrix;


//2-3 有漫反射光环境光和镜面光而且有很亮高光
glPushMatrix;
glTranslatef(1.25,0.0,0.0);
glMaterialfv(GL_FRONT,GL_AMBIENT,mat_ambient);
glMaterialfv(GL_FRONT,GL_DIFFUSE,mat_dfuse);
glMaterialfv(GL_FRONT,GL_SPECULAR,mat_specular);
glMaterialfv(GL_FRONT,GL_SHININESS,high_shininess);
glMaterialfv(GL_FRONT,GL_EMISSION,no_mat);
draw;
glPopMatrix;


//2-4有漫反射光、环境光和辐射光无镜面光
glPushMatrix;
glTranslatef(3.75,0.0,0.0);
glMaterialfv(GL_FRONT,GL_AMBIENT,mat_ambient);
glMaterialfv(GL_FRONT,GL_DIFFUSE,mat_dfuse);
glMaterialfv(GL_FRONT,GL_SPECULAR,no_mat);
glMaterialfv(GL_FRONT,GL_SHININESS,no_shininess);
glMaterialfv(GL_FRONT,GL_EMISSION,mat_emission);
draw;
glPopMatrix;
///////////////////////////////////////////////////////////////
//3-1 有漫反射光和有颜色环境光无镜面光
glPushMatrix;
glTranslatef(-3.75,-3.0,0.0);
glMaterialfv(GL_FRONT,GL_AMBIENT,mat_ambient_color);
glMaterialfv(GL_FRONT,GL_DIFFUSE,mat_dfuse);
glMaterialfv(GL_FRONT,GL_SPECULAR,no_mat);
glMaterialfv(GL_FRONT,GL_SHININESS,no_shininess);
glMaterialfv(GL_FRONT,GL_EMISSION,no_mat);
draw;
glPopMatrix;


//3-2有漫反射光和有颜色环境光以及镜面光且有低高光
glPushMatrix;
glTranslatef(-1.25,-3.0,0.0);
glMaterialfv(GL_FRONT,GL_AMBIENT,mat_ambient_color);
glMaterialfv(GL_FRONT,GL_DIFFUSE,mat_dfuse);
glMaterialfv(GL_FRONT,GL_SPECULAR,mat_specular);
glMaterialfv(GL_FRONT,GL_SHININESS,low_shininess);
glMaterialfv(GL_FRONT,GL_EMISSION,no_mat);
draw;
glPopMatrix;


//3-3 有漫反射光和有颜色环境光以及镜面光且有很亮高光
glPushMatrix;
glTranslatef(1.25,-3.0,0.0);
glMaterialfv(GL_FRONT,GL_AMBIENT,mat_ambient_color);
glMaterialfv(GL_FRONT,GL_DIFFUSE,mat_dfuse);
glMaterialfv(GL_FRONT,GL_SPECULAR,mat_specular);
glMaterialfv(GL_FRONT,GL_SHININESS,high_shininess);
glMaterialfv(GL_FRONT,GL_EMISSION,no_mat);
draw;
glPopMatrix;


//3-4 有漫反射光和有颜色环境光以及辐射光无镜面光
glPushMatrix;
glTranslatef(3.75,-3.0,0.0);
glMaterialfv(GL_FRONT,GL_AMBIENT,mat_ambient_color);
glMaterialfv(GL_FRONT,GL_DIFFUSE,mat_dfuse);
glMaterialfv(GL_FRONT,GL_SPECULAR,no_mat);
glMaterialfv(GL_FRONT,GL_SHININESS,no_shininess);
glMaterialfv(GL_FRONT,GL_EMISSION,mat_emission);
draw;
glPopMatrix;


glFlush;
}
void (void)
{
myinit;


auxReshapeFunc(reshape);
auxMainLoop(display);
}





这次把材质完全搞定呵呵
上次12个区别立体材质球运用glMaterialfv来改变材质
有其固有系统消耗


另外同样功能可以使用:
void glColorMaterial(GLenum face,GLenum mode)来实现
face取值:
GL_FRONT GL_BACK GL_FRONT_AND_BACK
mode取值:
GL_AMBIENT GL_DIFFUSE GL_AMBIENT_AND_DIFFUSE GL_SPECULAR GL_EMISSION


在想要使用这个要启用glEnable(GL_COLOR_MATERIAL)来是工作
在绘图时使用glColor*来改变材质颜色或用glMaterial来改变材质成分
使用完毕要用glDisable(GL_COLOR_MATERIAL)来关闭这种材质模式


例如:
glColorMaterial(GL_FRONT,GL_DIFFUSE);
glEnable(GL_COLOR_MATERIAL);


glColor3f(0.3,0.5,0.7);
//画些物体:
..


glColor3f(0.0,1.0,0.0);
//再画另些物体:
..


glDisable(GL_COLOR_MATERIAL);


介绍说明:
当需要改变场景中大部分方面单个材质时最好glColorMaterial
当修改不只个材质参数最好glMaterial*这是目前我体会到
使用功能上区别点吧
请看下面例子:
/////////////////////////////////////////////////////////
//sample.cpp
# "glos.h"
# <GL/gl.h>
# <GL/glaux.h>
# "windows.h"
void myinit(void);
void CALLBACK display(void);
void CALLBACK reshape(GLsizei w,GLsizei h);


void myinit(void)
{
auxInitDisplayMode(AUX_SINGLE|AUX_RGBA);
auxInitPosition(0,0,500,500);
auxInitWindow("sample1");
glClearColor(0.0,0.1,0.1,0.0);
glClear(GL_COLOR_BUFFER_BIT);
// glShadeModel(GL_FLAT);


//定义个白色简单光源
GLfloat light_position={0.0,3.0,2.0,0.0};
glLightfv(GL_LIGHT0,GL_POSITION,light_position);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);


//启用消隐
glDepthFunc(GL_LESS);
glEnable(GL_DEPTH_TEST);


//启用颜色材质模式
glColorMaterial(GL_FRONT,GL_DIFFUSE);
glEnable(GL_COLOR_MATERIAL);
}


void CALLBACK reshape(GLsizei w,GLsizei h)


{
glViewport(0,0,w,h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity;
(w<=h)
glOrtho(-6.0,6.0,-6.0*(GLfloat)h/(GLfloat)w,
6.0*(GLfloat)h/(GLfloat)w,-10.0,10.0);

glOrtho(-6.0*(GLfloat)h/(GLfloat)w,
6.0*(GLfloat)h/(GLfloat)w,-6.0,6.0,-10.0,10.0);


glMatrixMode(GL_MODELVIEW);
glLoadIdentity;
}


void CALLBACK display(void)
{
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);


//先画个黄色材质
glLoadIdentity;
glTranslatef(-0.7,0.0,0.0);
glColor3f(1.0,1.0,0.0);
auxSolidSphere(1.0);


//再在黄球右边2.7处画个红色
glLoadIdentity;
glRotatef(-60.0,1.0,0.0,0.0);
glTranslatef(2.7,0.0,0.0);
glColor3f(1.0,0.0,0.0);
auxSolidSphere(1.0);


//再再黄球左边(两球的间)靠后位置画个青色 3角锥
glLoadIdentity;
glTranslatef(-1.0,-1.0,-5.0);
glRotatef(30.0,1.0,0.0,0.0);
glColor3f(0.0,1.0,1.0);
auxSolidCone(2.0,2.0);


glFlush;
}
void (void)
{
myinit;


auxReshapeFunc(reshape);
auxMainLoop(display);
}
//end of sample
////////////////////////////////////////////////////////////
通过这个例子我们除了可以熟悉glColorMaterial使用还可以体会到OPENGL在消隐方面为我们做工作我们前面用彩色平面绘制 3角锥例子吗?那里可是哪个平面后画哪个平面遮挡以前平面这里我们看到虽然 3角锥虽然最后画出但是OPENGL消隐功能已经保证乐它实际应该被消隐你可以试试取消myinit中消隐两句那么 3角锥就跑到前面来乐呵呵





OPENGL位图和图象


位图定义区别OPENGL中位图是指用每个象素只有位信息;
而图象个象素可以包括多个信息(R、G、B、Alpha值)
另外位图可以用于掩码遮掩别图象而图象数据则简单覆盖先前
存在数据或者和的融合


()位图(BITMAP)和(FONT)
常常用来对窗口相应区域屏蔽比如当前颜色为红色则在矩阵中元素值为
1地方用红色取代0地方保持不变位图常用在显示


光栅位置:
void glRasterPos{234}{sd}[v](TYPE x,TYPE y,TYPE z,TYPE w);
设置当前所画位图或图象原点般颜色设置应该放在glRasterPos*
前面则紧跟其后位图都继承当前设置这种颜色


位图显示:
void glBitmap(GLsizei width,GLsizei height,GLfloat xbo,GLflaot ybo,
GLfloat xbi,GLfloat ybi,const GLu *bitmap);
xbo,ybo定义位图原点详细可参见例子:
//////////////////////////////////////////////////////////////////
//sample.cpp
# "glos.h"
# <GL/gl.h>
# <GL/glaux.h>
# "windows.h"
void myinit(void);
void CALLBACK display(void);
void CALLBACK reshape(GLsizei w,GLsizei h);
//定义位图从下到上(即第个数据是字模最下依次类推):
// 11111111
// 11111111
// 11000011
// 11000011
// 11000011
// 11111111
// 11111111
// 11000011
// 11000011
// 11000011
// 11111111
// 11111111
//组成个 8 字
GLu rasters[12]={0xff,0xff,0xc3,0xc3,0xc3,0xff,0xff,
0xc3,0xc3,0xc3,0xff,0xff};


void myinit(void)
{
auxInitDisplayMode(AUX_SINGLE|AUX_RGBA);
auxInitPosition(0,0,500,500);
auxInitWindow("sample1");
glClearColor(0.0,0.0,0.0,0.0);
glClear(GL_COLOR_BUFFER_BIT);


//描述位图数据在计算机内存中存储方式不必深究
glPixelStorei(GL_UNPACK_ALIGNMENT,1);


}


void CALLBACK reshape(GLsizei w,GLsizei h)
{


glViewport(0,0,w,h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity;
glOrtho(0,w,0,h,-1.0,1.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity;
}


void CALLBACK display(void)
{
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);


//先定义红色填充:
glColor3f(1.0,0.0,1.0);
glRasterPos2i(100,200);
//在2个区别位置绘制 8 (紫色)
glBitmap(8,12,0.0,0.0,20.0,20.0,rasters);
glBitmap(8,12,0.0,0.0,20.0,20.0,rasters);


//绘制另个 8 (黄色)
glColor3f(1.0,1.0,0.0);
glRasterPos2i(150,200);
glBitmap(8,12,0.0,0.0,0.0,0.0,rasters);


glFlush;
}
void (void)
{
myinit;


auxReshapeFunc(reshape);
auxMainLoop(display);
}
//end of sample
///////////////////////////////////////////////////////


( 2)图象


显示只是个小内容我想大家也许会更关心图象显示
1.象素读写
OPENGL提供基本象素读写:
void glReadPixels( GL x, GL y, GLsizei width, GLsizei height,
GLenum format, GLenum type, GLvoid *pixels );
参数(x,y)定义图象区域左下角坐标width height描述图象宽高
pixel是指针指向图象数据format指出数据元素格式(索引或
R、G、B、A值):


format: 介绍说明:
GL_INDEX 单个颜色索引
GL_RGB 依次 红、绿、蓝分量
GL_RED 单个红色分量
GL_GREEN 单个绿色分量


GL_BLUE 单个蓝色分量
GL_ALPHA 单个Alpha值
GL_LUMINANCE_ALPHA
GL_STENCIL_INDEX 单个模板索引
GL_DEPTH_COMPONENT 单个深度分量


而type指出元素数据类型:
type:
GL_UNSIGNED_BYTE 无符号8位整数
GL_BYTE 8位整数
GL_BITMAP 无符号8位整数中单个数位
GL_UNSIGNED_SHORT 无符号16位整数
GL_SHORT 16位整数
GL_UNSIGNED_INT 无符号32位整数
GL_INT 32位整数
GL_FLOAT 单精度浮点数


类似写象素:
void glDrawPixels( GLsizei width, GLsizei height, GLenum format,
GLenum type, const GLvoid *pixels );


2.象素拷贝
void glCopyPixels( GL x, GL y, GLsizei width,
GLsizei height, GLenum type );
这个很类似先用glReadPixels然后glDrawPixels但是它不消耗
系统内存只是拷贝
type可以是:GL_COLOR GL_STENCIL GL_DEPTH
在拷贝前type要按如下方式转换成format:
1)type为GL_DEPTH GL_STENCIL 那么format 对应应该是GL_DEPTH_COMPONENT
或GL_STENCIL_INDEX
2)type为GL_COLOR 那么format 应该是GL_RGB或GL_COLOR_INDEX


3.图象缩放
void glPixelZoom(GLfloat zoomx,GLfloat zoomy);
zoomx zoomy是X Y方向缩放因子缺省是1.0
# "glos.h"
# <GL/gl.h>
# <GL/glaux.h>
# "windows.h"
void myinit(void);
void CALLBACK display(void);
void CALLBACK reshape(GLsizei w,GLsizei h);


void myinit(void)
{
auxInitDisplayMode(AUX_SINGLE|AUX_RGBA);
auxInitPosition(0,0,500,500);
auxInitWindow("sample1");
glClearColor(0.0,0.0,0.0,0.0);
glClear(GL_COLOR_BUFFER_BIT);


// glPixelStorei(GL_UNPACK_ALIGNMENT,1);


}


void CALLBACK reshape(GLsizei w,GLsizei h)
{


glViewport(0,0,w,h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity;


(w<=h)
gluOrtho2D(0.0,15.0,0.0,15.0*(GLfloat)h/(GLfloat)w);

gluOrtho2D(0.0,15.0*(GLfloat)w/(GLfloat)h,0.0,15.0);


glMatrixMode(GL_MODELVIEW);
glLoadIdentity;
}


void draw
{
//绘制个彩色 3角形(2D)
glBegin(GL_TRIANGLES);
glColor3f(1.0,0.0,0.0);
glVertex2f(2.0,3.0);
glColor3f(0.0,1.0,0.0);
glVertex2f(12.0,3.0);
glColor3f(0.0,0.0,1.0);
glVertex2f(7.0,12.0);
glEnd;
}


void CALLBACK display(void)
{
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);


//在屏幕上方绘制原始图象
glPushMatrix;
glLoadIdentity;
glTranslatef(4.0,8.0,0.0);
glScalef(0.5,0.5,0.5);
draw;
glPopMatrix;


 i;
for(i=0;i<5;i)
{
//循环5次画出5个拷贝
//先定义显示缩放因子(递增)
glPixelZoom(1.0+0.1*i,1.0+0.1*i);
//再定义拷贝原点(越来越向右上)
glRasterPos2i(1+i*2,i);
//图象拷贝
glCopyPixels(160,310,180,160,GL_COLOR);
}


glFlush;
}
void (void)
{
myinit;


auxReshapeFunc(reshape);
auxMainLoop(display);
}
//end of sample
////////////////////////////////////////////////////////////


这个例子在屏幕上方中央绘制个彩色 3角然后在下面从左到右依次绘制它拷贝拷贝位置不断向右上方向而且(通过增加缩放因子)新拷贝变越来越大
当然后绘制拷贝会遮盖前面图形





OPENGL纹理
在3D图形中纹理映射是广泛使用纹理映射也是相当复杂过程:
 定义纹理
2 控制滤波
3 介绍说明映射方式
4 绘制场景给出顶点纹理坐标和几何坐标
注意!!纹理映射只能在RGBA模式下使用不适用于颜色索引模式


1.纹理定义
void glTexImage2D( GLenum target, GL level, GL components,
GLsizei width, GLsizei height, GL border,
GLenum format, GLenum type, const GLvoid *pixels );
定义个 2维纹理映射
target是常数 GL_TEXTURE_2D
level表示多级分辨率纹理图象级数若只有种分辨率level为0
components是从1到4整数1:选择R;2:选择R A;3:选择R G B;
4:选择R G B A;
width height是纹理尺寸
format和type描述映射格式和数据类型它们和前面讲glDrawPixels
意义相同你可以把纹理当成贴图来看待
另外还有维纹理定义:
void glTexImage1D( GLenum target, GL level, GL components,
GLsizei width, GL border, GLenum format,
GLenum type, const GLvoid *pixels );
区别的处在于target是常数GL_TEXTURE_1D例外提供数据应该是
般纹理数据维数应该是2幂次有时还要根据类型加上边界数据


2.纹理控制(滤波和重复和缩限)
所有纹理控制通过:
void glTexParameter{}[v](GLenum target,GLenum pname,TYPE param);
来实现target可以是GL_TEXTURE_1D GL_TEXTURE_2D来介绍说明是维还是 2维
纹理pname和param可能取值见下:
pname: param:
GL_TEXTURE_WRAP_S GL_CLAMP
GL_REPEAT


GL_TEXTURE_WRAP_T GL_CLAMP
GL_REPEAT
GL_TEXTURE_MAG_FILTER GL_NEAREST
GL_LINEAR
GL_TEXTURE_MIN_FILTER GL_NEAREST
GL_NEAREST_MIPMAP_NEAREST
GL_NEAREST_MIPMAP_LINEAR
GL_LINEAR_MIPMAP_NEAREST
GL_LINEAR_MIPMAP_LINEAR
2.1 滤波
原始纹理图象是个方形图象把它映射到奇形怪状物体上般不可能图象
个象素对应屏幕个象素因此局部放大缩小时就要定义合适
波方式(以2D为例):
void glTexParameter(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
void glTexParameter(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
前者是放大滤波(GL_TEXTURE_MAG_FILTER)
后者是缩小滤波(GL_TEXTURE_MIN_FILTER);
另外GL_NEAREST是利用最坐标最靠近象素中心纹理元素这有可能使图样
走型但计算速度快;GL_LINEAR利用线形插值效果好但计算量大


2.2重复和缩限
纹理映射可以重复映射或者缩限映射重复映射时纹理可以在自己坐标S T方
向重复
对于重复映射:
void glTexParameterfv(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT);
void glTexParameterfv(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT);
参数GL_REPEAT改为GL_CLAMP则缩限所有大于1纹理元素值置为1所有小于
0纹理元素值置为0


3. 映射方式
处理纹理本身图案颜色和物体本身颜色关系:
void glTexEnv{}[v](GLenum target,GLenum pname,TYPE param);
target必须是GL_TEXTURE_ENV;


pname是GL_TEXTURE_ENV_MODE则param可以是 GL_DECAL GL_MODULATE或
GL_BLEND介绍说明纹理值和原来颜色区别处理方式
pname是GL_TEXTURE_ENV_COLOR则参数param是包含4个浮点数(R、G、B、A)
这些值只在采用GL_BLEND纹理时才采用


4. 纹理坐标
坐标定义:纹理图象是方形纹理坐标可定义成s,t,r,q坐标仿照齐次
坐标系x,y,z,w坐标
void glTexCoord{1234}{sd}[v](TYPE coords);
设置当前纹理坐标此后glVertex*所产生顶点都赋予当前纹理坐标


5. 坐标自动产生
有时不需要为每个物体顶点赋予纹理坐标可以使用
void glTexGen{}(GLenum coord,GLenum pname,TYPE param);
coord为:GL_S GL_T GL_R或GL_Q指明哪个坐标自动产生


pname为GL_TEXTURE_GEN_MODE时
param为常数:GL_OBJECT_LINEAR GL_EYE_LINEAR或GL_SPHERE_MAP它们决定用
哪个来产生纹理坐标


pname为GL_OBJECT_PLANE或GL_EYE_PLANEparam时个指向参数指针


先请看个简单例子:
////////////////////////////////////////////
//sample.cpp
# "glos.h"
# <GL/gl.h>
# <GL/glaux.h>
# "windows.h"
void myinit(void);
void CALLBACK display(void);
void CALLBACK reshape(GLsizei w,GLsizei h);


//创建纹理图象
# TEXTUREWIDTH 64
# TEXTUREHEIGHT 64
GLu Texture[TEXTUREWIDTH][TEXTUREHEIGHT][3];
void makeTexture(void)
{
 i,j,r,g,b;
for(i=0;i<TEXTUREWIDTH;i)
{
for(j=0;j<TEXTUREHEIGHT;j)
{
r=(i*j)%255;
g=(4*i)%255;
b=(4*j)%255;
Texture[j][0]=(GLu)r;
Texture[j][1]=(GLu)g;
Texture[j][2]=(GLu)b;
}
}
}



void myinit(void)
{
auxInitDisplayMode(AUX_SINGLE|AUX_RGBA);
auxInitPosition(0,0,500,500);
auxInitWindow("sample1");
glClearColor(0.0,0.0,0.0,0.0);
glClear(GL_COLOR_BUFFER_BIT);


//创建纹理图象原始数据保存在Texture
makeTexture;
glPixelStorei(GL_UNPACK_ALIGNMENT,1);


//定义 2维纹理
glTexImage2D(GL_TEXTURE_2D,0,3,TEXTUREWIDTH,
TEXTUREHEIGHT,0,GL_RGB,GL_UNSIGNED_BYTE,
&Texture[0][0][0]);
//控制滤波
glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP);
glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP);
glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);


//介绍说明映射方式
glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_DECAL);


//这个应该很熟了启用纹理模式
glEnable(GL_TEXTURE_2D);
// glShadeModel(GL_FLAT);
}


void CALLBACK reshape(GLsizei w,GLsizei h)
{


glViewport(0,0,w,h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity;
//定义立体视景体
gluPerspective(60.0,1.0*(GLfloat)w/(GLfloat)h,1.0,30.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity;
glTranslatef(0.0,0.0,-3.6);
}


void CALLBACK display(void)
{
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);


glBegin(GL_QUADS);//绘制 4边形
//先绘制正方形用来显示实际未变形纹理图样
glTexCoord2f(0.0,0.0);glVertex3f(-2.0,-1.0,0.0);
glTexCoord2f(0.0,1.0);glVertex3f(-2.0,1.0,0.0);
glTexCoord2f(1.0,1.0);glVertex3f(0.0,1.0,0.0);
glTexCoord2f(1.0,0.0);glVertex3f(0.0,-1.0,0.0);


//绘制个不规则 4边形用来显示纹理是如何随物体形状而变形
glTexCoord2f(0.0,0.0);glVertex3f(0.0,-1.0,0.0);
glTexCoord2f(0.0,1.0);glVertex3f(0.0,1.0,0.0);
glTexCoord2f(1.0,1.0);glVertex3f(1.41421,1.0,-1.41421);
glTexCoord2f(1.0,0.0);glVertex3f(1.41421,-1.0,-1.41421);


glEnd;


glFlush;
}
void (void)
{
myinit;


auxReshapeFunc(reshape);
auxMainLoop(display);
}
//end of sample
///////////////////////////////////////////////////////////
从例子来看除了纹理定义和控制比较麻烦和不容易理解外其应用是十分方便只须从纹理坐标系选出合适点附在实际物体顶点上即可对于复杂纹理定义和控制你也可以自行改变些参数看看效果如何例如把GL_LINEAR改成GL_NEAREST则纹理明显变粗糙但计算结果却快
你也可以改动glTexCoord2f参数看看如何选定纹理部分(例子中是选定全部纹理)来贴图例如1.0改成0.5则选择实际纹理左上1/4部分来贴图
下次将给出个更复杂纹理应用例子和介绍说明18:03 98-1-21





这次将结束纹理内容紧接上次在上次平面纹理贴图中我们先
定义了(维或 2维...)来定义纹理数据所以纹理本身
个N维空间有自己坐标和顶点在上次例子中我们学会了
如何把纹理数据中坐标和屏幕物体坐标相结合就象把块布料扯成
合适形状贴在物体表面而上次唯没有使用是纹理坐标
动产生(最后个给出)意义是产生个环境纹理所有
环境内物体都赋予此纹理很象个特殊光源
/////////////////////////////////////////////////////////////
//sample.cpp
# "glos.h"
# <GL/gl.h>
# <GL/glaux.h>
# "windows.h"
void myinit(void);
void CALLBACK display(void);
void CALLBACK reshape(GLsizei w,GLsizei h);


//定义维纹理数据从生成来看保持红色、兰色分量255(MAX)
//所以是渐变紫色纹理饱和度不断变化
# TEXTUREWIDTH 64
GLu Texture[3*TEXTUREWIDTH];
void makeTexture(void)
{
 i;
for(i=0;i<TEXTUREWIDTH;i)
{
Texture[3*i]=255;
Texture[3*i+1]=255-2*i;
Texture[3*i+2]=255;
}
}
GLfloat sgenparams={1.0,1.0,1.0,0.0};


void myinit(void)
{
auxInitDisplayMode(AUX_SINGLE|AUX_RGBA);
auxInitPosition(0,0,500,500);
auxInitWindow("sample1");
glClearColor(0.0,0.0,0.0,0.0);
glClear(GL_COLOR_BUFFER_BIT);


//创建纹理
makeTexture;
glPixelStorei(GL_UNPACK_ALIGNMENT,1);
//控制纹理
glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_MODULATE);
glTexParameterf(GL_TEXTURE_1D,GL_TEXTURE_WRAP_S,GL_REPEAT);
glTexParameterf(GL_TEXTURE_1D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameterf(GL_TEXTURE_1D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexImage1D(GL_TEXTURE_1D,0,3,TEXTUREWIDTH,0,
GL_RGB,GL_UNSIGNED_BYTE,Texture);
//唯和前面例子区别地方:启用纹理坐标自动产生生成环境纹理
//纹理方向S
glTexGeni(GL_S,GL_TEXTURE_GEN_MODE,GL_OBJECT_LINEAR);
glTexGenfv(GL_S,GL_OBJECT_PLANE,sgenparams);
//启用纹理
glEnable(GL_TEXTURE_1D);
glEnable(GL_TEXTURE_GEN_S);



//启用消隐
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);


//些绘图控制详细可参阅VC5联机帮助
glEnable(GL_CULL_FACE);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glEnable(GL_AUTO_NORMAL);
glEnable(GL_NORMALIZE);
glFrontFace(GL_CW);
glCullFace(GL_BACK);
glMaterialf(GL_FRONT,GL_SHININESS,64.0);
// glShadeModel(GL_FLAT);
}


void CALLBACK reshape(GLsizei w,GLsizei h)
{


glViewport(0,0,w,h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity;


(w<=h)
glOrtho(-4.0,4.0,-4.0*(GLfloat)h/(GLfloat)w,
4.0*(GLfloat)h/(GLfloat)w,-4.0,4.0);

glOrtho(-4.0*(GLfloat)h/(GLfloat)w,
4.0*(GLfloat)h/(GLfloat)w,-4.0,4.0,-4.0,4.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity;
}


void CALLBACK display(void)
{
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glPushMatrix;
glRotatef(30.0,1.0,0.0,0.0);
//功能强大辅助库:呵呵画出个大茶壶
auxSolidTeapot(1.5);
glPopMatrix;
glFlush;
}
void (void)
{
myinit;


auxReshapeFunc(reshape);
auxMainLoop(display);
}
//end of sample
////////////////////////////////////////////////////////////
至此纹理全部内容已经完毕从运行结果来看个物体全部进行了表面纹理映射





此次讲解OPENGL复杂建模方式将分几个部分完成这篇先介绍图原扩展:
如何利用专用精确绘制平面图形下次会讲解如何利使用方法向量生成曲面
1.点和线
void glPoSize(GLfloat size);
设置点宽度size必须>0缺省1


void glLineWidth(GLfoat width);
设置线宽width>0缺省为1


void glLineStipple(GL factor,GLu pattern);
设置线模式factor用于对模式进行拉伸比例因子pattern是线模式
例如11001100是虚线(1绘制0不绘制)


必须要启用glEnable(GL_LINE_STIPPLE)才能使用以上不再使用时
glDisable(GL_LINE_STIPPLE)关闭这和以前glEnable;glDisable;
使用方法都是类似请看下面例子:
///////////////////////////////////////////////////////////////////
//sample.cpp
# "glos.h"
# <GL/gl.h>


# <GL/glaux.h>
# "windows.h"
void myinit(void);
void CALLBACK display(void);
void CALLBACK reshape(GLsizei w,GLsizei h);



void myinit(void)
{
auxInitDisplayMode(AUX_SINGLE|AUX_RGBA);
auxInitPosition(0,0,600,500);
auxInitWindow("sample1");
glClearColor(0.0,0.0,0.0,0.0);
glClear(GL_COLOR_BUFFER_BIT);


glShadeModel(GL_FLAT);
}
/*
void CALLBACK reshape(GLsizei w,GLsizei h)
{


glViewport(0,0,w,h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity;


(w<=h)
glOrtho(-4.0,4.0,-4.0*(GLfloat)h/(GLfloat)w,
4.0*(GLfloat)h/(GLfloat)w,-4.0,4.0);

glOrtho(-4.0*(GLfloat)h/(GLfloat)w,
4.0*(GLfloat)h/(GLfloat)w,-4.0,4.0,-4.0,4.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity;
}
*/


//自定义绘制直线参数为起始点和终止点坐标
void line2i(GL x1,GL y1,GL x2,GL y2)
{
glBegin(GL_LINES);
glVertex2f(x1,y1);
glVertex2f(x2,y2);
glEnd;
}


void CALLBACK display(void)
{
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);


//首先绘制系列点大小不断增加
 i;
glColor3f(0.8,0.6,0.4);
for(i=1;i<=10;i)
{
glPoSize(i*2);
glBegin(GL_POINTS);
glVertex2f(30.0+((GLfloat)i*50.0),330.0);
glEnd;
}
//再绘制两条虚线第 2条比第条松散由pattern参数即可看出
glLineWidth(1.0);
glEnable(GL_LINE_STIPPLE);
glLineStipple(1,0x0f0f);//间隔1位
glColor3f(1.0,0.0,0.0);
line2i(20,250,250,250);
glLineStipple(1,0x00ff);//间隔2位
glColor3f(0.0,0.0,1.0);
line2i(300,250,550,250);


//改变线绘制宽度效果--加宽
//重新画出上面两条虚线
glLineWidth(5.0);
glEnable(GL_LINE_STIPPLE);
glLineStipple(1,0x0f0f);
glColor3f(1.0,0.0,0.0);
line2i(50,150,250,150);
glLineStipple(1,0x00ff);
glColor3f(0.0,0.0,1.0);
line2i(300,150,550,150);


glFlush;
}
void (void)
{
myinit;


// auxReshapeFunc(reshape);
auxMainLoop(display);
}
//end of sample
//////////////////////////////////////////////


2.多边形
void glPolygonMode(GLenum face,GLenum mode);
控制多边形指定面绘图模式
face为:GL_FRONT GL_BACK或GL_FRONT_AND BACK
mode为:GL_POINT GL_LINE或GL_FILL表示多边型轮廓点、轮廓线和填充模式
绘制方式缺省是填充方式


void glPolygonStipple(const GLu *mask);
其中mask必须是指向32*32位图指针1是绘制、0不绘制


使用上述也要:
glEnable(GL_POLYGON-STIPPLE);
glDisable(GL_POLYGON_STIPPLE);
请看下面例子:
/////////////////////////////////////////////
//sample.cpp
# "glos.h"
# <GL/gl.h>
# <GL/glaux.h>
# "windows.h"
void myinit(void);
void CALLBACK display(void);
void CALLBACK reshape(GLsizei w,GLsizei h);


//定义填充模式32*32点阵
GLu pattern={
0x00,0x01,0x80,0x00,
0x00,0x03,0xc0,0x00,
0x00,0x07,0xe0,0x00,
0x00,0x0f,0xf0,0x00,
0x00,0x1f,0xf8,0x00,
0x00,0x3f,0xfc,0x00,
0x00,0x7f,0xfe,0x00,
0x00,0xff,0xff,0x00,
0x01,0xff,0xff,0x80,
0x03,0xff,0xff,0xc0,
0x07,0xff,0xff,0xe0,
0x0f,0xff,0xff,0xf0,
0x1f,0xff,0xff,0xf8,
0x3f,0xff,0xff,0xfc,
0x7f,0xff,0xff,0xfe,
0xff,0xff,0xff,0xff,


0xff,0xff,0xff,0xff,
0x7f,0xff,0xff,0xfe,
0x3f,0xff,0xff,0xfc,
0x1f,0xff,0xff,0xf8,
0x0f,0xff,0xff,0xf0,
0x07,0xff,0xff,0xe0,
0x03,0xff,0xff,0xc0,
0x01,0xff,0xff,0x80,
0x00,0xff,0xff,0x00,
0x00,0x7f,0xfe,0x00,
0x00,0x3f,0xfc,0x00,
0x00,0x1f,0xf8,0x00,
0x00,0x0f,0xf0,0x00,
0x00,0x07,0xe0,0x00,
0x00,0x03,0xc0,0x00,
0x00,0x01,0x80,0x00
};


void myinit(void)
{
auxInitDisplayMode(AUX_SINGLE|AUX_RGBA);
auxInitPosition(0,0,400,400);
auxInitWindow("sample1");
glClearColor(0.0,0.0,0.0,0.0);
glClear(GL_COLOR_BUFFER_BIT);


glShadeModel(GL_FLAT);
}
/*
void CALLBACK reshape(GLsizei w,GLsizei h)
{


glViewport(0,0,w,h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity;


(w<=h)
glOrtho(-4.0,4.0,-4.0*(GLfloat)h/(GLfloat)w,
4.0*(GLfloat)h/(GLfloat)w,-4.0,4.0);

glOrtho(-4.0*(GLfloat)h/(GLfloat)w,
4.0*(GLfloat)h/(GLfloat)w,-4.0,4.0,-4.0,4.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity;
}
*/


void CALLBACK display(void)
{
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
//选用兰色作为填充色
glColor3f(0.0,0.0,1.0);
//启用多边形绘制模式
glEnable(GL_POLYGON_STIPPLE);
//利用定义好填充模式绘制多边形
glPolygonStipple(pattern);
//绘制长方形
glRectf(48.0,80.0,210.0,305.0);


glFlush;
}
void (void)
{
myinit;


// auxReshapeFunc(reshape);


auxMainLoop(display);
}
//end of sample
例子中运行结果是给出个表面有定义图样长方形





这里讲解OPENGL曲线生成
1.曲线定义
void glMap1{fd}(GLenum target,TYPE u1,TYPE u2,GL stride,
GL order,const TYPE *pos);


target指出控制点意义以及在pos参数中需要多少值具体如下:


target 意义
GL_MAP1_VERTEX_3 X Y Z顶点坐标
GL_MAP1_VERTEX_4 X Y Z W顶点坐标
GL_MAP1_INDEX 颜色索引
GL_MAP1_COLOR_4 R G B A
GL_MAP1_NORMAL 法向量
GL_MAP1_TEXTURE_COORD_1 S 纹理坐标
GL_MAP1_TEXTURE_COORD_2 S T纹理坐标
GL_MAP1_TEXTURE_COORD_3 S T R纹理坐标


u1,u2是曲线变量U范围(具体可以参阅图形学书籍)般是0到1
stride是跨度表示pos中控制点偏移量(或说是控制点维数)
order是阶数和控制点数
pos是控制点坐标
曲线定义后要启用才能进行绘制同样用glEnable,glDisable
2.曲线计算绘制
void glEvalCoord1{fd}[v](TYPE u);
利用控制点产生曲线U坐标下某点坐标次只能产生个坐标
曲线绘制思路方法是让U变化从0到1(步长自定)然后把这些坐标
用直线连接起来
用以上这两个就可以完成绘制曲线功能


另外还有两个可以实现类似功能:
void glMapGrid1{fd}(GL n,TYPE u1,TYPE u2);
定义个空间网格从u1到u2分为n步是等间隔(曲线参数)
void glEvalMesh1(GLenum mode,GL p1,GL p2);
计算并绘制坐标点mode可以是GL_POINT、GL_LINE即延曲线绘点或连接直线段
它等价于:
glBegin(GL_POINT);
for(i=p1;i<=p2;i)
glEvalCoord1(u1+i*(u2-u1)/n);
glEnd;
下面给出个BEZIER曲线例子:
////////////////////////////////////////////////////////////////////
//sample.cpp
# "glos.h"
# <GL/gl.h>
# <GL/glaux.h>
# "windows.h"
void myinit(void);
void CALLBACK display(void);
void CALLBACK reshape(GLsizei w,GLsizei h);


//定义 4个控制点坐标
GLfloat pos[4][3]={
{-4.0,-4.0,0.0},{-2.0,4.0,0.0},{2.0,-4.0,0.0},{4.0,4.0,0.0}};


void myinit(void)
{


auxInitDisplayMode(AUX_SINGLE|AUX_RGBA);
auxInitPosition(0,0,500,500);
auxInitWindow("sample1");
glClearColor(0.0,0.0,0.0,0.0);
glClear(GL_COLOR_BUFFER_BIT);


//定义曲线并启用绘制曲线模式
glMap1f(GL_MAP1_VERTEX_3,0.0,1.0,3,4,&pos[0][0]);
glEnable(GL_MAP1_VERTEX_3);


glShadeModel(GL_FLAT);
}


void CALLBACK reshape(GLsizei w,GLsizei h)
{


glViewport(0,0,w,h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity;


(w<=h)
glOrtho(-5.0,5.0,-5.0*(GLfloat)h/(GLfloat)w,
5.0*(GLfloat)h/(GLfloat)w,-5.0,5.0);

glOrtho(-5.0*(GLfloat)h/(GLfloat)w,
5.0*(GLfloat)h/(GLfloat)w,-5.0,5.0,-5.0,5.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity;
}



void CALLBACK display(void)
{
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glColor3f(0.0,0.0,1.0);
glBegin(GL_LINE_STRIP);
//首先以30步直线段连接来绘制曲线注意使用GL_LINE_STRIP来连接直线段
 i;
for(i=0;i<=30;i)
glEvalCoord1f((GLfloat)i/30.0);
glEnd;


//下面绘制出4个控制点
glPoSize(4.0);
glColor3f(1.0,0.0,0.0);
glBegin(GL_POINTS);
for(i=0;i<4;i)
glVertex3fv(&pos[0]);
glEnd;


glFlush;



}
void (void)
{
myinit;


auxReshapeFunc(reshape);
auxMainLoop(display);
}
//end of sample
本例子绘制出个有4个控制点BEZIER曲线曲线经过头尾两个控制点中间曲线形状由控制点次序和位置决定总的落在其包围 4边形以内
下次将会用大篇幅介绍曲面生成和其表面纹理、颜色应用






曲面构造可以是网格线和填充曲面形式其实和曲线很类似只是变为
2维而已
1.曲面定义
void glMap2{fd}(GLenum target,TYPE u1,TYPE u2,GL ustride,GL uorder,
TYPE v1,TYPE v2,GL vstride,GL vorder,TYPE pos);
target定义同上次介绍曲线中target定义
U V是 2维曲面坐标
uorder,vorder;ustride,vstride定义都类似曲线定义
pos是控制点坐标


2.曲面任意计算
void glEvalCoord2{fd}[v](TYPE u,TYPE v);
以曲线坐标U V来计算曲面内任意世界坐标位置


3.曲面绘制控制
void glMapGrid2{fd}(GLenum nu,TYPE u1,TYPE u2,GLenum nv,TYPE v1,TYPE v2);
定义曲面参数空间均匀网格从u1到u2分为等间隔nu步从v1到v2分为等间隔nv步


下面给出个以网格线描绘曲面例子:
////////////////////////////////////////////////////////////
//sample.cpp
# "glos.h"
# <GL/gl.h>
# <GL/glaux.h>
# "windows.h"
void myinit(void);
void CALLBACK display(void);
void CALLBACK reshape(GLsizei w,GLsizei h);




//控制点坐标
GLfloat pos[4][4][3]={
{{-1.5,-1.5,2.0},{-0.5,-1.5,2.0},
{0.5,-1.5,-1.0},{1.5,-1.5,2.0}},
{{-1.5,-0.5,1.0},{-0.5,1.5,2.0},
{0.5,0.5,1.0},{1.5,-0.5,-1.0}},
{{-1.5,0.5,2.0},{-0.5,0.5,1.0},
{0.5,0.5,3.0},{1.5,-1.5,1.5}},
{{-1.5,1.5,-2.0},{-0.5,1.5,-2.0},
{0.5,0.5,1.0},{1.5,1.5,-1.0}}};


//为了清楚显示控制点而设置组颜色
GLfloat color[4][3]={
{1.0,0.0,0.0},{0.0,1.0,0.0},{0.0,0.0,1.0},{1.0,1.0,1.0}};


void myinit(void)
{


auxInitDisplayMode(AUX_SINGLE|AUX_RGBA);
auxInitPosition(0,0,500,500);
auxInitWindow("sample1");
glClearColor(0.0,0.0,0.0,0.0);
glClear(GL_COLOR_BUFFER_BIT);


//利用glEnable来启用曲面模式
glMap2f(GL_MAP2_VERTEX_3,0,1,3,4,0,1,12,4,&pos[0][0][0]);
glEnable(GL_MAP2_VERTEX_3);


glMapGrid2f(20,0.0,1.0,20,0.0,1.0);


glEnable(GL_DEPTH_TEST);
}


void CALLBACK reshape(GLsizei w,GLsizei h)
{


glViewport(0,0,w,h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity;


(w<=h)
glOrtho(-5.0,5.0,-5.0*(GLfloat)h/(GLfloat)w,
5.0*(GLfloat)h/(GLfloat)w,-5.0,5.0);

glOrtho(-5.0*(GLfloat)h/(GLfloat)w,
5.0*(GLfloat)h/(GLfloat)w,-5.0,5.0,-5.0,5.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity;
}



void CALLBACK display(void)
{
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glColor3f(0.0,0.0,1.0);
glPushMatrix;
glRotatef(35.0,1.0,1.0,1.0);
//用直线段连接描绘曲面结构
glBegin(GL_LINE_STRIP);
 i,j;
//在U V方向各画出8条网格线用以构造曲面结构
for(j=0;j<=8;j)
{
//在U方向用30条直线段描绘条曲线
glBegin(GL_LINE_STRIP);
for(i=0;i<=30;i)
glEvalCoord2f((GLfloat)i/30.0,(GLfloat)j/8.0);
glEnd;


//在V方向用30条直线段描绘条曲线
glBegin(GL_LINE_STRIP);
for(i=0;i<=30;i)
glEvalCoord2f((GLfloat)j/8.0,(GLfloat)i/30.0);
glEnd;
}


//用区别颜色把控制点显示出来
glPoSize(4.0);
glBegin(GL_POINTS);
for(i=0;i<4;i)
for(j=0;j<4;j)
{
glColor3fv(color);
glVertex3fv(&pos[j][0]);
}
glEnd;


glPopMatrix;
glFlush;
}
void (void)
{
myinit;


auxReshapeFunc(reshape);
auxMainLoop(display);
}
//end of sample
///////////////////////////////////////////////////////


应用中常常不满足曲面框架结构下面就介绍填充曲面绘制思路方法:


void glEvalMesh2(GLenum mode,GL p1,GL p2,GL q1,GL q2);
把用glMapGrid2{fd}设置网格应用到已经启用曲面计算上
mode可以是GL_POINT GL_LINE GL_FILL顾名思义GL_FILL就是生成填充曲面


这里给出个有光照处理BEZIER曲面例子(这个曲面除了绘制思路方法区别数学
形式和前面)
///////////////////////////////////////////////////////
//sample.cpp
# "glos.h"
# <GL/gl.h>
# <GL/glaux.h>
# "windows.h"
void myinit(void);
void CALLBACK display(void);
void CALLBACK reshape(GLsizei w,GLsizei h);


GLfloat pos[4][4][3]={
{{-1.5,-1.5,2.0},{-0.5,-1.5,2.0},
{0.5,-1.5,-1.0},{1.5,-1.5,2.0}},
{{-1.5,-0.5,1.0},{-0.5,1.5,2.0},
{0.5,0.5,1.0},{1.5,-0.5,-1.0}},
{{-1.5,0.5,2.0},{-0.5,0.5,1.0},
{0.5,0.5,3.0},{1.5,-1.5,1.5}},
{{-1.5,1.5,-2.0},{-0.5,1.5,-2.0},
{0.5,0.5,1.0},{1.5,1.5,-1.0}}};
GLfloat color[4][3]={
{1.0,0.0,0.0},{0.0,1.0,0.0},{0.0,0.0,1.0},{1.0,1.0,1.0}};


//化光照、材质过程
void initlights(void)
{
GLfloat ambient={0.4,0.6,0.2,1.0};
GLfloat position={0.0,1.0,3.0,1.0};
GLfloat mat_dfuse={0.2,0.4,0.8,1.0};
GLfloat mat_specular={1.0,1.0,1.0,1.0};
GLfloat mat_shininess={80.0};
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glLightfv(GL_LIGHT0,GL_AMBIENT,ambient);
glLightfv(GL_LIGHT0,GL_POSITION,position);
glMaterialfv(GL_FRONT,GL_DIFFUSE,mat_dfuse);
glMaterialfv(GL_FRONT,GL_SPECULAR,mat_specular);
glMaterialfv(GL_FRONT,GL_SHININESS,mat_shininess);
}


void myinit(void)
{


auxInitDisplayMode(AUX_SINGLE|AUX_RGBA);
auxInitPosition(0,0,500,500);
auxInitWindow("sample1");
glClearColor(0.0,0.0,0.0,0.0);
glClear(GL_COLOR_BUFFER_BIT);


glMap2f(GL_MAP2_VERTEX_3,0,1,3,4,0,1,12,4,&pos[0][0][0]);
glEnable(GL_MAP2_VERTEX_3);
glEnable(GL_AUTO_NORMAL);
// glEnable(GL_NORMALIZE);
glMapGrid2f(20,0.0,1.0,20,0.0,1.0);


glEnable(GL_DEPTH_TEST);
//化光照、材质
initlights;
// glShadeModel(GL_FLAT);
}


void CALLBACK reshape(GLsizei w,GLsizei h)
{


glViewport(0,0,w,h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity;


(w<=h)
glOrtho(-5.0,5.0,-5.0*(GLfloat)h/(GLfloat)w,
5.0*(GLfloat)h/(GLfloat)w,-5.0,5.0);



glOrtho(-5.0*(GLfloat)h/(GLfloat)w,
5.0*(GLfloat)h/(GLfloat)w,-5.0,5.0,-5.0,5.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity;
}



void CALLBACK display(void)
{
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glColor3f(0.0,0.0,1.0);
glPushMatrix;
glRotatef(35.0,1.0,1.0,1.0);


//将原来网格绘制部分注释掉代替以填充曲面绘制思路方法
glEvalMesh2(GL_FILL,0,20,0,20);
 i,j;
/* for(j=0;j<=8;j)
{
glBegin(GL_LINE_STRIP);
for(i=0;i<=30;i)
glEvalCoord2f((GLfloat)i/30.0,(GLfloat)j/8.0);
glEnd;


glBegin(GL_LINE_STRIP);
for(i=0;i<=30;i)
glEvalCoord2f((GLfloat)j/8.0,(GLfloat)i/30.0);
glEnd;
}
*/


glPoSize(4.0);
glBegin(GL_POINTS);
for(i=0;i<4;i)
for(j=0;j<4;j)
{
glColor3fv(color);
glVertex3fv(&pos[j][0]);
}
glEnd;
glPopMatrix;
glFlush;



}
void (void)
{
myinit;


auxReshapeFunc(reshape);
auxMainLoop(display);
}
//end of sample
////////////////////////////////////////////////////////////////
个真正具有实体曲面就展现出来乐控制点区别可以控制曲面形状
可以看出OPENGL强大功能只用很少原代码就产生真实3D效果
在以此篇结束复杂建模前给出个绘制NURBS曲面(非均匀B样条曲面)例子
这里用到乐些OPENGL实用库提供专门所有新东东都在中做乐注
注释给出过程含义具体操作可以详细查阅联机手册
///////////////////////////////////////////////////////////////
//sample.cpp
# "glos.h"
# <GL/gl.h>
# <GL/glaux.h>
# "windows.h"


void myinit(void);
void CALLBACK display(void);
void CALLBACK reshape(GLsizei w,GLsizei h);


//定义组控制点存储空间
GLfloat pos[4][4][3];
//定义个指向NURBS曲面对象指针
GLUnurbsObj *theNurb;


//用来生成控制点过程取代被注释掉原来直接赋值方式生成控制点
void init_surface(void)
{
 u,v;
for(u=0;u<4;u)
{
for(v=0;v<4;v)
{
pos[v][0]=2.0*((GLfloat)u-1.5);
pos[v][1]=2.0*((GLfloat)v-1.5);
((u1||u2)&&(v1||v2))
pos[v][2]=3.0;

pos[v][2]=-3.0;
}
}
}
/*
GLfloat pos[4][4][3]={
{{-1.5,-1.5,2.0},{-0.5,-1.5,4.0},
{0.5,-1.5,3.0},{1.5,-1.5,2.0}},
{{-1.5,-0.5,3.0},{-0.5,1.5,4.0},
{0.5,0.5,2.0},{1.5,-0.5,-1.0}},
{{-1.5,0.5,2.0},{-0.5,0.5,4.0},
{0.5,0.5,5.0},{1.5,-1.5,1.5}},
{{-1.5,1.5,-2.0},{-0.5,1.5,3.0},
{0.5,0.5,1.0},{1.5,1.5,-1.0}}};
*/
GLfloat color[4][3]={
{1.0,0.0,0.0},{0.0,1.0,0.0},{0.0,0.0,1.0},{1.0,1.0,1.0}};



void initlights(void)
{
GLfloat ambient={0.4,0.6,0.2,1.0};
GLfloat position={0.0,1.0,3.0,1.0};
GLfloat mat_dfuse={0.2,0.4,0.8,1.0};
GLfloat mat_specular={1.0,1.0,1.0,1.0};
GLfloat mat_shininess={80.0};
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glLightfv(GL_LIGHT0,GL_AMBIENT,ambient);
glLightfv(GL_LIGHT0,GL_POSITION,position);
glMaterialfv(GL_FRONT,GL_DIFFUSE,mat_dfuse);
glMaterialfv(GL_FRONT,GL_SPECULAR,mat_specular);
glMaterialfv(GL_FRONT,GL_SHININESS,mat_shininess);
//首先化控制点
init_surface;
//创建个NURBS曲面对象
theNurb=gluNewNurbsRenderer;
//修改此曲面对象属性
gluNurbsProperty(theNurb,GLU_SAMPLING_TOLERANCE,25.0);
gluNurbsProperty(theNurb,GLU_DISPLAY_MODE,GLU_FILL);
}


void myinit(void)
{


auxInitDisplayMode(AUX_SINGLE|AUX_RGBA);
auxInitPosition(0,0,500,500);
auxInitWindow("sample1");
glClearColor(0.0,0.0,0.0,0.0);
glClear(GL_COLOR_BUFFER_BIT);


glMap2f(GL_MAP2_VERTEX_3,0,1,3,4,0,1,12,4,&pos[0][0][0]);
glEnable(GL_MAP2_VERTEX_3);
glEnable(GL_AUTO_NORMAL);
glEnable(GL_NORMALIZE);
glMapGrid2f(20,0.0,1.0,20,0.0,1.0);


glEnable(GL_DEPTH_TEST);
initlights;
// glShadeModel(GL_FLAT);
}


void CALLBACK reshape(GLsizei w,GLsizei h)
{


glViewport(0,0,w,h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity;


(w<=h)
glOrtho(-5.0,5.0,-5.0*(GLfloat)h/(GLfloat)w,
5.0*(GLfloat)h/(GLfloat)w,-5.0,5.0);

glOrtho(-5.0*(GLfloat)h/(GLfloat)w,
5.0*(GLfloat)h/(GLfloat)w,-5.0,5.0,-5.0,5.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity;
}



void CALLBACK display(void)
{
//B样条曲面(NURBS)控制向量可以参阅图形学相关书籍
GLfloat knots[8]={0.0,0.0,0.0,0.0,1.0,1.0,1.0,1.0};


glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glColor3f(0.0,0.0,1.0);
glPushMatrix;
glRotatef(35.0,1.0,1.0,1.0);
glRotatef(-60.0,1.0,0.0,0.0);
glScalef(0.5,0.5,0.5);


//注释掉原来曲面绘制代的以新NURBS曲面绘制
// glEvalMesh2(GL_FILL,0,20,0,20);
//定义曲面数学模型确定其形状
gluNurbsSurface(theNurb,


8,knots,
8,knots,
4*3,
3,
&pos[0][0][0],
4,4,
GL_MAP2_VERTEX_3);
//结束曲面绘制此结构很类似于标准glBegin...glEnd
gluEndSurface(theNurb);


 i,j;
glPoSize(4.0);
glBegin(GL_POINTS);
for(i=0;i<4;i)
for(j=0;j<4;j)
{
glColor3fv(color);
glVertex3fv(&pos[j][0]);
}
glEnd;
glPopMatrix;
glFlush;



}
void (void)
{
myinit;


auxReshapeFunc(reshape);
auxMainLoop(display);
}
//end of sample
//////////////////////////////////////////////////////////////////
至此复杂建模告于段落下次介绍特殊光照






为什么3D作图常常能产生另人震惊效果?利用3D作图你可以生成
现实中难得实现真实感受特别是些特殊光影效果
其实光源前面已经讲很全面了只是缺少些专门例子这里我们来稍微
加深下认识我们将在例子中看到个地方光源对区别物体发出区别
这在现实中是少见吧?


1.双面光照:
void glLightModeli(LIGHT_MODEL_TWO_SIDE,GL_TRUE);
光照计算通常是对多边形进行般设置光照条件总是对正面多边形
不考虑背面但是如果考虑个物体被劈开光源个数又会影响可见性那么
有必要对多边形双面都进行计算这就是上面功能;取消这功能只须把
第 3个参数改为GL_FALSE


2.聚光源
定义聚光源仍是利用glLightfv需要设定参数包括:光源位置、光源
发散半角和光源聚光方向


具体实现可以看下面例子:
//////////////////////////////////////////////////////////
//sample.cpp
# "glos.h"
# <GL/gl.h>
# <GL/glaux.h>
# "windows.h"


void myinit(void);
void CALLBACK display(void);
void CALLBACK reshape(GLsizei w,GLsizei h);


void initlights(void)
{
//定义物体材质特性数值
GLfloat mat_ambient={0.2,0.2,0.2,1.0};
GLfloat mat_dfuse={0.8,0.8,0.8,1.0};
GLfloat mat_specular={1.0,1.0,1.0,1.0};
GLfloat mat_shininess={80.0};


//定义第0个光源属性(这是平行环境光没有聚光效果)
GLfloat light0_dfuse={0.0,0.0,1.0,1.0};
GLfloat light0_position={1.0,1.0,1.0,0.0};
//定义第个光源属性(聚光灯)
GLfloat light1_ambient={0.2,0.2,0.2,1.0};
GLfloat light1_dfuse={1.0,0.0,0.0,1.0};
GLfloat light1_specular={1.0,0.6,0.6,1.0};
GLfloat light1_position={-3.0,-3.0,3.0,1.0};
GLfloat spot_direction={1.0,1.0,-1.0};


//定义第 2个光源属性(聚光灯 2)
GLfloat light2_ambient={0.2,0.6,0.2,1.0};
GLfloat light2_dfuse={0.0,1.0,0.0,1.0};
GLfloat light2_specular={0.0,1.0,0.0,1.0};
GLfloat light2_position={-3.0,-3.0,3.0,1.0};
GLfloat spot2_direction={1.0,1.0,-1.0};
//!!!我们看到第和第 2个聚光源除了在颜色定义上个偏红个偏绿
//其他没有任何区别所以如果象我们后面作个物体开启个光源
//另个物体开启另个光源就会产生个点光源对区别物体发出区别光效果


//将前面属性定义加以应用
glLightfv(GL_LIGHT0,GL_DIFFUSE,light0_dfuse);
glLightfv(GL_LIGHT0,GL_POSITION,light0_position);


glLightfv(GL_LIGHT1,GL_AMBIENT,light1_ambient);
glLightfv(GL_LIGHT1,GL_DIFFUSE,light1_dfuse);
glLightfv(GL_LIGHT1,GL_SPECULAR,light1_specular);
glLightfv(GL_LIGHT1,GL_POSITION,light1_position);
//定义聚光灯发散角
glLightf(GL_LIGHT1,GL_SPOT_CUTOFF,30.0);
//定义聚光灯发射方向向量
glLightfv(GL_LIGHT1,GL_SPOT_DIRECTION,spot_direction);


glLightfv(GL_LIGHT2,GL_AMBIENT,light2_ambient);
glLightfv(GL_LIGHT2,GL_DIFFUSE,light2_dfuse);
glLightfv(GL_LIGHT2,GL_SPECULAR,light2_specular);
glLightfv(GL_LIGHT2,GL_POSITION,light2_position);


glLightf(GL_LIGHT2,GL_SPOT_CUTOFF,30.0);
glLightfv(GL_LIGHT2,GL_SPOT_DIRECTION,spot2_direction);


glMaterialfv(GL_FRONT,GL_AMBIENT,mat_ambient);
glMaterialfv(GL_FRONT,GL_DIFFUSE,mat_dfuse);
glMaterialfv(GL_FRONT,GL_SPECULAR,mat_specular);
glMaterialfv(GL_FRONT,GL_SHININESS,mat_shininess);


glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glEnable(GL_LIGHT1);
glEnable(GL_LIGHT2);


}


void myinit(void)
{


auxInitDisplayMode(AUX_SINGLE|AUX_RGBA);
auxInitPosition(0,0,500,500);
auxInitWindow("sample1");
glClearColor(0.0,0.0,0.0,0.0);
glClear(GL_COLOR_BUFFER_BIT);


glDepthFunc(GL_LESS);
glEnable(GL_DEPTH_TEST);
initlights;
// glShadeModel(GL_FLAT);
}


void CALLBACK reshape(GLsizei w,GLsizei h)
{


glViewport(0,0,w,h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity;


(w<=h)
glOrtho(-5.0,5.0,-5.0*(GLfloat)h/(GLfloat)w,
5.0*(GLfloat)h/(GLfloat)w,-5.0,5.0);

glOrtho(-5.0*(GLfloat)h/(GLfloat)w,
5.0*(GLfloat)h/(GLfloat)w,-5.0,5.0,-5.0,5.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity;
}



void CALLBACK display(void)
{
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);


//首先标出聚光源、 2位置(同位置)
glPushMatrix;
glTranslated(-3.0,-3.0,3.0);
glDisable(GL_LIGHTING);
glColor3f(1.0,0.0,0.0);
auxWireCube(0.1);
glEnable(GL_LIGHTING);
glPopMatrix;


//关掉第 2个光源只启用第个光源(红)绘制球体
glPushMatrix;
glDisable(GL_LIGHT2);
glTranslated(0.0,2.0,0.0);
auxSolidSphere(2.0);
glPopMatrix;


//关掉第个光源只启用第 2个光源(绿)绘制球体 2
glPushMatrix;
glDisable(GL_LIGHT1);
glEnable(GL_LIGHT2);
glTranslated(0.0,-2.0,0.0);
auxSolidSphere(2.0);
glPopMatrix;


glFlush;
}
void (void)
{
myinit;


auxReshapeFunc(reshape);
auxMainLoop(display);
}
//end of sample
///////////////////////////////////////////////////////////////
个现实中难以见到情景出现了还不快试试?


结束光源的前再给出个光源移动例子其中用到了鼠标消息响应实现
非常简单以OPENGL辅助库提供方式个CALLBACK即可和以前讲
响应键盘输入思路方法完全
//////////////////////////////////////////////////////////////
//sample.cpp
# "glos.h"
# <GL/gl.h>
# <GL/glaux.h>
# "windows.h"
void myinit(void);
void CALLBACK display(void);
void CALLBACK reshape(GLsizei w,GLsizei h);


//控制光源移动变量
  step=0;


//鼠标响应CALLBACK
void CALLBACK movelight(AUX_EVENTREC *event)
{
step=(step+15)%360;
}


void initlights(void)
{
GLfloat mat_ambient={0.2,0.2,0.2,1.0};
GLfloat mat_dfuse={0.8,0.8,0.8,1.0};
GLfloat mat_specular={1.0,1.0,1.0,1.0};
GLfloat mat_shininess={80.0};


GLfloat light0_dfuse={0.0,0.0,1.0,1.0};
GLfloat light0_ambient={0.2,0.5,0.5,1.0};





glLightfv(GL_LIGHT0,GL_DIFFUSE,light0_dfuse);
glLightfv(GL_LIGHT0,GL_AMBIENT,light0_ambient);





glMaterialfv(GL_FRONT,GL_AMBIENT,mat_ambient);
glMaterialfv(GL_FRONT,GL_DIFFUSE,mat_dfuse);
glMaterialfv(GL_FRONT,GL_SPECULAR,mat_specular);
glMaterialfv(GL_FRONT,GL_SHININESS,mat_shininess);


glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);


}


void myinit(void)
{


auxInitDisplayMode(AUX_SINGLE|AUX_RGBA);
auxInitPosition(0,0,500,500);
auxInitWindow("sample1");
glClearColor(0.0,0.0,0.0,0.0);
glClear(GL_COLOR_BUFFER_BIT);


glDepthFunc(GL_LESS);
glEnable(GL_DEPTH_TEST);
initlights;
// glShadeModel(GL_FLAT);
}


void CALLBACK reshape(GLsizei w,GLsizei h)
{


glViewport(0,0,w,h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity;


(w<=h)
glOrtho(-5.0,5.0,-5.0*(GLfloat)h/(GLfloat)w,
5.0*(GLfloat)h/(GLfloat)w,-5.0,5.0);

glOrtho(-5.0*(GLfloat)h/(GLfloat)w,
5.0*(GLfloat)h/(GLfloat)w,-5.0,5.0,-5.0,5.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity;
}



void CALLBACK display(void)
{
GLfloat position={0.0,0.0,1.5,1.0};


glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);


glPushMatrix;
glTranslatef(0.0,0.0,-5.0);
glPushMatrix;


//光源位置只由旋转变量step决定每按下鼠标左键step值便会改变
//导致光源位置改变
glRotated((GLdouble)step,-1.0,1.0,1.0);
glLightfv(GL_LIGHT0,GL_POSITION,position);
glTranslated(0.0,0.0,1.5);


glDisable(GL_LIGHTING);
glColor3f(1.0,1.0,0.0);
auxWireSphere(0.25);
glEnable(GL_LIGHTING);


glPopMatrix;
auxSolidTorus(0.5,2.5);
glPopMatrix;


glFlush;



}
void (void)
{
myinit;


auxMouseFunc(AUX_LEFTBUTTON,AUX_MOUSEDOWN,movelight);
auxReshapeFunc(reshape);
auxMainLoop(display);
}
//end of sample
/////////////////////////////////////////////////////////////
在例子中黄色小球表示当前光源位置旋转导致了环状体表面受光照部分光影变化每按下鼠标左键光源就会作响应旋转





OPENGL特殊效果


1 融合
前面从未接触过透明或半透明物体我们从未启用过融合处理
所谓融合就是假设在RGBA模式下源色为(Rs,Gs,Bs,As)目标色为
(Rd,Gd,Bd,Ad),源因子为(Sr,Sg,Sb,Sa)因子为(Dr,Dg,Db,Da)
则融合最终效果为:(Rs*Sr+Rd*Dr,Gs*Sg+Gd*Dg,Bs*Sb+Bd*Db,As*Sa+Ad*Da)
然后再归公式挺复杂不过仔细看看跟平常融合倒是定性
关键就是如何设定融合因子(Sr,Sg,Sb,Sa)(Dr,Dg,Db,Da)来实现区别融合效果
利用:
void glBlendFunc(GLenum sfactor,GLenum dfactor);
其中两个参数可以取下面值:


取值 相关因子 计算后融合因子
GL_ZERO 源、目 (0,0,0,0)
GL_ONE 源、目 (1,1,1,1)
GL_DST_COLOR 源 (Rd,Gd,Bd,Ad)
GL_SRC_COLOR 目 (Rs,Gs,Bs,As)
GL_ONE_MINUS_DST_COLOR 源 (1,1,1,1)-(Rd,Gd,Bd,Ad)
GL_ONE_MINUS_SRC_COLOR 目 (1,1,1,1)-(Rs,Gs,Bs,As)


GL_SRC_ALPHA 源、目 (As,As,As,As)
GL_ONE_MINUS_SRC_ALPHA 源、目 (1,1,1,1)-(As,As,As,As)
GL_DST_ALPHA 源、目 (Ad,Ad,Ad,Ad)
GL_ONE_MINUS_DST_ALPHA 源、目 (1,1,1,1)-(Ad,Ad,Ad,Ad)
GL_SRC_ALPHA_SATURATE 源 (f,f,f,1)-min(As,1-Ad)


还要利用glEnable(GL_BLEND) glDisable(gl_blend)来启用、关闭融合处理
////////////////////////////////////////////////
//sample.cpp
# "glos.h"
# <GL/gl.h>
# <GL/glaux.h>
# "windows.h"
void myinit(void);
void CALLBACK display(void);
void CALLBACK reshape(GLsizei w,GLsizei h);



void myinit(void)
{


auxInitDisplayMode(AUX_SINGLE|AUX_RGBA);
auxInitPosition(0,0,500,500);
auxInitWindow("sample1");
glClearColor(0.0,0.0,0.0,0.0);
glClear(GL_COLOR_BUFFER_BIT);


//设置融合效果并启用
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
// glDepthFunc(GL_LESS);
// glEnable(GL_DEPTH_TEST);
glShadeModel(GL_FLAT);
}


void CALLBACK reshape(GLsizei w,GLsizei h)
{
glViewport(0,0,w,h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity;
(w<=h)
gluOrtho2D(0.0,1.0,0.0,1.0*(GLfloat)h/(GLfloat)w);

gluOrtho2D(0.0,1.0*(GLfloat)w/(GLfloat)h,0.0,1.0);
glMatrixMode(GL_MODELVIEW);
}


void CALLBACK display(void)
{


glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);


// 3个区别颜色和透明度方块重合颜色融合效果
glColor4f(1.0,0.0,0.0,0.7);
glRectf(0.25,0.4,0.75,0.9);


glColor4f(0.0,1.0,0.0,1.0);
glRectf(0.1,0.1,0.6,0.6);


glColor4f(0.0,0.0,1.0,0.3);
glRectf(0.4,0.1,0.9,0.6);


glFlush;


}
void (void)
{
myinit;


auxReshapeFunc(reshape);
auxMainLoop(display);
}
//end of sample
/////////////////////////////////////////////////////////
你可以试试调节参数大小体会下个参数含义


2 反走样Anti-aliasing
由于计算机以离散点生成图形生成图形必然和真实景物存在差距这种差距
表现为:直线或光滑曲面锯齿、花纹失去原有色彩形状、细小物体在画面
消失等统统叫做走样反走样可以减少这种情况粗略设想就是把原
来边界地方锯齿部分用低饱和度点补上这样既不影响整体轮廓又获得
较好平滑效果反走样前提供“提示”采用:


void glH(GLenum target,GLenum h);
其中h可以是:GL_FASTEST 给出最有效选择
GL_NICEST 给出最高质量选择
GL_DONT_CARE 没有选择


target 意义


GL_POINT_SMOOTH_HINT 指定点、
GL_LINE_SMOOTH_HINT 线、
GL_POLYGON_SMOOTH_HINT 多边形采样质量


GL_FOG_HINT 指出雾化计算是按每个象素进行(GL_NICEST)
还是按每个顶点进行(GL_FASTEST)


GL_PERSPECTIVE_CORRECTION_HINT 指定颜色纹理插值质量
其中GL_PERSPECTIVE_CORRECTION_HINT用以纠正单纯线性插值带来观察


当然最主要工作还是glEnable来完成


先给出个点、线反走样例子需要介绍说明是这个工作最好在RGBA模式下进行
首先利用glEnable(参数为GL_POINT_SMOOTH GL_LINE_SMOOTH或
GL_POLYGON_SMOOTH)启用反走样在RGBA模式下启用反走样必须启用融合处理
而且最常用融合因子分别是:GL_SRC_ALPHA(源)和GL_ONE_MINUS_SRC_ALPHA
或GL_ONE(目)


///////////////////////////////////////////////////////////////////////
//sample.cpp
# "glos.h"
# <GL/gl.h>
# <GL/glaux.h>
# "windows.h"
void myinit(void);
void CALLBACK display(void);
void CALLBACK reshape(GLsizei w,GLsizei h);


void myinit(void)
{


auxInitDisplayMode(AUX_SINGLE|AUX_RGBA);
auxInitPosition(0,0,500,500);
auxInitWindow("sample1");
glClearColor(0.0,0.0,0.0,0.0);
glClear(GL_COLOR_BUFFER_BIT);


//例子所有新内容都在下4句你可以试试取消反走样语句(1、4)
//则可以很清楚比较下反走样对图象质量改进
glEnable(GL_LINE_SMOOTH);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
glH(GL_LINE_SMOOTH_HINT,GL_DONT_CARE);


glDepthFunc(GL_LESS);
glEnable(GL_DEPTH_TEST);
glShadeModel(GL_FLAT);
}


void CALLBACK reshape(GLsizei w,GLsizei h)
{


glViewport(0,0,w,h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity;


(w<=h)
glOrtho(-5.0,5.0,-5.0*(GLfloat)h/(GLfloat)w,
5.0*(GLfloat)h/(GLfloat)w,-5.0,5.0);

glOrtho(-5.0*(GLfloat)h/(GLfloat)w,
5.0*(GLfloat)h/(GLfloat)w,-5.0,5.0,-5.0,5.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity;
}



void CALLBACK display(void)
{


glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);


glLineWidth(5.0);
glColor4f(1.0,1.0,0.0,0.7);
glPushMatrix;
glRotatef(45.0,1.0,1.0,0.0);


auxWireOctahedron(2.0);
glPopMatrix;
glFlush;



}
void (void)
{
myinit;


auxReshapeFunc(reshape);
auxMainLoop(display);
}
//end of sample
///////////////////////////////////////////////////////////////////


再给出个多边形反走样例子
///////////////////////////////////////////////////////////////////
//sample.cpp
# "glos.h"
# <GL/gl.h>
# <GL/glaux.h>
# "windows.h"
void myinit(void);
void CALLBACK display(void);
void CALLBACK reshape(GLsizei w,GLsizei h);



void myinit(void)
{


auxInitDisplayMode(AUX_SINGLE|AUX_RGBA);
auxInitPosition(0,0,500,500);
auxInitWindow("sample1");
glClearColor(0.0,0.0,0.0,0.0);
glClear(GL_COLOR_BUFFER_BIT);


GLfloat mat_ambient={0.5,0.5,0.0,1.0};
GLfloat mat_dfuse={1.0,0.8,0.1,1.0};
GLfloat position={1.0,0.0,1.0,0.0};


glMaterialfv(GL_FRONT,GL_AMBIENT,mat_ambient);
glMaterialfv(GL_FRONT,GL_DIFFUSE,mat_dfuse);
glLightfv(GL_LIGHT0,GL_POSITION,position);


glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glCullFace(GL_BACK);
glEnable(GL_CULL_FACE);
//启用多边形反走样
glEnable(GL_POLYGON_SMOOTH);


glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA,GL_ONE);


glDepthFunc(GL_LESS);
glEnable(GL_DEPTH_TEST);
glShadeModel(GL_FLAT);
}


void CALLBACK reshape(GLsizei w,GLsizei h)
{
glViewport(0,0,w,h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity;


(w<=h)
glOrtho(-5.0,5.0,-5.0*(GLfloat)h/(GLfloat)w,
5.0*(GLfloat)h/(GLfloat)w,-5.0,5.0);

glOrtho(-5.0*(GLfloat)h/(GLfloat)w,
5.0*(GLfloat)h/(GLfloat)w,-5.0,5.0,-5.0,5.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity;
}



void CALLBACK display(void)
{
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);


glLineWidth(5.0);
glColor4f(1.0,1.0,0.0,0.7);
glPushMatrix;
glRotatef(45.0,1.0,1.0,0.0);
auxSolidIcosahedron(2.0);
glPopMatrix;
glFlush;
}
void (void)
{
myinit;


auxReshapeFunc(reshape);
auxMainLoop(display);
}
//end of sample
////////////////////////////////////////////////////////////////////
比较采用反走样后结果可以明显看出多变形直线边界出锯齿得到了平滑


3 雾化
最后来介绍雾化雾化不但可以使景物更加真实而且大大减少计算量开过
F22玩家不会忘记雾化远近直接影响游戏速度吧雾化模型是考虑
把物体实际颜色和雾化颜色向融合具体雾化浓淡有定义数学模型来决定
包括线性变化、指数变化和指数平方变化等定义雾化也很简单只要遵循下面
步骤:
 启用雾化 glEnable(GL_FOG);
2 控制雾化 glFog*
void glFog{}[v](GLenum,TYPE param);


当GLenum是GL_FOG MODE时param可以是GL_EXP(指数)
GL_EXP2(指数平方)
GL_LINEAR(线性)


当GLenum是GL_FOG_DENSITY GL_FOG_START GL_FOG_END时param分别指定区别
雾化数学模型下区别计算公式参量具体可以参阅连机手册


当GLenum时GL_FOG_COLOR时param是指向颜色向量指针
3 必要时可以用glH(GL_FOG_HINT,XX)指定雾化效果
下面给出例子:
///////////////////////////////////////////////////////////////////
//sample.cpp
# "glos.h"
# <GL/gl.h>
# <GL/glaux.h>
# "windows.h"
void myinit(void);
void CALLBACK display(void);
void CALLBACK reshape(GLsizei w,GLsizei h);



void myinit(void)
{


auxInitDisplayMode(AUX_SINGLE|AUX_RGBA);
auxInitPosition(0,0,500,500);
auxInitWindow("sample1");
glClearColor(0.0,0.0,0.0,0.0);
glClear(GL_COLOR_BUFFER_BIT);


GLfloat mat_ambient={0.0,0.1,0.8,1.0};
GLfloat mat_dfuse={0.0,0.3,0.6,1.0};
GLfloat mat_specular={1.0,0.0,1.0,1.0};
GLfloat mat_shininess={15.0};
GLfloat position={5.0,5.0,5.0,0.0};
GLfloat fogColor[4]={0.6,0.6,0.0,1.0};


glMaterialfv(GL_FRONT,GL_AMBIENT,mat_ambient);
glMaterialfv(GL_FRONT,GL_DIFFUSE,mat_dfuse);
glMaterialfv(GL_FRONT,GL_SPECULAR,mat_specular);
glMaterialfv(GL_FRONT,GL_SHININESS,mat_shininess);
glLightfv(GL_LIGHT0,GL_POSITION,position);


glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glFrontFace(GL_CW);
// glEnable(GL_POLYGON_SMOOTH);
// glEnable(GL_BLEND);
// glBlendFunc(GL_SRC_ALPHA,GL_ONE);


glDepthFunc(GL_LESS);
glEnable(GL_DEPTH_TEST);


//启用雾化处理
glEnable(GL_FOG);
{
//采用线性变化雾化效果
glFogi(GL_FOG_MODE,GL_LINEAR);
//指定雾化颜色(黄色)
glFogfv(GL_FOG_COLOR,fogColor);
//指定按线性变化时计算公式参量
glFogf(GL_FOG_START,3.0);
glFogf(GL_FOG_END,15.0);
//规定雾化效果质量
glH(GL_FOG_HINT,GL_DONT_CARE);


}
// glShadeModel(GL_FLAT);
}


void CALLBACK reshape(GLsizei w,GLsizei h)
{


glViewport(0,0,w,h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity;


(w<=h*3)
glOrtho(-6.0,6.0,-2.0*(GLfloat)h*3/(GLfloat)w,
2.0*(GLfloat)h*3/(GLfloat)w,0.0,10.0);

glOrtho(-6.0*(GLfloat)h/(GLfloat)w,
6.0*(GLfloat)h/(GLfloat)w,-2.0,2.0,0.0,10.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity;
}



void CALLBACK display(void)
{


glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);


//在区别远近(Z方向)绘制同样大小、颜色显示雾化效果
glPushMatrix;
glTranslatef(-3.0,-1.5,-3.0);
auxSolidTorus(0.6,1.5);
glPopMatrix;


glPushMatrix;
glTranslatef(-0.5,-0.5,-6.0);
auxSolidTorus(0.6,1.5);
glPopMatrix;


glPushMatrix;
glTranslatef(2.0,0.5,-8.0);
auxSolidTorus(0.6,1.5);
glPopMatrix;


glFlush;



}
void (void)
{
myinit;


auxReshapeFunc(reshape);
auxMainLoop(display);
}
//end of sample
////////////////////////////////////////////////////////////////////






OPENGL显示列表


()介绍
所谓显示列表就是组预选存储起来留待以后语句此显示列表
时就按次序执行其中以前所有可以称的为立即方式(Immediate
mode)现在我们将介绍显示列表方式(Display list)


显示列表可以优化运行性能它被设计成命令高速缓存Cache而不是动态数据
库缓存Cache旦建立列表删除前则不能被修改否则会带来系统效率降低
显示列表主要目就是提高运行效率例如任何个几何变换处于显示列表
中时系统只保留最后变换矩阵这样工作量比现由参数生成数学
模型再矩阵变换效率显然提高般来讲显示列表食用于:
 矩阵操作 将最终变换矩阵保存以提高效率
2 光栅位图和图象编译后列表和高级数据区别将是匹配硬件实现

3 光、材质和光照模型 省却复杂模型计算
4 纹理
5 多边形图案填充模式


注意以下般不用于显示列表作为用于传递参数或者返回数值则列
表有可能在参数作用域外被因此即使列表中有这些实际系统也往往按
照立即方式完成有时甚至会出错
glDeleteLists glIsEnable glFeedbackBuffer glIsList
glFinish glPixelStore glGenLists glRenderMode glGet*
glSelectBuffer


( 2)实现
创建列表(格式很类似glBegin...glEnd)


void glNewList(GLu list,GLenum mode);
介绍说明列表开始其后存入列表直至结束标志(见后)
mode:GL_COMPILE 只编译保存
GL_COMILE_AND_EXECUTE 编译保存后再立即执行


void glEndList(void)
列表结束


只需使用
void glCallList(GLu list);
就象子过程样简单
/////////////////////////////////////////////
例如你在某处定义:
{
GLu listName=1;


glNewList(listName,GL_COMPILE);
glColor3f(1.0,0.0,0.0);
glBegin(GL_TRIANGLES);
...
glEnd;
glEndList;


}
再绘制:
{
glCallList(listName);
}
即可
////////////////////////////////////////////////
( 3)管理显示列表
上面例子中我们指定乐使用1显示列表这个索引已经被占用乐呢?
因此需要套管理列表工具


void GLu glGenList(GLsize range);
系统生成range个相临未被占用可用列表空间返回其索引
若不能正常分配空间返回0


void GLboolean glIsList(GLu list);
判断列表是否已经被占用


void GLDeleteLists(GLu list,GLsizei range);
删除组连续显示列表从list开始连续删除range个
介绍说明:当以个已经存在索引创建列表时以前旧列表被删除


个安全创建可以如下:
listIndex=glGenLists(1);
(listIndex!=0)
{
glNewList(listIndex,GL_COMPILE);
...
glEndList;
}


( 4)多级显示列表
显示列表中可以个显示列表
例如:
已经创建显示列表1 2 3
现在创建显示列表4
glNewList(4,GL_COMPILE);
glBegin(GL_OLYGON);
glCallList(1);
glCallList(2);
glCallList(3);
glEnd;
glEndList;


由于这部分内容没有任何视觉上新享受所以就不给出新例子乐
大家可以试试自己修改前面至少我没看出太大差别xixi






OPENGL帧缓存Cache和动画
作为最后我们将架设自己即时光影动画让没有VOODOO玩家看看OPENGL
这震撼(至少我是这么认为吧)效果完成所有这将近20次灌水最终目标


我们前面(好象是第 3还是第 4次)讲过如何用几何变换实现动画那时效果
现在看肯定不尽人意频繁闪烁不是我们需要那时(到这的前也
是)采用是单缓存Cache模式对正在显示部分边计算边修改必然造成速度瓶颈
出现闪烁般正规动画制作在实现上都是通过双缓存Cache实现(硬件也好
件也好)大家可以参考家用电脑和游戏机98-2中篇文章当前台显示
缓存Cache用于显示时后台缓存Cache已经进行计算计算完毕把所有内容通过缓存Cache拷贝
次性完成防止闪烁出现


 OPENGL帧缓存Cache实现


1 颜色缓存Cache(Color Buffer)其中内容可以是颜色索引或者RGBA数据如果用


OPENGL系统支持立体图则有左右两个缓存Cache


2 深度缓存Cache(Depth Buffer) 就是Z-BUFFER用于保存象素Z方向数值深度
被深度小代替用以实现消隐


3 模板缓存Cache(Stencil Buffer)用以保持屏幕上某些位置图形不变而其他部分
重绘例如大家熟悉开飞机和赛车游戏驾驶舱视角只有挡风外面景物
变化舱内仪表等等并不变化


4 累计缓存Cache(Accumulation Buffer) 只保存RGBA数据用于合成图象例如有某
缓存Cache中位图调入这里合成幅新图


2 帧缓存Cache清除
对高分辨率模式清除缓存Cache是工作量巨大任务OPENGL般先寻求硬件同时完成
否则软件Software依次解决我们前面每次必用glClearColor大家已经不陌生吧


首先设置清除值
void glClearColor(GLclampf red,GLclampf green,GLclampf blue,GLclampf alpha);
void glClearIndex(GLfloat index);
void glClearDepth(GLclampd depth);
void glClearStencil(GL s);
void glClerAccum(GLfloat red,GLfloat green,GLfloat blue,GLfloat alpha);


然后进行清除
void glClear(GLbitfield mask);
mask: GL_COLOR_BUFFER_BIT|
GL_DEPTH_BUFFER_BIT|
GL_STENCIL_BUFFER_BIT|
GL_ACCUM_BUFFER_BIT


3 双缓存Cache动画
你可以把所有变换工作看成后台缓存Cache计算然后把所有结果拷贝到前台即可
因此我们只需两个新内容:


首先化时
auxInitDisplayMode(AUX_DOUBLE|AUX_RGBA);
用AUX_DOUBLE代替AUX_SINGLE设置成双缓存Cache模式


然后在绘制完毕(glFlush;后)
auxSwapBuffers;
进行缓存Cache拷贝Easy like sunday morning!!
当然区别系统下这个也许区别(毕竟是辅助库么)例如X-WINDOWS
下可以使用glxSwapBuffers意思完全


先说说下面这个例子功能:
个兰色环作为主体个黄色高亮球表示光源位置
小球不断从屏幕左方运动到右方可以看出环状物上光影变化
操作:
鼠标左键/右键:开始/停止光源运动
键盘 上/下/左/右:控制环状物 前进/后退/旋转


//////////////////////////////////////////////////////////////////
//sample.cpp
# "glos.h"
# <GL/gl.h>
# <GL/glaux.h>
# "windows.h"


void myinit(void);
void CALLBACK display(void);
void CALLBACK reshape(GLsizei w,GLsizei h);
void CALLBACK stepDisplay(void);
void CALLBACK startIdleFunc(AUX_EVENTREC *event);
void CALLBACK stopIdleFunc(AUX_EVENTREC *event);


//step是表示环状物旋转参数;z是控制其前后坐标参数
 GLfloat step=0.0,z=0.0;
//position是控制光源位置参数
 GLfloat position={-20.0,0.0,-5.0,1.0};


void myinit(void)
{
//化注意是双缓存Cache模式
auxInitDisplayMode(AUX_DOUBLE|AUX_RGBA);


auxInitPosition(0,0,500,500);
auxInitWindow("sample1");
glClearColor(0.0,0.0,0.0,0.0);
glClear(GL_COLOR_BUFFER_BIT);



glFrontFace(GL_CW);


glEnable(GL_LIGHTING);
glFrontFace(GL_CW);
// glEnable(GL_POLYGON_SMOOTH);
// glEnable(GL_BLEND);
// glBlendFunc(GL_SRC_ALPHA,GL_ONE);


glDepthFunc(GL_LESS);
glEnable(GL_DEPTH_TEST);
// glShadeModel(GL_FLAT);
}


void CALLBACK reshape(GLsizei w,GLsizei h)
{


glViewport(0,0,w,h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity;
/*(w<=h*3)
glOrtho(-2.0,2.0,-2.0*(GLfloat)h/(GLfloat)w,
2.0*(GLfloat)h/(GLfloat)w,-10.0,10.0);

glOrtho(-2.0*(GLfloat)h/(GLfloat)w,
2.0*(GLfloat)h/(GLfloat)w,-2.0,2.0,-10.0,10.0);
*/


//启用立体视景具有近大远小效果
glFrustum(-6.0,6.0,-6.0,6.0,3.0,20.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity;


}



void CALLBACK display(void)
{


glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);


//首先在当前位置设置光源
glPushMatrix;
GLfloat light_ambient={0.3,0.5,0.3};
GLfloat light_dfuse={1.0,1.0,1.0};
GLfloat light_specular={0.8,0.8,0.0};
glLightfv(GL_LIGHT0,GL_AMBIENT,light_ambient);
glLightfv(GL_LIGHT0,GL_DIFFUSE,light_dfuse);
glLightfv(GL_LIGHT0,GL_SPECULAR,light_specular);
glLightfv(GL_LIGHT0,GL_POSITION,position);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
//在光源旁边绘制黄色高亮小球标志光源位置
//小球和光源位置由position决定
glTranslatef(position[0],position[1],position[2]-1.0);
GLfloat mat_ambient={1.0,0.0,0.0,1.0};
GLfloat mat_dfuse={1.0,1.0,0.0,1.0};
GLfloat mat_specular={1.0,1.0,0.0,1.0};
GLfloat mat_shininess={50.0};
glMaterialfv(GL_FRONT,GL_AMBIENT,mat_ambient);
glMaterialfv(GL_FRONT,GL_DIFFUSE,mat_dfuse);
glMaterialfv(GL_FRONT,GL_SPECULAR,mat_specular);
glMaterialfv(GL_FRONT,GL_SHININESS,mat_shininess);
auxSolidSphere(0.5);
glPopMatrix;


//在当前位置绘制兰色环状物其位置由step z共同决定
glPushMatrix;
glTranslatef(0.0,0.0,-8.0+z);
glRotatef(135.0+step,0.0,1.0,0.0);


GLfloat mat2_ambient={0.0,0.0,1.0,1.0};
GLfloat mat2_dfuse={0.2,0.0,0.99,1.0};
GLfloat mat2_specular={1.0,1.0,0.0,1.0};
GLfloat mat2_shininess={50.0};
glMaterialfv(GL_FRONT,GL_AMBIENT,mat2_ambient);
glMaterialfv(GL_FRONT,GL_DIFFUSE,mat2_dfuse);
glMaterialfv(GL_FRONT,GL_SPECULAR,mat2_specular);
glMaterialfv(GL_FRONT,GL_SHININESS,mat2_shininess);
auxSolidTorus(2.0,3.5);
glPopMatrix;


glFlush;
//绘制完毕缓存Cache交换
auxSwapBuffers;


}
void CALLBACK Up(void)
{
//键盘“上”处理
z=z+0.05;
}
void CALLBACK Down(void)
{
//键盘“下”处理
z=z-0.05;
}
void CALLBACK Left(void)
{
//键盘“左”处理
step=step+2.0;
}
void CALLBACK Right(void)
{
//键盘“右”处理
step=step-2.0;
}


void CALLBACK stepDisplay(void)
{
//系统闲时过程
position[0]=position[0]+0.5;
(position[0]>20.0) position[0]=-20.0;
display;
}


void CALLBACK startFunc(AUX_EVENTREC *event)
{
//鼠标左键处理
auxIdleFunc(stepDisplay);
}


void CALLBACK stopIdleFunc(AUX_EVENTREC *event)
{
//鼠标右键处理
auxIdleFunc(0);
}


void (void)
{
myinit;


auxReshapeFunc(reshape);
auxIdleFunc(stepDisplay);
auxMouseFunc(AUX_LEFTBUTTON,AUX_MOUSEDOWN,startFunc);
auxMouseFunc(AUX_RIGHTBUTTON,AUX_MOUSEDOWN,stopIdleFunc);
auxKeyFunc(AUX_UP,Up);
auxKeyFunc(AUX_DOWN,Down);
auxKeyFunc(AUX_LEFT,Left);
auxKeyFunc(AUX_RIGHT,Right);
auxMainLoop(display);
}
//end of sample
////////////////////////////////////////////////////////////////////
其中用到大量CALLBACK分别处理区别消息比较前面演示动画效果闪烁现象明显改善乐(你可以把这个两个有关双缓存Cache地方改成单缓存Cache:设置AUX_SINGLE和去掉auxSwapBuffers看看闪烁多么厉害)至于本身绘图可能拖尾现象只能怪自己机器不好乐
写到这里终于打穿乐OPENGL!!!实现当初提出“长长见识”设想
今后有什么新内容我还会尽量补充大家也可以自由补充

Tags:  opengl驱动 opengl2.0 opengl模式 opengl

延伸阅读

最新评论

发表评论