glColor4f()与光照是平级的,且两者互斥,水火不容,有我没你.对于纹理图片中的某个像素P(r,g,b,1):
(1)如果有光照L(Lr,Lg,Lb,x),则glColor4f(Cr,Cg,cb,Calpha)无用,像素P应该只乘以光照L,则像素P的实际颜色P1=P*L=(r*Lr,g*Lg,b*Lb,1);(注:P1的alpha恒为1,无须乘以光照的alpha值,即光照的alpha值在此处无用。下面的程序中可验证,无论x取何值,都对结果无影响)。
(2)如果无光照,则glColor4f(Cr,Cg,cb,Calpha)有效,则P1=P*C=( r*Cr,g*Cg,b*Cb,Calpha).如果还有混合的话,则P1再按alpha比例与以前的点混合.
总结:
(1)有光照时:像素点最终颜色P1的alpha恒为1,P1的RGB=像素RGB*光照RGB。
(2)无光照时:像素点最终颜色P1的alpha为glColor4f()的alpha值,P1的RGB=像素RGB*glColor4f()的RGB。
可以通过下面的程序来验证结果(可用QQ截图查看最终显示图的像素).
代码如下(摘自nehe的opengl教程-07-灯光,且可在DrawGLScene()函数内更改混合状态(glEnable(GL_BLEND) 或者glDisable(GL_BLEND)),程序运行后按大写的L可打开/关闭光源,且为了便于计算,我把纹理图片.bmp特意做成背景为白色,里面有几个红色,绿色,和像素为100的小方框):
其中,opengl默认背景glClearColor(0.6,0.6,0.6),光照值为(0.4,0.4,0.4,x),待检验的像素为100,即(100/255,100/255,100/255),设r=100/255,无光照时glColor4f(0.2,0.2,0.2,0.1)的alpha=0.1:
一、如果混合方式为glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA):
(1)无光源:则glColor4f(0.2,0.2,0.2,0.1)有效,所以像素P的实际颜色为
P1=背景色RGB*对应alpha+像素色RGB*glColor4f颜色RGB*对应alpha
=(0.6,0.6,0.6)*0.9+(100/255,100/255,100/255)*(0.2,0.2,0.2)*0.1
=(0.6*0.9,0.6*0.9,0.6*0.9)+(100/255 *0.2*0.1,100/255 *0.2*0.1,100/255 *0.2*0.1),各乘以255后为(140, 140, 140);
(2)有光源:则glColor4f()无效,所以像素P的实际颜色为
P1=背景色RGB*对应alpha +像素色RGB*光照颜色RGB*对应alpha
=(0.6,0.6,0.6)*0+(100/255,100/255,100/255)*( 0.4,0.4,0.4)*1
=(0.6*0,0.6*0,0.6*0)+(100/255 *0.4* 1,100/255 *0.4* 1,100/255 *0.4* 1),各乘以255后为(40, 40, 40)。
二、如果混合方式为glBlendFunc(GL_SRC_ALPHA, GL_ONE);即已画的(目标)不变,再加上要画的源):
(1)无光源:则glColor4f(0.2,0.2,0.2,0.1)有效,所以像素P的实际颜色为
P1=背景色RGB*对应alpha+像素色RGB*glColor4f颜色RGB*对应alpha
=(0.6,0.6,0.6)*1+(100/255,100/255,100/255)*(0.2,0.2,0.2)*0.1
=(0.6,0.6,0.6)+(100/255 *0.2*0.1,100/255 *0.2*0.1,100/255 *0.2*0.1),各乘以255后为(155, 155, 155);
(2)有光源:则glColor4f()无效,所以像素P的实际颜色为
P1=背景色RGB*对应alpha +像素色RGB*光照颜色RGB*对应alpha
=(0.6,0.6,0.6)*1+(100/255,100/255,100/255)*( 0.4,0.4,0.4)*1
=(0.6,0.6,0.6)+(100/255 *0.4* 1,100/255 *0.4* 1,100/255 *0.4* 1),各乘以255后为(193, 193, 193)。
三、如果混合方式为glBlendFunc(GL_SRC_ALPHA, GL_DST_ALPHA);则与glBlendFunc(GL_SRC_ALPHA, GL_ONE);的结果一样,这表示,帧缓存中像素的alpha值就是1。
四、而上面有无光照的2种情况,在无混合时,无需乘以对应的alpha:
(1)无光源:则glColor4f(0.2,0.2,0.2,0.1)有效,所以像素P的实际颜色为P1=像素色RGB*glColor4f颜色RGB=(100/255,100/255,100/255)*(0.2,0.2,0.2)
=(100/255* 0.2, 100/255* 0.2, 100/255* 0.2),各乘以255后为(20, 20, 20);
(2)有光源:则glColor4f()无效,所以像素像素P的实际颜色为P1=像素色RGB*光照颜色RGB= (100/255,100/255,100/255)*( 0.4,0.4,0.4)
=(100/255* 0.4, 100/255* 0.4, 100/255* 0.4) ,各乘以255后为(40, 40, 40)。
验证时,为简化,可只检验一个颜色,如颜色(r,g,b)的r值。
下面这段代码可控制光源中只有全局环境光(为(0.4,0.4,0.4,0.7)),这样在计算某个点的光照,混合,纹理时可把光照值定下来(此处为(0.4,0.4,0.4, 0.7)),再确定其他操作(如混合)以像素产生的效果.
注:顶点光照值为:自发散光+全局环境光+光源环境光+散射光+镜面光=
Emission+ LIGHT_MODEL_AMBIENT+ Ambient+ Diffuse+ Specular
(此处只有全局环境光(0.4,0.4,0.4, 0.7))
且结果与全局环境光的alpha值0.7无关。即当前点的alpha值与光照的alpha值是无关的。
GLfloat mat_ambient[] = { 1.0, 1.0, 1.0, 1.0 };
GLfloat mat_diffuse[] = { 0.0, 0.0, 0.0, 1.0 };//无散射光
GLfloat mat_emission[] = { 0.0, 0.0, 0.0, 1.0 };//无自发散光
GLfloat mat_specular[] = { 0.4, 0.4, 0.4, 1.0 };//
GLfloat mat_shininess[] = { 2.0 };
GLfloat LightPosition[] = { 1.0, 1.0, 1.0, 1.0 };//点光源(位置性光源)
GLfloat LightAmbient[] = { 0.0, 0.0, 0.0, 1.0};//无光源的环境光
GLfloat LightDiffuse[] = {1.0, 1.0, 1.0, 1.0};
GLfloat light_specular[] ={ 0.0, 0.0, 0.0, 1.0};//无镜面光
GLfloat lmodel_ambient[] = { 0.4, 0.4, 0.4, 0.7};//只有全局环境光
glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient);
glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
glMaterialfv(GL_FRONT, GL_EMISSION, mat_emission);
glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess);
glLightfv(GL_LIGHT0, GL_POSITION, LightPosition);//点光源相对视点的位置始终不变,此处是(1,1,1)
glLightfv(GL_LIGHT0, GL_AMBIENT, LightAmbient);
glLightfv(GL_LIGHT0, GL_DIFFUSE, LightDiffuse);
glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular);
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient);//全局环境光
glEnable(GL_LIGHTING); // 启用光源
glEnable(GL_LIGHT0); // 启用0号光源
glClearColor( 0.6f, 0.6f, 0.6f, 0.3f);//背景色
前面(一)glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)对应的完整源代码如下:
#pragma comment( lib, "opengl32.lib" )
#pragma comment( lib, "glu32.lib" )
#pragma comment( lib, "glut32.lib")
#pragma comment( lib, "glew32.lib")
#pragma comment( lib, "glaux.lib")
#pragma comment( lib, "vfw32.lib" )
/********************************************************************************************************************************/
#include <windows.h> // Windows的头文件
#include "glew.h" // 包含最新的gl.h,glu.h库
#include <stdio.h> // 标准输入/输出库的头文件
#include "glaux.h" // GLaux库的头文件
GLfloat xrot; // X 旋转量
GLfloat yrot; // Y 旋转量
GLfloat zrot; // Z 旋转量
/***********************************新添的代码***********************************************************************************/
GLfloat xspeed; // X 旋转速度
GLfloat yspeed; // Y 旋转速度
BOOL light; // 光源的开/关
BOOL lp; // L键按下了么?
BOOL fp; // F键按下了么?
GLfloat z=-5.0f; // 深入屏幕的距离
GLuint filter; // 滤波类型
GLuint texture[3]; // 3种纹理的储存空间
GLfloat spot1_direction[] = { 0.0f, 0,-1.0f}; // light1的聚光方向,沿相机视线方向
GLfloat angle_Light1 = 30.370f; //聚光源light1的截止角
GLfloat mat_ambient[] = { 1.0, 1.0, 1.0, 1.0 };
//GLfloat mat_diffuse[] = { 0.4, 0.4, 0.4, 1.0 };
GLfloat mat_diffuse[] = { 0.0, 0.0, 0.0, 1.0 };//无散射光
GLfloat mat_emission[] = { 0.0, 0.0, 0.0, 1.0 };//无自发散光
GLfloat mat_specular[] = { 0.4, 0.4, 0.4, 1.0 };
GLfloat mat_shininess[] = { 2.0 };
GLfloat LightPosition[] = { 1.0, 1.0, 1.0, 1.0 };//点光源(位置性光源)
GLfloat LightAmbient[] = { 0.0, 0.0, 0.0, 1.0};//无光源的环境光
GLfloat LightDiffuse[] = {1.0, 1.0, 1.0, 1.0};
GLfloat light_specular[] ={ 0.0, 0.0, 0.0 /*1.0, 1.0, 1.0*/, 1.0};//无镜面光
GLfloat lmodel_ambient[] = { 0.4, 0.4, 0.4, 0.7/*1.0*/};//只有全局环境光
//GLfloat lmodel_ambient[] = { 0.0, 0.0, 0.0, 1.0};
/********************************************************************************************************************************/
HDC hDC=NULL; // 窗口着色描述表句柄
HGLRC hRC=NULL; // OpenGL渲染描述表句柄
HWND hWnd=NULL; // 保存我们的窗口句柄
HINSTANCE hInstance; // 保存程序的实例
bool keys[256]; // 保存键盘按键的数组
bool active=TRUE; // 窗口的活动标志,缺省为TRUE
bool fullscreen=TRUE; // 全屏标志缺省,缺省设定成全屏模式
LRESULT CAL