OpenGL(1)——环境搭建

转载自:http://johnhany.net/2014/01/environment-for-opengl-with-vs2010/

OpenGL 简介

        OpenGL(Open Graphics Library)是一个开放的、跨编程语言、跨平台的API库,提供了大量的针对图形硬件的软件接口,主要用于绘制高性能的二维和三维图形。它的一个子集OpenGL ES主要针对嵌入式系统,比如手机、平板等,目前也开始流行起来。

        GLSL(OpenGL Shading Language)是OpenGL 2.0版本开始引入的编程语言,用来编写运行在GPU上的着色程序,以代替之前所采用的固定功能管线(fixed-function pipeline)。直到3.x版本起,固定功能管线被彻底弃用,而完全被基于着色器(shader)的新功能所代替。OpenGL 3.0是最后一个同时存在新老两种功能的版本。

        目前OpenGL最新版本是4.4,GLSL的最新版本是4.4。

        由于OpenGL本身只包含涉及渲染的核心函数,而不包括平台相关的UI、文件输入输出、键盘鼠标交互等功能,在不同平台上一般采用不同的扩展库来辅助开发。在UNIX、Linux和Mac OS X平台上一般采用GLUT库实现图形界面,但已经很久没有更新了;在Windows平台上,freeglut会更实用一些。因为调用OpenGL的函数时需要频繁地调用和管理函数指针,可以使用GLEW代替这些繁琐的操作,而且GLEW还会根据你的平台决定使用哪些扩展。


检查兼容性

        OpenGL版本众多,而且各显卡厂商也有自己开发的扩展库。要想使用某个版本进行开发,既需要显卡本身支持所需的功能,又需要驱动程序能兼容这个版本。决定使用哪一个版本之前,先要用GPU Caps Viewer检查一下支持的OpenGL和GLSL的最高版本和具体支持哪些扩展。我的笔记本比较老,仅能支持OpenGL 3.0和GLSL 1.3。

gpu-caps-viewer
image-448

准备文件

        在http://www.opengl.org/resources/libraries/glut/glutdlls37beta.zip下载GLUT;

        在https://sourceforge.net/projects/glew/files/glew/1.10.0/glew-1.10.0-win32.zip/download下载GLEW。

        可以在http://www.transmissionzero.co.uk/software/freeglut-devel/下载freeglut。为了尽可能减少干扰因素,下文的样例程序没有用freeglut,而仅使用GLUT库。

        把解压得到的glutdlls37beta文件夹中的glut.h,和glew-1.10.0-win32\glew-1.10.0\include\GL文件夹中的glew.h、glxew.h、wglew.h共4个文件拷贝到C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Include\gl目录下。(粗体的2个文件是必需的)

include-gl
image-449

        把解压得到的glutdlls37beta文件夹中的glut.lib、glut32.lib,和glew-1.10.0-win32\glew-1.10.0\lib\Release\Win32文件夹中的glew32.lib、glew32s.lib,还有glew-1.10.0-win32\glew-1.10.0\lib\Release MX\Win32文件夹中的glew32mx.lib、glew32mxs.lib共6个文件拷贝到C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Lib目录下。(粗体的3个文件是必需的)

lib
image-450

        把解压得到的glutdlls37beta文件夹中的glut.dll、glut32.dll,和glew-1.10.0-win32\glew-1.10.0\bin\Release\Win32文件夹中的glew32.dll拷贝到C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\bin目录下。(粗体的2个文件是必需的)

bin
image-451

        如果发现这样运行下面的样例代码时提示缺少lib或dll文件,可以参考这篇文档修改添加文件的位置。

        所需的文件也可以在这里下载。

        如果想使用freeglut,其.h、.lib和.dll文件的位置与GLUT和GLEW是相同的。


