效果

Honeycam 2021-12-13 10-45-06

思路

5个面用5个RenderTexture来接受5个摄像机分别获取的小场景图像;

RenderTexture就当成屏幕来理解,MainCamera是把画面显示在屏幕上,屏幕就是最大的RenderTexture且允许里面有子渲染;

把子摄像机拍摄到的画面当成纹理贴图理解,RenderTexture是从子摄像机画面上取样再根据宽高比缩放显示画面;

RenderTexture贴图是不会跟据面与主摄像机位置改变做变化的(其实可以理解为公告牌,这个贴图里的内容一直朝向主摄像机);

要实现上面的效果,在主摄像机空间下,顶点着色器阶段记录裁剪空间下顶点投影到屏幕的坐标,在片元着色器阶段,根据上面记录的屏幕坐标归一化到NDC坐标系(透视除法),再映射根据游戏窗口大小做缩放(屏幕映射),根据这个结果做纹理采样;

Shader

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
Shader "Unlit/WindowsShader"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_ScreenHW ("ScreenHW", Float) = 0.5521
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 100

Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag

#include "UnityCG.cginc"

struct appdata
{
float4 vertex : POSITION;
};

struct v2f
{
float4 vertex :SV_POSITION;
float4 screenPos :TEXCOORD1;
};

sampler2D _MainTex;
float _ScreenHW;

v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.screenPos = ComputeScreenPos(o.vertex);
return o;
}

fixed4 frag (v2f i) : SV_Target
{
float2 screenPos = i.screenPos.xy / i.screenPos.w;
float2 uv = screenPos.xy * float2(1, _ScreenHW);

fixed4 col = tex2D(_MainTex, uv);
return col;
}
ENDCG
}
}
}

具体实现细节可以看大佬的文章:在Unity中实现笼中窥梦的效果;