现在的位置: 首页 > 综合 > 正文

学习OpenGL(五)颜色、光照与材质

2017年10月04日 ⁄ 综合 ⁄ 共 8089字 ⁄ 字号 评论关闭

       

学习OpenGL(五)颜色、光照与材质

kezunhai@gmail.com

http://blog.csdn.net/kezunhai

           颜色、光照和材质是OpenGL的重要内容,其中glColor函数设置当前的颜色,该函数之后绘制的所有顶点(图形)都使用该颜色。对于一个点,其颜色就是设置的颜色,而对于一条直线而言,如果两个顶点的颜色不同,那么两点之间线的颜色取决于阴暗(Shade)处理的模型。明暗处理的定义就是从一种颜色到另一种颜色的平滑过滤。

          光滑的明暗处理(GL_SMOOTH)让颜色沿着直线变动,就像RGB颜色立方体中一个颜色到另一个颜色点的平滑果断。在数学上,明暗处理是先找到三维RGB颜色空间中的直线方程,然后再从直线的一段到另一端进行插值提供颜色。

           1)光照类型

           OpenGL可以根据光照添加创造出跟真实世界非常接近的图形来,除了物体本身发光以外,还可以有环境光、散射光和镜面光三种光照。

          (1)环境光(Ambient)

            环境光不来自任何特殊的方向,它有光源,但是被房间或场景多次反射,以至于变得没有方向。被环境光照射的物体表面的各个方向都均等受光。

         (2)散射光(Diffuse)

           散射光来自某个方向,被物体表面均匀反射,即使光是被均匀反射回去的,它直射的物体表面比从某个角度照射过来时要亮,比较典型的散射光源是荧光屏照明设备或中午时摄入侧窗的太阳光束。

         (3)镜面光(Specular)

          镜面光跟散射光一样有方向性,但被强烈地反射到另一特定的方向,高亮度的镜面光往往能在被照射的物体表面产生称之为亮斑的亮点。

          2)启用光照

            通过调用glEnalbe(GL_LIGHTING);可以启用光照,然后通过材质属性和光照参数来决定场景中每个顶点的颜色。

          3)设置光照模型

          启用光照后,首先需要做的第一件事就是设置光照模型,影响光照模型的三个参数是在glLightModel函数中设置的。全局环境光设置(GL_LIGHT_MODEL_AMBIENT), 该参数允许指定一个全局环境光,它从各个方向均匀照射所有物体,下面指定的是一种明亮的白光:

	GLfloat ambientLight[] = { 1.0f, 1.0f, 1.0f, 1.0f };
	glEnable(GL_LIGHTING);
	glLightModelfv( GL_LIGHT_MODEL_AMBIENT, ambientLight);

          4)设置材质属性

           设置全局环境光后,现在需要设置材质属性时多变形能反射光。有两种设置材质属性的方法:

          (1)在指定多边形集合之前调用glMaterial()函数,如下:

	GLfloat gray[] = { 0.75f, 0.75f, 0.75f, 1.0f};
	glMaterialfv ( GL_FRONT, GL_AMBIENT_AND_DIFFUSE, gray);

	glBegin(GL_TRIANGLES);
		glVertex3f( -15.0f, 0.0f, 30.0f );
		glVertex3f( 0.0f, 15.0f, 30.0f );
		glVertex3f( 0.0f, 0.0f, -56.0f );
	glEnd();

         glMaterial函数的第一个参数指定材质的前面、背面(GL_FRONT、BL_BACK或GL_FRONT_AND_BACK)或两面属性。第二个参数指定需要设置的属性,上面代码将环境光和散射光设置为相同的值。该种方式设置后,后续的图像材质属性都使用最后一次设置的参数值,直到重新调用glMaterial为止。大多数情况下环境光和散射光的成分是相同的,一般没必要定义镜面反射属性(特殊需要除外)。

        (2)颜色跟踪法

          通过颜色跟踪法,值需要通过调用glColor就可以设置材质属性,要使用颜色跟踪法,首先必须调用带有GL_COLOR_MATERIAL的glEnable函数,然后glColorMaterial函数就可以根据glColor指定的颜色值来指定材质属性了。实例代码如下:

	glEnable(GL_COLOR_MATERIAL);
	glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
	glColor3f( 0.75f, 0.75f, 0.75f);
	glBegin(GL_TRIANGLES);
		glVertex3f( -15.0f, 0.0f, 30.0f );
		glVertex3f( 0.0f, 15.0f, 30.0f );
		glVertex3f( 0.0f, 0.0f, -56.0f );
	glEnd();

          (3)通常我们可以在SetupRC()函数(不一定非得命名SetupRC,只要是进行初始化的其他函数也可以)中设置环境光照射,相关代码如下:

