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

第十七节:高级材质 - ShaderMaterial揭秘

第十七节:高级材质 - ShaderMaterial揭秘

用GLSL编写自定义着色器实现高级视觉效果

在这里插入图片描述

1. 核心概念解析

1.1 ShaderMaterial vs 标准材质
特性MeshStandardMaterialShaderMaterial
灵活性低(预设参数)高(完全自定义)
性能优化好依赖着色器复杂度
学习曲线简单陡峭(需GLSL知识)
适用场景常规渲染特效/自定义光照/后处理
可控性有限完全控制渲染管线
1.2 GLSL着色器工作流程
顶点数据
顶点着色器
图元装配
光栅化
片元着色器
帧缓冲输出

2. GLSL语法精要

2.1 数据类型与精度
// 精度限定符(必需)
precision highp float; // 高精度
precision mediump float; // 中精度
precision lowp float; // 低精度// 基本数据类型
float value = 1.0;     // 浮点数
int count = 5;         // 整数
bool isActive = true;  // 布尔值// 向量与矩阵
vec2 uv = vec2(1.0, 0.5);    // 二维向量
vec3 position;               // 三维向量
vec4 color = vec4(1.0);      // 四维向量(RGBA)
mat4 matrix;                 // 4x4矩阵
2.2 变量传递机制
// Uniforms(CPU→GPU传递,所有顶点/片元相同)
uniform float uTime;         // 时间
uniform vec3 uColor;         // 颜色
uniform sampler2D uTexture;  // 纹理// Attributes(每个顶点独有)
attribute vec3 position;     // 顶点位置
attribute vec2 uv;           // UV坐标// Varyings(顶点着色器→片元着色器)
varying vec2 vUv;            // 传递UV坐标
varying vec3 vPosition;      // 传递位置

3. 创建自定义着色器

3.1 基础ShaderMaterial创建
// 创建着色器材质
const material = new THREE.ShaderMaterial({// Uniforms定义uniforms: {uTime: { value: 0 },uColor: { value: new THREE.Color(0xff0000) },uTexture: { value: new THREE.TextureLoader().load('/textures/noise.jpg') }},// 顶点着色器vertexShader: `uniform float uTime;varying vec2 vUv;varying vec3 vPosition;void main() {vUv = uv;vPosition = position;// 简单的波浪效果float wave = sin(position.x * 3.0 + uTime) * 0.1;vec3 newPosition = position + normal * wave;gl_Position = projectionMatrix * modelViewMatrix * vec4(newPosition, 1.0);}`,// 片元着色器fragmentShader: `uniform vec3 uColor;uniform sampler2D uTexture;varying vec2 vUv;varying vec3 vPosition;void main() {// 纹理采样vec4 texColor = texture2D(uTexture, vUv);// 颜色混合vec3 finalColor = uColor * texColor.rgb;// 基于位置的颜色渐变float gradient = vPosition.y * 0.5 + 0.5;finalColor *= gradient;gl_FragColor = vec4(finalColor, 1.0);}`,// 材质配置side: THREE.DoubleSide,wireframe: false
});
3.2 动态Uniform更新
// 在渲染循环中更新uniform
function animate() {requestAnimationFrame(animate);// 更新时间uniformmaterial.uniforms.uTime.value = performance.now() * 0.001;renderer.render(scene, camera);
}
animate();

4. 实战案例:动态波浪水面

