UnityShader入门精要学习笔记(十五):渲染纹理

时间:2021-01-18 10:19:57

一.简介
现代GPU允许我们把整个三维场景渲染到一个中间缓冲中,即渲染目标纹理(Render Target Texture,RTT)。与之相关的是多重渲染目标(Multiple Render Target,MRT),这种技术指的是GPU允许我们把场景同时渲染到多个渲染目标纹理中,而不需要为每个渲染目标纹理单独渲染完整的场景。

二.摄像机渲染目标设置实现镜子效果

1.创建一个RenderTexture

UnityShader入门精要学习笔记(十五):渲染纹理

2.将摄像机的渲染目标设置为该RenderTexture

UnityShader入门精要学习笔记(十五):渲染纹理

3.创建一个shader,代码如下:

Shader "Custom/Edu/Mirror" {
Properties {
_Color ("Color", Color) = (1,1,1,1)
_MainTex ("Albedo (RGB)", 2D) = "white" {}
}
SubShader {
Tags { "RenderType"="Opaque" "Queue" = "Geometry" }
Pass
{
Tags{"LightMode"="ForwardBase"}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#include "Lighting.cginc"
#include "AutoLight.cginc"

fixed4 _Color;
sampler2D _MainTex;
float4 _MainTex_ST;

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 = TRANSFORM_TEX(v.texcoord,_MainTex);
o.uv = v.texcoord;
o.uv.x = 1 - o.uv.x;
return o;
}

fixed4 frag(v2f i):SV_Target
{
return tex2D(_MainTex,i.uv) * _Color;
}


ENDCG
}
}
FallBack "Diffuse"
}

4.创建一个材质,使用刚刚创建的shader,并把RenderTexture赋予该Material

5.场景搭建以及效果:

UnityShader入门精要学习笔记(十五):渲染纹理

三.使用GrabPass实现玻璃效果

1.基本思路

在Shader中定义一个GrabPass后,Unity会把当前屏幕的图像绘制在一张纹理中,以便我们在后续Pass中访问它。

渲染队列设置成透明队列,以此保证渲染该物体时,所有的不透明物体都已经被绘制在屏幕上了。

使用一张凹凸纹理(BumpMap来模拟光线的折射效果)
使用该BumpMap对GrabPass中获得的纹理进行uv偏移,获得扭曲效果

同时也使用该BumpMap来计算反射方向,来对环境立方体纹理进行采样

2.代码实践

Shader "Custom/Edu/Glass" {
Properties {
//潜意识中错误写法
//_Cubemap ("Environment CubeMap",texCUBE) = "_Skybox"{}
_Cubemap ("Environment CubeMap",CUBE) = "_Skybox"{}
_MainTex ("MainTex", 2D) = "white"{}
_BumpMap ("BumpMap", 2D) = "bump"{}
_Distortion ("Distortion",Range(0,100))= 10
_RefractAmount ("RefractAmount",Range(0.0,1.0)) = 0.5
}
SubShader {
Tags { "RenderType"="Opaque" "Queue" = "Transparent"}
//注意这里一定要在名字前面加”_“!!!!!!!!
GrabPass{"_RefractionTex"}
Pass
{
Tags{"LightMode" = "ForwardBase"}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#include "AutoLight.cginc"
#include "Lighting.cginc"

sampler2D _MainTex;
float4 _MainTex_ST;
samplerCUBE _Cubemap;
sampler2D _BumpMap;
float4 _BumpMap_ST;
fixed _Distortion;
fixed _RefractAmount;
sampler2D _RefractionTex;
float4 _RefractionTex_TexelSize;

struct a2v
{
float4 vertex:POSITION;
fixed3 normal:NORMAL;
fixed4 tangent:TANGENT;
float2 texcoord:TEXCOORD0;
};

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

v2f vert(a2v v)
{
v2f o;
o.pos = mul(UNITY_MATRIX_MVP,v.vertex);
//输入齐次剪裁空间下的坐标,得到屏幕图像的采样坐标?
o.scrPos = ComputeGrabScreenPos(o.pos);

o.uv.xy = TRANSFORM_TEX(v.texcoord,_MainTex);
o.uv.zw = TRANSFORM_TEX(v.texcoord,_BumpMap);

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

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

o.TtoW0 = float4(worldTangent.x,worldBionormal.x,worldNormal.x,worldPos.x);
o.TtoW1 = float4(worldTangent.y,worldBionormal.y,worldNormal.y,worldPos.y);
o.TtoW2 = float4(worldTangent.z,worldBionormal.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));

//记得要Unpack!!
fixed3 bump = UnpackNormal(tex2D(_BumpMap,i.uv.zw)).xyz;

//_Refraction_TexelSize可以让我们得到该纹理的纹素大小,如一个大小为256X512的纹理
//它的纹素大小为(1/256,1/512
float2 offset = bump.xy * _Distortion * _RefractionTex_TexelSize.xy;
i.scrPos.xy = offset * i.scrPos.z + i.scrPos.xy;
//i.scrPos.xy = offset + i.scrPos.xy;
fixed3 refrCol = tex2D(_RefractionTex,i.scrPos.xy/i.scrPos.w).rgb;

//将法线转换到世界空间
bump = normalize( float3(dot(i.TtoW0.xyz,bump),dot(i.TtoW1.xyz,bump),dot(i.TtoW2.xyz,bump)) );


fixed3 reflDir = reflect(-worldViewDir,bump);
fixed3 reflCol = texCUBE(_Cubemap,reflDir).rgb;

fixed3 finalColor = _RefractAmount * refrCol + (1-_RefractAmount)*reflCol;

return fixed4(finalColor,1.0);
}
ENDCG
}
}
FallBack "Diffuse"
}

3.效果图

UnityShader入门精要学习笔记(十五):渲染纹理

UnityShader入门精要学习笔记(十五):渲染纹理