计算机图形学第十周,shader编程

#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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值