3. glNormal3f 函数

void glNormal3f( GLfloat nx, GLfloat ny, GLfloat nz )
void glNormal3fv( const GLfloat *v )

但是第一个的参数就是浮点型的三个数,分别代表法向量的x、y、z。
第二个的参数是一个三元素数组的首地址,这个三元素数组分别代表法向量的x、y、z。

使用光源相关知识

使用光源

要模拟真实世界,仅有环境光是不够的,需要指定更多的光源来提升真实感。OpenGL至少提供8种光源,可以在场景中的任意位置甚至是可视区域之外。你可以指定光源位于无限远处以获得平行光束,或者光源位于近处向外发射光束。还可以制造出聚光灯的效果。

选择哪种方式?

你可以指定一个光源位于哪里朝哪个方向发射光线。通常光源朝所有方向发射光线,但也可以为它指定方向。在指定的方向的光源环境下,并非每个多边形都需要被照射到。我们可以制造物体的阴影效果。OpenGL可以计算光线和物体的角度。

如下图:光源发射出的光线照射到四边形上,形成一个入射角,再反射到观察者眼中形成一个反射角。根据这个入射角和反射角结合光源和材料的属性我们可以计算出该点应呈现出什么样的颜色。

在编程的角度上看,每一个多边形由一系列的顶点创建的。多边形就是由点组成的,那么如何计算光线与点之间的角度。我们无法在3D空间中找到一个切确的线与点之间的角度,因此我们为每一个点设置一个法线。三维平面的法线是垂直于该平面的三维向量。曲面在某点P处的法线为垂直于该点切平面的向量。(wiki)

平面法线

法线向量是一条垂直于真实平面或虚拟平面的线。下图是2D和3D中的法线向量。

为什么需要为每个顶点设置法线向量,而不是为一个多边形指定一个法线向量。其中的原因是,并不是所有的物体的表面都是平的,有时法线向量并不需要精确地垂直于物体的表面。通过扭曲平面的法线向量可以制造出光滑的曲面的视觉效果。

指定法线

如上图:为多边形的顶点(1,1,0)处指定一个法线向量,我们可以选定一另个点(1,10,0),并以(1,1,0)为起点连接第二个点(1,10,0),所形成的线就是法线向量。第二个点说明了法线向量的方向是y轴向上。法线向量的方向还可以用于表明多边形的正面和反面。法线是由正面指向外面的(或者说从法线的箭头方向往下看到的就是多边形的正面)。

用法线的第二个点减去第一个顶点,所得的结果就是相对于x、y和z的单位距离。

(1,10,0) - (1,1,0) = (0,9,0)

如果把这个顶点移动到原点,上面两点相减得出的点指定了和表面呈90度角的方向。如下图:

向量的方向告诉OpenGL顶点所在多边形的面朝哪个方向的。下面的例子演示如何指定法线向量

glBegin(GL_TRIANGLES);

glNormal3f(0.0f, -1.0f, 0.0f);

glVertex3f(0.0f, 0.0f, 60.0f);

glVertex3f(-15.0f, 0.0f, 30.0f);

glVertex3f(15.0f, 0.0f, 30.0f);

glEnd();

glNormal3f接受3个表示坐标的值,指定一条垂直于三角形表面的法线向量。上面的例子的三个顶点的法线具有相同的方向。

单位法线

单位法线即长度为1的法线向量。已知法线向量(x,y,z)求单位法线,先求出法线向量的长度即,再用(x,y,z)除以这个长度,就得到单位法线。这个过程叫归一化(normalization)。在光照计算的中所有的法线向量都会归一化。

可以让OpenGL自动把法线向量转换为单位法线,通过调用glEnable接受一个参数GL_NORMALIZE;

glEnable(GL_NORMALIZE);

这种做法在某些实现上,会带来性能的开销。最好的方式在指定法线向量的时候,就直接指定为单位法线,而不是依靠OpenGL来帮你做转换。

PS:glScale缩放函数也会缩放法线的长度。如果一起使用glScale和光照,有可能会得到不是你想要的光照效果。

如果每个顶点指定的法线都是单位法线,并且glScale使用相同的比例进行缩放的情况下,有一个替代方案是使用GL_RESCALE_NORMALS替代GL_NORMALIZE.

glEnable(GL_RESCALE_NORMALS);

这样就告诉了OpenGL,你的法线向量不是单位长度的,但是可以通过相同比例因子的缩放来把它转化为单位长度(单位法线)。这样OpenGL会检查你的模型视图变换矩阵来逆转换。这样在每个顶点所做的数学操作要少一些。

个人理解:

