shader入门精要第十章

//立方体纹理在之前被我整合到了第六章的内容里,不再赘述

高级纹理

渲染纹理

现代GPU允许把整个三维场景渲染到中间缓冲中,而不是帧缓冲当中,这个中间缓冲叫做渲染目标纹理(Render Target Texture RTT) ,与之对应的是多重渲染目标(Mutil-Render Target) MRT 将场景渲染到多个渲染目标纹理中。为此,Unity专门定义了一种纹理类型——渲染纹理(Render Texture)。其使用通常有两种方式:

  • 创建渲染纹理,将某个摄像机的渲染目标设置成该渲染纹理,摄像机的渲染结果就会实时渲染到该纹理中
  • 通过后期处理抓取当前屏幕图像,Unity将屏幕图像放到一张同等分辨率的渲染纹理中

使用渲染纹理实现镜子效果

通过一个额外的摄像机,调整到对应位置,设置渲染目标为一张渲染纹理,将该渲染纹理作为一张2D纹理,在采样是,将UV坐标的进行翻转

Shader "Unlit/镜子"
{       
    Properties{                 
        _MainTex("MainTex",2D) = "white"{}
    }



    SubShader{
        Tags {
            "RenderType" = "Opaque"
        }
        Pass {
            Name "FORWARD"
            Tags {
                "LightMode" = "ForwardBase"
            }

            CGPROGRAM

            #pragma vertex vert//哪个函数包含了顶点着色器的代码
            #pragma fragment frag//哪个函数包含了片元着色器的代码
        #include "Lighting.cginc"

            sampler2D _MainTex;
            float4        _MainTex_ST;
           


struct VertexInput {                           //输入结构
    float4 vertex : POSITION;
    float4 uv0:TEXCOORD0;
};


struct VertexOutput {                          //输出结构
    float4 pos : SV_POSITION;
    float4 uv:TEXCOORD0;
};


VertexOutput vert(VertexInput v) {            //顶点Shader
    VertexOutput o = (VertexOutput)0;
    o.pos = UnityObjectToClipPos(v.vertex);
    o.uv = v.uv0;
    o.uv.x = 1 - o.uv.x;   //将uv.x分量进行翻转,实现镜子效果

    return o;
}

            float4 frag(VertexOutput i) : COLOR {          //像素Shader
                return tex2D(_MainTex,i.uv);
            }
            ENDCG
        }
    }
        FallBack "Diffuse"
}

 物体和镜面和摄像机位置


通过调整摄像机角度,获得最佳效果

玻璃效果
Unity Shader中可以使用GrabPass完成对屏幕图像的抓取。定义GrabPass后,Unity将当前屏幕图像绘制在一张纹理中,使用GrabPass模拟玻璃透明效果,可以对物体后面的图像做更复杂的处理(使用法线模拟折射效果),而不是像使用透明度混合,只是颜色上的混合。 在使用GrabPass进行透明效果模拟时,要注意渲染顺序的设置 ,先保证场景中所有不透明物体已经绘制在屏幕上,再对屏幕进行抓取图像,因此一般设置成 "Queue"="Transparent"
实现玻璃效果:
●Step1 获取指定位置的立方体纹理,通过反射方向采样得到反射颜色
●Step2 获取屏幕抓取图像,通过法线纹理得到法线方向作为影响值与影响因子相乘,调整获取的屏幕图像扭曲程度来模拟折射
●Step3 将两者颜色进行混合,通过混合值调整反射和折射的混合程度

