OGL(教程5)——统一变量

原文地址:http://ogldev.atspace.co.uk/www/tutorial05/tutorial05.html

背景知识:
本节教程中我们会遇到几个shader的变量——统一变量。属性和统一变量的区别是,属性变量包含的数据是顶点相关的,所以对于每个shader的调用,都会从顶点缓冲加载新的值,而统一变量则在整个draw call范文保持常量。这就意味着在drawcall之前会赋值统一变量,然后在顶点shader中你可以访问整个值,并且此值保持不变。统一变量能够有效用来存储数据比如光照参数(光照的位置和方向等等),变换矩阵,贴图对象句柄等等。

本节我们将会在屏幕上展示移动的物体。我们是通过在每一帧中改变统一变量的值,然后调用GLUT提供的回调函数。GLUT不会主动调用渲染回调函数,除非我们有必要的情况下。GLUT在以下情况下要调用回调函数,比如最小化和最大化窗口,或者移动另外一个覆盖自己的窗口,此时自己变得可见了,此时也会调用渲染回调函数。如果我们在窗口中没有改变任何事情,那么回调函数只是在启动的时候被调用一次。你可以打印log来观察调用的情况。你会发现每次最大化和最小化窗口的时候会输出一次。在之前的章节中注册回调函数没有问题,但是本节我们希望重复的改变变量的值。我们需要注册一个空转的回调函数。GLUT在窗口系统没有接收到任何事件的时候会调用空转函数。你可定制一个专用的函数,比如当你想在update的时候想调用,或者是简单注册一个类似于空转函数的一样。本节我们后面会见到如何改变和这个值。

代码注视:

glutIdleFunc(RenderSceneCB);

这里我们注册了一个渲染回到函数作为空转函数。注意到如果你决定使用空转函数,你需要在函数调用的最后调用下glutPostRedisplay()函数。glutPostRedisplay()函数标记当前的窗口需要被重画,下一次循环GLUT的main函数会被调用。

gScaleLocation = glGetUniformLocation(ShaderProgram, "gScale");
assert(gScaleLocation != 0xFFFFFFFF);

在链接程序之后,我们查询这个全局变量的位置。这里需要在C/C++执行环境和shader执行环境做一个映射。你不需要直接访问shader的内容,你也不能直接更新它的变量。当你编译shader时,GLSL编译器给每一个统一变量分配一个索引。编译器是通过这个索引找到shader的内部变量。这个是索引也可以通过glGetUniformLocation函数得到。你可以通过程序对象句柄和变量的名字来调用此函数。函数的返回值为变量的index,如果找不到则返回-1。通过上面的断言能够检测出出错信息,有很多的原因会导致这个函数出错。比如变量的名字拼写错误,或者被编译器优化了。如果GLSL编译器发现这个变量在shader没有用到,他会把它丢弃掉。此时glGetUniformLocation会出错。

static float Scale = 0.0f;
Scale += 0.001f;
glUniform1f(gScaleLocation, sinf(Scale));

