蛋哥的学习笔记之-基于Unity的Shader编程:X-1 音乐水波特效

2024-02-29 12:20

本文主要是介绍蛋哥的学习笔记之-基于Unity的Shader编程:X-1 音乐水波特效,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

蛋哥的学习笔记之-基于Unity的Shader编程:X-1 音乐水波特效

热度 13728 2015-7-11 23:34 |个人分类:蛋哥的学习笔记之-基于Unity的Shader编程| 音乐, Unity, Shader, 水波, Shader, Shader, Shader, Shader

一、要干些啥:
        很久很久没有写文档了,前段时间做了个个人很喜欢的,自认为比较原创的小特效,所以写个文档纪念下 (本人特别喜欢音乐)
思路其实很简单,首先用顶点着色器实现一般的水波特效,然后解析音频数据(我这里是用listener获取的数据来解析的),然后划分出低音,中音和高音,最后用是Shader控制显示;然后再加上一些Cubemap啊,Phone反射啊什么的,让它看起来好看一些就OK料~
关于音频解析的,如果你有兴趣的话,还可以参考下这篇文章:
http://tips.hecomi.com/entry/2014/11/11/021147
是讲解如何用音频控制角色口型的,这样在做妹子唱歌动画的时候,就不用一帧一帧K动画鸟~~
二、码儿预览:
首先看下Shader码儿吧:(码儿中有部分模块和变量是没有用到的,有些是我直接拿以前写好的东西搬过来,有些是为了达到我想要的效果调调改改)
/
a、ShaderWaterWave.shader 文件 用以控制水波的Shader

 

