OpenGL编程逐步深入(五)Uniform 变量
准备知识
在这个教程中我们会遇到一种新的Shader变量类型,即uniform变量。attribute(属性)变量和uniform变量的不同之处在于attribute 变量中包含顶点的具体数据,当每次执行shader调用时会从顶点缓存中重新加载一个新的值。而uniform类型的变量在整个绘制调用中始终使用同一个变量。这意味着你在绘制调用前加载的值在每个vertex shader调用时能访问到相同的值。uniform变量在存储光照参数(光照位置、方向等)、变换矩阵、纹理对象句柄等这一类型的数据时非常有用。
在这个教程中我们最终会看到一些东西在屏幕上移动。我们將它和一个uniform变量进行绑定,GLUT为我们提供了空闲回调函数,在绘制每一帧的时候改变变量的值。GLUT并不会重复的调用渲染回调函数,除非在需要的时候,例如窗口最大化、最小化或被其他窗口覆盖。如果我们在启动应用程序后不对窗口进行任何操作,渲染回调函数仅仅会被调用一次。可以通过在这个回调函数中使用printf向控制台打印信息来验证这个结论。在GLUT中只注册渲染回调函数在前几节教程中没什么问题,但本节我们需要反复的改变变量的值,因此我们通过注册空闲回调函数实现。空闲处理函数即使没有接收到来自Windows系统事件时也会被GLUT实时的调用。你可以为这个回调专门写一个函数,或者把渲染回调函数也指定为空闲回调函数。在本教程我们我们采用后者,在渲染回调函数中更新变量的值。
项目配置
参考上节。
程序代码
我们在上一节代码基础上进行调整。
清单1.主程序 tutorial05.cpp代码
/*
Copyright 2010 Etay Meiri
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Tutorial 05 - uniform variables
*/
#include "stdafx.h"
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <math.h>
#include <GL/glew.h>
#include <GL/freeglut.h>
#include "ogldev_math_3d.h"
GLuint VBO;
GLuint gScaleLocation;
const char* pVSFileName = "shader.vs";
const char* pFSFileName = "shader.fs";
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(1);
}
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);
}
string vs, fs;
if (!ReadFile(pVSFileName, vs)) {
exit(1);
};
if (!ReadFile(pFSFileName, fs)) {
exit(1);
};
AddShader(ShaderProgram, vs.c_str(), GL_VERTEX_SHADER);
AddShader(ShaderProgram, fs.c_str(), 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 _tmain(int argc, _TCHAR* 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;
}
printf("GL version: %s\n", glGetString(GL_VERSION));
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
CreateVertexBuffer();
CompileShaders();
glutMainLoop();
return 0;
}
代码解读
glutIdleFunc(RenderSceneCB);
这里我们將渲染回调函数RenderSceneCB也注册为空闲回调函数,要注意的是如果你你打算定义一个专门的函数处理空闲回调,需要在后面增加glutPostRedisplay() 函数的调用,这样的话空闲回调函数就会反复的调用而渲染回调函数则不会。
gScaleLocation = glGetUniformLocation(ShaderProgram, "gScale");
assert(gScaleLocation != 0xFFFFFFFF);
在链接后,我们查询Program对象获取uniform变量的位置,这是另外一个c/c++执行环境需要映射到shader执行环境的案例。你不能直接访问shader的内容,也不能直接更新shader的变量。当你编译shader后,GLSL编译器会为每一个uniform变量分配一个索引。shader在编译器内部表示中都通过索引来访问它的变量。这个索引在程序中通过glGetUniformLocation也能够获取,调用函数时需要传入program对象的句柄和变量名称,该函数会返回变量的索引(出错时返回-1)。这里检测错误是非常必要的,否则将来更新变量时不会传递到shader中。这个函数调用失败主要两个原因,你的变量名拼写错误或它被编译器优化掉了,如果GLSL编译器发现该变量在Shader中没有用到就会去除它,这种情况下会导致glGetUniformLocation 调用失败。
static float Scale = 0.0f;
Scale += 0.001f;
glUniform1f(gScaleLocation, sinf(Scale));
这里我们定义一个静态float类型变量Scale ,在每次调用渲染回调函数时把它的值增加0.001,实际上传递给shader的值是Scale 变量的正弦值,这样做很好的创建了一个在-1.0到1.0之间的循环。需要注意的是sinf的参数是要传入一个弧度还是角度,这里我们无需关注,我们只需要产生一个在-1到1的正弦波。sinf函数的返回值通过glUniform1f函数传递到shader中,OpenGl提供的这个函数有多种形式glUniform{1234}{if}。你可以使用它將值加载到1维、2维、3维或4维向量中。第一个参数为之前调用glGetUniformLocation获取的位置索引。
清单2. shader.vs代码
#version 330
layout (location = 0) in vec3 Position;
uniform float gScale;
void main()
{
gl_Position = vec4(gScale * Position.x, gScale * Position.y, Position.z, 1.0);
}
uniform float gScale;
这里我们定义了一个uniform类型变量。
gl_Position = vec4(gScale * Position.x, gScale * Position.y, Position.z, 1.0);
我们用gScale乘上Positon向量X/Y的值,确保vec4函数参数值在每一帧渲染时会改变,然后你就能够解释屏幕中的三角形为什么一会变大一会变小。
编译运行
运行程序你会看到大小不断变化的三角形。
OpenGL编程逐步深入(五)Uniform 变量的更多相关文章
- (Python OpenGL)【4】Uniform变量 PyOpenGL
(Python OpenGL) 原文:http://ogldev.atspace.co.uk/www/tutorial05/tutorial05.html(英文) __author__ = " ...
- OpenGL红宝书例子2.2 uniform变量的使用
1. 简单介绍一下OpenGL可编程渲染管线的流程 顶点着色 --> 细分着色 --> 几何着色 --> 片元着色 --> 计算着色 一般我们主要参与的阶段是顶点着色和片元着色 ...
- OpenGL ES着色器语言之变量和数据类型(一)(官方文档第四章)和varying,uniform,attribute修饰范围
OpenGL ES着色器语言之变量和数据类型(一)(官方文档第四章) 所有变量和函数在使用前必须声明.变量和函数名是标识符. 没有默认类型,所有变量和函数声明必须包含一个声明类型以及可选的修饰符. ...
- 用MFC实现OpenGL编程
一.OpenGL简介 众所周知,OpenGL原先是Silicon Graphics Incorporated(SGI公司)在他们的图形工作站上开发高质量图像的接口.但最近几年它成为一个非常优秀的开放式 ...
- OpenGL学习笔记(五)变换
目录 变换 向量 向量的运算 向量与标量运算 向量取反 向量加减 求向量长度 向量的单位化 向量相乘 点乘(Dot Product) 叉乘 矩阵 矩阵的加减 矩阵的数乘 矩阵相乘 矩阵与向量相乘 与单 ...
- CSharpGL(33)使用uniform块来优化对uniform变量的读写
CSharpGL(33)使用uniform块来优化对uniform变量的读写 +BIT祝威+悄悄在此留下版了个权的信息说: Uniform块 如果shader程序变得比较复杂,那么其中用到的unifo ...
- OpenGL编程指南(第七版)
OpenGL编程指南(第七版) 转自:http://blog.csdn.net/w540982016044/article/details/21287645 在接触OpenGL中,配置显得相当麻烦,特 ...
- C#编程总结(五)多线程带给我们的一些思考
C#编程总结(五)多线程带给我们的一些思考 如有不妥之处,欢迎批评指正. 1.什么时候使用多线程? 这个问题,对于系统架构师.设计者.程序员,都是首先要面对的一个问题. 在什么时候使用多线程技术? 在 ...
- OpenGL ES着色器语言之变量和数据类型(二)(官方文档第四章)
OpenGL ES着色器语言之变量和数据类型(二)(官方文档第四章) 4.5精度和精度修饰符 4.5.1范围和精度 用于存储和展示浮点数.整数变量的范围和精度依赖于数值的源(varying,unifo ...
随机推荐
- JDBC连接mysql时出现的ssl问题
使用MySQL数据库时出现如下错误: WARN: Establishing SSL connection without server's identity verification is not r ...
- 測试jbpm6.2使用的基础类
方便了解jbpm6.2功能我们能够建立一个測试项目,在当中构建一个測试基础类,详细过程例如以下所看到的. 在集成了插件org.drools.updatesite-6.2.0.Final.zip的ecl ...
- Binary Indexed Tree
我借鉴了这个视频中的讲解的填坑法,我认为非常易于理解.有FQ能力和基本英语听力能力请直接去看视频,并不需要继续阅读. naive 算法 考虑一个这样的场景: 给定一个int数组, 我们想知道它的连续子 ...
- 线上服务CPU100%问题快速定位实战--转
来自微信公众号 架构师之路 功能问题,通过日志,单步调试相对比较好定位. 性能问题,例如线上服务器CPU100%,如何找到相关服务,如何定位问题代码,更考验技术人的功底. 58到家架构部,运维部,58 ...
- servlet中怎么注入service
在工作中使用到spring的mvc框架,分为controller/service/dao三个层次.偶尔会用到servlet替换掉controller,这就遇到如何在servlet中使用注入到sprin ...
- xxx while the managed IDbConnection interface was being used: Login failed for user xxx
Process cube的时候遇到如下错误. Errors in the high-level relational engine. The following exception occurre ...
- Ubuntu16.04 Mysql
1.安装mysql root@ubuntu:~# sudo apt-get install mysql-server root@ubuntu:~# apt install mysql-client r ...
- Android 常用系统服务
WindowManager:WindowManager服务是全局的唯一的.它会将用户在屏幕上的操作发送给界面上的各个Window,Activity会将顶层控件注册到WindowManager中.Win ...
- lftp简单使用
连接服务器: lftp -e "参数;" "username":"password"@"ip" -p port lftp ...
- C++12.1.4 类的前向声明、不完全类型类
只声明却没有定义的类称为—————–不完全类型,不完全类型不能定义该类型的对象,只能用于定义指向该类型的指针及引用,或者用于声明(不是定义)使用该类型作为形参类型或返回类型的函数. 在创建类的对象之前 ...