4.1 完整代码实现
// 顶点着色器代码
const vertexShader = `uniform float uTime;uniform float uWaveHeight;uniform float uWaveFrequency;varying vec2 vUv;varying float vElevation;void main() {vUv = uv;// 计算波浪位移float elevation = sin(position.x * uWaveFrequency + uTime) *cos(position.z * uWaveFrequency + uTime) *uWaveHeight;vElevation = elevation;vec3 newPosition = position + normal * elevation;gl_Position = projectionMatrix * modelViewMatrix * vec4(newPosition, 1.0);}
`;// 片元着色器代码
const fragmentShader = `uniform vec3 uWaterColor;uniform vec3 uFoamColor;uniform sampler2D uNormalMap;varying vec2 vUv;varying float vElevation;void main() {// 法线贴图vec3 normalMap = texture2D(uNormalMap, vUv + uTime * 0.1).rgb;// 基于高度的颜色混合vec3 baseColor = mix(uWaterColor, uFoamColor, vElevation * 2.0);// 添加光照效果(简单版)vec3 lightDir = normalize(vec3(0.5, 1.0, 0.5));float diffuse = max(dot(normalMap, lightDir), 0.2);vec3 finalColor = baseColor * diffuse;gl_FragColor = vec4(finalColor, 0.9);}
`;// 创建水面材质
const waterMaterial = new THREE.ShaderMaterial({uniforms: {uTime: { value: 0 },uWaveHeight: { value: 0.2 },uWaveFrequency: { value: 2.0 },uWaterColor: { value: new THREE.Color(0x1e90ff) },uFoamColor: { value: new THREE.Color(0xffffff) },uNormalMap: { value: new THREE.TextureLoader().load('/textures/water-normals.jpg') }},vertexShader,fragmentShader,transparent: true,side: THREE.DoubleSide
});// 创建水面几何体
const waterGeometry = new THREE.PlaneGeometry(20, 20, 128, 128);
const waterMesh = new THREE.Mesh(waterGeometry, waterMaterial);
waterMesh.rotation.x = -Math.PI / 2;
scene.add(waterMesh);
4.2 交互控制界面
// 使用dat.GUI添加控制
import GUI from 'lil-gui';const gui = new GUI();
const waveFolder = gui.addFolder('波浪参数');waveFolder.add(waterMaterial.uniforms.uWaveHeight, 'value', 0, 1).name('波浪高度');
waveFolder.add(waterMaterial.uniforms.uWaveFrequency, 'value', 0, 5).name('波浪频率');
waveFolder.addColor({ color: 0x1e90ff }, 'color').onChange((value) => {waterMaterial.uniforms.uWaterColor.value.set(value);
}).name('水体颜色');waveFolder.open();

5. 重点核心与注意事项

5.1 性能优化要点
优化策略实现方法效果
精度选择根据需求使用lowp/mediump性能提升20-30%
纹理优化使用压缩纹理格式(KTX2)内存占用降低70%
循环优化避免循环中的复杂计算帧率稳定
条件语句尽量在顶点着色器中使用避免GPU分支惩罚
5.2 常见问题与解决方案

问题1:着色器编译错误

  • 现象:屏幕黑屏或控制台报错
  • 排查步骤
    1. 检查GLSL语法错误(缺少分号等)
    2. 确认uniform变量名称一致
    3. 验证精度限定符已声明

问题2:性能突然下降

  • 原因:片元着色器过于复杂
  • 解决方案
    // 优化前(每像素多次采样)
    for(int i = 0; i < 10; i++) {color += texture2D(texture, uv + offset * i);
    }// 优化后(预计算或减少采样)
    color = texture2D(texture, uv) * 0.5 +texture2D(texture, uv + offset) * 0.3 +texture2D(texture, uv - offset) * 0.2;
    

问题3:移动端兼容性问题

  • 限制:最多16个纹理单元
  • 应对策略
    1. 合并纹理(纹理图集)
    2. 减少同时使用的纹理数量
    3. 使用WEBGL_lose_context检测资源释放
5.3 调试技巧
// 1. 颜色调试法
gl_FragColor = vec4(vUv, 0.0, 1.0); // 可视化UV坐标
gl_FragColor = vec4(vec3(vElevation), 1.0); // 可视化高度// 2. 边界检测
if(vUv.x > 0.99 || vUv.y > 0.99) {gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); // 红色边界
}// 3. 数值可视化
float value = someComplexCalculation();
gl_FragColor = vec4(value, value, value, 1.0);

6. 完整案例:全息投影效果