void SetupRC(void)
{
	GLfloat ambientLight[] ={ 1.0f, 1.0f, 1.0f, 1.0f }; // White light
	glEnable( GL_DEPTH_TEST); // Hiddden surface removal
	glEnable( GL_CULL_FACE); // Do not calculate inside of JET
	glFrontFace( GL_CCW); // Counter clock-wise polygon face out

	glEnable( GL_LIGHTING);
	glLightModelfv( GL_LIGHT_MODEL_AMBIENT, ambientLight);

	glEnable( GL_COLOR_MATERIAL);  // Enable Material Color Tracking
	glColorMaterial( GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
	glClearColor( 0.0f, 0.0f, 1.0f, 1.0f);
}

         5)使用光源

           在指定光源时,需要告诉OpenGL它的位置和发光的方向。对于多边形来说,如果指定光源的方向?采用的思路:从假想的平面(或多边形)上 的一个顶点引出来一条垂直向上的线,叫法线矢量。法线矢量仅仅表示一条垂直某个真实或假象平面的线。法线矢量是一条指向某方向的线,它与多边形的表明成90°(垂直)。法线矢量可以由一个多边形的三个顶点计算所得,如:

void reduceToUnit( float V[3])
{
	float length;
	length = sqrtf( V[0]*V[0] + V[1]*V[1] + V[2]*V[2]);
	if ( length == 0.0f)
		length = 1.0f;

	V[0] /= length;
	V[1] /= length;
	V[2] /= length;
}

void calcNormal( float v[3][3], float out[3])
{
	float v1[3], v2[3];
	static const int x = 0;
	static const int y = 1;
	static const int z = 3;

	v1[x] = v[0][x] - v[1][x];
	v1[y] = v[0][y] - v[1][y];
	v1[z] = v[0][z] - v[1][z];

	v2[x] = v[1][x] - v[2][x];
	v2[y] = v[1][y] - v[2][y];
	v2[z] = v[1][z] - v[2][z];

	// Take the cross product
	out[x] = v1[y]*v2[z] - v1[z]*v2[y];
	out[y] = v1[z]*v2[x] - v1[x]*v2[z];
	out[z] = v1[x]*v2[y] - v1[y]*v2[x];

	// Normalize the vector
	reduceToUnit(out);
}

         而关于这部分内容的综合知识请参考OpenGL超级宝典(第六章),最后文章以OpenGL超级宝典(第六章)的演示示例Jet的效果图结尾:

            由于没有附件功能,本示例的源代码直接附后面:

// Jet.cpp
// A hand modeled Jet airplane
// OpenGL SuperBible
// Beginning of OpenGL lighting sample
// Program by Richard S. Wright Jr.

#include "stdafx.h"
#include<GL/glut.h>
#include <cmath>
#include <cstdlib>

using namespace std;

// Rotation amounts
static GLfloat xRot = 0.0f;
static GLfloat yRot = 0.0f;

// Called to draw scene
void RenderScene_JET(void)
{
	// Clear the window with current clearing color
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	// Save matrix state and do the rotation
	glPushMatrix();
	glRotatef(xRot, 1.0f, 0.0f, 0.0f);
	glRotatef(yRot, 0.0f, 1.0f, 0.0f);


	// Nose Cone /////////////////////////////
	// White
	glColor3ub(255, 255, 255);
	glBegin(GL_TRIANGLES);
	glVertex3f(0.0f, 0.0f, 60.0f);
	glVertex3f(-15.0f, 0.0f, 30.0f);
	glVertex3f(15.0f,0.0f,30.0f);

	// Black
	glColor3ub(0,0,0);
	glVertex3f(15.0f,0.0f,30.0f);
	glVertex3f(0.0f, 15.0f, 30.0f);
	glVertex3f(0.0f, 0.0f, 60.0f);

	// Red
	glColor3ub(255,0,0);
	glVertex3f(0.0f, 0.0f, 60.0f);
	glVertex3f(0.0f, 15.0f, 30.0f);
	glVertex3f(-15.0f,0.0f,30.0f);


	// Body of the Plane ////////////////////////
	// Green
	glColor3ub(0,255,0);
	glVertex3f(-15.0f,0.0f,30.0f);
	glVertex3f(0.0f, 15.0f, 30.0f);
	glVertex3f(0.0f, 0.0f, -56.0f);

	glColor3ub(255,255,0);
	glVertex3f(0.0f, 0.0f, -56.0f);
	glVertex3f(0.0f, 15.0f, 30.0f);
	glVertex3f(15.0f,0.0f,30.0f);	

	glColor3ub(0, 255, 255);
	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
	glColor3ub(128,128,128);
	glVertex3f(0.0f,2.0f,27.0f);
	glVertex3f(-60.0f, 2.0f, -8.0f);
	glVertex3f(60.0f, 2.0f, -8.0f);

	glColor3ub(64,64,64);
	glVertex3f(60.0f, 2.0f, -8.0f);
	glVertex3f(0.0f, 7.0f, -8.0f);
	glVertex3f(0.0f,2.0f,27.0f);

	glColor3ub(192,192,192);
	glVertex3f(60.0f, 2.0f, -8.0f);
	glVertex3f(-60.0f, 2.0f, -8.0f);
	glVertex3f(0.0f,7.0f,-8.0f);

	// Other wing top section
	glColor3ub(64,64,64);
	glVertex3f(0.0f,2.0f,27.0f);
	glVertex3f(0.0f, 7.0f, -8.0f);
	glVertex3f(-60.0f, 2.0f, -8.0f);

	// Tail section///////////////////////////////
	// Bottom of back fin
	glColor3ub(255,128,255);
	glVertex3f(-30.0f, -0.50f, -57.0f);
	glVertex3f(30.0f, -0.50f, -57.0f);
	glVertex3f(0.0f,-0.50f,-40.0f);

	// top of left side
	glColor3ub(255,128,0);
	glVertex3f(0.0f,-0.5f,-40.0f);
	glVertex3f(30.0f, -0.5f, -57.0f);
	glVertex3f(0.0f, 4.0f, -57.0f);

	// top of right side
	glColor3ub(255,128,0);
	glVertex3f(0.0f, 4.0f, -57.0f);
	glVertex3f(-30.0f, -0.5f, -57.0f);
	glVertex3f(0.0f,-0.5f,-40.0f);

	// back of bottom of tail
	glColor3ub(255,255,255);
	glVertex3f(30.0f,-0.5f,-57.0f);
	glVertex3f(-30.0f, -0.5f, -57.0f);
	glVertex3f(0.0f, 4.0f, -57.0f);

	// Top of Tail section left
	glColor3ub(255,0,0);
	glVertex3f(0.0f,0.5f,-40.0f);
	glVertex3f(3.0f, 0.5f, -57.0f);
	glVertex3f(0.0f, 25.0f, -65.0f);

	glColor3ub(255,0,0);
	glVertex3f(0.0f, 25.0f, -65.0f);
	glVertex3f(-3.0f, 0.5f, -57.0f);
	glVertex3f(0.0f,0.5f,-40.0f);

	// Back of horizontal section
	glColor3ub(128,128,128);
	glVertex3f(3.0f,0.5f,-57.0f);
	glVertex3f(-3.0f, 0.5f, -57.0f);
	glVertex3f(0.0f, 25.0f, -65.0f);

	glEnd(); // Of Jet

	glPopMatrix();

	// Display the results
	glutSwapBuffers();
}