一个单位法线向量(1.0,1.0,1.0),在进行过glScalef(2.0, 2.0, 2.0)之后,就变为了(2.0,2.0,2.0),那么在启用了GL_RESCALE_NORMALS之后,OpenGL会检查模型视图矩阵得知,可以通过反向的缩放把法线向量转换会单位法线即等比例的缩小2倍乘以0.5.又得到了(1.0, 1.0, 1.0)。

PS:最佳实践是在一开始为顶点指定法线时,就指定为单位法线。

寻找法线

当一个多边形不平行于任何一个轴面时,通过简单的观察来指定一个法线会比较困难。所以需要一个简单的方法来计算3D空间中任意多边形的法线。

可以通过多边形上的任意三个点来计算法线。

如上图,知道了P1,P2,P3点之后。由P1和P2可以求出向量V1,P1和P3可以求出向量V2,再用V1 X V2(叉乘)计算得出正交于V1和V2的法线向量。

math3d代码示例:

void m3dFindNormal(M3DVector3f vNormal, const M3DVector3f vP1, const M3DVector3f vP2, const M3DVector3f vP3)
{M3DVector3f v1, v2;v1[0] = vP2[0] - vP1[0];v1[1] = vP2[1] - vP1[1];v1[2] = vP2[2] - vP1[2];v2[0] = vP3[0] - vP1[0];v2[1] = vP3[1] - vP1[1];v2[2] = vP3[2] - vP1[2];m3dCrossProduct(vNormal, v1, v2);
}

设置光源

创建一个位于左上角的温和的白光光源。

GLfloat ambientLight[] = {0.3f, 0.3f, 0.3f, 1.0f};
GLfloat diffuseLight[] = {0.7f, 0.7f, 0.7f, 1.0f};//设置和开启光源light0
glLightfv(GL_LIGHT0, GL_AMBIENT, ambientLight);
glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuseLight);//开启光照
glEnable(GL_LIGHT0);//设置光源位置
GLfloat lightPos[] = {-50.f, 50.f, 100.0f, 1.0f};
glLightfv(GL_LIGHT0, GL_POSITION, lightPos);

lightPos中最后一个值1.0说明这个lightPos指定了光源的位置,如果这个值是0.0,则指定了光源在无限远处。

设置材料属性

开启颜色追踪

glEnable(GL_COLOR_MATERIAL);

glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);

设置多边形和法线向量

