原文地址:http://www.redblack.cn/?p=147
在虚拟现实中有时候会用到投影效果,比如将灯光投射到墙壁,人物倒影,火焰投影效果等等,如下:
在wifi上有一篇文章讲到了如何在unity中制作投影的shader。这里只是拿来主义,顺便加上些自己的理解。
wiki:https://en.wikibooks.org/wiki/Cg_Programming/Unity/Projectors
下面讲讲怎么在unity中使用投影:
1、首先在gameobject上添加一个Projector组件,这个组件完成以下几个工作:
(1)生成投影物体的投影矩阵_Projector,并在将这个uniform传入材质球中。
(2)通过投影矩阵生成的视锥体以及选择的图层,筛选需要绘制投影的物体。
(3)将需要绘制投影的物体通过我们设置的材质球再次渲染一遍,并通过我们在shader中设置的混合模式,生成最终的颜色。
2、 新建一个用来作为投影材质球的shader,这个shader的原理就是将需要被投影的物体的顶点变换到投影物体的坐标空间中。并将投影物前方的像素重新绘制并叠加。
代码如下:
01
02
03
04
05
06
07
08
09
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
55
56
57
58
59
|
Shader
"Unlit/Projector"
{
Properties {
_ShadowTex (
"Projected Image"
, 2D) =
"white"
{}
}
SubShader {
Pass {
Blend One One
//影子与原色按1:1混合颜色
ZWrite Off
// 不写入深度缓存
Offset -1, -1
// 防止zbuff冲突,做的偏移
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
uniform sampler2D _ShadowTex;
// Projector组件传入的从模型空间到投影空间的矩阵
uniform float4x4 _Projector;
struct
vertexInput {
float4 vertex : POSITION;
float3 normal : NORMAL;
};
struct
vertexOutput {
float4 pos : SV_POSITION;
float4 posProj : TEXCOORD0;
//投影空间的坐标值
};
vertexOutput vert(vertexInput input)
{
vertexOutput output;
output.posProj = mul(_Projector, input.vertex);
output.pos = mul(UNITY_MATRIX_MVP, input.vertex);
return
output;
}
float4 frag(vertexOutput input) : COLOR
{
if
(input.posProj.w > 0.0)
// 在投影物前方
{
//最后那个0.1可以用来调节投影在最终效果中所占的比重
return
tex2D(_ShadowTex ,
input.posProj.xy / input.posProj.w) * 0.1;
// 或者使用: return tex2Dproj(
// _ShadowTex, input.posProj);
}
else
// 投影物体后方
{
return
float4(0.0, 0.0, 0.0, 0.0);
}
}
ENDCG
}
}
Fallback
"Projector/Light"
}
|
3、 最后将用来投影的贴图的warp mode修改为clamp,否则投影出来的物体将会循环。
0.3的比例后混合效果如下:
了解更多: