课时60 Fragment shader – UV动画 1
1.需求:将具有m行n列格子的图片在一个平面上,按照从上向下,从左至右顺序播放每一个格子;也可以设置播放顺序为从下向上,从右制作反序播放。
2.代码:
using UnityEngine;
using System.Collections;
public class SetTextureUVST : MonoBehaviour
{
public int rowCount; //行数
public int columCount; //列数
public int fps; //播放速度
public bool toUpper;//从上至下,从做到右
private int currentIndex;//当前播放索引值
float itemWidth ;
float itemHeight;
private Material mat ;
void Start()
{
itemWidth = 1.0f / rowCount; //每一帧宽度
itemHeight = 1.0f / columCount; //每一帧高度
mat = GetComponent<Renderer>().material;
if(toUpper)
{
StartCoroutine(OneToNine());
}else
{
StartCoroutine(NineToOne());
}
}
IEnumerator OneToNine()
{
while (true)
{
float offset_x = currentIndex % columCount * itemWidth;
float offset_y =- currentIndex / rowCount * itemHeight+itemHeight*2;
mat.SetTextureScale("_MainTex", new Vector2(itemWidth, itemHeight));
mat.SetTextureOffset("_MainTex", new Vector2(offset_x, offset_y));
yield return new WaitForSeconds(1 / fps);
currentIndex = (++currentIndex) % (rowCount * columCount);
}
}
IEnumerator NineToOne()
{
while (true)
{
float offset_x = -currentIndex % columCount * itemWidth+itemWidth*2;
float offset_y = currentIndex / rowCount * itemHeight;
mat.SetTextureScale("_MainTex", new Vector2(itemWidth, itemHeight));
mat.SetTextureOffset("_MainTex", new Vector2(offset_x, offset_y));
yield return new WaitForSeconds(1 / fps);
currentIndex = (++currentIndex) % (rowCount * columCount);
}
}
}
3.效果:
-
课时60 Fragment shader – UV动画 1
1.需求,实现在波光粼粼的水面中间叠加一个水波纹效果。
2.代码:
Shader "Custom/Lesson61"
{
//课时60 Fragment shader – UV动画 1
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_Speed("Speed",Range(1,10))=1
_F("F",Range(1,30))=10
_A("A",Range(0,0.1))=0.01
_R("R",Range(0,1))=0//半径
}
SubShader
{
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
sampler2D _MainTex;
float4 _MainTex_ST;
float _F;
float _A;
float _R;
struct v2f
{
float4 pos:POSITION;
float2 uv:TEXCOORD0;
};
v2f vert (appdata_full v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
return o;
}
fixed4 frag (v2f IN) : SV_Target
{
// IN.uv.x+=sin(IN.uv.x*3.14*_F+_Time.y)*0.01;
// IN.uv.y+=sin(IN.uv.y*3.14*_F+_Time.y)*0.01;
IN.uv+=0.08*sin(IN.uv*3.14*_F+_Time.y)*_A;//水波荡漾效果,sin可以对一个向量进行求值,这里变化因子是UV
float dis=distance(IN.uv,float2(0.5,0.5));
float scale=0;
_A*=saturate(1-dis/_R);//振幅,波浪高度 https://blog.csdn.net/qq_26941173/article/details/81156278
scale=_A*sin(-dis*3.14*_F+_Time.y);//这里变化因子是距中心点距离和时间
IN.uv+=IN.uv*scale;
fixed4 color = tex2D(_MainTex, IN.uv);//+fixed4(1,1,1,1)*saturate(scale)*100;
return color;
}
ENDCG
}
}
}
效果:
-
课时62 Fragment shader – UV动画 3
1.需求,实现物体表面从背对到面向摄像机过程中,逐渐变清晰效果。
2.代码:
Shader "Custom/Lesson62"
{
//课时62 Fragment shader – UV动画 3
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_Speed("Speed",Range(1,10))=1
_F("F",Range(1,30))=10
_A("A",Range(0,0.1))=0.01
_R("R",Range(0,1))=0//半径
}
SubShader
{
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#pragma target 3.0
sampler2D _MainTex;
float4 _MainTex_ST;
float _F;
float _A;
float _R;
struct v2f
{
float4 pos:POSITION;
float2 uv:TEXCOORD0;
float z:TEXCOORD1;
};
v2f vert (appdata_full v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
o.z=UnityObjectToViewPos(v.vertex).z;
return o;
}
//实现表面与视线夹角越大,像素越模糊
fixed4 frag (v2f IN) : SV_Target
{
float2 dsdx=ddx(IN.z)*10;//ddx,ddy灵活返回float和float2类型
float2 dsdy=ddx(IN.z)*10;
fixed4 color=tex2D(_MainTex,IN.uv,dsdx,dsdy);//tex2D重载函数,导数形式采样,需要SM3.0
return color;
}
//实现图片模糊效果的两种方式
fixed4 frag111 (v2f IN) : SV_Target
{
//=================简单模糊效果=====================================
// float offset_uv=0.01;
// float2 uv=IN.uv;
// fixed4 color=tex2D(_MainTex,uv);
// uv.y=IN.uv.y+offset_uv;
// color.rgb+= tex2D(_MainTex, uv)/2;
// uv.y=IN.uv.y-offset_uv;
// color.rgb+= tex2D(_MainTex, uv)/5;
// color.rgb/=3;
//=================end===================================
//=================模糊效果=====================================
float dx=ddx(IN.uv.x)*10;//一节偏导数,反映的是x轴向上像素变化率。见 https://baike.baidu.com/item/%E4%B8%80%E9%98%B6%E5%AF%BC%E6%95%B0/4026914?fr=aladdin
float2 dsdx=float2(dx,dx);
float dy=ddy(IN.uv.y)*10;
float2 dsdy=float2(dy,dy);
fixed4 color=tex2D(_MainTex,IN.uv,dsdx,dsdy);//tex2D重载函数,导数形式采样,需要SM3.0
//=================end===================================
return color;
}
ENDCG
}
}
}
效果:
-
课时63 Fragment shader –纹理混合动画 1
1.需求:利用一张星空图片,实现星星朝向两个不同方向运动扭曲效果。
2.代码:
Shader "Custom/Lesson63"
{
//课时63 Fragment shader –纹理混合动画 1
Properties
{
_F("F",Range(1,10))=4
_MainTex ("Texture", 2D) = "white" {}
}
SubShader
{
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
float _F;
sampler2D _MainTex;
struct v2f
{
float4 pos:POSITION;
float2 uv:TEXCOORD0;
};
v2f vert (appdata_full v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.uv=v.texcoord.xy;
return o;
}
//两次采样,运动方向相反
fixed4 frag (v2f IN) : SV_Target
{
float2 uv=IN.uv;
float2 uv_offset=sin(IN.uv*_F+_Time.x*4)*0.05;
uv+=uv_offset;
fixed4 color_1=tex2D(_MainTex,uv);
uv=IN.uv;
uv-=uv_offset*1;
fixed4 color_2=tex2D(_MainTex,uv);
return (color_1+color_2)/2;
}
ENDCG
}
}
}
效果:
-
课时64 Fragment shader –纹理混合动画 2
1.需求:将星空图片和下面的清晨图片混合,实现朦胧的效果。
2.代码:
Shader "Custom/Lesson64"
{
//课时64 Fragment shader –纹理混合动画 2
Properties
{
_F("F",Range(1,10))=4
_MainTex ("Texture", 2D) = "white" {}
_SecondTex("SecondTex",2D)="white"{}
}
SubShader
{
Pass
{
ColorMask rg //决定哪个颜色通道可以输出
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
float _F;
sampler2D _MainTex;
sampler2D _SecondTex;
struct v2f
{
float4 pos:POSITION;
float2 uv:TEXCOORD0;
};
v2f vert (appdata_full v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.uv=v.texcoord.xy;
return o;
}
//多次采样。不用blend和多pass,透明
fixed4 frag (v2f IN) : SV_Target
{
fixed4 mainColor=tex2D(_MainTex,IN.uv);
float2 offset_uv=sin(IN.uv*_F+_Time.x*4)*0.05;
float2 uv=IN.uv+offset_uv;
uv.y+=0.3;
fixed4 color_1=tex2D(_SecondTex,uv);
mainColor.rgb*=color_1.b;
mainColor.rgb*=2;
uv=IN.uv-offset_uv;
uv.y+=0.3;
fixed4 color_2=tex2D(_SecondTex,uv);
mainColor.rgb*=color_2.b;
mainColor.rgb*=2;
return mainColor;
// float2 uv=IN.uv;
// uv+=uv_offset;
// fixed4 color_1=tex2D(_MainTex,uv);
// uv=IN.uv;
// uv-=uv_offset*1;
// fixed4 color_2=tex2D(_MainTex,uv);
// return (color_1+color_2)/2;
}
ENDCG
}
}
}
效果:
-
课时65 Fragment shader – 程序纹理
水波纹理C#仿真Project资源:https://download.csdn.net/download/a592733740/11827202
-
课时66 Fragment shader – 程序纹理水波仿真1
-
课时67 Fragment shader – 程序纹理水波仿真2
-
课时68 Fragment shader – 程序纹理水波仿真3
-
课时69 Fragment shader – 程序纹理水波仿真4
1.需求:①要求鼠标在模型上点击或拖动,产生水波纹效果。
2.代码:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading;
using UnityEngine;
//优化:1.使用多线程计算并缓存颜色数据;2.关闭垂直同步;3.和CPU协同的异构平台的通用化计算GP-GPU,例如opencell,CUDA,DirectCompute(对应ComputeShader)
public class WaveTexture : MonoBehaviour {
public int waveWidth;
public int waveHeight;
public int radius=8;//水波初始半径
float[,] waveA;
float[,] waveB;
Color[] ColorBuffer;
Texture2D tex_uv;
bool isRun=true;
int sleepTime;
// Use this for initialization
void Start () {
waveA=new float[waveWidth,waveHeight];
waveB=new float[waveWidth,waveHeight];
tex_uv=new Texture2D(waveWidth,waveHeight);
ColorBuffer=new Color[waveWidth*waveHeight];
GetComponent<Renderer>().material.SetTexture("_WaveTex",tex_uv);
PutDrop(0,0);
Thread thread=new Thread(new ThreadStart(ComputeWave));
thread.Start();
}
// Update is called once per frame
void Update () {
sleepTime=(int)Time.deltaTime*1000;
tex_uv.SetPixels(ColorBuffer);
tex_uv.Apply();
if(Input.GetMouseButton(0))
{
RaycastHit hit;
Ray ray=Camera.main.ScreenPointToRay(Input.mousePosition);
if(Physics.Raycast(ray,out hit))
{
Vector3 pos=hit.point;
pos=transform.worldToLocalMatrix.MultiplyPoint(pos);
pos=pos+new Vector3(0.5f,0.5f,0);
PutDrop((int)(waveWidth*pos.x),(int)(waveHeight*pos.y));
}
}
// ComputeWave();
}
void setPixels()
{
tex_uv.Apply();
}
void PutDrop(int x,int y)
{
float dist;
for(int i=-radius;i<=radius;i++)
{
for(int j=-radius;j<=radius;j++)
{
if(((x+i>=0)&&(x+i<waveWidth-1))&&((y+j>=0)&&(y+j<waveHeight-1)))
{
dist=Mathf.Sqrt(i*i+j*j);
if(dist<radius)
waveA[x+i,y+j]=Mathf.Cos(dist*Mathf.PI/radius);
}
}
}
}
private void ComputeWave()
{
while(isRun)
{
for(int w=1;w<waveWidth-1;w++){
for(int h=1;h<waveHeight-1;h++)
{
waveB[w,h]=(waveA[w-1,h]+
waveA[w+1,h]+
waveA[w,h-1]+
waveA[w,h+1]+
waveA[w-1,h+1]+
waveA[w-1,h-1]+
waveA[w+1,h+1]+
waveA[w+1,h-1])/4-waveB[w,h];
float value=waveB[w,h];
if(value>1)
{
waveB[w,h]=1;
}
if(value<-1)
{
waveB[w,h]=-1;
}
//做插值,计算折射用
float offset_u=(waveB[w-1,h]-waveB[w+1,h])/2;//-1~1
float offset_v=(waveB[w,h-1]-waveB[w,h+1])/2;
float r=offset_u/2+0.5f;//0~1
float g=offset_v/2+0.5f;
// tex_uv.SetPixel(w,h,new Color(r,g,0));
ColorBuffer[waveWidth*h+w]=new Color(r,g,0);
waveB[w,h]-=waveB[w,h]*0.015f;//衰减
}
Thread.Sleep(sleepTime);//与Update调用频率一致
}
// tex_uv.Apply();
float[,] temp =waveA;
waveA=waveB;
waveB=temp;
}
}
void OnDestroy()
{
isRun=false;
}
}
Shader "Custom/Lesson66-69"
{
//课时66 Fragment shader – 程序纹理水波仿真1
Properties
{
_MainTex ("Texture", 2D) = "white" {}
}
SubShader
{
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct v2f
{
float4 pos : POSITION;
float2 uv : TEXCOORD0;
};
sampler2D _MainTex;
sampler2D _WaveTex;
v2f vert (appdata_full v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.uv = v.texcoord.xy;
return o;
}
fixed4 frag (v2f IN) : COLOR
{
float2 uv=tex2D(_WaveTex,IN.uv).xy;
uv=uv*2-1;//-1~1
uv*=0.025;
IN.uv+=uv;
fixed4 col = tex2D(_MainTex, IN.uv);
return col;
}
ENDCG
}
}
}
效果: