文章目录
LearnGL - 学习笔记目录
- 思路
- 着色器
- 创建三个纹理对象
- 绑定到纹理单元
- 加载三个纹理对象
- 设置采样器采样对应的纹理单元
- 传入 time 时间控制 uv 纹理坐标动画
- 运行效果
- 完整代码
本人才疏学浅,如有什么错误,望不吝指出。
上一篇:LearnGL - 05.1 - Texture Wrap Mode,了解到可以使用纹理坐标来滚动动画。
这一篇:我们使用纹理坐标滚动动画 + 多纹理,实现类似 2D UI 流光动画
实现过程与思路的参考可以查看我之前写的:Unity Shader - 实现类似UI遮罩流光
(个人觉得 Unity 中的 ShaderLab 结合了 GLSL 与 HLSL 的有点,还是比 OpenGL GLSL有好很多的,而且还柔和了多种渲染状态相关的设置在 ShaderLab 里,提升了渲染状态设置的内聚性,便于理解与维护)
思路- 准备流光图
- 准备流光遮罩图
- 主要显示纹理
流光图(我用GIMP随便画的,还是PS好用)
流光遮罩图
主纹理
// jave.lin - tex_2d_ui_flash_light.vert - 测试实现 2D UI 流光的顶点着色器
#version 450 compatibility
attribute vec3 vPos;
attribute vec2 vUV;
varying vec2 fUV;
void main() {
gl_Position = vec4(vPos, 1.0);
fUV = vUV;
}
// jave.lin - tex_2d_ui_flash_light.frag - 测试实现 2D UI 流光的片段着色器
#version 450 compatibility
varying vec2 fUV; // uv 坐标
uniform sampler2D main_tex; // 主纹理
uniform sampler2D mask_tex; // 遮罩纹理
uniform sampler2D flash_light_tex; // 闪光/流光纹理
uniform float time; // 时间(秒)用于动画
void main() {
vec3 mainCol = texture(main_tex, fUV).rgb;
float mask = texture(mask_tex, fUV).r;
vec4 flashCol = texture(flash_light_tex, fUV + vec2(-time, 0));
flashCol *= flashCol.a * mask;
mainCol = mainCol + flashCol.rgb;
gl_FragColor = vec4(mainCol, 1.0);
}
创建三个纹理对象
glCreateTextures(GL_TEXTURE_2D, 3, texture); // 创建 3 个纹理对象
绑定到纹理单元
glActiveTexture(GL_TEXTURE0); // 激活第 0 索引纹理单元
glBindTextureUnit(0, texture[0]); // 纹理单元 0 绑定:主纹理
glActiveTexture(GL_TEXTURE1); // 激活第 1 索引纹理单元
glBindTextureUnit(1, texture[1]); // 纹理单元 0 绑定:遮罩纹理
glActiveTexture(GL_TEXTURE2); // 激活第 2 索引纹理单元
glBindTextureUnit(2, texture[2]); // 纹理单元 0 绑定:闪光/流光纹理
加载三个纹理对象
loadTexture(texture[0], "my_tex.png"); // 加载纹理对象0:主纹理
loadTexture(texture[1], "my_tex_flash_mask.jpg"); // 加载纹理对象1:遮罩纹理
loadTexture(texture[2], "flash.png"); // 加载纹理对象2:闪光/流光纹理
设置采样器采样对应的纹理单元
shaderProgram->setInt("main_tex", 0); // 主 纹理设置采样器采样 0 索引纹理单元
shaderProgram->setInt("mask_tex", 1); // 遮罩 纹理设置采样器采样 1 索引纹理单元
shaderProgram->setInt("flash_light_tex", 2); // 闪光/流光 纹理设置采样器采样 2 索引纹理单元
传入 time 时间控制 uv 纹理坐标动画
shaderProgram->setFloat("time", (float)glfwGetTime()); // 测试用就直接用字符串了,方便一些
运行效果
// jave.lin
#include"glad/glad.h"
#include"GLFW/glfw3.h"
//#include"linmath.h"
// 把linmath.h 放在 iostream 之前include会有错误,所以放到iostream 后include就好了
// 而这个错误正式 xkeycheck.h 文件内 #error 提示的,所以可以使用 #define _XKEYCHECK_H 这个头文件的引用标记宏
// 就可以避免对 xkeycheck.h 头文件的 include 了。
#include
#include"linmath.h"
#include"shader.h"
// 使用 stb_image.h 的加载库
// github 源码:https://github.com/nothings/stb/blob/master/stb_image.h
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
// 将之前的打印版本信息代码包含一下
#include"print_gl_version_info.h"
GLfloat vertices[] = {
// x, y, z
// 直接放4个顶点
-0.5f, -0.5f, 0.0f, // 第0个顶点,左下角
0.5f, -0.5f, 0.0f, // 第1个顶点,右下角
0.5f, 0.5f, 0.0f, // 第2个顶点,右上角
-0.5f, 0.5f, 0.0f, // 第3个顶点,左上角
};
GLfloat uvs[] = { // 顶点的 uv 坐标
0.0f, 0.0f, // 左下角
1.0f, 0.0f, // 右下角
1.0f, 1.0f, // 右上角
0.0f, 1.0f, // 左上角
};
GLuint indices[] = { // 注意索引从0开始!通过索引缓存来指定 图元 组成 用的 顶点有哪些
0, 1, 3, // 放置顶点的索引,第一个三角形
1, 2, 3 // 放置顶点的索引,第二个三角形
};
// 定义:获取 Shader 目录的回调函数原型
typedef char* (__stdcall* GetShaderPathCallback)(char*, const char*);
GetShaderPathCallback g_GetShaderPathCallback = NULL;
// 定义:获取 Pic 目录的回调函数原型
typedef char* (__stdcall* GetPicturePathCallback)(char*, const char*);
GetPicturePathCallback g_GetPicturePathCallback = NULL;
static void error_callback(int error, const char* description) {
fprintf(stderr, "ErrorCode : %d(0x%08x), Error: %s\n", error, error, description);
}
static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) { // 当键盘按键ESCAPE按下时,设置该window为:需要关闭
if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
glfwSetWindowShouldClose(window, GLFW_TRUE);
}
// 时候开启检测GL的错误
#define CHECK_GL_ERROR
#ifdef CHECK_GL_ERROR
// 检测如果有GL的错误,则提示并退出程序
#define checkGLError() \
{\
GLenum errorCode = glGetError(); \
if (errorCode != 0) { \
std::cout
关注
打赏
最近更新
- 深拷贝和浅拷贝的区别(重点)
- 【Vue】走进Vue框架世界
- 【云服务器】项目部署—搭建网站—vue电商后台管理系统
- 【React介绍】 一文带你深入React
- 【React】React组件实例的三大属性之state,props,refs(你学废了吗)
- 【脚手架VueCLI】从零开始,创建一个VUE项目
- 【React】深入理解React组件生命周期----图文详解(含代码)
- 【React】DOM的Diffing算法是什么?以及DOM中key的作用----经典面试题
- 【React】1_使用React脚手架创建项目步骤--------详解(含项目结构说明)
- 【React】2_如何使用react脚手架写一个简单的页面?