...
{M3DVector3f vPoints[3] = {{ 15.0f, 0.0f,  30.0f},{ 0.0f,  15.0f, 30.0f},{ 0.0f,  0.0f,  60.0f}};// 计算法线向量m3dFindNormal(vNormal, vPoints[0], vPoints[1], vPoints[2]);glNormal3fv(vNormal);glVertex3fv(vPoints[0]);glVertex3fv(vPoints[1]);glVertex3fv(vPoints[2]);}
...
喷气式飞机的完整代码:
// LitJet.cpp
// OpenGL SuperBible
// Demonstrates OpenGL Lighting
// Program by Richard S. Wright Jr.#include "gltools.h"       // gltools library
#include "math3d.h"        // 3D Math Library// Rotation amounts
static GLfloat xRot = 0.0f;
static GLfloat yRot = 0.0f;// Called to draw scene
void RenderScene(void)
{M3DVector3f vNormal;    // Storeage for calculated surface normal// Clear the window with current clearing colorglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);// Save the matrix state and do the rotationsglPushMatrix();glRotatef(xRot, 1.0f, 0.0f, 0.0f);glRotatef(yRot, 0.0f, 1.0f, 0.0f);// Nose Cone - Points straight down// Set material colorglColor3ub(128, 128, 128);glBegin(GL_TRIANGLES);glNormal3f(0.0f, -1.0f, 0.0f);glNormal3f(0.0f, -1.0f, 0.0f);glVertex3f(0.0f, 0.0f, 60.0f);glVertex3f(-15.0f, 0.0f, 30.0f);glVertex3f(15.0f,0.0f,30.0f);// Verticies for this panel{M3DVector3f vPoints[3] = {{ 15.0f, 0.0f,  30.0f},{ 0.0f,  15.0f, 30.0f},{ 0.0f,  0.0f,  60.0f}};// Calculate the normal for the planem3dFindNormal(vNormal, vPoints[0], vPoints[1], vPoints[2]);glNormal3fv(vNormal);glVertex3fv(vPoints[0]);glVertex3fv(vPoints[1]);glVertex3fv(vPoints[2]);}    {M3DVector3f vPoints[3] = {{ 0.0f, 0.0f, 60.0f },{ 0.0f, 15.0f, 30.0f },{ -15.0f, 0.0f, 30.0f }};m3dFindNormal(vNormal, vPoints[0], vPoints[1], vPoints[2]);glNormal3fv(vNormal);glVertex3fv(vPoints[0]);glVertex3fv(vPoints[1]);glVertex3fv(vPoints[2]);}// Body of the Plane {M3DVector3f vPoints[3] = {{ -15.0f, 0.0f, 30.0f },{ 0.0f, 15.0f, 30.0f },{ 0.0f, 0.0f, -56.0f }};m3dFindNormal(vNormal, vPoints[0], vPoints[1], vPoints[2]);glNormal3fv(vNormal);glVertex3fv(vPoints[0]);glVertex3fv(vPoints[1]);glVertex3fv(vPoints[2]);}{M3DVector3f vPoints[3] = {{ 0.0f, 0.0f, -56.0f },{ 0.0f, 15.0f, 30.0f },{ 15.0f,0.0f,30.0f }};m3dFindNormal(vNormal, vPoints[0], vPoints[1], vPoints[2]);glNormal3fv(vNormal);glVertex3fv(vPoints[0]);glVertex3fv(vPoints[1]);glVertex3fv(vPoints[2]);}glNormal3f(0.0f, -1.0f, 0.0f);glVertex3f(15.0f,0.0f,30.0f);glVertex3f(-15.0f, 0.0f, 30.0f);glVertex3f(0.0f, 0.0f, -56.0f);///// Left wing// Large triangle for bottom of wing{M3DVector3f vPoints[3] = {{ 0.0f,2.0f,27.0f },{ -60.0f, 2.0f, -8.0f },{ 60.0f, 2.0f, -8.0f }};m3dFindNormal(vNormal, vPoints[0], vPoints[1], vPoints[2]);glNormal3fv(vNormal);glVertex3fv(vPoints[0]);glVertex3fv(vPoints[1]);glVertex3fv(vPoints[2]);}{M3DVector3f vPoints[3] = {{ 60.0f, 2.0f, -8.0f},{0.0f, 7.0f, -8.0f},{0.0f,2.0f,27.0f }};m3dFindNormal(vNormal, vPoints[0], vPoints[1], vPoints[2]);glNormal3fv(vNormal);glVertex3fv(vPoints[0]);glVertex3fv(vPoints[1]);glVertex3fv(vPoints[2]);}{M3DVector3f vPoints[3] = {{60.0f, 2.0f, -8.0f},{-60.0f, 2.0f, -8.0f},{0.0f,7.0f,-8.0f }};m3dFindNormal(vNormal, vPoints[0], vPoints[1], vPoints[2]);glNormal3fv(vNormal);glVertex3fv(vPoints[0]);glVertex3fv(vPoints[1]);glVertex3fv(vPoints[2]);}{M3DVector3f vPoints[3] = {{0.0f,2.0f,27.0f},{0.0f, 7.0f, -8.0f},{-60.0f, 2.0f, -8.0f}};m3dFindNormal(vNormal, vPoints[0], vPoints[1], vPoints[2]);glNormal3fv(vNormal);glVertex3fv(vPoints[0]);glVertex3fv(vPoints[1]);glVertex3fv(vPoints[2]);}// Tail section///// Bottom of back finglNormal3f(0.0f, -1.0f, 0.0f);glVertex3f(-30.0f, -0.50f, -57.0f);glVertex3f(30.0f, -0.50f, -57.0f);glVertex3f(0.0f,-0.50f,-40.0f);{M3DVector3f vPoints[3] = {{ 0.0f,-0.5f,-40.0f },{30.0f, -0.5f, -57.0f},{0.0f, 4.0f, -57.0f }};m3dFindNormal(vNormal, vPoints[0], vPoints[1], vPoints[2]);glNormal3fv(vNormal);glVertex3fv(vPoints[0]);glVertex3fv(vPoints[1]);glVertex3fv(vPoints[2]);}{M3DVector3f vPoints[3] = {{ 0.0f, 4.0f, -57.0f },{ -30.0f, -0.5f, -57.0f },{ 0.0f,-0.5f,-40.0f }};m3dFindNormal(vNormal, vPoints[0], vPoints[1], vPoints[2]);glNormal3fv(vNormal);glVertex3fv(vPoints[0]);glVertex3fv(vPoints[1]);glVertex3fv(vPoints[2]);}{M3DVector3f vPoints[3] = {{ 30.0f,-0.5f,-57.0f },{ -30.0f, -0.5f, -57.0f },{ 0.0f, 4.0f, -57.0f }};m3dFindNormal(vNormal, vPoints[0], vPoints[1], vPoints[2]);glNormal3fv(vNormal);glVertex3fv(vPoints[0]);glVertex3fv(vPoints[1]);glVertex3fv(vPoints[2]);}{M3DVector3f vPoints[3] = {{ 0.0f,0.5f,-40.0f },{ 3.0f, 0.5f, -57.0f },{ 0.0f, 25.0f, -65.0f }};m3dFindNormal(vNormal, vPoints[0], vPoints[1], vPoints[2]);glNormal3fv(vNormal);glVertex3fv(vPoints[0]);glVertex3fv(vPoints[1]);glVertex3fv(vPoints[2]);}{M3DVector3f vPoints[3] = {{ 0.0f, 25.0f, -65.0f },{ -3.0f, 0.5f, -57.0f},{ 0.0f,0.5f,-40.0f }};m3dFindNormal(vNormal, vPoints[0], vPoints[1], vPoints[2]);glNormal3fv(vNormal);glVertex3fv(vPoints[0]);glVertex3fv(vPoints[1]);glVertex3fv(vPoints[2]);}{M3DVector3f vPoints[3] = {{ 3.0f,0.5f,-57.0f },{ -3.0f, 0.5f, -57.0f },{ 0.0f, 25.0f, -65.0f }};m3dFindNormal(vNormal, vPoints[0], vPoints[1], vPoints[2]);glNormal3fv(vNormal);glVertex3fv(vPoints[0]);glVertex3fv(vPoints[1]);glVertex3fv(vPoints[2]);}glEnd();// Restore the matrix stateglPopMatrix();// Display the resultsglutSwapBuffers();
}// This function does any needed initialization on the rendering
// context.
void SetupRC()
{// Light values and coordinatesGLfloat  ambientLight[] = { 0.3f, 0.3f, 0.3f, 1.0f };GLfloat  diffuseLight[] = { 0.7f, 0.7f, 0.7f, 1.0f };glEnable(GL_DEPTH_TEST);    // Hidden surface removalglFrontFace(GL_CCW);        // Counter clock-wise polygons face outglEnable(GL_CULL_FACE);        // Do not calculate inside of jet// Enable lightingglEnable(GL_LIGHTING);// Setup and enable light 0glLightfv(GL_LIGHT0,GL_AMBIENT,ambientLight);glLightfv(GL_LIGHT0,GL_DIFFUSE,diffuseLight);glEnable(GL_LIGHT0);// Enable color trackingglEnable(GL_COLOR_MATERIAL);// Set Material properties to follow glColor valuesglColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);// Light blue backgroundglClearColor(0.0f, 0.0f, 1.0f, 1.0f );glEnable(GL_NORMALIZE);
}/
// Handle arrow keys
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(key > 356.0f)xRot = 0.0f;if(key < -1.0f)xRot = 355.0f;if(key > 356.0f)yRot = 0.0f;if(key < -1.0f)yRot = 355.0f;// Refresh the WindowglutPostRedisplay();
}//
// Reset projection and light position
void ChangeSize(int w, int h)
{GLfloat fAspect;GLfloat lightPos[] = { -50.f, 50.0f, 100.0f, 1.0f };// Prevent a divide by zeroif(h == 0)h = 1;// Set Viewport to window dimensionsglViewport(0, 0, w, h);// Reset coordinate systemglMatrixMode(GL_PROJECTION);glLoadIdentity();fAspect = (GLfloat) w / (GLfloat) h;gluPerspective(45.0f, fAspect, 1.0f, 225.0f);glMatrixMode(GL_MODELVIEW);glLoadIdentity();glLightfv(GL_LIGHT0,GL_POSITION,lightPos);glTranslatef(0.0f, 0.0f, -150.0f);
}int main(int argc, char* argv[])
{glutInit(&argc, argv);glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);glutInitWindowSize(800,600);glutCreateWindow("Lighted Jet");glutReshapeFunc(ChangeSize);glutSpecialFunc(SpecialKeys);glutDisplayFunc(RenderScene);SetupRC();glutMainLoop();return 0;
}

