废话不多说先上效果图,我使用的是在.3.3版本。
一、原理
1、首先要准备的素材是三个,对没错,就是三个因为镜子里面的那个物体其实是实物的复制体而已;一个Plane作为镜子,还有一个实物和虚物体。
2、新建一个材质使用下面的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
|
Shader
"Custom/Cg shader for virtual objects in mirrors"
{
Properties{
_Color(
"Virtual Object's Color"
, Color) = (1, 1, 1, 1)
}
SubShader{
Tags{
"Queue"
=
"Transparent+20"
}
Pass{
Blend OneMinusDstAlpha DstAlpha
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
uniform float4 _Color;
uniform float4x4 _WorldToMirror;
struct
vertexInput {
float4 vertex : POSITION;
};
struct
vertexOutput {
float4 pos : SV_POSITION;
float4 posInMirror : TEXCOORD0;
};
vertexOutput vert(vertexInput input)
{
vertexOutput output;
output.posInMirror = mul(_WorldToMirror,
mul(_Object2World, input.vertex));
output.pos = mul(UNITY_MATRIX_MVP, input.vertex);
return
output;
}
float4 frag(vertexOutput input) : COLOR
{
//如果镜子里的物体出来了就剔除掉
if
(input.posInMirror.y > 0.0)
{
discard;
}
return
float4(_Color.rgb, 0.0);
}
ENDCG
}
}
}
|
3、另外在建一个材质使用下面的Shader代码,并将此材质球赋值给实物体
/em>
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
|
Shader
"Unlit/Cg shader for Real objects"
{
Properties{
_Color(
"Virtual Object's Color"
, Color) = (1, 1, 1, 1)
}
SubShader {
Pass {
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
uniform float4 _Color;
float4 vert(float4 vertexPos : POSITION) : SV_POSITION
{
return
mul(UNITY_MATRIX_MVP, vertexPos);
}
float4 frag(
void
) : COLOR
{
return
float4(_Color.rgb, 1.0);
}
ENDCG
}
}
}
|
4、在建一个材质使用下面的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
60
61
62
63
64
65
66
|
Shader
"Unlit/Mirrors"
{
Properties{
_Color(
"Mirrors's Color"
, Color) = (1, 1, 1, 1)
}
SubShader{
Tags{
"Queue"
=
"Transparent+10"
}
// draw after all other geometry has been drawn
// because we mess with the depth buffer
//确保在所有的真实物体渲染之后再渲染
// 1st pass: mark mirror with alpha = 0
Pass{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
float4 vert(float4 vertexPos : POSITION) : SV_POSITION
{
return
mul(UNITY_MATRIX_MVP, vertexPos);
}
float4 frag(
void
) : COLOR
{
return
float4(1.0, 0.0, 0.0, 0.0);
// this color should never be visible,
// only alpha is important
}
ENDCG
}
// 2nd pass: set depth to far plane such that
// we can use the normal depth test for the reflected geometry
Pass{
ZTest Always
Blend OneMinusDstAlpha DstAlpha
//==float4 result = float4(1.0 - pixel_color.a) * fragment_output + float4(pixel_color.a) * pixel_color;
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
uniform float4 _Color;
// user-specified background color in the mirror
float4 vert(float4 vertexPos : POSITION) : SV_POSITION
{
float4 pos = mul(UNITY_MATRIX_MVP, vertexPos);
pos.z = pos.w;
// the perspective division will divide pos.z
// by pos.w; thus, the depth is 1.0,
// which represents the far clipping plane
return
pos;
}
float4 frag(
void
) : COLOR
{
return
float4(_Color.rgb, 0.0);
// set alpha to 0.0 and
// the color to the user-specified background color
}
ENDCG
}
}
}
|
5、最后新建一个C#脚本,代码如下,将此代码赋给虚物体,并将Plane和虚物体拖动赋值给里面的对应两个变量
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
|
using
UnityEngine;
using
System.Collections;
[ExecuteInEditMode]
public
class
PlacingTheVirtualObj : MonoBehaviour {
public
GameObject objectInFrontOfMirror;
public
GameObject mirrorPlane;
// Use this for initialization
void
Start () {
}
// Update is called once per frame
void
Update() {
if
(
null
!= mirrorPlane)
{
//这句话决定了镜子里的物体是否可见
GetComponent<Renderer>().sharedMaterial.SetMatrix(
"_WorldToMirror"
,mirrorPlane.GetComponent<Renderer>().worldToLocalMatrix);
if
(
null
!= objectInFrontOfMirror)
{
//将实物的颜色值赋给镜中的物体
Color realColor = objectInFrontOfMirror.GetComponent<Renderer>().material.GetColor(
"_Color"
);
GetComponent<Renderer>().material.SetColor(
"_Color"
, realColor);
transform.position = objectInFrontOfMirror.transform.position;
transform.rotation = objectInFrontOfMirror.transform.rotation;
transform.localScale =
-objectInFrontOfMirror.transform.localScale;
//new Vector3(0.0f, 1.0f, 0.0f)为表面的法线方向
transform.RotateAround(objectInFrontOfMirror.transform.position,mirrorPlane.transform.TransformDirection(
new
Vector3(0.0f, 1.0f, 0.0f)), 180.0f);
Vector3 positionInMirrorSpace =
mirrorPlane.transform.InverseTransformPoint(objectInFrontOfMirror.transform.position);
positionInMirrorSpace.y = -positionInMirrorSpace.y;
transform.position = mirrorPlane.transform.TransformPoint(
positionInMirrorSpace);
}
}
}
}
|
二、此方案的优劣
1、优点:性能开销比较小,镜子里的虚物体清晰
2、缺点:目前虚物体只能实时的同步实物体的颜色,贴图和其他纹理或者模型面数复杂的情况都没有响应的处理、并不是完全的实时反射物体,因为要实现创建好虚物体。
3、有待发现…..
三、后续待….
原贴地址
蛮牛网凯尔八阿哥转载请注明出处
之前有童鞋没有实现出来,是我太粗心了,一激动少说了一个Shader脚本,就是第四个,现在已经添加进来了,还是附上最后的工程文件吧,方便大家学习和参考。
工程文件下载地址
https://pan.baidu.com/s/1o84hcdO