【计算机图形学-9】OpenGL程序实例分析1——绘制三角形

这一小节回顾一下基于C++的OpenGL Hello World程序代码。
在这里插入图片描述

这一小节,我们要绘制LearnOpenGL上的一个三角形实例,基于OpenGL+GLEW+FreeGLUT。我们用代码加注释的形式进行走读。

main.cpp文件:

#include "Angel.h"
#include <string>

const int NUM_POINTS = 3;

// 绑定数据都是有套路的,一般来说,就是:分配vao-绑定vao-分配vbo-绑定vbo-喂数据-读取着色器并使用-传数据给GPU
void init()
{
	// 定义三角形的三个点,注意范围应该都在[-1,1]
	vec2 vertices[3] = {
		vec2(-0.75, -0.75), vec2(0.0, 0.75), vec2(0.75, -0.75)
	};

	// 创建顶点数组对象
	GLuint vao;
	#ifdef __APPLE__	// for MacOS
		glGenVertexArraysAPPLE(1, &vao);	// 分配1个顶点数组对象
		glBindVertexArrayAPPLE(vao);		// 绑定顶点数组对象
	#else				// for Windows
		glGenVertexArrays(1, &vao);		// 分配1个顶点数组对象
		glBindVertexArray(vao);			// 绑定顶点数组对象
	#endif

	// 创建顶点缓存对象
	GLuint buffer;
	// 分配1个顶点缓存对象
	glGenBuffers(1, &buffer);
	// 绑定顶点缓存对象
	glBindBuffer(GL_ARRAY_BUFFER, buffer);
	// 分配数据所需的存储空间,将数据拷贝到OpenGL服务端内存
	glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

	// 读取着色器并使用
	std::string vshader, fshader;
	#ifdef __APPLE__	// for MacOS
		vshader = "shaders/vshader_mac.glsl";
		fshader = "shaders/fshader_mac.glsl";
	#else				// for Windows
		vshader = "shaders/vshader_win.glsl";
		fshader = "shaders/fshader_win.glsl";
	#endif
	GLuint program = InitShader(vshader.c_str(), fshader.c_str());
	glUseProgram(program);

	// 从顶点着色器中初始化顶点的位置(在着色器中有vPosition这个变量,后面讲)
	GLuint location = glGetAttribLocation(program, "vPosition");
	// 启用顶点属性数组
	glEnableVertexAttribArray(location);
	// 关联到顶点属性数组 (index, size, type, normalized, stride, *pointer)
	glVertexAttribPointer(location, 2, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0));

	// 白色背景
	glClearColor(1.0, 1.0, 1.0, 1.0);
}

void display(void)
{
	// 清理窗口
	glClear(GL_COLOR_BUFFER_BIT);
	// 绘制所有点
	glDrawArrays(GL_TRIANGLES, 0, NUM_POINTS);
	glFlush();
}

int main(int argc, char **argv)
{
	// 初始化GLUT库,必须是应用程序调用的第一个GLUT函数
	glutInit(&argc, argv);

	// 配置窗口的显示特性
	glutInitDisplayMode(GLUT_RGBA);
	// 配置窗口大小
	glutInitWindowSize(512, 512);
	// 创建窗口,指令窗口名
	glutCreateWindow("Red Triangle");

	// for Windows
	#ifdef WIN32
		// 检测是否使用了freeglut,并检测是否使用到了OpenGL 3.3
		glutInitContextVersion(3, 3);
		glutInitContextProfile(GLUT_CORE_PROFILE);
		// 保证GLEW使用更多的现代技术管理OpenGL,防止core profile出现崩溃
		glewExperimental = GL_TRUE;
		glewInit();
	#endif

	// 定义、初始化、绑定三角形数据
	init();
	// 指定当前窗口进行重绘时要调用的函数
	glutDisplayFunc(display);
	// 负责一直处理窗口和操作系统的用户输入等操作
	glutMainLoop();

	return 0;
}