配置工程

        打开Visual Studio 2010,新建一个Visual C++的Win32 Console Application,选项使用默认的,即Application Type为Console Application,Additional Options选Precompiled Header,其他选项都不勾选。

        打开项目Properties窗口,找到Configuration Properties -> Linker -> Input ->Additional Dependencies,添加glew32.lib。如果使用了freeglut,还要添加freeglut.lib。

linker-input
image-452

        如果还使用了freeglut库,还需要在Configuration Properties -> VC++ Directories -> Include Directories中增加 C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Include\freeglut。

include-directories
image-453


样例代码

        把下面的代码粘贴到main.cpp文件(如果使用了 fleeglut,需要把第 8 行的“gl/glut.h”改为“freeglut.h”):

#include <stdafx.h>
#include <stdio.h>
#include <stdlib.h>
#include <gl/glew.h>
#ifdef __APPLE__
#  include <gl/glut.h>
#else
#  include <gl/glut.h>
#endif

static struct {
	GLuint vertex_buffer, element_buffer, color_buffer;
	GLuint vertex_shader, fragment_shader, program;
	//用于保存CPU端的object名称

	struct {
		GLint position;
		GLint inColor;
	} attributes;
	//用于保存GPU端attribute变量的地址
} names;

static const GLfloat position_data[] = { 
	0.0, 0.6,
	-0.6, -0.4,
	0.6, -0.4
};
static const GLfloat color_data[] = {
	1.0, 0.0, 0.0, 1.0,
	0.0, 1.0, 0.0, 1.0,
	0.0, 0.0, 1.0, 1.0
};
static const GLushort element_data[] = { 0, 1, 2 };

static void infoLog(GLuint object, PFNGLGETSHADERIVPROC glGet__iv, PFNGLGETSHADERINFOLOGPROC glGet__InfoLog)
{
	GLint log_length;
	char *log;

	glGet__iv(object, GL_INFO_LOG_LENGTH, &log_length);
	log = (char *)malloc(log_length);
	glGet__InfoLog(object, log_length, NULL, log);
	fprintf(stderr, "%s", log);
	free(log);
}

void *readShader(const char *filename, GLint *length)
{
	FILE *f = fopen(filename, "r");
	void *buffer;

	if (!f) {
		fprintf(stderr, "Unable to open %s for reading\n", filename);
		return NULL;
	}

	fseek(f, 0, SEEK_END);
	*length = ftell(f);
	fseek(f, 0, SEEK_SET);

	buffer = malloc(*length+1);
	*length = fread(buffer, 1, *length, f);
	fclose(f);
	((char*)buffer)[*length] = '\0';

	return buffer;
}

static GLuint initShader(GLenum type, const char *filename)
{
	GLint length;
	GLchar *source = (GLchar *)readShader(filename, &length);
	GLuint shader;
	GLint shader_ok;

	if (!source)
		return 0;

	shader = glCreateShader(type);
	//创建shader object
	glShaderSource(shader, 1, (const GLchar**)&source, &length);
	//导入shader的代码
	//count - string的行数
	//length - 指向包含string每行字数的数组
	free(source);
	glCompileShader(shader);
	//编译shader代码

	glGetShaderiv(shader, GL_COMPILE_STATUS, &shader_ok);
	//查询shader的状态,导出可能的编译错误
	if (!shader_ok) {
		fprintf(stderr, "Failed to compile %s:\n", filename);
		infoLog(shader, glGetShaderiv, glGetShaderInfoLog);
		glDeleteShader(shader);
		getchar();
	}
	return shader;
}