// 全息效果着色器材质
const hologramMaterial = new THREE.ShaderMaterial({uniforms: {uTime: { value: 0 },uScanSpeed: { value: 2.0 },uScanColor: { value: new THREE.Color(0x00ffff) },uBaseColor: { value: new THREE.Color(0x0088ff) }},vertexShader: `varying vec2 vUv;varying vec3 vPosition;void main() {vUv = uv;vPosition = position;gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);}`,fragmentShader: `uniform float uTime;uniform float uScanSpeed;uniform vec3 uScanColor;uniform vec3 uBaseColor;varying vec2 vUv;varying vec3 vPosition;void main() {// 扫描线效果float scanLine = sin(vPosition.y * 20.0 - uTime * uScanSpeed) * 0.5 + 0.5;scanLine = pow(scanLine, 3.0); // 增强对比度// 边缘光效果float edgeGlow = 1.0 - smoothstep(0.0, 0.1, abs(vUv.x - 0.5) * 2.0);edgeGlow *= 1.0 - smoothstep(0.0, 0.1, abs(vUv.y - 0.5) * 2.0);// 颜色合成vec3 color = mix(uBaseColor, uScanColor, scanLine);color += edgeGlow * uScanColor * 0.5;// 透明度渐变float alpha = 0.6 + scanLine * 0.4;gl_FragColor = vec4(color, alpha);}`,transparent: true,side: THREE.DoubleSide,blending: THREE.AdditiveBlending
});// 应用到的模型
const model = new THREE.Mesh(new THREE.TorusGeometry(2, 0.5, 16, 100),hologramMaterial
);
scene.add(model);

下一节预告:骨骼动画 - 角色动画控制

第十八节:GLTF动画剪辑与状态混合技术

核心内容

  1. 骨骼系统原理

    • 骨骼树结构与权重分配
    • 矩阵变换层级传递
  2. 动画控制四部曲

    加载GLTF
    提取动画剪辑
    创建混合器
    控制播放状态
  3. 高级技术

    • 动画混合(行走→奔跑平滑过渡)
    • 动画遮罩(上半身攻击+下半身行走)
    • 根运动处理(角色位移匹配动画)
  4. 性能优化

    • 动画压缩技术
    • GPU骨骼动画加速

重点掌握:实现可交互的3D角色控制系统,为游戏开发奠定基础。

http://www.xdnf.cn/news/1362637.html

相关文章:

  • 物联网时序数据库IoTDB架构解析
  • h5和微信小程序查看pdf文件
  • DrissionPage 能控制火狐或edge吗
  • 20.14 QLoRA微调Whisper-Large-v2终极指南:3倍速训练+显存直降68%调参秘籍
  • ADB 调试工具的学习[特殊字符]
  • 【智慧城市】2025年中国地质大学(武汉)暑期实训优秀作品(2):智慧城市西安与一带一路
  • 技术速递|使用 AI 应用模板扩展创建一个 .NET AI 应用与自定义数据进行对话
  • 通过C#上位机串口写入和读取浮点数到stm32实战5(通过串口读取bmp280气压计的数值并在上位机显示)
  • .NET表格控件Spread .NET v18.0——支持富文本、增强PDF导出
  • 算法学习8.25
  • 如何生成雪碧图和 WEBVTT
  • Elasticsearch脑裂紧急处理与预防
  • [React]Antd Upload组件上传多个文件
  • 微服务商城构筑其一
  • VIVO/OPPO手机,显示5G开关
  • 【Wrangler(Cloudflare 的官方 CLI)和 npm/npx 的区别一次讲清】
  • 大模型面试题剖析:Pre-Norm与Post-Norm的对比及当代大模型选择Pre-Norm的原因
  • openharmony之DRM开发:数字知识产权保护揭秘
  • ESP8266学习
  • 迁移面试题
  • 将跨平台框架或游戏引擎开发的 macOS 应用上架 Mac App Store
  • Docker基本使用方法和常用命令
  • 8851定期复盘代码实现设计模式的于芬应用
  • 从2D序列帧到3D体积感:我用AE+UE5 Niagara构建次世代风格化VFX工作流
  • TDengine IDMP 应用场景:IT 系统监控
  • Ubuntu 14.10 i386桌面版安装教程(U盘启动详细步骤-附安装包下载)​
  • 800G时代!全场景光模块矩阵解锁数据中心超高速未来
  • 5分钟发布技术博客:cpolar简化Docsify远程协作流程
  • Zabbix企业级监控运维实践为主(新)
  • ╳╳╳╳╳╳╳╳╳╳头像商店╳╳╳╳╳╳╳╳╳╳