尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
Cocos Creator 3.7.2 Shader进阶:打造可交互的动态扫光材质系统
1. 动态扫光效果的核心原理扫光效果本质上是通过Shader对UV坐标进行动态计算实现的。想象一下用手电筒在黑暗的房间里扫过墙面的场景——光束中心最亮边缘逐渐衰减。在Shader中我们通过以下几个关键参数来模拟这个效果光束中心点(lightCenterPoint)用二维向量表示范围在[0,1]的UV空间内光束宽度(lightWidth)控制光束的照射范围光束角度(lightAngle)决定光束的倾斜方向光束颜色(lightColor)RGBA格式的光照颜色核心算法是通过计算当前像素UV到光束中心线的距离结合宽度参数生成一个0-1的衰减系数。这个系数会与原始纹理颜色进行混合实现扫光效果。具体公式如下// 计算UV到光束中心线的距离 float angleRad radians(lightAngle); float distanceToBeam abs((uv.x - centerX) * sin(angleRad) - (uv.y - centerY) * cos(angleRad)); // 生成衰减系数 float attenuation smoothstep(lightWidth/2.0, 0.0, distanceToBeam);2. 基础扫光Shader实现2.1 Effect资源配置首先创建Effect文件定义Shader需要的属性和渲染管线CCEffect %{ techniques: - passes: - vert: sprite-vs:vert frag: sprite-fs:frag properties: texture: { value: white } // 主纹理 lightColor: { value: [1.0, 1.0, 0.0, 1.0], // 默认黄色光束 editor: { type: color } } lightCenter: { value: [0.5, 0.5] } // 中心点默认居中 lightWidth: { value: 0.3 } // 默认宽度 lightAngle: { value: 45.0 } // 默认45度角 }%2.2 顶点着色器顶点着色器主要负责坐标变换和UV传递CCProgram sprite-vs %{ precision highp float; #include cc-global in vec3 a_position; in vec2 a_texCoord; out vec2 uv; void main() { gl_Position cc_matViewProj * vec4(a_position, 1); uv a_texCoord; } }%2.3 片段着色器片段着色器实现核心扫光逻辑CCProgram sprite-fs %{ precision highp float; in vec2 uv; uniform sampler2D texture; uniform vec4 lightColor; uniform vec2 lightCenter; uniform float lightWidth; uniform float lightAngle; void main() { vec4 texColor texture2D(texture, uv); // 计算角度和距离 float angleRad radians(lightAngle); vec2 dir vec2(sin(angleRad), cos(angleRad)); vec2 toCenter uv - lightCenter; float distanceToBeam abs(dot(toCenter, vec2(dir.y, -dir.x))); // 生成平滑衰减 float attenuation smoothstep(lightWidth/2.0, 0.0, distanceToBeam); // 混合颜色 gl_FragColor texColor lightColor * attenuation * texColor.a; } }%3. 动态参数控制3.1 创建材质脚本控制器通过TypeScript脚本动态控制Shader参数const { ccclass, property } _decorator; ccclass(ScanLightController) export class ScanLightController extends Component { property(Sprite) targetSprite: Sprite null; property({ type: CCFloat, tooltip: 扫描速度 }) scanSpeed: number 1.0; property({ type: CCFloat, tooltip: 扫描宽度 }) lightWidth: number 0.3; private _material: Material; private _scanPos: number 0; start() { this._material this.targetSprite.getMaterial(0); this._material.setProperty(lightWidth, this.lightWidth); } update(dt: number) { this._scanPos dt * this.scanSpeed; if (this._scanPos 1.5) this._scanPos -0.5; // 沿对角线扫描 this._material.setProperty(lightCenter, new Vec2(this._scanPos, this._scanPos)); } }3.2 参数动画过渡实现平滑的参数过渡效果// 在控制器类中添加方法 public setLightColor(targetColor: Color, duration: number 0.5) { const currentColor this._material.getProperty(lightColor); tween(currentColor) .to(duration, targetColor, { onUpdate: (color: Color) { this._material.setProperty(lightColor, color); } }) .start(); } // 调用示例 this.setLightColor(new Color(255, 100, 255, 255)); // 过渡到紫色光4. 高级功能扩展4.1 边缘裁剪与雾化效果增强扫光的视觉效果// 在片段着色器中添加 uniform float edgeSoftness; // 0-1的软边参数 uniform float fogIntensity; // 雾化强度 // 修改衰减计算 float edge smoothstep(lightWidth/2.0, lightWidth/2.0 * (1.0 - edgeSoftness), distanceToBeam); float fog exp(-distanceToBeam * fogIntensity); attenuation edge * fog;4.2 多光束混合支持多个扫光效果叠加uniform vec4 lightColors[3]; uniform vec2 lightCenters[3]; uniform float lightWidths[3]; void main() { vec4 texColor texture2D(texture, uv); vec4 finalColor texColor; for(int i0; i3; i) { // 计算每个光束的贡献 float atten calculateAttenuation(uv, lightCenters[i], lightWidths[i]); finalColor lightColors[i] * atten * texColor.a; } gl_FragColor min(finalColor, vec4(1.0)); // 防止颜色值超过1.0 }5. 性能优化技巧5.1 指令数优化减少Shader指令数以提升性能// 优化后的距离计算 vec2 beamVec vec2(sin(angleRad), cos(angleRad)); float distanceToBeam abs(beamVec.y*(uv.x-center.x) - beamVec.x*(uv.y-center.y)); // 使用step替代smoothstep获得更硬朗的边缘性能更好 float edge step(distanceToBeam, lightWidth/2.0);5.2 批处理优化确保材质实例化参数正确设置// 在脚本中设置 this._material.initialize({ defines: { USE_INSTANCING: true } }); // 对于动态参数使用setProperty的instanced版本 this._material.setProperty(lightCenter, new Vec2(x,y), true);6. 实际应用案例6.1 UI高亮提示为重要按钮添加扫光效果// 按钮提示控制器 ccclass(UIHighlight) export class UIHighlight extends Component { property(Button) targetButton: Button null; private _material: Material; start() { const sprite this.targetButton.node.getComponent(Sprite); this._material sprite.getMaterial(0); this.targetButton.node.on(Node.EventType.MOUSE_ENTER, () { this._material.setProperty(lightColor, new Color(0, 255, 255, 255)); }); this.targetButton.node.on(Node.EventType.MOUSE_LEAVE, () { this._material.setProperty(lightColor, new Color(0, 0, 0, 0)); }); } }6.2 道具稀有度表现不同稀有度道具使用不同扫光效果enum ItemRarity { Common, Rare, Epic, Legendary } ccclass(ItemRarityEffect) export class ItemRarityEffect extends Component { property({ type: Enum(ItemRarity) }) rarity: ItemRarity ItemRarity.Common; private _colors [ new Color(200, 200, 200, 100), // 普通 new Color(0, 150, 255, 150), // 稀有 new Color(180, 0, 255, 200), // 史诗 new Color(255, 100, 0, 255) // 传说 ]; start() { const mat this.node.getComponent(Sprite).getMaterial(0); mat.setProperty(lightColor, this._colors[this.rarity]); mat.setProperty(lightWidth, 0.1 this.rarity * 0.1); } }
RELATED