参考链接:

glViewport()函数和glOrtho()函数的理解

OpenGl 之学习笔记 glNormal3f 函数理解和光源相关知识总结相关推荐

  1. OpenGl 之学习笔记 glTexCoord2f() 函数以及纹理相关知识总结

    2. glTexCoord2f() 函数 原型:glTexCoord2f(GLfloat s,GLfloat t): s代表x坐标,t代表y坐标: s∈[0.0,1.0],t∈[0.0,1.0]: 一 ...

  2. ICT学习笔记(1) 网络以及网络模型的相关知识

    文章目录 网络 一.网络的构成 二.传输介质 1.同轴电缆 2. 双绞线 3.光纤 4.串口电缆 三.网络模型及各层作用 1.OSI模型 开放式系统互联通信参考模型(七层模型) 2.TCP/IP模型( ...

  3. 安全技术学习笔记与分享6——web功能相关知识

    个人归纳: HTTP请求使用4种主要方式向应用程序传送参数: 1.通过url插叙字符串 2.通过REST风格的url文件路径 3.通过HTTP cookie 4.通过在请求主体中使用POST方法 现在 ...

  4. python函数是一段具有特定功能的语句组_Python学习笔记(五)函数和代码复用

    本文将为您描述Python学习笔记(五)函数和代码复用,具体完成步骤: 函数能提高应用的模块性,和代码的重复利用率.在很多高级语言中,都可以使用函数实现多种功能.在之前的学习中,相信你已经知道Pyth ...

  5. OpenGL入门学习笔记(一)——简单实现FFT海洋

    一.前言 文章不赘述OpenGL的使用入门,使用入门请参考LearnOpenGL CN(https://learnopengl-cn.github.io/). 文章主要参考: [1][学习笔记]Uni ...

  6. Python学习笔记:函数(Function)

    Python学习笔记:函数(Function) 一.函数基本概念 函数是Python里组织与重用代码最重要的方法.一般来说,如果你期望多次重复相同或相似的代码,写一个可重用的函数可能是值得的.函数通过 ...

  7. php中声明一个函数,php学习笔记之 函数声明

    /* 函数定义: * 1.函数是一个被命名的 * 2.独立的代码段 * 3.函数执行特定任务 * 4.并可以给调用它的程序返回一个值 * * 函数的优点: * 1.提高程序的重用性 * 2.提高程序的 ...

  8. ROS学习笔记六:理解ROS服务和参数

    ROS学习笔记六:理解ROS服务和参数 主要介绍ROS服务和参数,同时使用命令行工具rosservice和rosparam. ROS service service是节点之间互相通信的另一种方式,se ...

  9. ROS学习笔记五:理解ROS topics

    ROS学习笔记五:理解ROS topics 本节主要介绍ROS topics并且使用rostopic和rqt_plot命令行工具. 例子展示 roscore 首先运行roscore系列服务,这是使用R ...

  10. ROS学习笔记四:理解ROS节点

    ROS学习笔记四:理解ROS节点 本节主要介绍ROS图形概念,讨论ROS命令行工具roscore.rosnode和rosrun. 要求 要求已经在Linux系统中安装一个学习用的ros软件包例子: s ...

最新文章

  1. python从入门到实践和从入门到精通-Python从入门到实践之列表|第1天
  2. 接口入口在什么地方_弱电工程施工图审查要点?有哪些地方需要审核?审核要求是什么?...
  3. 没有bug队——加贝——Python 练习实例 35,36
  4. html5 canvas 不兼容safari浏览器_HTML5简介
  5. 网站SEO优化过程中的几个注意事项
  6. [案例分析] 打造值得信任的个人品牌究竟靠什么?
  7. redis 从节点如何选举从节点升级为主节点_Redis哨兵的配置和原理
  8. main run方法没用_多线程:解决Runnable接口无start()方法的问题
  9. Ubuntu18.04安装OpenPCDet及配置spconv
  10. 语音识别软件、语音识别平台和语音识别技术
  11. mongodb查询find(
  12. android适配各种分辨率的问题
  13. Linux基本信息查看命令
  14. linux看注册的定时任务,Linux下定时任务的查看及取消
  15. 秒、毫秒和年月日的转换
  16. Laravel 加密
  17. Linux解决中文乱码问题及LANG与NLS_LANG的区别
  18. Android App 图表制作之--ichartJs
  19. 洛谷P1510 精卫填海(DP)
  20. 高端风再起,小爱、小度、天猫精灵发新芽?

热门文章

  1. 【論文筆記】MIDAS:Microcluster-Based Detector of Anomalies in Edge Streams
  2. C 顺序表求交集和并集
  3. web网站测试点整理
  4. 使用IIS发布ASP.NET网页
  5. 类和对象12:容器方法
  6. Linux系统root用户登录后显示 “-bash-4.2#” 解决方案
  7. 职场新人注意事项:抖包袱可以,抖机灵不要
  8. 国家或地区内期货市场竞争格局的变迁
  9. android原生组件,RN原生的安卓UI组件
  10. Python基础笔记_Day10_Python面向对象、类和对象、__init__、__str__、访问限制、set、get