自言自语
好久没有更新笔记了,一是因为时间少,二是因为搬家,三是因为要啃PBR了太难压力大,四是因为懒惰。好吧,我承认,就是懒惰了。于是今天赶紧更新一篇笔记。督促自己进入学习状态。明天开始啃PBR。但愿我能看懂。
今天是在shader中实现一个计时器。功能是到一定时间进行一种操作。 运用到了smoothstep 和lerp 包含了间隔时间,单次播放时间,淡入淡出时间。和两种颜色混合算法。 看代码挺简单。 但是我当时自己研究了快10个小时没研究出来一个满意的淡入淡出的计算办法,后来经大佬指点2分钟。实现了。。。。 既高兴又羞愧啊 太笨了我。好了不废话了 输入正经内容吧。
一、材质面板
这次我稍微对材质面板进行了一点点小小的整理,这样方便我们这样的美术调整参数时看起来清爽下,其实可以又更好的 GUI实现效果,但是太复杂了。。我好懒,没有继续学习 就用Unity内置的用起来挺轻松 排版效果也够了。
二、动态效果
三、shader部分
Shader "TNShaderPractise/ShaderPractise_TimeClock"
{
Properties
{
[Header(LerpColor)]
[HDR]_Color01 ("测试颜色1",COLOR)=(1,1,1,1)
//[HDR]_Color02 ("测试颜色2",COLOR)=(0,0,0,0)
//为了方便观察放张纹理
_TestTex("测试贴图",2D)="white"{}
[Space(20)][Header(ColorBlendMode)]
//内设的单选形式的属性面板写法之一
[Toggle]_IsLerp("是否插值混合",Float) = 0
//自定义材质面板风格 当然是UNITY内设好的 Space是上下行间距 (10) 表示10个单位 后边 Header 可以理解为分段标题,方便识别 括号内是标题名 只能用英文 中文测试过编译失败
[Space(20)][Header(TimeSet)]
_OncePlay("单次播放时长(为0则不进行变换)",Float)=0
_TimeInvertal("间隔时长(0为不间隔持续循环播放)",Float)=0
_FadeIn("淡入时长(0为不淡入无渐变)",Float)=0
_FadeOut("淡出时长(0为不淡出无过度)",Float)=0
}
SubShader
{
//因为直接新建的是URP工程 因此不用特别写明 Render Pipeline 就是默认的urp管线shader
Tags { "RenderType"="Opaque" }
LOD 100
Pass
{
HLSLPROGRAM
#pragma vertex vert
#pragma fragment frag
//由于只是简单的计算 没有光照模型 引入这么一个文件够了 应该
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
//为了支持SRPBatcher 将参数都声明在CBUFFER块内
CBUFFER_START(UnityPerMaterial)
float4 _Color01;
float4 _Color02;
//URP下的纹理声明方式 感觉比built in 繁琐了.. 之前写2行就行 代码还少,现在得写3行。。。
TEXTURE2D (_TestTex);
SAMPLER(sampler_TestTex);
float4 _TestTex_ST;
//URP下的纹理声明方式 感觉比built in 繁琐了.. 之前写2行就行 代码还少,现在得写3行。。。
float _IsLerp;
float _OncePlay;
float _TimeInvertal;
float _FadeIn;
float _FadeOut;
CBUFFER_END
struct a2v
{
float4 vertex : POSITION;
float2 texcoord : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 pos : SV_POSITION;
};
v2f vert (a2v v)
{
v2f o;
//尝试用URP 封装好的方法来进行坐标空间转换
VertexPositionInputs input = GetVertexPositionInputs(v.vertex.xyz);
o.pos = input.positionCS;
o.uv = TRANSFORM_TEX(v.texcoord,_TestTex);
return o;
}
//声明一个方法 当做计时器
float TimeClock (float TimeInvertal,float OncePlay,float FadeIn,float FadeOut )
{
////防止为0为负数的Bug
FadeIn =max(FadeIn,0.001);
FadeOut =max(FadeOut,0.001);
//总时长 由间隔时间 播放时间 淡入淡出时间相加而得
float totalTime = TimeInvertal+OncePlay+FadeIn+FadeOut;
//用Unity内置时间变量除以总时长取余数 用作一轮时间段的循环计时 举例 假如 总时长为5秒 取余操作则为 随着时间每秒变化 0 1 2 3 4 递增
float playTime = fmod(_Time.y,totalTime);
//声明最终返回的变量,在片元着色器中可以当做插值使用
float Clock;
//当取余时长小于单次播放时间和淡入时间总和时,则表明插值参数为0到1曲线递增后持续为1 这里用smoothstep一是方便限制到0到1区间 而是非线性的递增曲线会视觉上看起来更平滑
if (playTime<OncePlay+FadeIn)
{
//这里需要注意 虽然长度是 _OncePlay+_FadeIn 但我们不能用这个作为最大值,因为这样 如果淡入时间为0 那么smoothstep也会把_OncePlay也算进去 设置淡入时间就不对了
Clock = smoothstep(0,FadeIn,playTime);
}
//当取余时长大于单次播放时间和淡入时间总和时,则需要参数从1到0曲线变化,且持续到一轮时间的最后, 所以根据当前时间点和当前时间段的对应时刻做smoothstep的反向操作.这点需要画图理解.也是利用smoothstep函数的特性 很好用
else
{
Clock = smoothstep(OncePlay+FadeIn+FadeOut,OncePlay+FadeIn,playTime);
}
//最后返回Clock作为插值 用于片元着色器中
return Clock;
}
float4 frag (v2f i) : SV_Target
{
//调用TimeClock方法 取得Clock插值
float Clock = TimeClock (_TimeInvertal,_OncePlay,_FadeIn,_FadeOut);
//为了方便观察还是放张纹理吧 同样这也是 URP下的繁琐的采样纹理贴图的写法... 注意 这里是SAMPLE 不是 SAMPLER....反正我在这里写错很多次。。。坑啊Unity
float4 col = SAMPLE_TEXTURE2D(_TestTex,sampler_TestTex,i.uv);
//判断开关状态 决定颜色混合算法
if (_IsLerp == 1)
{
//利用TimeClock依据时间得到的插值参考值 进行颜色插值计算
return lerp (_Color01,col,Clock);
}
else
{
return lerp (_Color01,_Color01+col,Clock);
}
}
ENDHLSL
}
}
FallBack "Universal Render Pipeline/Unlit"
}
总结
写完笔记又到凌晨了。祈祷我这么学习,熬夜能有成果。别猝死了。。。。ORZ 没有天赋又笨又懒只能这么可劲儿造自己了 哈哈 其实夜深人静的时候学习 还蛮爽的 我很Enjoy but 明儿还得上班。。。白天又要工作 又困又累。才是要挺住哦。。。 自己嘴碎,吐槽比代码敲的还多。还好没啥人看。哈哈哈哈哈。