static void installShaders(void)
{
	names.vertex_shader = initShader(GL_VERTEX_SHADER, "HelloWorld-vs.glsl");
	names.fragment_shader = initShader(GL_FRAGMENT_SHADER, "HelloWorld-fs.glsl");

	GLint program_ok;
	names.program = glCreateProgram();
	glAttachShader(names.program, names.vertex_shader);
	glAttachShader(names.program, names.fragment_shader);
	//把shader依附在同一个program上,以连接两个shader
	glLinkProgram(names.program);
	//链接program,在GPU端创建相应可执行文件,并初始化uniform变量及其地址
	glGetProgramiv(names.program, GL_LINK_STATUS, &program_ok);
	//查询program的状态,并导出可能的错误
	if (!program_ok) {
		fprintf(stderr, "Failed to link shader program:\n");
		infoLog(names.program, glGetProgramiv, glGetProgramInfoLog);
		glDeleteProgram(names.program);
		getchar();
	}
	glUseProgram(names.program);
	//激活program后才能为shader指定uniform变量的值
}

static void initBuffers(void)
{
	names.attributes.position = glGetAttribLocation(names.program, "position");
	names.attributes.inColor = glGetAttribLocation(names.program, "inColor");
	//获取GPU端attribute变量的地址保存在本地变量中,用于值的传递

	glGenBuffers(1, &names.vertex_buffer);
	//产生1个buffer object的名称,并分配显存空间
	glBindBuffer(GL_ARRAY_BUFFER, names.vertex_buffer);
	//把产生的buffer object与相应target绑定,以改变其值
	glBufferData(GL_ARRAY_BUFFER, sizeof(position_data), position_data, GL_STATIC_DRAW);
	//GL_STATIC_DRAW其他可用参数:
	//STATIC - 长时间不更改的值		DYNAMIC - 需要频繁改变的值		STREAM - 需要偶尔重写整个buffer的值
	//DRAW - 保存于GPU用于绘制的值		READ - 保存于CPU用于读取的值		COPY - 折衷
	glVertexAttribPointer(names.attributes.position, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat)*2, (void*)0);
	glEnableVertexAttribArray(names.attributes.position);

	glGenBuffers(1, &names.color_buffer);
	glBindBuffer(GL_ARRAY_BUFFER, names.color_buffer);
	glBufferData(GL_ARRAY_BUFFER, sizeof(color_data), color_data, GL_STATIC_DRAW);
	glVertexAttribPointer(names.attributes.inColor, 4, GL_FLOAT, GL_FALSE, sizeof(GLfloat)*4, (void*)0);
	glEnableVertexAttribArray(names.attributes.inColor);

	glGenBuffers(1, &names.element_buffer);
	glBindBuffer(GL_ARRAY_BUFFER, names.element_buffer);
	glBufferData(GL_ARRAY_BUFFER, sizeof(element_data), element_data, GL_STATIC_DRAW);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, names.element_buffer);
}

static void idleFunc(void)
{
}

static void displayFunc(void)
{
	glClearColor(1.0, 1.0, 1.0, 1.0);
	glClear(GL_COLOR_BUFFER_BIT);

	glDrawElements(GL_TRIANGLE_STRIP, 3, GL_UNSIGNED_SHORT, (void*)0);

	glutSwapBuffers();
}

int main(int argc, char** argv)
{
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
	glutInitWindowSize(400, 400);
	glutCreateWindow("Hello World");
	glutIdleFunc(&idleFunc);
	glutDisplayFunc(&displayFunc);

	glewInit();
	if (!GLEW_VERSION_2_0) {
		fprintf(stderr, "OpenGL 2.0 not available\n");
		getchar();
	}
	//与glew扩展库相关的函数要在glewInit()后执行
	installShaders();
	initBuffers();

	glutMainLoop();
	return 0;
}

在工程内新建一个名为HelloWorld-vs.glsl的文件,内容如下:

#version 130

attribute vec2 position;
attribute vec4 inColor;

varying vec4 outColor;
void main()
{
    gl_Position = vec4(position, 0.0, 1.0);
	outColor = inColor;
}
再新建一个名为HelloWorld-fs.glsl的文件,内容如下:
#version 130

varying vec4 outColor;

void main()
{
    gl_FragColor = outColor;
}

运行结果

triangle-ibo

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值