相关推荐

2026最适合中医理疗馆低成本获客神器:餐宝盈GEO+小程序模式,获客转化一手抓

2026最适合中医理疗馆低成本获客神器:餐宝盈GEO+小程序模式,获客转化一手抓

为什么中医理疗馆现在不能只做小程序,也不能只做流量如果只看单点工具,中医理疗馆做小程序像是在解决承接问题,做 GEO 像是在解决流量问题。但如果顺着真实经营链路往下看,会发现中医理疗馆当前最核心的问题,不是单独缺…

📅 2026/9/12 17:03:21
嵌入式 Linux 高波特率串口丢包全链路解决方案

嵌入式 Linux 高波特率串口丢包全链路解决方案

前言 做嵌入式 Linux 开发,没人能绕开串口调试。 我之前在做工业数据网关项目时,就结结实实栽在了串口丢包上:外接传感器用 921600 波特率连续上报数据,应用层 read 总是随机丢字节,少则几个多则几十字节;降到 115200 就正常,一升高波特率就复现。 前后调了整整半个月:…

📅 2026/8/20 21:47:18
【HarmonyOS】根据文本内容动态测算Text文本控件宽高行高(TextMeasure最全实战)

【HarmonyOS】根据文本内容动态测算Text文本控件宽高行高(TextMeasure最全实战)

适用版本HarmonyOS NEXT 5.0ArkTSStage模型API12前言在实际开发过程中,我们经常需要根据文字内容动态计算控件尺寸,例如:聊天气泡评论列表标签(Tag)Flow布局WaterFlow瀑布流富文本Canvas绘制文字图片文字水印自动换行动态Cell高度Popup/Dialo…

📅 2026/9/8 21:20:41
MORE NEWS

更多资讯

📰

Redisson 对象引用(Object References):让 Redis 对象像 Java 对象一样互相嵌套

Redisson 对象引用(Object References):让 Redis 对象像 Java 对象一样互相嵌套 【免费下载链接】redisson Redisson: Valkey & Redis Java Client and Real-Time Data Platform. Sync/Async/RxJava/Reactive API. Over 50 Valkey and Re…

📰

渐进式披露重构实战:Cloudflare Zaraz 参考文档 5 文件分层体系在 Codex Skills 目录中的设计与落地

渐进式披露重构实战:Cloudflare Zaraz 参考文档 5 文件分层体系在 Codex Skills 目录中的设计与落地 【免费下载链接】skills Skills Catalog for Codex 项目地址: https://gitcode.com/GitHub_Trending/skills4/skills 本篇围绕 skills/.curated/cloudflare…

📰

基于51单片机的TLC2543数据采集Proteus仿真实战

简介:基于51单片机的12位AD数据采集完整设计方案,适合单片机初学者和Proteus仿真爱好者。资源围绕TLC2543模拟转换器、44键盘、8位LED显示器和两个发光二极管,实现通过键盘输入通道号并完成11路模拟通道的数据采集,在LED上同步显示…

📰

文件是怎么变成预览页的:kkFileView 核心链路深度拆解

文件是怎么变成预览页的:kkFileView 核心链路深度拆解 【免费下载链接】kkFileView Universal File Online Preview Project based on Spring-Boot 项目地址: https://gitcode.com/GitHub_Trending/kk/kkFileView kkFileView 是一个基于 Spring Boot 的通用文…

📰

Data Engineering Zoomcamp 如何创建 GCP Dataproc 集群并提交 PySpark 作业

Data Engineering Zoomcamp 如何创建 GCP Dataproc 集群并提交 PySpark 作业 【免费下载链接】data-engineering-zoomcamp Data Engineering Zoomcamp is a free 9-week course on building production-ready data pipelines. Join the course here 👇🏼…

📰

Go语言Context取消机制深度解析与实践指南

1. Go Context 取消信号传播机制解析 在Go语言并发编程中,Context是一个极其重要的基础组件。它最初由Google内部开发,后来成为Go标准库的一部分。Context的核心功能之一就是提供跨API边界和进程边界的取消信号传播能力,这正是我们今天要深入…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