// This function does any needed initialization on the rendering
// context. 
void SetupRC_JET()
{
	glEnable(GL_DEPTH_TEST);	// Hidden surface removal
	glEnable(GL_CULL_FACE);		// Do not calculate inside of jet
	glFrontFace(GL_CCW);		// Counter clock-wise polygons face out

	// Nice light blue
	glClearColor(0.0f, 0.0f, 05.f,1.0f);
}

void SpecialKeys_JET(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 Window
	glutPostRedisplay();
}


void ChangeSize_JET(int w, int h)
{
	GLfloat nRange = 80.0f;
	// Prevent a divide by zero
	if(h == 0)
		h = 1;

	// Set Viewport to window dimensions
	glViewport(0, 0, w, h);

	// Reset coordinate system
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();

	// Establish clipping volume (left, right, bottom, top, near, far)
	if (w <= h) 
		glOrtho (-nRange, nRange, -nRange*h/w, nRange*h/w, -nRange, nRange);
	else 
		glOrtho (-nRange*w/h, nRange*w/h, -nRange, nRange, -nRange, nRange);

	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
}

void reduceToUnit( float V[3])
{
	float length;
	length = sqrtf( V[0]*V[0] + V[1]*V[1] + V[2]*V[2]);
	if ( length == 0.0f)
		length = 1.0f;

	V[0] /= length;
	V[1] /= length;
	V[2] /= length;
}

void calcNormal( float v[3][3], float out[3])
{
	float v1[3], v2[3];
	static const int x = 0;
	static const int y = 1;
	static const int z = 3;

	v1[x] = v[0][x] - v[1][x];
	v1[y] = v[0][y] - v[1][y];
	v1[z] = v[0][z] - v[1][z];

	v2[x] = v[1][x] - v[2][x];
	v2[y] = v[1][y] - v[2][y];
	v2[z] = v[1][z] - v[2][z];

	// Take the cross product
	out[x] = v1[y]*v2[z] - v1[z]*v2[y];
	out[y] = v1[z]*v2[x] - v1[x]*v2[z];
	out[z] = v1[x]*v2[y] - v1[y]*v2[x];

	// Normalize the vector
	reduceToUnit(out);
}

int main(int argc, char* argv[])
{
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
	glutInitWindowSize(800,600);
	glutCreateWindow("Jet");
	glutReshapeFunc(ChangeSize_JET);
	glutSpecialFunc(SpecialKeys_JET);
	glutDisplayFunc(RenderScene_JET);
	SetupRC_JET();
	glutMainLoop();

	return 0;
}

参考资料:

1、OpenGL超级宝典

作者:kezunhai出处:http://blog.csdn.net/kezunhai欢迎转载或分享,但请务必声明文章出处。  

           

抱歉!评论已关闭.