用OpenGL绘制平滑着色的三角形与相交区域的混合着色
一、三角形的绘制
在OpenGL中,面是由多边形构成的。三角形可能是最简单的多边形,它有三条边。可以使用GL_TRIANGLES模式通过把三个顶点连接到一起而绘出三角形。
使用GL_TRIANGLE_STRIP模式可以绘制几个相连的三角形,系统根据前三个顶点绘制第一个多边形,以后每指定一个顶点,就与构成上一个三角形的后两个顶点绘制形的一个三角形。
使用GL_TRIANGLE_FAN模式可以绘制一组相连的三角形,这些三角形绕着一个中心点成扇形排列。
第一个顶点构成扇形的中心,用前三个顶点绘制会最初的三角形后,随后的所有顶点都和扇形中心以及紧跟在它前面的顶点构成下一个三角形,此时是以顺时针方向穿过顶点。
二、绕法
在绘制三角形的过程中,三个顶点将三角形封闭的过程是有序的,即三角形的构成路径具有方向性,我们把指定顶点时顺序和方向的组合称为"绕法"。绕法是任何多边形图元的一个重要特征。
一般默认情况下,OpenGL认为逆时针绕法的多边形是正对着的,这一特性对于希望给多边形的正面和背面赋予不同的物理特性十分有用。
如果要反转OpenGL的默认行为,调用glFrontFace(GL_CW);GL_CW告诉OpenGL应该把顺时针缠绕的多边形正对着的。为了改回把逆时针绕法视为正面,可以使用GL_CCW。
三、明暗处理
在绘制多边形时,我们常常指定绘制的颜色,而在OpenGL中,颜色实际上是对各个顶点而不是对各个多边形指定的。
多边形的轮廓或者内部用单一的颜色或许多不同的颜色来填充的处理方式成为明暗处理。
在OpenGL中,用单一颜色处理的称为平面明暗处理(FlatShading),用许多不同颜色处理的称为光滑明暗处理(Smooth Shading),也称为Gourand明暗处理(Gourand Shading).设置明暗处理模式的函数void glShadeModel(GLenum mode)参数mode取值为GL_FLAT或GL_SMOOTH。
应用平面明暗处理模式时,多边形内每个点的法向一致,其颜色也一致,OpenGL用指定多边形最后一个顶点时的颜色作为填充多边形的纯色。
应用光滑明暗处理模式时,多边形所有点的法向是有内插生产的,具有一定的连续性,因此每个点的颜色也相应内插,故呈现不同色。这种模式下,插值方法采用的是双线性插值法。
Gourand明暗处理通常算法为:先用多边形顶点的光强线性插值出当前扫描线与多边形边交叉处的光强,然后再用交点的光强线插值处扫描线位于多边形内区段上每一像素处的光强值。
采用Gourand明暗处理不但可以使用多边形表示的曲面光强连续,而且计算量很小。这种算法还可以以增量的形式改进,且能用硬件直接实现算法,从而广泛用于计算机实时图形生成。
四、多边形的模式
多边形不是必须用当前颜色填充的。默认情况下绘制的多边形是实心的,但可以通过指定把多边形绘制为轮廓或只是点(只画出顶点)来修改这项默认行为。
函数glPolygonMode(Glenum face,Glenum mode);允许把多边形渲染为填充的实心,轮廓线或只是点。
另外,可以把这项渲染模式应用到多边形的两面或只应用到正面或背面。参数face指定多边形的哪一面受模式改变的影响——GL_FRONT,GL_BACK或GL_FRONT_AND_BACK。
参数mode用于指定新的绘图模式。GL_FILL是默认值,生成填充的多边形;GL_LINE生成多边形的轮廓;而GL_POINT只画出顶点。
GL_LINE和GL_POINT绘制的点和线受glEdgeFlag所设置边缘标记的影响。
五、多边形的绘制规则
在使用大量多边形构造一个复杂表面时,有两条重要规则。
第一条规则是所有多边形都必须是平面的,也就是说,多边形的所有顶点必须唯有一个平面上,不能在空间中扭曲
第二条规则是多边形的边缘不能相交,而且多边形必须是凸的。
六、相交区域的混合着色
glBlendFunc( GL_SRC_ALPHA , GL_ONE_MINUS_SRC_ALPHA ); // 是最常使用的。
若源色为 ( 1.0 ,
0.9 , 0.7 , 0.8 )
源色使用 GL_SRC_ALPHA为0.8,
即 0.8*1.0 , 0.8*0.9 , 0.8*0.8 , 0.8*0.8
结果为 0.8 , 0.72
, 0.64 , 0.56
目标色为 ( 0.6 , 0.5 , 0.4 , 0.3 )
目标色使用GL_ONE_MINUS_SRC_ALPHA
即 1 - 0.8 =
0.2
0.2*0.6 , 0.2*0.5 , 0.2*0.4 , 0.2*0.3
结果为 0.12 , 0.1
, 0.08 , 0.06
由此而见,使用这个混合函数,源色的α值决定了结果颜色的百分比。
这里源色的α值为0.8,即结果颜色中源色占80%,目标色占20%。
将多边形从远至近排列,并使用以下函数
glBlendFunc( GL_SRC_ALPHA_SATURATE , GL_ONE );
glEnable( GL_POLYGON_SMOOTH );
可以优化多边形反走样;但必须有α位平面,以用来存储累加的覆盖值。
七、混合 3D 物体
混合 3D 物体时,基本原理和混合 2D 物体一样,但需要将深度检测关闭或设置为只读。
因为深度检测会剔除被遮挡的部分物体。
glEnable( GL_DEPTH_TEST ); // 启用深度缓存
glDisable( GL_DEPTH_TEST ); // 禁用深度缓存 glDepthMask( GL_FALSE ); // 深度缓存为 只读
glDepthMask( GL_TRUE ); // 深度缓存为 读/写
八、示例程序如下
#include "stdafx.h"
//三角形的绘制程序
#include <GL/glut.h> //旋转参数
static GLfloat xRot=0.0f;
static GLfloat yRot=0.0f; //确定多边形绕法的方向
bool bWinding = true; //初始化窗口
void init()
{
//设置窗口背景颜色为黑色
glClearColor(0.0f,0.0f,0.0f,1.0f);
} //显示函数:绘制几何体的命令
void display()
{
//清除背景
glClear(GL_COLOR_BUFFER_BIT); glPushMatrix(); //把当前变换矩阵压入堆栈 glRotatef(xRot,1.0f,0.0f,0.0f);//使整个场景绕着x轴旋转
glRotatef(yRot,0.0f,1.0f,0.0f);//使整个场景绕着y轴旋转 //设置点的大小和线宽
glPointSize();
glLineWidth(); //设置多边形绕法的方向是顺时针还是逆时针
if (bWinding)
{
glFrontFace(GL_CW); //CW---clock wise顺时针
}
else
{
glFrontFace(GL_CCW); //CCW---
} //绘制三角形
glBegin(GL_TRIANGLES);
glColor3f(0.8f,1.0f,0.0f);
glVertex3f(,,); glColor3f(1.0f,0.0f,0.0f);
glVertex3f(-,-,); glColor3f(0.0f,0.0f,1.0f);
glVertex3f(,-,); glColor3f(0.0f,0.0f,1.0f);
glVertex3f(,-,); glColor3f(0.0f,0.7f,1.0f);
glVertex3f(,-,);
glEnd(); glBegin(GL_LINES);
glVertex3f(-100.3, 10.2, 10.5);
glVertex3f(, -10.2, -);
glEnd(); glPopMatrix(); //还原 glutSwapBuffers();//刷新命令缓冲区
} void reshape(int w,int h)
{
if (h == )
{
h = ;
}
glViewport(,,w,h); glMatrixMode(GL_PROJECTION); //矩阵模式:投影视图
glLoadIdentity();
if (w <= h)
{
//正交参数设置:x=[-100, 100], y=[-100.0*h/w, 100.0*h/w], z=[-100,100]
glOrtho(-100.0f,100.0f,-100.0f*h/w,100.0f*h/w,-100.0f,100.0f);
}
else
{
glOrtho(-100.0f*w/h,100.0f*w/h,-100.0f,100.0f,-100.0f,100.0f);
} glMatrixMode(GL_MODELVIEW); //矩阵模式:模型视图
glLoadIdentity();
} //由键盘控制旋转
void SpecialKeys(int key,int x,int y)
{
if (key == GLUT_KEY_UP)
xRot -=5.0f;
if (key == GLUT_KEY_DOWN)
xRot +=5.0f;
if (key == GLUT_KEY_LEFT)
yRot -=5.0f;
if (key == GLUT_KEY_RIGHT)
yRot +=5.0f; if (xRot > 356.0f)
xRot = 0.0f;
if (xRot < -1.0f)
xRot = 355.0f;
if (yRot > 356.0f)
yRot = 0.0f;
if (yRot < -1.0f)
yRot = 355.0f;
glutPostRedisplay();//刷新窗口
} //菜单处理
void ProcessMenu(int value)
{
switch(value)
{
case :
{
//修改多边形正面为填充模式
glPolygonMode(GL_FRONT,GL_FILL);
break;
}
case :
{
//修改多边形正面为线模式
glPolygonMode(GL_FRONT,GL_LINE);
break;
}
case :
{
//修改多边形正面为点填充模式
glPolygonMode(GL_FRONT,GL_POINT);
break;
}
case :
{
//修改多边形背面为填充模式
glPolygonMode(GL_BACK,GL_FILL);
break;
}
case :
{
//修改多边形背面为线模式
glPolygonMode(GL_BACK,GL_LINE);
break;
}
case :
{
//修改多边形背面为点填充模式
glPolygonMode(GL_BACK,GL_POINT);
break;
}
case :
{
//设置多边形的阴影模式为平面明暗模式
glShadeModel(GL_FLAT);
break;
}
case :
{
//设置多边形的阴影模式为光滑明暗模式
glShadeModel(GL_SMOOTH);
break;
}
case :
{
bWinding = !bWinding;
break;
}
default:
break;
}
//提交修改并强制重新绘图
glutPostRedisplay();
} void main()
{
init();
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE); //双缓冲
glutCreateWindow("多边形演示"); glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutSpecialFunc(SpecialKeys);//设置特殊键响应回调函数 //菜单的句柄
int nModeMenu;
int nMainMenu;
int nColorMenu; //创建一个子菜单并定于菜单回调函数
nModeMenu = glutCreateMenu(ProcessMenu);
//添加菜单项,1表示选择菜单条目时传递的参数值
glutAddMenuEntry("正面多边形填充模式",);
glutAddMenuEntry("正面线框模式",);
glutAddMenuEntry("正面点模式",);
glutAddMenuEntry("反面多边形填充模式",);
glutAddMenuEntry("反面线框模式",);
glutAddMenuEntry("反面点模式",); //添加一个子菜单
nColorMenu = glutCreateMenu(ProcessMenu);
glutAddMenuEntry("平面明暗模式",);
glutAddMenuEntry("光滑明暗模式",); //创建主菜单
nMainMenu = glutCreateMenu(ProcessMenu);
glutAddSubMenu("多边形模式",nModeMenu);
glutAddSubMenu("颜色模式",nColorMenu);
glutAddMenuEntry("改变绕法",); //将创建的菜单与右键关联,即把菜单设置为右键弹出式菜单
glutAttachMenu(GLUT_RIGHT_BUTTON); glutMainLoop();
}
三角形的绘制程序
#include <GL/glut.h>
#include <stdlib.h> static int leftFirst = GL_TRUE; /* Initialize alpha blending function.
*/
static void init(void)
{
glEnable (GL_BLEND);
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
//glBlendFunc(GL_ONE, GL_ONE);
glShadeModel (GL_FLAT);
glClearColor (0.0, 0.0, 0.0, 0.0);
} static void drawLeftTriangle(void)
{
/* draw yellow triangle on LHS of screen */ glBegin (GL_TRIANGLES);
glColor4f(1.0, 0.0, 0.0, 0.55);
glVertex3f(0.1, 0.9, 0.0);
glVertex3f(0.1, 0.1, 0.0);
glVertex3f(0.7, 0.5, 0.0);
glEnd();
} static void drawRightTriangle(void)
{
/* draw cyan triangle on RHS of screen */ glBegin (GL_TRIANGLES);
glColor4f(0.0, 1.0, 0.0, 0.55);
glVertex3f(0.9, 0.9, 0.0);
glVertex3f(0.3, 0.5, 0.0);
glVertex3f(0.9, 0.1, 0.0);
glEnd();
} void display(void)
{
glClear(GL_COLOR_BUFFER_BIT); if (leftFirst) {
drawLeftTriangle();
drawRightTriangle();
}
else {
drawRightTriangle();
drawLeftTriangle();
} glFlush();
} void reshape(int w, int h)
{
glViewport(, , (GLsizei) w, (GLsizei) h); glMatrixMode(GL_PROJECTION);
glLoadIdentity();
//2D正交投影参数
if (w <= h)
gluOrtho2D (0.0, 1.0, 0.0, 1.0*(GLfloat)h/(GLfloat)w);
else
gluOrtho2D (0.0, 1.0*(GLfloat)w/(GLfloat)h, 0.0, 1.0);
} void keyboard(unsigned char key, int x, int y)
{
switch (key) {
case 't':
case 'T':
leftFirst = !leftFirst;
glutPostRedisplay();
break;
case : /* Escape key */
exit();
break;
default:
break;
}
} int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB);
glutInitWindowSize (, );
glutCreateWindow (argv[]);
init();
glutReshapeFunc (reshape);
glutKeyboardFunc (keyboard);
glutDisplayFunc (display);
glutMainLoop();
return ;
}
相交区域的混合着色
用OpenGL绘制平滑着色的三角形与相交区域的混合着色的更多相关文章
- opengl绘制三角形
顶点数组对象:Vertex Array Object,VAO 顶点缓冲对象:Vertex Buffer Object,VBO 索引缓冲对象:Element Buffer Object,EBO或Inde ...
- 1.opengl绘制三角形
顶点数组对象:Vertex Array Object,VAO,用于存储顶点状态配置信息,每当界面刷新时,则通过VAO进行绘制. 顶点缓冲对象:Vertex Buffer Object,VBO,通过VB ...
- [Modern OpenGL系列(三)]用OpenGL绘制一个三角形
本文已同步发表在CSDN:http://blog.csdn.net/wenxin2011/article/details/51347008 在上一篇文章中已经介绍了OpenGL窗口的创建.本文接着说如 ...
- OpenGL超级宝典笔记——画三角形(转)
http://my.oschina.net/sweetdark/blog/161002 学习了画线的知识,我们可以使用GL_LINE_LOOP来画闭合的多边形.但是使用这种方式画出来的只有线框,多边形 ...
- OpenGL绘制自由落体小球
OpenGL绘制自由落体小球 一. 程序运行的软硬件环境 本次设计在window10系统下进行,运用C++进行编写,在CodeBlocks环境下使用OpenGL进行设计. 所需环境配置分为2部分 ...
- OpenGL教程(3)——第一个三角形
我们已经学会了创建窗口,这一讲,我们将学习如何使用现代OpenGL画一个三角形.在开始写代码之前,我们需要先了解一些OpenGL概念.本文会很长,请大家做好心理准备~ 注:以下OpenGL概念翻译自h ...
- opengl绘制正弦曲线
利用opengl绘制正弦曲线 ,见代码: #include <windows.h> //#include <GLUT/glut.h> #include <GL/glut. ...
- OpenGL绘制简单场景,实现旋转缩放平移和灯光效果
本项目实现了用OpenGL绘制一个简单场景,包括正方体.球体和网格,实现了物体的旋转.缩放.平移和灯光效果.附有项目完整代码.有具体凝视.适合刚開始学习的人熟悉opengl使用. 开发情况 开发环境V ...
- Opengl绘制我们的小屋(二)第一人称漫游
这章我们先讲第一人称漫游的实现.在openTK里,我们用函数Matrix4.LookAt(caram.Eye,caram.Target,Vector3.UnitY)来放置摄像机,其中三个参数分别与摄像 ...
随机推荐
- lua -- 商店控制器部分
-- 创建商店类,继承了Behavior local UIShopController = class("UIShopController", Behavior); -- 包含并引 ...
- NLP资料
https://towardsdatascience.com/how-to-get-started-in-nlp-6a62aa4eaeff?source=rss-299377188126------3
- 每日英语:15 places to find inspiration
If you’re a writer or artist, you understand the power of location when it comes to creativity and f ...
- 【工具】Windows7搭建FTP服务器
有时候需要将文件在各台电脑间拷贝,所以想建一个ftp服务器方便些,这里的设置仅为家用设置的记录日志,严谨的生产环境请参考其他文章. 创建一个专用于ftp的用户 开始 > 控制面板 > 用户 ...
- (转)Maven学习-处理资源文件
转自:http://www.cnblogs.com/now-fighting/p/4888343.html 在前面两篇文章中,我们学习了Maven的基本使用方式和Maven项目的标准目录结构.接下来, ...
- 12.22日wagas学习笔记
第一部分:vue-cli3 vue.config.js配置: baseUrl:process.env.NODE_ENV === 'production'?'/production-sub-path': ...
- STL之std::set、std::map的lower_bound和upper_bound函数使用说明
由于在使用std::map时感觉lower_bound和upper_bound函数了解不多,这里整理并记录下相关用法及功能. STL的map.multimap.set.multiset都有三个比较特殊 ...
- android 修改listview item view 的方法
具体的解答办法很简单: 代码如下 : 1.获取需要更新的view int visiblePosition = mListView.getFirstVisiblePosition(); View vie ...
- Android.mk高级写法
转:http://blog.csdn.net/langresser_king/article/details/8275291 原本只是想记录一些常用的使用技巧,但是越写越得意(>_<),忍 ...
- LeetCode: Convert Sorted Array to Binary Search Tree 解题报告
Convert Sorted Array to Binary Search Tree Given an array where elements are sorted in ascending ord ...