您的位置:首页 > 移动开发 > Unity3D

Unity Shader学习笔记:渲染纹理

2017-08-29 19:00 806 查看
一个摄像机的渲染结果会输出到颜色缓冲中,并显示到我们的屏幕上。现代的GPU允许我们把整个三维场景渲染到一个中间缓冲中,即渲染目标纹理。

渲染纹理:Unity为渲染目标纹理定义的一种专门的纹理类型。在Unity中使用渲染纹理通常有两种方式:一种方式是在Project目录下创建一个渲染纹理,然后把某个摄像机的渲染目标设置成该渲染纹理,这样一来该摄像机的渲染结果就会实时更新到渲染纹理中,而不会显示在屏幕上。使用这种方法,我们可以选择渲染纹理的分辨率、滤波模式等纹理属性。另一种方式是在屏幕后处理时使用GrabPass命令或OnRenderImage函数来获取当前屏幕图像,Unity会把这个屏幕图像放到一张和屏幕分辨率等同的纹理中。

1.镜子效果

Shader "Own/Chapter10-Mirror"
{
Properties
{
_MainTex ("Main Tex", 2D) = "white" {}
}
SubShader
{
Tags { "RenderType"="Opaque" "Queue" = "Geometry"}

Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
sampler2D _MainTex;
struct a2v{
float4 vertex : POSITION;
float3 texcoord : TEXCOORD0;
};
struct v2f{
float4 pos : SV_POSITION;
float2 uv : TEXCOORD0;
};
v2f vert(a2v v){
v2f o;
o.pos = mul(UNITY_MATRIX_MVP,v.vertex);
o.uv = v.texcoord;
//由于镜子里显示的图像都是左右相反的,故翻转x分量
o.uv.x = 1 - o.uv.x;
return o;
}
fixed4 frag(v2f i):SV_Target{
return tex2D(_MainTex,i.uv);
}
ENDCG
}
}
FallBack Off
}


其中Texture需要拖拽到该摄像机的Target Texture下。

2.玻璃效果

Shader "Own/Chapter10-GlassRefraction"
{
Properties
{
//该玻璃的材质,默认白色纹理
_MainTex("Main Tex",2D) = "white"{}
//该玻璃的法线纹理
_BumpMap("Normal Map",2D) = "bump"{}
//用于模拟反射的环境纹理
_Cubemap("Environment Cubemap",Cube) = "_Skybox"{}
//用于控制模拟折射时图像的扭曲程度
_Distortion("Distortion",Range(0,100)) = 10
//用于控制折射程度,当值为0时,该玻璃只包含反射效果,当值为1时,该玻璃只包含折射效果。
_RefractAmount("Refract Amount",Range(0.0,1.0)) = 1.0
}
SubShader
{
//Transparent:确保该物体渲染时,其他所有不透明物体都已经渲染到屏幕上了,否则就可能无法正确得到"透过玻璃看到的图像"
//Opaque:为了在使用着色器替换(Shader Replacement)时,该物体可以在需要时被正确渲染。这通常发生在我们需要得到摄像机的
//的深度和法线纹理时。
Tags { "RenderType"="Opaque" "Queue" = "Transparent"}
//定义一个抓取屏幕图像的Pass,其中_RefractionTex表示抓取得到的屏幕图像将会被存入哪个纹理中。
GrabPass{"_RefractionTex"}

Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"

sampler2D _MainTex;
float4 _MainTex_ST;
sampler2D _BumpMap;
float4 _BumpMap_ST;
samplerCUBE _Cubemap;
float _Distortion;
fixed _RefractAmount;
//抓取的屏幕图像
sampler2D _RefractionTex;
//该屏幕图像的纹素大小
float4 _RefractionTex_TexelSize;

struct a2v{
float4 vertex : POSITION;
float3 normal : NORMAL;
float4 tangent : TANGENT;
float2 texcoord : TEXCOORD0;
};
struct v2f{
float4 pos : SV_POSITION;
float4 scrPos : TEXCOORD0;
float4 uv : TEXCOORD1;
float4 TtoW0 : TEXCOORD2;
float4 TtoW1 : TEXCOORD3;
float4 TtoW2 : TEXCOORD4;
};
v2f vert(a2v v){
v2f o;
o.pos = mul(UNITY_MATRIX_MVP,v.vertex);
//通过调用内置的ComputeGrabScreenPos函数来得到对应被抓取的屏幕图像的采样坐标。
o.scrPos = ComputeGrabScreenPos(o.pos);
o.uv.xy = TRANSFORM_TEX(v.texcoord,_MainTex);
o.uv.zw = TRANSFORM_TEX(v.texcoord,_BumpMap);

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 = float4(worldTangent.x,worldBinormal.x,worldNormal.x,worldPos.x);
o.TtoW1 = float4(worldTangent.y,worldBinormal.y,worldNormal.y,worldPos.y);
o.TtoW2 = float4(worldTangent.z,worldBinormal.z,worldNormal.z,worldPos.z);
return o;
}
fixed4 frag(v2f i):SV_Target{
float3 worldPos = float3(i.TtoW0.w,i.TtoW1.w,i.TtoW2.w);
fixed3 worldViewDir = normalize(UnityWorldSpaceViewDir(worldPos));
fixed3 bump = UnpackNormal(tex2D(_BumpMap,i.uv.zw));
float2 offset = bump.xy * _Distortion * _RefractionTex_TexelSize.xy;
i.scrPos.xy = offset * i.scrPos.z + i.scrPos.xy;
fixed3 refrCol = 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 reflDir = reflect(-worldViewDir,bump);
fixed4 texColor = tex2D(_MainTex,i.uv.xy);
fixed3 reflCol = texCUBE(_Cubemap,reflDir).rgb * texColor.rgb;
fixed3 finalColor = reflCol * (1 - _RefractAmount) + refrCol * _RefractAmount;
return fixed4(finalColor,1);
}
ENDCG
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  unity