当前位置: 首页 > news >正文

基于Babylon.js的Shader入门三(让Shader中的纹理动起来)

        本来是做一个纹理偏移的效果,不过感觉应该很无聊,最后觉得还是做一个FlipBook效果吧,该效果使用了一张5*5的爆炸动画序列纹理,如下:

最终呈现效果参考:

        该部分内容的顶点着色器与 Babylon.js的Shader入门二(让Shader使用一个纹理)中的内容没有区别(即本次顶点着色器名称为FlipBook.vertex.fx与上一篇中的BaseTexture.vertex.fx内容相同),下面直接展示片元着色器的内容改变。

片元着色器

        FlipBook.fragment.fx文件内容:

precision highp float;

uniform sampler2D textureSampler;   // 5x5 动画序列纹理
uniform float rows;                 // 序列帧行数
uniform float cols;                 // 序列这列数
uniform float time;                 // 时间变量,用于控制动画播放

varying vec2 vUV;

void main() {
    // 计算总帧数
    float totalFrames = rows * cols;

    // 根据时间计算当前帧索引
    float frameIndex = mod(time * 10.0, totalFrames); // 假设每秒播放 10 帧
    frameIndex = floor(frameIndex);

    // 计算当前帧的行列索引
    float rowIndex = floor(frameIndex / cols);
    float colIndex = mod(frameIndex, cols);

    // 计算纹理坐标偏移
    vec2 frameSize = vec2(1.0 / cols, 1.0 / rows); // 每帧的纹理大小
    vec2 offset = vec2(colIndex * frameSize.x, 1.0 - (rowIndex + 1.0) * frameSize.y); // 注意 Y 轴方向

    // 调整纹理坐标
    vec2 flipbookUV = vUV * frameSize + offset;

    // 采样纹理
    vec4 color = texture2D(textureSampler, flipbookUV);
    gl_FragColor = color;
}

JavaScript 实现

        在 Babylon.js 中,你需要将时间变量 time 传递给 Shader,并更新它的值。

创建 ShaderMaterial

const shaderMaterial = new BABYLON.ShaderMaterial("shader", scene, 
    "./src/Shader/FlipBook",
    {
        attributes: ["position", "uv"],
        uniforms: ["worldViewProjection", "textureSampler", "time"], // 添加 time 变量
    });

// 加载纹理
const texture = new BABYLON.Texture("path/to/texture.png", scene);
shaderMaterial.setTexture("textureSampler", texture);

// 初始化时间变量
let time = 0;
shaderMaterial.setFloat("time", time);
//设置爆炸序列图片行数
shaderMaterial.setFloat("rows", 5);
//设置爆炸序列图片列数
shaderMaterial.setFloat("cols", 5);

// 创建网格并应用材质
const mesh = BABYLON.MeshBuilder.CreateBox("box", {}, scene);
mesh.material = shaderMaterial;

更新时间变量

        在渲染循环中更新 time 变量,并传递给 Shader。

scene.registerBeforeRender(() => {
    time += scene.getEngine().getDeltaTime() / 1000; // 更新时间,单位为秒
    shaderMaterial.setFloat("time", time);
});

原理说明

(1) 动画帧索引计算

  • 根据时间 time 和帧率(如每秒 10 帧)计算当前帧索引 frameIndex

  • 使用 mod 和 floor 函数确保帧索引在有效范围内(0 到 24,因为 5x5 纹理有 25 帧)。

(2) 行列索引计算

  • 根据帧索引 frameIndex 计算当前帧的行索引 rowIndex 和列索引 colIndex

  • 行索引:rowIndex = floor(frameIndex / cols)

  • 列索引:colIndex = mod(frameIndex, cols)

(3) 纹理坐标调整

  • 每帧的纹理大小:frameSize = vec2(1.0 / cols, 1.0 / rows)

  • 计算当前帧的纹理坐标偏移:offset = vec2(colIndex * frameSize.x, 1.0 - (rowIndex + 1.0) * frameSize.y)

    • 注意 Y 轴方向需要翻转,因为纹理坐标的原点在左下角。

  • 调整纹理坐标:flipbookUV = vUV * frameSize + offset

(4) 采样纹理

  • 使用调整后的纹理坐标 flipbookUV 采样纹理。

相关文章:

  • Jmeter的简单使用
  • STM32-SPI通信外设
  • Python 与 JavaScript 交互及 Web 逆向分析全解析
  • 3D文物线上展览如何实现?
  • 一些docker命令
  • L1正则化与L2正则化的区别
  • DataWhale 大语言模型 - 大模型技术基础
  • 数据库技术
  • EB-Cable许可与软件版本兼容性的关系
  • 常见的企业软件和工业软件种类
  • Springboot中的异常处理
  • 棒球和垒球区别·棒球1号位
  • Marp 高效 Markdown 幻灯片制作指南
  • 爱普生车规级晶振SG2520CAA智能汽车电子系统的应用
  • Java Stream API 的使用
  • vulnhub靶场之healthcare靶机
  • IROS论文分享:动态场景双向树规划算法RT-RRT
  • 端口转发、隧道与Pivoting技术详解及区别解析
  • uv命令介绍(高性能Python包管理工具,旨在替代pip、pip-tools和virtualenv等传统工具)
  • 计算机网络——DNS
  • 王楚钦球拍受损,乒乓球裁判揭秘大赛球拍检测
  • F4方程式上海站引擎轰鸣,见证中国赛车运动不断成长
  • 习近平:坚定信心推动高质量发展高效能治理,奋力谱写中原大地推进中国式现代化新篇章
  • 济南一医院救护车未执行紧急任务时违规鸣笛
  • 上海合作组织减贫和可持续发展论坛开幕,沈跃跃宣读习近平主席贺信
  • 减重人生|吃得越少越好?比体重秤上的数字,更有意义的是什么?