#include <stdio.h>
#include <gl/glew.h>
#include <gl/glut.h>
#include <math.h>
#include "gmath.h"
#include "gmatrix3d.h"
#include "gvector3d.h"
#include "gcamera.h"
#include "gmaterial.h"
#include "glight.h"
#include "gtexture2d.h"
GMatrix3d gRotMatrix;
GTexture2D gEarthTex;
bool gIsLButtonDown = false;
int gMouseX = 0;
int gMouseY = 0;
GCamera gCamera;
GLight gLight0;
GLuint gSpotProgram = 0;
void drawPlane()
{
glColor3f(0.6f, 0.6f, 0.6f);
int nx = 10;
double dx = 2.0 / nx;
double x, y0, y1;
double da = 2*PI / nx;
double alpha = 0;
glBegin(GL_QUADS);
x = -1;
for (int i=0; i<nx; i++)
{
GVector3d v0, v1;
y0 = sin(alpha) * 0.2;
y1 = sin(alpha + da) * 0.2;
v0.set(-0.2*cos(alpha), 1.0/PI, 0);
v0.normalize();
v1.set(-0.2*cos(alpha+da), 1.0/PI, 0);
v1.normalize();
glNormal3dv(v0);
glVertex3d(x, y0, -1);
glNormal3dv(v0);
glVertex3d(x, y0, 1);
glNormal3dv(v1);
glVertex3d(x+dx, y1, 1);
glNormal3dv(v1);
glVertex3d(x+dx, y1, -1);
x += dx;
alpha += da;
}
glEnd();
/*glBegin(GL_LINES);
for (float u=-1.0f; u<1.01f; u+=0.2f)
{
glVertex3d(-1, 0, u);
glVertex3d(1, 0, u);
glVertex3d(u, 0, -1);
glVertex3d(u, 0, 1);
}
glEnd();*/
}
void drawSphere(int nslice, int nstack)
{
double theta, dth, alpha, da, x, z, y, dy, r;
double s, t, ds, dt;
dth = 2*PI / nslice;
dy = 2.0 / nstack;
da = PI / nstack;
alpha = 0;
ds = 1.0 / nslice;
dt = 1.0 / nstack;
t = 1.0;
//glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
glBegin(GL_TRIANGLE_STRIP);
for (int j=0; j<nstack; j++)
{
theta = 0;
s = 0;
for (int i=0; i<=nslice; i++)
{
y = cos(alpha);
r = sin(alpha);
x = r * sin(theta);
z = r * cos(theta);
glTexCoord2d(s, t);
glNormal3d(x, y, z);
glVertex3d(x, y, z);
y = cos(alpha+da);
r = sin(alpha+da);
x = r * sin(theta);
z = r * cos(theta);
glTexCoord2d(s, t-dt);
glNormal3d(x, y, z);
glVertex3d(x, y, z);
theta += dth;
s += ds;
}
alpha += da;
t -= dt;
}
glEnd();
}
void drawCylinder(int nslice, int nstack)
{
double theta, dth, x, z, y, dy;
dth = 2*PI / nslice;
dy = 2.0 / nstack;
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
glBegin(GL_TRIANGLE_STRIP);
for (int j=0; j<nstack; j++)
{
theta = 0;
for (int i=0; i<=nslice; i++)
{
x = cos(theta);
z = sin(theta);
y = 1 - j*dy;
glNormal3d(x, 0, z);
glVertex3d(x, y, z);
glNormal3d(x, 0, z);
glVertex3d(x, y-dy, z);
theta += dth;
}
}
glEnd();
}
void onDisplay()
{
// RGBA
glClearColor(0, 0, 0, 1);
// 清除缓存
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
gCamera.lookAt();
//glTranslated(0, 0, -1.5);
glMultMatrixd(gRotMatrix);
glLineWidth(3);
GMaterial mat;
glEnable(GL_LIGHTING);
mat.setDiffuseColor(1, 1, 1);
mat.setSpecularColor(0.8, 0.8, 0.8);
mat.setShininess(30);
mat.apply();
glutSolidTeapot(1);
/*glEnable(GL_TEXTURE_2D);
glPushMatrix();
glScaled(0.5, 0.5, 0.5);
drawSphere(32, 16);
glPopMatrix();
glDisable(GL_TEXTURE_2D);*/
/*drawPlane();
mat.setSpecularColor(0, 0, 0);
mat.setDiffuseColor(1, 0, 0);
mat.apply();
glPushMatrix();
glTranslatef(-0.3f, 0, -0.3f);
glColor3f(1, 0, 0);
glutSolidCube(0.4f);
glPopMatrix();
mat.setDiffuseColor(0, 1, 0);
mat.setEmissiveColor(0, 0.2, 0);
mat.apply();
mat.setEmissiveColor(0, 0, 0);
glPushMatrix();
glTranslatef(0.3f, 0, -0.3f);
glColor3f(0, 1, 0);
glutSolidSphere(0.2f, 16, 16);
glPopMatrix();
mat.setDiffuseColor(1, 1, 0);
mat.setSpecularColor(0.8, 0.8, 0.8);
mat.setShininess(10);
mat.apply();
glPushMatrix();
glTranslatef(0, 0, 0.3f);
glRotatef(-90, 1, 0, 0);
glColor3f(1, 1, 0);
glutSolidCone(0.2f, 0.6f, 32, 16);
glPopMatrix();*/
glLineWidth(1);
glDisable(GL_LIGHTING);
// 交换缓存
glutSwapBuffers();
}
void onReshape(int w, int h)
{
gCamera.setScreenSize(w, h);
gCamera.project();
glutPostRedisplay();
}
GVector3d mousePt2SphereVec(int x, int y, int cw, int ch)
{
double lx, ly, lz, r;
lx = (2.0*x - cw) / cw;
ly = (ch - 2.0*y) / ch;
r = lx*lx + ly*ly;
if (r > 1) r = 1;
lz = sqrt(1 - r);
return GVector3d(lx, ly, lz).getNormal();
}
void onMouse(int button, int state, int x, int y)
{
if (button == GLUT_LEFT_BUTTON)
{
if (state == GLUT_DOWN)
{
gIsLButtonDown = true;
gMouseX = x;
gMouseY = y;
}
else if (state == GLUT_UP)
{
gIsLButtonDown = false;
}
}
}
void onMotion(int x, int y)
{
if (gIsLButtonDown)
{
GVector3d v1, v2;
int cw = glutGet(GLUT_WINDOW_WIDTH);
int ch = glutGet(GLUT_WINDOW_HEIGHT);
v1 = mousePt2SphereVec(gMouseX, gMouseY, cw, ch);
v2 = mousePt2SphereVec(x, y, cw, ch);
gMouseX = x;
gMouseY = y;
GVector3d n = v1.crossMult(v2);
if (n.getLength() < 1e-6) return ;
double cosa = v1.dotMult(v2);
if (cosa < -1) cosa = -1;
if (cosa > 1) cosa = 1;
double af = acos(cosa) * RADIAN_TO_ANGLE;
gRotMatrix *= GMatrix3d::createRotate(af, n);
glutPostRedisplay();
}
}
char * readTextFile(const char *fname)
{
FILE *fp = fopen(fname, "r");
if (!fp) return NULL;
fseek(fp, 0, SEEK_END);
int size = ftell(fp);
char *buf = new char[size+1];
rewind(fp);
size = fread(buf, sizeof(char), size, fp);
buf[size] = 0;
fclose(fp);
return buf;
}
GLuint createShaderProgram(const char *vfname, const char *ffname)
{
// 创建Shader
GLuint v = glCreateShader(GL_VERTEX_SHADER);
GLuint f = glCreateShader(GL_FRAGMENT_SHADER);
// 读取Shader源文件
char *vs = readTextFile(vfname);
if (!vs) return 0;
char *fs = readTextFile(ffname);
if (!fs)
{
delete []vs;
return 0;
}
// 将源文件与Shader挂接
glShaderSource(v, 1, (const char **)&vs, NULL);
glShaderSource(f, 1, (const char **)&fs, NULL);
// 释放源文件字符串
delete []vs;
delete []fs;
// 编译Shader
glCompileShader(v);
glCompileShader(f);
// 创建Shader程序
GLuint shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, f);
glAttachShader(shaderProgram, v);
// 链接、使用程序
glLinkProgram(shaderProgram);
glUseProgram(shaderProgram);
return shaderProgram;
}
void initGL()
{
gCamera.setViewVolume(45, 1, 0.1, 10);
gCamera.setPosition(GPoint3d(0, 0, 5));
gCamera.setForward(GVector3d(0, 0, -1));
gCamera.setUp(GVector3d(0, 1, 0));
glEnable(GL_DEPTH_TEST);
glShadeModel(GL_SMOOTH);
gEarthTex.init();
if (!gEarthTex.loadTexImage("earthmap.jpg"))
{
printf("Load Texture Image Failed!\n");
}
gLight0.init(0, gSpotLight);
gLight0.setPosition(0, 0.5f, 5);
gLight0.setSpotDirection(0, -0.05f, -1);
gLight0.setConstantAttenuation(1);
gLight0.setLinearAttenuation(0.05);
gLight0.setCutoffAngle(5);
gLight0.turnOn();
gSpotProgram = createShaderProgram("spot.vert", "spot.frag");
}
int main(int argc, char *argv[])
{
// 初始化glut
glutInit(&argc, argv);
// 设置OpenGL显示模式(双缓存, RGB颜色模式, 深度缓存)
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
// 设置窗口初始尺寸
glutInitWindowSize(800, 600);
// 设置窗口初始位置
glutInitWindowPosition(100, 100);
// 设置窗口标题
glutCreateWindow("Graphics Study");
glewInit();
if (glewIsSupported("GL_VERSION_2_0"))
{
printf("Ready for OpenGL 2.0\n");
}
else
{
printf("OpenGL 2.0 not supported\n");
exit(1);
}
initGL();
char *txt = readTextFile("main.cpp");
printf("%s\n", txt);
delete []txt;
// 设置显示回调
glutDisplayFunc(onDisplay);
// Reshape回调
glutReshapeFunc(onReshape);
// 鼠标按键回调
glutMouseFunc(onMouse);
// 鼠标移动回调
glutMotionFunc(onMotion);
// 进入glut事件循环
glutMainLoop();
return 0;
}
新建了spot.vert和spot.frag两个文件,代码如下:
spot.vert
varying vec4 diffuse,ambientGlobal,ambient;
varying vec3 normal,lightDir,halfVector;
varying float dist;
void main()
{
vec4 ecPos;
vec3 aux;
normal = normalize(gl_NormalMatrix * gl_Normal);
ecPos = gl_ModelViewMatrix * gl_Vertex;
aux = vec3(gl_LightSource[0].position - ecPos);
lightDir = normalize(aux);
dist = length(aux);
halfVector = normalize(gl_LightSource[0].halfVector.xyz);
diffuse = gl_FrontMaterial.diffuse * gl_LightSource[0].diffuse;
ambient = gl_FrontMaterial.ambient * gl_LightSource[0].ambient;
ambientGlobal = gl_LightModel.ambient * gl_FrontMaterial.ambient;
gl_Position = ftransform();
}
spot.frag
spot.frag
varying vec4 diffuse,ambientGlobal,ambient;
varying vec3 normal,lightDir,halfVector;
varying float dist;
void main()
{
vec3 n,halfV;
float NdotL,NdotHV;
vec4 color = ambientGlobal;
float att,spotEffect;
n = normalize(normal);
NdotL = max(dot(n,normalize(lightDir)),0.0);
if(NdotL > 0.0)
{
spotEffect = dot(normalize(gl_LightSource[0].spotDirection),normalize(-lightDir));
if(spotEffect > gl_LightSource[0].spotCosCutoff)
{
spotEffect = pow(spotEffect,gl_LightSource[0].spotExponent);
att = spotEffect / (gl_LightSource[0].constantAttenuation +
gl_LightSource[0].linearAttenuation * dist +
gl_LightSource[0].quadraticAttenuation * dist * dist);
color += att * (diffuse * NdotL + ambient);
halfV = normalize(halfVector);
NdotHV = max(dot(n,halfV),0.0);
color += att * gl_FrontMaterial.specular *
gl_LightSource[0].specular *
pow(NdotHV,gl_FrontMaterial.shininess);
}
}
gl_FragColor = color;
}