Shader "EggBrother/ShaderWaterWave" 
{Properties {_MainTex ("Base (RGB)", 2D) = "white" {}_TintAmount ("Tint Amount", Range(0, 1)) = 0.5					// 色彩叠加强度_ColorA ("Color A", Color) = (1, 1, 1, 1)						// 第一个颜色_ColorB ("Color B", Color) = (1, 1, 1, 1)						// 第二个颜色_Speed ("Wave Speed", Range(0.1, 80)) = 5						// 波浪速度_Frequency ("Wave Frequency", Range(0, 5)) = 2					// 波浪频率_Amplitude ("Wave Amplitude", Range(0, 1)) = 1					// 波浪振幅_Displacement ("Displacement", Range(0, 1.0)) = 0.3				// 加入杂波的量//_SpeedStrength ("Speed Strength", Vector3) = (1, 1, 1)_Alpha ("Alpha Value", Range(0, 1)) = 0.5						// 透明度// 用于blinnPhone反射_SpecularColor ("Specular Color", Color) = (1, 1, 1, 1)		// 高光颜色_SpecPower ("Specular Power", Range(0.1, 100)) = 2			// 高光强度// 用于cubemap反射_Cubemap ("Cube Map", CUBE) = "" {}							// cubemap_ReflAmount ("Reflection Amount", Range(0.01, 1)) = 0.5		// 反射强度// 用于纹理动画_ScrollSpeedX ("Scroll Speed X", Range(-2, 2)) = -0.5			// X方向速度_ScrollSpeedY ("Scroll Speed Y", Range(-2, 2)) = -0.5			// Y方向速度}SubShader{ Tags { "RenderType"="Opaque" }LOD 300CGPROGRAM// 加载我们自定义的模块#include "EggBrother/EggBrotherLightings.cginc"#include "EggBrother/EggBrotherFunctions.cginc"#pragma surface surf EGBlinnPhong vertex:vert alpha//#pragma target 5.0// 顶点处理 /fixed _Speed;fixed _Frequency;fixed _Amplitude;fixed _Displacement; //float3 _SpeedStrength;samplerCUBE _Cubemap;fixed _ReflAmount;fixed _ScrollSpeedX;fixed _ScrollSpeedY;struct Input {float2 uv_MainTex;float3 vertColor;		// 用以在surf函数中使用float3 worldRefl;};void vert(inout appdata_full v, out Input o){ // 使用 DX11 的规则UNITY_INITIALIZE_OUTPUT(Input, o);// 根据振幅和频率计算变化值float time = _Time * _Speed / 2;float waveValueA = sin((v.vertex.x + v.vertex.z) * _Frequency + time * _Frequency) * _Amplitude;// 修改顶点位置v.vertex.xyz = float3(v.vertex.x, v.vertex.y + waveValueA, v.vertex.z);// 修改顶点法线(用以光照计算)v.normal = normalize(float3(v.normal.x + waveValueA, v.normal.y, v.normal.z));// 顶点细分//float d = tex2Dlod(_MainTex, float4(v.texcoord.xy,0,0)).r * _Displacement;              //v.vertex.xyz += v.normal * d;  // 输出最终颜色o.vertColor = float3(waveValueA, waveValueA, waveValueA);}// surf 颜色处理 /sampler2D _MainTex;float _TintAmount;float4 _ColorA;float4 _ColorB;float _Alpha;void surf (Input IN, inout SurfaceOutput o) { float3 tintColor = lerp(_ColorA, _ColorB, IN.vertColor).rgb;// 计算纹理动画fixed2 scrolledUV = IN.uv_MainTex;fixed xScrollValue = _ScrollSpeedX * _Time;fixed yScrollValue = _ScrollSpeedY * _Time;scrolledUV += fixed2(xScrollValue, yScrollValue);half4 c = tex2D (_MainTex, scrolledUV);// 获取Cubemap的uv信息o.Emission = texCUBE(_Cubemap, IN.worldRefl).rgb * _ReflAmount;o.Albedo = c.rgb * (tintColor * _TintAmount);o.Specular = 0.2;  o.Gloss = 1.0;o.Alpha = c.a * _Alpha;}ENDCG} FallBack "Diffuse"
}
/
b、ShaderWaterBright.shader 文件: 用以控制屏幕特效(亮度、饱和度、对比度等),在这个demo里只使用了亮度控制

 

Shader "EggBrother/ShaderWaterBright" 
{Properties {_MainTex ("Base (RGB)", 2D) = "white" {}_BlendTex ("Blend Texture", 2D) = "white" {}					// 混合贴图_Opacity ("Blend Opacity", Range(0, 1)) = 1						// 混合指数_LuminosityAmount ("GrayScale Amount", Range(0.0, 1)) = 1.0		// 灰度值_DepthPower ("Depth Power", Range(1, 5)) = 1					// 深度值_BrightnessAmount ("Brightness Amount", Range(0.0, 1)) = 1.0	// 亮度_SaturationAmount ("Satruation Amount", Range(0.0, 1)) = 1.0	// 饱和度_ContrastAmount ("Contrast Amount", Range(0.0, 1)) = 1.0		// 对比度}SubShader {Tags { "RenderType"="Opaque" }LOD 200Pass{CGPROGRAM#pragma vertex vert_img#pragma fragment frag#pragma fragmentoption ARB_precision_hint_fastest#include "UnityCG.cginc"uniform sampler2D _MainTex;uniform sampler2D _BlendTex;	// 混合贴图fixed _Opacity;					// 混合指数fixed _LuminosityAmount;		// 灰度fixed _DepthPower;				// 深度fixed _BrightnessAmount;		// 亮度fixed _SaturationAmount;		// 饱和度fixed _ContrastAmount;			// 对比度sampler2D _CameraDepthTexture;// 根据亮度、饱和度、对比度计算颜色float3 ContrastSaturationBrightness(float3 color, float brt, float sat, float con){float AvgLumR = 0.5;float AvgLumG = 0.5;float AvgLumB = 0.5;// 系数为CIE颜色匹配函数得来,为行业标准float3 LuminanceCoeff = float3(0.2125, 0.7154, 0.0721);// 根据亮度计算float3 AvgLumin = float3(AvgLumR, AvgLumG, AvgLumB);float3 brtColor = color * brt;float intensityf = dot(brtColor, LuminanceCoeff);float3 intensity = float3(intensityf, intensityf, intensityf);// 根据饱和度计算float3 satColor = lerp(intensity, brtColor, sat);// 根据对比度计算float3 conColor = lerp(AvgLumin, satColor, con);// 返回最终结果return conColor;}// 单个通道叠加fixed OverlayBlendModeSingle(fixed basePixel, fixed blendPixel){if(basePixel < 0.5){return (2.0 * basePixel * blendPixel);}else{return (1.0 - 2.0 * (1.0 - basePixel) * (1.0 - blendPixel));}}// 叠加混合fixed4 OverlatBlendMode(fixed4 baseTexture, fixed4 blendPixel){fixed4 finalTex = baseTexture;finalTex.r = OverlayBlendModeSingle(baseTexture.r, blendPixel.r);finalTex.g = OverlayBlendModeSingle(baseTexture.g, blendPixel.g);finalTex.b = OverlayBlendModeSingle(baseTexture.b, blendPixel.b);return finalTex;}fixed4 frag(v2f_img i) : Color{fixed4 renderTex = tex2D(_MainTex, i.uv);// 根据灰度值计算float luminosity = 0.299 * renderTex.r + 0.587 * renderTex.g + 0.114 * renderTex.b;fixed4 finalColor = lerp(renderTex, luminosity, _LuminosityAmount);// 根据深度值计算float depth = UNITY_SAMPLE_DEPTH(tex2D(_CameraDepthTexture, i.uv.xy));depth = pow(Linear01Depth(depth), _DepthPower);finalColor = finalColor * depth;// 根据从亮度,饱和度,对比度计算finalColor.rgb = ContrastSaturationBrightness(finalColor.rgb,_BrightnessAmount,_SaturationAmount,_ContrastAmount);// 混合计算fixed4 blendTex = tex2D(_BlendTex, i.uv);// 乘法混合//fixed4 finalTex = finalColor * blendTex;			// 乘法混合//fixed4 finalTex = finalColor + blendTex;			// 加法混合//fixed4 finalTex = 1.0 - (1.0 - finalColor) * (1.0 - blendTex);	// 屏幕混合fixed4 finalTex = OverlatBlendMode(finalColor, blendTex);		// 叠加混合finalTex = lerp(finalColor, finalTex, _Opacity);return finalTex;}ENDCG}} FallBack "Diffuse"
}
/
c、AudioEffect.cs 文件: 用以解析音频文件

 

using UnityEngine;
using System.Collections;public class AudioEffect : MonoBehaviour {public float[] spectrum = new float[1024];      // 监听器获取的音乐数据public int resolution = 1024;                   // 音乐数据长度public GameObject WaterWave;                    // 水波objectpublic float lowFreqThreshold = 14700;          // 低音public float midFreqThreshold = 29400;          // 中音public float highFreqThreshold = 44100;         // 高音public Transform[] audioCube = new Transform[10];       // 音乐柱子public float[] freqThreshold = new float[10];           // 音频阈值    public float lowEnhance = 1f, midEnhance = 10f, highEnhance = 100f; //音效增强private Material m_material;                    // 材质球private AudioWaterEffect m_waterBright;         // 控制屏幕特效void Start(){m_material = WaterWave.transform.GetComponent<MeshRenderer>().material;m_waterBright = transform.GetComponent<AudioWaterEffect>();}void Update(){spectrum = AudioListener.GetSpectrumData(resolution, 0, FFTWindow.BlackmanHarris);int deltaFreq = AudioSettings.outputSampleRate / resolution;// 控制音乐柱子ControlAudioCubes(deltaFreq);// 设置水波ControlWaterWave(deltaFreq);}// 设置水波public void ControlWaterWave(float deltaFreq){float low = 0f, mid = 0f, high = 0f;for (int i = 0; i < resolution; ++i){float freq = deltaFreq * i;if (freq <= lowFreqThreshold)low += spectrum[i];else if (freq <= midFreqThreshold) mid += spectrum[i];else if (freq <= highFreqThreshold) high += spectrum[i];}low *= lowEnhance;mid *= midEnhance;high *= highEnhance;// 设置水波的振幅mid = mid / 5;if (WaterWave != null){// 根据中音设置振幅if (mid > 0.8){mid = 0.8f;}else if (mid < 0.1){mid = 0.1f;}m_material.SetFloat("_Amplitude", mid);// 设置亮度m_waterBright.brightnessAmount = 0.6f + mid / 2;if (m_waterBright.brightnessAmount > 0.7){m_waterBright.brightnessAmount = 0.7f;}else if (m_waterBright.brightnessAmount < 0.6f){m_waterBright.brightnessAmount = 0.6f;}}}// 控制音乐柱子public void ControlAudioCubes(float deltaFreq){float[] freqList = new float[10];for (int i = 0; i < resolution; ++i){float freq = deltaFreq * i;if (freq <= freqThreshold[0]){freqList[0] += spectrum[i];}else if (freq <= freqThreshold[1]){freqList[1] += spectrum[i];}else if (freq <= freqThreshold[2]){freqList[2] += spectrum[i];}else if (freq <= freqThreshold[3]){freqList[3] += spectrum[i];}else if (freq <= freqThreshold[4]){freqList[4] += spectrum[i];}else if (freq <= freqThreshold[5]){freqList[5] += spectrum[i];}else if (freq <= freqThreshold[6]){freqList[6] += spectrum[i];}else if (freq <= freqThreshold[7]){freqList[7] += spectrum[i];}else if (freq <= freqThreshold[8]){freqList[8] += spectrum[i];}else if (freq <= freqThreshold[9]){freqList[9] += spectrum[i];}}for (int i = 0; i < 10; i++){audioCube[i].localScale = new Vector3(audioCube[i].localScale.x, freqList[i] * 2, audioCube[i].localScale.z);}}private void elseif(bool p){throw new System.NotImplementedException();}
}
/
d、AudioWaterEffect.cs 文件: 用以控制屏幕特效

 

using UnityEngine;
using System.Collections;[ExecuteInEditMode]     // 在没有运行的状态下也可以调试
public class AudioWaterEffect : MonoBehaviour
{#region Variablespublic Shader curShader;public Texture2D blendTexture;public float blendOpacity = 1.0f;public float grayScaleAmount = 1.0f;    // 灰度public float depthPower = 1.0f;         // 深度public float brightnessAmount = 1.0f;   // 亮度public float saturationAmount = 1.0f;   // 饱和度public float contrastAmount = 1.0f;     // 对比度private Material m_curMaterial;public AudioListener listener;#endregion// 检查材质#region PropertiesMaterial material{get{if (m_curMaterial == null){m_curMaterial = new Material(curShader);m_curMaterial.hideFlags = HideFlags.HideAndDontSave;}return m_curMaterial;}}#endregion// 检查平台是否支持特效void Start () {if (!SystemInfo.supportsImageEffects){enabled = false;return;}if (!curShader && !curShader.isSupported){enabled = false;}} // Unity内置的渲染图像函数void OnRenderImage(RenderTexture sourceTexture, RenderTexture destTexture){if (curShader != null){// 设置混合纹理material.SetTexture("_BlendTex", blendTexture);material.SetFloat("_Opacity", blendOpacity);// 设置灰度值material.SetFloat("_LuminosityAmount", grayScaleAmount);// 设置深度值material.SetFloat("_DepthPower", depthPower);// 设置亮度,饱和度,对比度material.SetFloat("_BrightnessAmount", brightnessAmount);material.SetFloat("_SaturationAmount", saturationAmount);material.SetFloat("_ContrastAmount", contrastAmount);Graphics.Blit(sourceTexture, destTexture, material);}else{Graphics.Blit(sourceTexture, destTexture);}}// Update is called once per framevoid Update () {// 设置开启深度模式Camera.main.depthTextureMode = DepthTextureMode.Depth;grayScaleAmount = Mathf.Clamp(grayScaleAmount, 0.0f, 1.0f);depthPower = Mathf.Clamp(depthPower, 0.0f, 1.0f);brightnessAmount = Mathf.Clamp(brightnessAmount, 0.0f, 5.0f);saturationAmount = Mathf.Clamp(saturationAmount, 0.0f, 5.0f);contrastAmount = Mathf.Clamp(contrastAmount, 0.0f, 5.0f);}void OnDisable(){if (m_curMaterial){DestroyImmediate(m_curMaterial);}}
}
三、Unity里的设置:
由于代码比较多,就不一行一行说了,太麻烦鸟  自认为注释什么的,也写得挺明白的,如果有不懂的话,再问我吧~~
这里简单截下Unity里面文件放置的位置:
ShaderWaterWave放到水波的材质球上,里面需要一个材质贴图,直接用Unity里面自带的水波贴图就可以了
AudioEffect文件放到摄像机上:
AudioWaterEffect也放到摄像机上
最后场景里放置的物体
四、轻松一下:
《古墓丽影9》劳拉的35种残忍死法,你永远都不知道玩家会怎么去玩游戏~~

路过

鸡蛋
11

鲜花

握手

雷人

转载于:https://www.cnblogs.com/unity3d-Yang/p/4661711.html

这篇关于蛋哥的学习笔记之-基于Unity的Shader编程:X-1 音乐水波特效的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/758756

相关文章

Java深度学习库DJL实现Python的NumPy方式

《Java深度学习库DJL实现Python的NumPy方式》本文介绍了DJL库的背景和基本功能,包括NDArray的创建、数学运算、数据获取和设置等,同时,还展示了如何使用NDArray进行数据预处理... 目录1 NDArray 的背景介绍1.1 架构2 JavaDJL使用2.1 安装DJL2.2 基本操

C#多线程编程中导致死锁的常见陷阱和避免方法

《C#多线程编程中导致死锁的常见陷阱和避免方法》在C#多线程编程中,死锁(Deadlock)是一种常见的、令人头疼的错误,死锁通常发生在多个线程试图获取多个资源的锁时,导致相互等待对方释放资源,最终形... 目录引言1. 什么是死锁?死锁的典型条件:2. 导致死锁的常见原因2.1 锁的顺序问题错误示例:不同

PyCharm接入DeepSeek实现AI编程的操作流程

《PyCharm接入DeepSeek实现AI编程的操作流程》DeepSeek是一家专注于人工智能技术研发的公司,致力于开发高性能、低成本的AI模型,接下来,我们把DeepSeek接入到PyCharm中... 目录引言效果演示创建API key在PyCharm中下载Continue插件配置Continue引言

C#反射编程之GetConstructor()方法解读

《C#反射编程之GetConstructor()方法解读》C#中Type类的GetConstructor()方法用于获取指定类型的构造函数,该方法有多个重载版本,可以根据不同的参数获取不同特性的构造函... 目录C# GetConstructor()方法有4个重载以GetConstructor(Type[]

HarmonyOS学习(七)——UI(五)常用布局总结

自适应布局 1.1、线性布局(LinearLayout) 通过线性容器Row和Column实现线性布局。Column容器内的子组件按照垂直方向排列,Row组件中的子组件按照水平方向排列。 属性说明space通过space参数设置主轴上子组件的间距,达到各子组件在排列上的等间距效果alignItems设置子组件在交叉轴上的对齐方式,且在各类尺寸屏幕上表现一致,其中交叉轴为垂直时,取值为Vert

Ilya-AI分享的他在OpenAI学习到的15个提示工程技巧

Ilya(不是本人,claude AI)在社交媒体上分享了他在OpenAI学习到的15个Prompt撰写技巧。 以下是详细的内容: 提示精确化:在编写提示时,力求表达清晰准确。清楚地阐述任务需求和概念定义至关重要。例:不用"分析文本",而用"判断这段话的情感倾向:积极、消极还是中性"。 快速迭代:善于快速连续调整提示。熟练的提示工程师能够灵活地进行多轮优化。例:从"总结文章"到"用

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

学习hash总结

2014/1/29/   最近刚开始学hash,名字很陌生,但是hash的思想却很熟悉,以前早就做过此类的题,但是不知道这就是hash思想而已,说白了hash就是一个映射,往往灵活利用数组的下标来实现算法,hash的作用:1、判重;2、统计次数;

Linux 网络编程 --- 应用层

一、自定义协议和序列化反序列化 代码: 序列化反序列化实现网络版本计算器 二、HTTP协议 1、谈两个简单的预备知识 https://www.baidu.com/ --- 域名 --- 域名解析 --- IP地址 http的端口号为80端口,https的端口号为443 url为统一资源定位符。CSDNhttps://mp.csdn.net/mp_blog/creation/editor

【Python编程】Linux创建虚拟环境并配置与notebook相连接

1.创建 使用 venv 创建虚拟环境。例如,在当前目录下创建一个名为 myenv 的虚拟环境: python3 -m venv myenv 2.激活 激活虚拟环境使其成为当前终端会话的活动环境。运行: source myenv/bin/activate 3.与notebook连接 在虚拟环境中,使用 pip 安装 Jupyter 和 ipykernel: pip instal