目录
课时63:FragmentShader-纹理混合动画1-星空
课时63:FragmentShader-纹理混合动画1-星空
视频:https://www.bilibili.com/video/BV1YK41157AC?p=63
找一张夜晚星空的图片先 hipwallpaper.com/view/XdrL4n
简单移动
fixed4 frag(v2f IN) :COLOR
{
float2 uv=IN.uv+_Time.x;
fixed4 color=tex2D(_MainTex,uv);
return color;
}
需要贴图无缝对接
简单三角函数动画
fixed4 frag(v2f IN) :COLOR
{
float2 uv=IN.uv;
float offset_uv=_A*sin(IN.uv*_F+_Time.x);
uv+=offset_uv;
fixed4 color=tex2D(_MainTex,uv);
return color;
}
多次采样,营造空间感
fixed4 frag(v2f IN) :COLOR
{
float2 uv=IN.uv;
float offset_uv=_A*sin(IN.uv*_F+_Time.x);
fixed4 color1=tex2D(_MainTex,(uv+offset_uv));
fixed4 color2=tex2D(_MainTex,(uv-offset_uv*2));
fixed4 color=(color1+color2)/2;
return color;
}
效率高,不用多张贴图,不用多个pass,不用透明。
课时64:FragmentShader-纹理混合动画2
找一个贴图 https://hipwallpaper.com/view/JeNAkE
这张图作为主背景,上面的星空图作为动画的图。
fixed4 frag(v2f IN) :COLOR
{
fixed4 mainColor=tex2D(_MainTex,IN.uv);
float2 uv=IN.uv;
float offset_uv=_A*sin(IN.uv*_F+_Time.x*_T);//_A:0.02,_F:5,_T:2
fixed4 color1=tex2D(_SecondTex,(uv+offset_uv));
fixed4 color=(mainColor+color1)/_L;//_L:1-2,1.5
return color;
}
灰度值
fixed4 color=mainColor*color1.a;
这也太暗了,叠加再乘。
fixed4 color=(mainColor+color1)*color1.a;//_L:1-2,1.5
再乘与一个系数
fixed4 color=mainColor*color1.a*_L;//_L:1-3,3
蓝色部分
fixed4 color=mainColor*color1.b;
可以做一个枚举类型,切换不同的通道测试
float a=_L;
if(_Type==1)
{
a*=color1.r;
}
if(_Type==2)
{
a*=color1.g;
}
if(_Type==3)
{
a*=color1.b;
}
if(_Type==4)
{
a*=color1.a;
}
fixed4 color=mainColor*a;//_L:1-3,3
多次取样,空间感
colormask r
colormask g
这个colormask好像会和前面的重合,比如,先colormask r,再改成 colormask g,结果和colormask g不一样,而是
不过和教程不同,不是纯一个的效果。
发现时少了一步
课时65:FragmentShader-程序纹理1
多次点击水面的波纹效果,上回我的练习卡住的部分。
一个c#控件:https://www.codeproject.com/Articles/2812/A-C-water-effect-picture-control
这节课就是讲了一些主要代码,下节课要移植到unity里面
/// <summary>
/// Timer handler
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void effectTimer_Tick(object sender, System.EventArgs e)
{
if(_weHaveWaves)
{
Invalidate();
ProcessWaves();
}
}
/// <summary>
/// Paint handler
///
/// Calculates the final effect-image out of
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
public void WaterEffectControl_Paint(object sender, System.Windows.Forms.PaintEventArgs e)
{
using(Bitmap tmp = (Bitmap)_bmp.Clone())
{
int xOffset, yOffset;
byte alpha;
if(_weHaveWaves)
{
BitmapData tmpData = tmp.LockBits(new Rectangle(0,0,_bmpWidth,_bmpHeight), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
byte[] tmpBytes = new Byte[_bmpWidth*_bmpHeight*4];
Marshal.Copy(tmpData.Scan0,tmpBytes,0,_bmpWidth*_bmpHeight*4);
for(int x=1; x<_bmpWidth -1; x++)
{
for(int y=1; y<_bmpHeight -1; y++)
{
int waveX = (int)x >> _scale;
int waveY = (int)y >> _scale;
//check bounds
if(waveX <= 0) waveX = 1;
if(waveY <= 0) waveY = 1;
if(waveX >= _waveWidth-1) waveX = _waveWidth-2;
if(waveY >= _waveHeight-1) waveY = _waveHeight-2;
//this gives us the effect of water breaking the light
xOffset = (_waves[waveX-1,waveY,_activeBuffer] -_waves[waveX+1,waveY,_activeBuffer]) >> 3;
yOffset = (_waves[waveX,waveY-1,_activeBuffer] -_waves[waveX,waveY+1,_activeBuffer]) >> 3;
if((xOffset != 0) || (yOffset != 0))
{
//check bounds
if(x+xOffset >= _bmpWidth-1) xOffset = _bmpWidth - x - 1;
if(y+yOffset >= _bmpHeight-1) yOffset = _bmpHeight - y - 1;
if(x+xOffset < 0) xOffset = -x;
if(y+yOffset < 0) yOffset = -y;
//generate alpha
alpha = (byte)(200-xOffset);
if(alpha < 0) alpha = 0;
if(alpha > 255) alpha = 254;
//set colors
tmpBytes[4*(x + y*_bmpWidth)] = _bmpBytes[4*(x+xOffset + (y+yOffset)*_bmpWidth)];
tmpBytes[4*(x + y*_bmpWidth) + 1] = _bmpBytes[4*(x+xOffset + (y+yOffset)*_bmpWidth) + 1];
tmpBytes[4*(x + y*_bmpWidth) + 2] = _bmpBytes[4*(x+xOffset + (y+yOffset)*_bmpWidth) + 2];
tmpBytes[4*(x + y*_bmpWidth) + 3] = alpha;
}
}
}
//copy data back
Marshal.Copy(tmpBytes, 0, tmpData.Scan0, _bmpWidth*_bmpHeight*4);
tmp.UnlockBits(tmpData);
}
e.Graphics.DrawImage(tmp,0,0,this.ClientRectangle.Width, this.ClientRectangle.Height);
}
}
/// <summary>
/// This is the method that actually does move the waves around and simulates the
/// behaviour of water.
/// </summary>
private void ProcessWaves()
{
int newBuffer = (_activeBuffer == 0) ? 1 : 0;
bool wavesFound = false;
for(int x=1; x<_waveWidth -1; x++)
{
for(int y=1; y<_waveHeight -1; y++)
{
_waves[x,y,newBuffer] = (short)(
((_waves[x-1,y-1,_activeBuffer] +
_waves[x,y-1,_activeBuffer] +
_waves[x+1,y-1,_activeBuffer] +
_waves[x-1,y,_activeBuffer] +
_waves[x+1,y,_activeBuffer] +
_waves[x-1,y+1,_activeBuffer] +
_waves[x,y+1,_activeBuffer] +
_waves[x+1,y+1,_activeBuffer]) >> 2) - _waves[x,y,newBuffer]);
//damping
if(_waves[x,y,newBuffer] != 0)
{
_waves[x,y,newBuffer] -= (short)(_waves[x,y,newBuffer] >> 4);
wavesFound = true;
}
}
}
_weHaveWaves = wavesFound;
_activeBuffer = newBuffer;
}
课时66:FragmentShader-程序纹理2