Shader "Unlit/玻璃"
{
    Properties{
        _CubeMap("Cubemap", Cube) = "_Skybox" {}                 
       _MainTex("Main Tex",2D) = "white"{}
       _BumpTex("Bump Tex",2D) = "bump"{}
        _Distortion("Distortion",Range(0,100)) = 10
         _RefractionAmount("RefractionAmount",Range(0,1)) = 1
        
    }
        SubShader{
            Tags { "Queue" = "Transparent"
               "RenderType" = "Opaque"}
            
             GrabPass {"_RefractionTex"}
            Pass {
                Name "FORWARD"
                Tags {
                    "LightMode" = "ForwardBase"
                }


                CGPROGRAM
                #pragma vertex vert
                #pragma fragment frag
                #include "UnityCG.cginc"
             #include "Lighting.cginc"
        #include "AutoLight.cginc"
              

            //输入参数
            sampler2D _MainTex;
            float4 _MainTex_ST;
            sampler2D _BumpTex;
            float4 _BumpTex_ST;
             uniform samplerCUBE _CubeMap;          
             float _Distortion;
             float _RefractAmount;
             sampler2D _RefractionTex;   //存储GrabPass抓取的屏幕图像
             float4 _RefractionTex_TexelSize;  //得到屏幕图像的纹素值,在做偏移计算时使用

           
             //输入结构
             struct VertexInput {
                 float4 vertex : POSITION;  //顶点信息
                 float3 normal : NORMAL;    //法线信息,用作之后法线采样与TBN矩阵的计算            
                 float4 tangent:TANGENT;
                 float4 uv0:TEXCOORD0;

             };

             //输出结构
             struct VertexOutput {
                 float4 pos      : SV_POSITION;  // 屏幕空间顶点位置
                 float4 uv       : TEXCOORD0;
                 float4 posWS    : TEXCOORD1;    // 世界空间顶点位置
                 float3 nDirWS   : TEXCOORD2;    // 世界空间法线方向
                 float3 tDirWS   : TEXCOORD3;    // 世界空间切线方向
                 float3 bDirWS   : TEXCOORD4;    // 世界空间副切线方向 
                 float4 scrPos   :TEXCOORD5;
                 float3 vDirWS:TEXCOORD6;
             };

             //顶点Shader
             VertexOutput vert(VertexInput v) {
                 VertexOutput o = (VertexOutput)0;                   //新建一个输出结构
                 o.pos = UnityObjectToClipPos(v.vertex);       // 从模型空间转换到裁剪空间的顶点位置
                 o.scrPos = ComputeGrabScreenPos(o.pos);
                 o.uv.xy = v.uv0.xy * _MainTex_ST.xy + _MainTex_ST.zw; // 传递UV
                 o.uv.zw = v.uv0.xy * _BumpTex_ST.xy + _BumpTex_ST.zw;
                 o.posWS = mul(unity_ObjectToWorld, v.vertex);   // 从模型空间转换到世界空间的顶点位置
                 o.nDirWS = UnityObjectToWorldNormal(v.normal);  // 从模型空间转换到世界空间的法线方向
                 o.tDirWS = normalize(mul(unity_ObjectToWorld, float4(v.tangent.xyz, 0.0)).xyz); // 从模型空间转换到世界空间的切线方向
                 o.bDirWS = normalize(cross(o.nDirWS, o.tDirWS) * v.tangent.w);  // 从模型空间转换到世界空间的副切线方向           
                 o.vDirWS = UnityWorldSpaceViewDir(o.posWS);
                 return o;                                           // 将输出结构 输出
             }

             //像素Shader
             float4 frag(VertexOutput i) : COLOR{
                 float3x3 TBN = float3x3(i.tDirWS, i.bDirWS, i.nDirWS);     // TBN矩阵
                    float3 nDirTS = UnpackNormal(tex2D(_BumpTex,  i.uv.zw));//采集法线贴图
                    float2 offset = nDirTS * _Distortion * _RefractionTex_TexelSize.xy;
                    i.scrPos.xy = offset + i.scrPos.xy;
                    fixed3 refrColor = tex2D(_RefractionTex, i.scrPos.xy / i.scrPos.w).rgb;
             
                   return fixed4(refrColor, 1.0); }

             ENDCG
         }
        }
            FallBack "Tranparent/VertexLit"
}

 


