openGL 灯光与材质例子. 顺带完成了一个颇复杂的平面分级算法, 修正版,列出了所有易错的地方:
1. 开启了 GL_XXX_ARRAY 后一定要使用对应的pointer, 否则就把 GL_XXX_ARRAY disable 掉.
2. 法线不一定要设置, openGL会自动为每一Vertex生成一个默认的, 自己设置当然可控性更好.
3. initLights() 等GL具体到场景内容的设置必须放在 GLUT 基本设置之后(一开始就死在这个弱智的问题).
4. 灯光的 GL_POSITION, 齐次坐标最后一位如果是 0, 则为平行光, 无需设置 GL_SPOT_DIRECTION 和 GL_SPOT_CUTOFF(这个值为照射角的一半). 如果是1, 则为聚光灯.
5. GL 环境光对所有面都会有影响.尝试变换灯光的颜色和环境光颜色的数组值,观察其变化.
6. 材质的 SHINESS 参数, 1 端接近橡胶与织物, 128 端接近金属与清漆.
7. 灯灯灯凳~ 最麻烦的还是平面分级算法, 理论上分级越细, 关照效果越细致, 代码如下:
#include <gl/GLUT.h>
#include <stdio.h>
static GLfloat LEVEL=12;
static GLfloat LENGTH=2;
static GLfloat START_PT=-1*(LENGTH/2);
static GLfloat END_PT=1*(LENGTH/2);
GLfloat angle=0;
GLfloat *vertices;
//GLfloat *colors;
short *indices;
GLfloat *normals;
//GLfloat vertices[]={-1,-1,1,
// -0.3333f,-1,1,
// 0.3333f,-1,1,
// 1,-1,1,
// -1,-0.3333,1,
// -0.3333f,-0.3333,1,
// 0.3333f,-0.3333,1,
// 1,-0.3333,1,
// -1,0.3333,1,
// -0.3333f,0.3333,1,
// 0.3333f,0.3333,1,
// 1,0.3333,1,
// -1,1,1,
// -0.3333f,1,1,
// 0.3333f,1,1,
// 1,1,1};
//short indices[]={0,1,4, 1,5,4, 1,2,5, 2,6,5, 2,3,6, 3,7,6,
// 4,5,8, 5,9,8, 5,6,9, 6,10,9, 6,7,10, 7,11,10,
// 8,9,12, 9,13,12, 9,10,13, 10,14,13, 10,11,14, 11,15,14};
//lights
GLfloat lightPos[]={0,0,2.5f,1};
GLfloat lightColor[]={0.6f,0.3f,0.3f,1}; //red
GLfloat lightDir[]={0,0,-1};
//ambient light
GLfloat light_ambient[]={0.3f,0.3f,0.4f,1}; //light blue
//materials
GLfloat cubeColor[]={0.6f,0.6f,0.6f,1}; //gray color
GLfloat cubeSpecular[]={1,1,1,1};
void setMaterial(){
glMaterialfv(GL_FRONT_AND_BACK,GL_AMBIENT_AND_DIFFUSE,cubeColor);
glMaterialfv(GL_FRONT_AND_BACK,GL_SPECULAR,cubeSpecular);
//try to change the shiness from 1(rubber/frabic)-128(metal/clear painted)
glMaterialf(GL_FRONT_AND_BACK,GL_SHININESS,20);
}
void drawPlane(){
glVertexPointer(3,GL_FLOAT,0,vertices);
//glNormalPointer(GL_FLOAT,0,normals);
//glColorPointer(4,GL_FLOAT,0,colors);
glDrawElements(GL_TRIANGLES,(GLsizei)((LEVEL-1)*(LEVEL-1)*2*3),GL_UNSIGNED_SHORT,indices);
}
void drawCube(){
//set material
setMaterial();
glPushMatrix();
drawPlane();
glPopMatrix();
glPushMatrix();
glRotatef(-90,1,0,0);
drawPlane();
glPopMatrix();
glPushMatrix();
glRotatef(90,1,0,0);
drawPlane();
glPopMatrix();
glPushMatrix();
glRotatef(180,1,0,0);
drawPlane();
glPopMatrix();
glPushMatrix();
glRotatef(90,0,1,0);
drawPlane();
glPopMatrix();
glPushMatrix();
glRotatef(-90,0,1,0);
drawPlane();
glPopMatrix();
}
void rendering(void){
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glPushMatrix();
glRotatef(angle,0,1,0);
drawCube();
glPopMatrix();
glutSwapBuffers();
angle+=0.01;
}
void reshape(int w, int h){
if(h==0){
h=1;
}
GLfloat ratio=(GLfloat)(w/h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glViewport(0,0,w,h);
gluPerspective(45,ratio,0.1,1000);
gluLookAt(0,5,10,0,0,0,0,1,0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
void makeArrays(){
//build vertices array for one face
GLfloat step=(GLfloat)(LENGTH/(LEVEL-1));
GLint total=LEVEL*LEVEL*3;
GLint oneLine=LEVEL*3; //12
//printf("level: %f ", step);
vertices=new GLfloat[total];
for(int i=0;i<LEVEL;i++){
//every point x,y,z
for(int j=0;j<LEVEL*3;j+=3){
vertices[(i*oneLine)+j]=(GLfloat)(START_PT+(j*step/3));
vertices[(i*oneLine)+(j+1)]=(GLfloat)(START_PT+i*step);
vertices[(i*oneLine)+(j+2)]=(GLfloat)(LENGTH/2);
printf("pt : x: %f, y: %f, z: %f \n",
vertices[(i*oneLine)+j],
vertices[(i*oneLine)+j+1],
vertices[(i*oneLine)+j+2]);
}
}
//build colors array, normal white color;
/*GLint totalColor=LEVEL*LEVEL*4;
colors=new GLfloat[totalColor];
for(int r=0;r<totalColor;r+=4){
colors[r]=1;
colors[r+1]=1;
colors[r+2]=1;
colors[r+3]=1;
}*/
//build index array for one face
//using TRIANGLES
indices=new short[(LEVEL-1)*(LEVEL-1)*2*3]; //square of LEVEL-1, 2 triangles, 3 points;
for(int m=0;m<LEVEL-1;m++){
for(int n=0;n<LEVEL-1;n++){
indices[m*((GLint)LEVEL-1)*6+n*6+0]=n+m*((GLint)LEVEL-1)+m+0;
indices[m*((GLint)LEVEL-1)*6+n*6+1]=n+m*((GLint)LEVEL-1)+m+1;
indices[m*((GLint)LEVEL-1)*6+n*6+2]=n+m*((GLint)LEVEL-1)+m+(LEVEL);
indices[m*((GLint)LEVEL-1)*6+n*6+3]=n+m*((GLint)LEVEL-1)+m+1;
indices[m*((GLint)LEVEL-1)*6+n*6+4]=n+m*((GLint)LEVEL-1)+m+(LEVEL)+1;
indices[m*((GLint)LEVEL-1)*6+n*6+5]=n+m*((GLint)LEVEL-1)+m+(LEVEL);
}
}
normals=new GLfloat[LEVEL*LEVEL*3];
for(int s=0;s<LEVEL*LEVEL*3;s+=3){
normals[s]=0;
normals[s+1]=0;
normals[s+2]=1;
}
}
void initLights(){
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glLightfv(GL_LIGHT0,GL_POSITION,lightPos);
glLightfv(GL_LIGHT0,GL_AMBIENT,lightColor);
glLightfv(GL_LIGHT0,GL_DIFFUSE,lightColor);
glLightfv(GL_LIGHT0,GL_SPECULAR,lightColor);
glLightfv(GL_LIGHT0,GL_SPOT_DIRECTION,lightDir);
glLightf(GL_LIGHT0,GL_SPOT_CUTOFF,45);
//
glLightModelfv(GL_LIGHT_MODEL_AMBIENT,light_ambient);
}
int main(int argc, char* args[]){
//make arrays
makeArrays();
//basic init
glutInit(&argc,args);
glutInitDisplayMode(GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE);
//window init
glutInitWindowPosition(100,100);
glutInitWindowSize(600,600);
glutCreateWindow("light cube");
//functions init
glutDisplayFunc(rendering);
glutIdleFunc(rendering);
glutReshapeFunc(reshape);
//gl init
glEnable(GL_DEPTH_TEST);
glEnableClientState(GL_VERTEX_ARRAY);
//glEnableClientState(GL_NORMAL_ARRAY);
//glEnableClientState(GL_COLOR_ARRAY);
glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
//init lights
initLights();
//run main loop, trigger all the funtions
glutMainLoop();
return 0;
}