前言
学习在Unity中怎么创建shader,实现模型半透明效果,同时从C#代码中获取shader中的参数进行不透明度的修改。
下一期讲解模型中如果有很复杂的贴图,非常多的材质的情况下,如何在UnityEditor中一键生成并替换对应的shader材质,将原本的材质替换为新的、挂载自己的shader脚本的材质球prefabs.
一、shader是什么?
shader中文名称为着色器,其实就是专门用来渲染图形的一种技术,通过shader,我们可以自定义显卡渲染画面的算法,使画面达到我们想要的效果。其中就包括本期讲的透明度修改的渲染算法。
二、使用流程
1.创建shader编辑器
在Unity3D的Project页面中合适的位置右键创建一个最基础的shader文件
2.创建材质
同样是在对应位置创建一个空的材质球,这个材质球是是有模型默认的基础材质,我们需要把这个shader赋予对应的材质球上,需要将创建的shader拖入Material上.
3.编写shader代码
双击shader,编写对应的shader脚本
代码如下:
Shader "Custom/Translucent"
{
Properties {
_Color ("Color Tint", Color) = (1, 1, 1, 1)
_MainTex ("Main Tex", 2D) = "white" {}
//我们使用一个新的属性_AlphaScale 来替代原先的_Cutoff 属性。_AlphaScale用于在透明纹理的基础上控制整体的透明度。
_AlphaScale ("Alpha_Scale", Range(0, 1)) = 1
}
SubShader {
//把Queue标签设置为Alphaparent
//把IgnoreProjector设置为true,意味着这个Shader不会受到投影器(Properties)的影响
//RenderType标签可以让Unity把这个Shader归入到提前定义的组(这里就是Transparent组),以指明该Shader是一个使用了透明度混合的Shader
//使用了透明度测试的Shader都应该在SubShader设置这三个标签
Tags {"Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent"}
Pass {
ZWrite On
ColorMask 0
}
Pass {
Tags { "LightMode"="ForwardBase" }
//为透明度混合进行合适的混合状态设置
//关闭深度写入
ZWrite Off
//使用了Blend SrcFactor DstFactor语义
//把源颜色(该片元着色器产生的颜色)的混合因子SrcFactor设为SrcAlpha, 而目标颜色(已经存在于颜色缓冲中的颜色)的混合因子 DstFactor设为 OneMinusSrcAlpha 。
Blend SrcAlpha OneMinusSrcAlpha//这部分在下面 六 会讲到
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "Lighting.cginc"
fixed4 _Color;
sampler2D _MainTex;
float4 _MainTex_ST;
fixed _AlphaScale;
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;
o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
return o;
}
fixed4 frag(v2f i) : SV_Target {
fixed3 worldNormal = normalize(i.worldNormal);
fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));
fixed4 texColor = tex2D(_MainTex, i.uv);
fixed3 albedo = texColor.rgb * _Color.rgb;
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo;
fixed3 diffuse = _LightColor0.rgb * albedo * max(0, dot(worldNormal, worldLightDir));
//设置了该片元着色器返回值中的透明通道,它是纹理像素的透明通道和材质参数_AlphaScale的乘积。
return fixed4(ambient + diffuse, texColor.a * _AlphaScale);
}
ENDCG
}
}
FallBack "Transparent/VertexLit"
}
其中这一行语句为透明度修改的变量,透明度只能在0-1之间进行修改,默认为1
_AlphaScale ("Alpha_Scale", Range(0, 1)) = 1
4.材质赋予
在场景中拖入对应模型,将这个模型的材质,将带有这个shader的材质球赋予这个模型,此时用Cube替代,将材质球拖动给此模型。然后发现这个cube身上的材质已经被替换成对应的shader材质。
5.材质页面修改
然后我们发现对应的材质文件替换后,材质页面会显示我们shader代码中的变量,其中提到的_AlphaScale透明度修改变量也在其中,拖动此进度条会修改此模型的材质,具体的数值为透明度,例如0是完全透明,1是完全不透明。
6.C#代码动态修改或者动态获取透明度
首先是获取透明度参数,比如把脚本挂载在此cube上,然后获取Renderer的材质从而获取shader的变量。
private Renderer shaderRenderer; // 用于存储shader材质
shaderRenderer= shaderRenderer.material.GetFloat("_AlphaScale"); // 获取属性值,_AlphaScale为自定义属性名称
其次是修改对应的透明度,原理一样。
[Header("透明度")]
public float alpha;
shaderRenderer.material.SetFloat("_AlphaScale", alpha);
其中采用了协程的递归,实现透明度在0.2到0.5之间来回渐变切换,每秒渐变一次,如果当前是0.5透明度,则下次递归返回自己时透明度在1秒内变为0.2,如果不是,则变回0.5。
IEnumerator DelayChange(float _alpha)
{
DOTween.To(() => alpha, x => alpha = x, _alpha, 1);//第一个1是透明度,第二个1是时间,1秒内将alpha变为1
yield return new WaitForSeconds(1f);
yield return StartCoroutine(DelayChange(_alpha == 0.5f ? 0.2f : 0.5f));
}
其中用了Dotween插件,就是修改float值alpha在1秒内变为一个值,如果不用Dotween的话,则可以用计时器来写。
DOTween.To(() => alpha, x => alpha = x, _alpha, 1);//第一个1是透明度,第二个1是时间,1秒内将alpha变为1
最终代码如下:
using DG.Tweening;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MaterialControl : MonoBehaviour
{
[Header("透明度")]
public float alpha;
[Header("是否透明一直切换")]
public bool isChangeAlways;
private Renderer shaderRenderer; // 用于存储shader材质
private void Start()
{
TryGetComponent(out shaderRenderer);
isChangeAlways = true;
//propertyValue = shaderRenderer.material.GetFloat("_AlphaScale"); // 获取属性值,_PropertyName为自定义属性名称
StartCoroutine(DelayChange(0.5f));
}
private void Update()
{
if (isChangeAlways)
{
shaderRenderer.material.SetFloat("_AlphaScale", alpha);
}
}
IEnumerator DelayChange(float _alpha)
{
DOTween.To(() => alpha, x => alpha = x, _alpha, 1);//第一个1是透明度,第二个1是时间,1秒内将alpha变为1
yield return new WaitForSeconds(1f);
yield return StartCoroutine(DelayChange(_alpha == 0.5f ? 0.2f : 0.5f));
}
}
将此脚本挂载在需要变色的物体上后,会发现有两个变量,一个是alpha值,这个对应的是shader里的透明度,还有一个bool变量isChangeAlways,这个变为true时会一直切换,否则会停留在上次关闭时的透明度值。
总结
下一期讲解模型中如果有很复杂的贴图,非常多的材质的情况下,如何在UnityEditor中一键生成并替换对应的shader材质,将原本的材质替换为新的、挂载自己的shader脚本的材质球prefabs.