Shader "Custom/Chapter10_GlassRefraction" {
Properties{
	_MainTex("Main Tex",2D)="white"{}
	_BumpTex("Bump Tex",2D)="bump"{}
	_CubeMap("Cube Map",Cube)="_Skybox"{}
	_Distortion("Distortion",Range(0,100))=10
	_RefractAmount("Refract Amount",Range(0.0,1.0))=1.0
}
SubShader{
	Tags{"Queue"="Transparent" "RenderType"="Opaque"}
	//指定渲染队列为"Transparent",确保所有不透明物体先渲染完成
	GrabPass {"_RefractionTex"}
	//声明GrabPass 该Pass会将屏幕抓取图像存储到名为"_RefractionTex"的纹理中
	Pass{
		CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag 

			#include "UnityCG.cginc"

			sampler2D _MainTex;
			float4 _MainTex_ST;
			sampler2D _BumpTex;
			float4 _BumpTex_ST;
			samplerCUBE _CubeMap;
			float _Distortion;
			float _RefractAmount;
			sampler2D _RefractionTex;   //存储GrabPass抓取的屏幕图像
			float4 _RefractionTex_TexelSize;  //得到屏幕图像的纹素值,在做偏移计算时使用

			struct a2v{
				float4 vertex:POSITION;
				float3 normal:NORMAL;
				float4 tangent:TANGENT;
				float4 texcoord:TEXCOORD0;
			};

			struct v2f{
				float4 pos:SV_POSITION;
				float4 uv:TEXCOORD0;
				float4 scrPos:TEXCOORD1;
				float4 TtoW0:TEXCOORD2;
				float4 TtoW1:TEXCOORD3;
				float4 TtoW2:TEXCOORD4;
			};

			v2f vert(a2v v){
				v2f o;
				o.pos=UnityObjectToClipPos(v.vertex);
				o.scrPos=ComputeGrabScreenPos(o.pos);
				o.uv.xy=TRANSFORM_TEX(v.vertex,_MainTex);
				o.uv.zw=TRANSFORM_TEX(v.vertex,_BumpTex);

				float3 worldPos=mul(unity_ObjectToWorld,v.vertex).xyz;

				fixed3 worldNormal=UnityObjectToWorldNormal(v.normal);
				fixed3 worldTangent=UnityObjectToWorldDir(v.tangent.xyz);
				fixed3 worldBinormal=cross(worldNormal,worldTangent)*v.tangent.w;

				o.TtoW0=(worldTangent.x,worldBinormal.x,worldNormal.x,worldPos.x);
				o.TtoW1=(worldTangent.y,worldBinormal.y,worldNormal.y,worldPos.y);
				o.TtoW2=(worldTangent.z,worldBinormal.z,worldNormal.z,worldPos.z);

				return o;
			}

			fixed4 frag(v2f i):SV_Target{
				float3 worldPos=(i.TtoW0.w,i.TtoW1.w,i.TtoW2.w);
				fixed3 worldViewDir=normalize(UnityWorldSpaceViewDir(worldPos));

				fixed3 bump=UnpackNormal(tex2D(_BumpTex,i.uv.zw));

				float2 offset=bump*_Distortion*_RefractionTex_TexelSize.xy;
				i.scrPos.xy=offset+i.scrPos.xy;
				fixed3 refrColor=tex2D(_RefractionTex,i.scrPos.xy/i.scrPos.w).rgb;

				bump=normalize(half3(dot(i.TtoW0.xyz,bump),dot(i.TtoW1.xyz,bump),dot(i.TtoW2.xyz,bump)));
				fixed3 reflectDir=reflect(-worldViewDir,bump);
				fixed4 texColor=tex2D(_MainTex,i.uv.xy);
				fixed3 reflColor=texCUBE(_CubeMap,reflectDir).rgb*texColor.rgb;

				fixed3 finalColor=reflColor*(1-_RefractAmount)+refrColor*_RefractAmount;

				return fixed4(finalColor,1.0);

			}
		ENDCG
	}
}
FallBack "Tranparent/VertexLit"
}

 

