Shader半透明物体的制作

mac2026-09-22  12

Shader 04

透明度混合

先来一张效果图 先放源代码:

//这里每个人得到名字不一样,自己修改 Shader "Custom/AlphaTest" { Properties { _Color("Main Tint",Color) = (1,1,1,1) _MainTex ("Main Tex", 2D) = "white" {} //控制透明度,范围是0-1。 _AlphaScale("_AlphaScale",float)= 1 _Speed("_Speed",float) = 0.1 } SubShader { //定义Tags,IgnoreProjector 决定 shader 是否会受投影器的影响,RenderType 可以让 shader 归入提前定义的组(这里是 TransparentCutout) Tags{"Queue" = "Transparent" "IgnoreProjector" = "True" "RenderType" = "Transparent"} //渲染后面 Pass { Tags{"LightMode" = "ForwardBase"} Cull Front ZWrite Off Blend SrcAlpha OneMinusSrcAlpha CGPROGRAM #pragma vertex vert #pragma fragment frag //引入dll文件 #include "Lighting.cginc" #include "UnityCG.cginc" //声明变量 fixed4 _Color; sampler2D _MainTex; float4 _MainTex_ST; float _AlphaScale; float _Speed; struct a2v { float4 vertex : POSITION; float3 normal : NORMAL; float4 texcoord : TEXCOORD0; }; struct v2f { float4 pos : SV_POSITION; float3 worldNormal : TEXCOORD0; float3 worldPos : TEXCOORD1; float2 uv : TEXCOORD2; }; v2f vert (a2v v) { v2f o; o.pos = UnityObjectToClipPos(v.vertex); o.worldNormal = UnityObjectToWorldNormal(v.normal); o.worldPos = mul(unity_ObjectToWorld,v.vertex).xyz; //TRANSFORM_TEX宏来确保正确应用纹理比例和偏移 o.uv = TRANSFORM_TEX(v.texcoord,_MainTex); // o.uv = v.uv; return o; } fixed4 frag (v2f i) : SV_TARGET0 { fixed2 tmpUv = i.uv; tmpUv.x += _Time.y * _Speed; fixed3 worldNormal = normalize(i.worldNormal); fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos)); fixed4 texcolor = tex2D(_MainTex,tmpUv); fixed3 albedo = texcolor.rgb * _Color.rgb; fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo; fixed3 diffues = _LightColor0.rgb * albedo * max(0,dot(worldNormal,worldLightDir)); // just invert the colors // col.rgb = 1 - col.rgb; return fixed4(ambient + diffues,texcolor.a * _AlphaScale); } ENDCG } //渲染前面 Pass { Tags{"LightMode" = "ForwardBase"} Cull Back ZWrite Off Blend SrcAlpha OneMinusSrcAlpha CGPROGRAM #pragma vertex vert #pragma fragment frag //引入dll文件 #include "Lighting.cginc" #include "UnityCG.cginc" //声明变量 fixed4 _Color; sampler2D _MainTex; float4 _MainTex_ST; float _AlphaScale; float _Speed; struct a2v { float4 vertex : POSITION; float3 normal : NORMAL; float4 texcoord : TEXCOORD0; }; struct v2f { float4 pos : SV_POSITION; float3 worldNormal : TEXCOORD0; float3 worldPos : TEXCOORD1; float2 uv : TEXCOORD2; }; v2f vert (a2v v) { v2f o; o.pos = UnityObjectToClipPos(v.vertex); o.worldNormal = UnityObjectToWorldNormal(v.normal); o.worldPos = mul(unity_ObjectToWorld,v.vertex).xyz; //TRANSFORM_TEX宏来确保正确应用纹理比例和偏移 o.uv = TRANSFORM_TEX(v.texcoord,_MainTex); // o.uv = v.uv; return o; } fixed4 frag (v2f i) : SV_TARGET0 { fixed2 tmpUv = i.uv; tmpUv.x += 1-_Time.y * _Speed; fixed3 worldNormal = normalize(i.worldNormal); fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos)); fixed4 texcolor = tex2D(_MainTex,tmpUv); fixed3 albedo = texcolor.rgb * _Color.rgb; fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo; fixed3 diffues = _LightColor0.rgb * albedo * max(0,dot(worldNormal,worldLightDir)); // just invert the colors // col.rgb = 1 - col.rgb; return fixed4(ambient + diffues,texcolor.a * _AlphaScale); } ENDCG } } FallBack "Transparent/VertexLit" }

通过滑动条控制透明度与uv的速度 源码如下:

using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; public class AlphaCtrl : MonoBehaviour { public Slider[] Allslider; void Start() { //给每一个slider注册事件 foreach (Slider item in Allslider) { //用lamuda表达式解决函数的回调,改变滑动条的值就可以改变,材质的参数 item.onValueChanged.AddListener((float value)=> ValueChange(value,item)); } } public void ValueChange(float value, Slider EventSender) { switch (EventSender.name) { //控制Alpha值 case "Alpha": GetComponent<Renderer>().material.SetFloat("_AlphaScale", value); Debug.Log("Alpha value == " + value.ToString("f2")); break; //控制UV速度 case "UVspeed": GetComponent<Renderer>().material.SetFloat("_Speed", value*5); Debug.Log("UvSpeed value == " + (value * 5).ToString("f2")); break; } } void Update() { } }

学了shader后,发现之前的很多无法实现的效果,现在都可以实现了

在制作类似这种半透明的时候,首先要指定队列,要渲染的半透明的物体的时候,就需要 在Tags里面写下"Queue" = “Transparent”。

遇到的Bug:

第一个:由于我用的vs code编辑器所以提示效果不好,很多都是手打上去的,在编写字符串的时候要注意,没有高亮显示,所以要细心,如字母的大小写,虽然shader对大小写不是很敏感,但是调用Unity写的方法或者接口的时候,规定了格式就要遵守。

第二个,算是拓展我想通过Slider(滑动条)来控制透明度参数与uv的速度,在获取参数的时候发生了一个比较有趣的事情,由于我用了两个滑动条,我不想写两遍控制滑动条的方法,所以用了一个数组,存放两个滑动条,因为UI要用回调(可以用mvc框架实现),如果不知道mvc框架的,我下次更新在说,就用了匿名函数 **拉姆达表达式(float value)=> ValueChange(value,item)**来代替了回调那整个过程,(偷懒写法)

然后在ValueChange()中分别写对应要控制的sahder的参数GetComponent().material.SetFloat("_AlphaScale", value);这里就获取到了shader中控制透明度的参数,这里是我纠结了很久的地方,我第一次写的参数是AlphaScale,在shader中可以运行,但是通过滑动条始终无法控制,无法获取参数,我去看了一下SetFloat方法(可以双击这个方法,然后vs的按F12就可以看到Unity封装的的方法) 在后面name哪里,必须是下划线加变量名(我当时就是…)无语,改了之后完美运行。所以多看一下官方的东西,有些不够的可以去找资料补充。

当在Unity中创建一个shader脚本的时候,就会有一个默认的框架,如果是刚学shader的,建议先看一下 shader1.0(固定管线渲染),开关式的编程,有助于理解shader的基本语法,当学完shader1.0后就可以去看shader2.0了,最好的学习资料就是官方文档,虽然是英文的,不过都不是什么复杂的英语,查一查,问一问就能理解的差不多。

距离上一次的更新是好久了,要坚持下去。

参考文章: [https://blog.csdn.net/weixin_37027464/article/details/82878815] UGUI Slider的onValueChanged事件

最新回复(0)