InitShader.cpp当成黑盒子使用就可以了,通吃顶点着色器和片元着色器:

#include "Angel.h"

namespace Angel {

// Create a NULL-terminated string by reading the provided file
static char*
readShaderSource(const char* shaderFile)
{
	#ifdef __APPLE__	// for MacOS
		FILE *fp;
		fp = fopen(shaderFile, "r");
	#else				// for windows
		FILE *fp;
		fopen_s(&fp, shaderFile, "r");
	#endif

    if ( fp == NULL ) { return NULL; }

    fseek(fp, 0L, SEEK_END);
    long size = ftell(fp);

    fseek(fp, 0L, SEEK_SET);
    char* buf = new char[size + 1];

    memset(buf, 0, size + 1);

    fread(buf, 1, size, fp);

    buf[size] = '\0';
    fclose(fp);

    return buf;
}


// Create a GLSL program object from vertex and fragment shader files
GLuint
InitShader(const char* vShaderFile, const char* fShaderFile)
{
    struct Shader {
	const char*  filename;
	GLenum       type;
	GLchar*      source;
    }  shaders[2] = {
	{ vShaderFile, GL_VERTEX_SHADER, NULL },
	{ fShaderFile, GL_FRAGMENT_SHADER, NULL }
    };

    GLuint program = glCreateProgram();
    
    for ( int i = 0; i < 2; ++i ) {
	Shader& s = shaders[i];
	s.source = readShaderSource( s.filename );
	if ( shaders[i].source == NULL ) {
	    std::cerr << "Failed to read " << s.filename << std::endl;
	    exit( EXIT_FAILURE );
	}

	GLuint shader = glCreateShader( s.type );
	glShaderSource( shader, 1, (const GLchar**) &s.source, NULL );
	glCompileShader( shader );

	GLint  compiled;
	glGetShaderiv( shader, GL_COMPILE_STATUS, &compiled );
	if ( !compiled ) {
	    std::cerr << s.filename << " failed to compile:" << std::endl;
	    GLint  logSize;
	    glGetShaderiv( shader, GL_INFO_LOG_LENGTH, &logSize );
	    char* logMsg = new char[logSize];
	    glGetShaderInfoLog( shader, logSize, NULL, logMsg );
	    std::cerr << logMsg << std::endl;
	    delete [] logMsg;

	    exit( EXIT_FAILURE );
	}

	delete [] s.source;

	glAttachShader( program, shader );
    }

    /* link  and error check */
    glLinkProgram(program);

    GLint  linked;
    glGetProgramiv( program, GL_LINK_STATUS, &linked );
    if ( !linked ) {
	std::cerr << "Shader program failed to link" << std::endl;
	GLint  logSize;
	glGetProgramiv( program, GL_INFO_LOG_LENGTH, &logSize);
	char* logMsg = new char[logSize];
	glGetProgramInfoLog( program, logSize, NULL, logMsg );
	std::cerr << logMsg << std::endl;
	delete [] logMsg;

	exit( EXIT_FAILURE );
    }

    /* use program object */
    glUseProgram(program);

    return program;
}

}  // Close namespace Angel block

顶点着色器vshader.glsl:

#version 330 core

in vec3 vPosition;

void main()
{
    gl_Position = vec4(vPosition, 1.0);
}

片元着色器fshader.glsl:

#version 330 core

out vec4 fColor;

void main()
{
    fColor = vec4(0.3, 0.4, 0.5, 1.0);
}

在这里插入图片描述
让着色器稍微复杂一点(其实也不复杂→_→),我们就可以得到一个颜色插值三角形。
vshader.glsl:

#version 330 core

in vec3 vPosition;
out vec3 vColor;

void main()
{
    gl_Position = vec4(vPosition, 1.0);
    vColor = vPosition;
}

fshader.glsl:

#version 330 core

in vec3 vColor;
out vec4 fColor;

void main()
{
    // 暂时把顶点位置信息当作颜色信息
    fColor = vec4(vColor, 1.0);
}

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值