我们声明一个静态变量然后每次调用渲染函数的时候增加一点点。这个值做sin变化之后传给shader的变量的Scale变量。这个值会在-1到1之间变化。注意sinf接收到的参数是弧度值而不是角度,但此时我们并不关心这个。我们只希望能够得到一个波浪形的变化。这个结果是通过glUniform1f传递给shader的。OpenGL提供多个函数类似于:
glUniform{1234{if}。你可以用它来加载1D、2D、3D或者4D的向量。其值类型可以为i整型,f浮点类型。也能够通过传递向量的地址作为参数代表矩阵。第一个参数是shader变量的地址索引。

然后我们注意下vs着色器中的变化,fs着色器没有变化。

uniform float gScale;

上面我们声明了一个统一变量。

gl_Position = vec4(gScale * Position.x, gScale * Position.y, Position.z, 1.0);

我们对xy分量乘以了这个gScale,z轴保持不变。

代码如下:

// GLUT.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <stdio.h>
#include <glew.h>
#include <freeglut.h>
#include <assert.h>
#include <math.h>
#include "math_3d.h"

#pragma comment( lib, "glew32d.lib" )

GLuint VBO;
GLuint gScaleLocation;
static const char* pVS = " \n\
#version 330 \n\
\n\
layout (location = 0) in vec3 Position; \n\
\n\
uniform float gScale; \n\
\n\
void main() \n\
{ \n\
gl_Position = vec4(gScale * Position.x, gScale * Position.y, Position.z, 1.0); \n\
}";
static const char* pFS = " \n\
#version 330 \n\
\n\
out vec4 FragColor; \n\
\n\
void main() \n\
{ \n\
FragColor = vec4(1.0, 0.0, 0.0, 1.0); \n\
}";
static void RenderSceneCB()
{
	glClear(GL_COLOR_BUFFER_BIT);
	static float Scale = 0.0f;
	Scale += 0.001f;
	glUniform1f(gScaleLocation, sinf(Scale));
	glEnableVertexAttribArray(0);
	glBindBuffer(GL_ARRAY_BUFFER, VBO);
	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
	glDrawArrays(GL_TRIANGLES, 0, 3);
	glDisableVertexAttribArray(0);
	glutSwapBuffers();
}
static void InitializeGlutCallbacks()
{
	glutDisplayFunc(RenderSceneCB);
	glutIdleFunc(RenderSceneCB);
}
static void CreateVertexBuffer()
{
	Vector3f Vertices[3];
	Vertices[0] = Vector3f(-1.0f, -1.0f, 0.0f);
	Vertices[1] = Vector3f(1.0f, -1.0f, 0.0f);
	Vertices[2] = Vector3f(0.0f, 1.0f, 0.0f);
	glGenBuffers(1, &VBO);
	glBindBuffer(GL_ARRAY_BUFFER, VBO);
	glBufferData(GL_ARRAY_BUFFER, sizeof(Vertices), Vertices, GL_STATIC_DRAW);
}
static void AddShader(GLuint ShaderProgram, const char* pShaderText, GLenum ShaderType)
{
	GLuint ShaderObj = glCreateShader(ShaderType);
	if (ShaderObj == 0) {
		fprintf(stderr, "Error creating shader type %d\n", ShaderType);
		exit(0);
	}
	const GLchar* p[1];
	p[0] = pShaderText;
	GLint Lengths[1];
	Lengths[0] = strlen(pShaderText);
	glShaderSource(ShaderObj, 1, p, Lengths);
	glCompileShader(ShaderObj);
	GLint success;
	glGetShaderiv(ShaderObj, GL_COMPILE_STATUS, &success);
	if (!success) {
		GLchar InfoLog[1024];
		glGetShaderInfoLog(ShaderObj, 1024, NULL, InfoLog);
		fprintf(stderr, "Error compiling shader type %d: '%s'\n", ShaderType, InfoLog);
		exit(1);
	}
	glAttachShader(ShaderProgram, ShaderObj);
}
static void CompileShaders()
{
	GLuint ShaderProgram = glCreateProgram();
	if (ShaderProgram == 0) {
		fprintf(stderr, "Error creating shader program\n");
		exit(1);
	}
	AddShader(ShaderProgram, pVS, GL_VERTEX_SHADER);
	AddShader(ShaderProgram, pFS, GL_FRAGMENT_SHADER);
	GLint Success = 0;
	GLchar ErrorLog[1024] = { 0 };
	glLinkProgram(ShaderProgram);
	glGetProgramiv(ShaderProgram, GL_LINK_STATUS, &Success);
	if (Success == 0) {
		glGetProgramInfoLog(ShaderProgram, sizeof(ErrorLog), NULL, ErrorLog);
		fprintf(stderr, "Error linking shader program: '%s'\n", ErrorLog);
		exit(1);
	}
	glValidateProgram(ShaderProgram);
	glGetProgramiv(ShaderProgram, GL_VALIDATE_STATUS, &Success);
	if (!Success) {
		glGetProgramInfoLog(ShaderProgram, sizeof(ErrorLog), NULL, ErrorLog);
		fprintf(stderr, "Invalid shader program: '%s'\n", ErrorLog);
		exit(1);
	}
	glUseProgram(ShaderProgram);
	gScaleLocation = glGetUniformLocation(ShaderProgram, "gScale");
	assert(gScaleLocation != 0xFFFFFFFF);
}
int main(int argc, char** argv)
{
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);
	glutInitWindowSize(1024, 768);
	glutInitWindowPosition(100, 100);
	glutCreateWindow("Tutorial 05");
	InitializeGlutCallbacks();
	// Must be done after glut is initialized!
	GLenum res = glewInit();
	if (res != GLEW_OK) {
		fprintf(stderr, "Error: '%s'\n", glewGetErrorString(res));
		return 1;
	}
	glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
	CreateVertexBuffer();
	CompileShaders();
	glutMainLoop();
	return 0;
}

展示图,是一个放大缩小的过程。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值