/两个对法线部分处理不一样,第一个没办法设置cubemap透明度。第二个为源码

 

程序纹理

程序纹理是通过计算机计算生成的图像,使用特定的算法创建个性化图案或非常真实的自然元素。

[ExecuteInEditMode]
public class ProceduralTextureGeneration : MonoBehaviour {//脚本名称一定要对应

public Material material = null;
#region Material properties
[SerializeField,SetProperty("textureWidth")]
private int m_textureWidth = 512;
public int textureWidth {
    get {
        return m_textureWidth;
    }
    set {
        m_textureWidth = value;
        _UpdateMaterial();
    }
}

[SerializeField, SetProperty("backgroundColor")]
private Color m_backgroundColor = Color.white;
public Color backgroundColor {
    get {
        return m_backgroundColor;
    }
    set {
        m_backgroundColor = value;
        _UpdateMaterial();
    }
}

[SerializeField, SetProperty("circleColor")]
private Color m_circleColor = Color.yellow;
public Color circleColor {
    get {
        return m_circleColor;
    }
    set {
        m_circleColor = value;
        _UpdateMaterial();
    }
}

[SerializeField, SetProperty("blurFactor")]
private float m_blurFactor = 2.0f;
public float blurFactor {
    get {
        return m_blurFactor;
    }
    set {
        m_blurFactor = value;
        _UpdateMaterial();
    }
}
#endregion

private Texture2D m_generateTexture = null;


// Use this for initialization
void Start () {
    if (material == null)
    {
        Renderer renderers = gameObject.GetComponent<Renderer>();
        if (renderers == null)
        {
            Debug.LogWarning("Cannot find a renderer.");
            return;
        }
        material = GetComponent<Renderer>().sharedMaterial;
    }
    _UpdateMaterial();
}

// Update is called once per frame
private void _UpdateMaterial() {
    if (material != null)
    {
        m_generateTexture = _GenerateProceduralTexture();
        material.SetTexture("_MainTex",m_generateTexture);
    }
}

private Texture2D _GenerateProceduralTexture()
{
    Texture2D proceduralTexture=new Texture2D(textureWidth,textureWidth);

    //定义圆与圆之间的距离
    float circleInterval = textureWidth/4.0f;
    //定义圆的半径
    float radius = textureWidth/10.0f;
    //定义模糊系数
    float edgeBlur = 1.0f/blurFactor;

    for (int w = 0; w < textureWidth; w++)
    {
        for (int h = 0; h < textureWidth; h++)
        {
            Color pixel = backgroundColor;

            //绘制9个圆
            for (int i = 0; i < 3; i++)
            {
                for (int j = 0; j < 3; j++)
                {
                    //计算当前所绘制圆的位置
                    Vector2 circleCenter=new Vector2(circleInterval*(i+1),circleInterval*(j+1));
                    //计算当前像素与圆边界的距离
                    float dist = Vector2.Distance(new Vector2(w, h), circleCenter)-radius;

                    //模糊圆的边界
                    Color color = _MixColor(circleColor, new Color(pixel.r,pixel.g,pixel.b,0.0f),Mathf.SmoothStep(0f,1f,dist*edgeBlur));

                    //与之前得到的颜色混合
                    pixel = _MixColor(pixel, color, color.a);
                }
            }
            proceduralTexture.SetPixel(w,h,pixel);
        }
    }
    proceduralTexture.Apply();
    return proceduralTexture;
}


private Color _MixColor(Color color0, Color color1, float mixFactor)
{
    Color mixColor = Color.white;
    mixColor.r = Mathf.Lerp(color0.r, color1.r, mixFactor);
    mixColor.g = Mathf.Lerp(color0.g, color1.g, mixFactor);
    mixColor.b = Mathf.Lerp(color0.b, color1.b, mixFactor);
    mixColor.a = Mathf.Lerp(color0.a, color1.a, mixFactor);
    return mixColor;
}
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值