Advertisement

Unity Shader 案例之 镜面材质制作

阅读量:

打开镜像世界

在Unity引擎中开启镜子世界似乎非常简单呢!只需添加一个Mirror Camera即可完成这一操作。具体来说,在镜子表面设置当前相机的镜像映射(Transform)。

  1. 镜像矩阵
公式

这个概念比较复杂,记公式就可以了。

有了公式,代码就好写了

复制代码
    public static void CalculateReflectionMatrix(ref Matrix4x4 reflectionMat, Vector4 plane)    
    {        
    	reflectionMat.m00 = (1F - 2F * plane[0] * plane[0]);        
    	reflectionMat.m01 = (-2F * plane[0] * plane[1]);        
    	reflectionMat.m02 = (-2F * plane[0] * plane[2]);        
    	reflectionMat.m03 = (-2F * plane[0] * plane[3]);
    	reflectionMat.m10 = (-2F * plane[1] * plane[0]);        
    	reflectionMat.m11 = (1F - 2F * plane[1] * plane[1]);        
    	reflectionMat.m12 = (-2F * plane[1] * plane[2]);        
    	reflectionMat.m13 = (-2F * plane[1] * plane[3]);
    	reflectionMat.m20 = (-2F * plane[2] * plane[0]);        
    	reflectionMat.m21 = (-2F * plane[2] * plane[1]);        
    	reflectionMat.m22 = (1F - 2F * plane[2] * plane[2]);        
    	reflectionMat.m23 = (-2F * plane[2] * plane[3]);
    	reflectionMat.m30 = 0F;        
    	reflectionMat.m31 = 0F;        
    	reflectionMat.m32 = 0F;        
    	reflectionMat.m33 = 1F;   
    }

将Mirror Camera放置于镜像点上,并对以下属性进行调整以配置其变换矩阵:reflectionCamera.worldToCameraMatrix = cam.worldToCameraMatrix * reflection;

剪切矩阵我们要把MirrorCamera与镜面间的内容剪切掉。

在这里插入图片描述

Unity的Camera确实提供了现成的方法来实现某些功能,但在这一场景下,我们采用了另一种计算方式,如下面链接所述,无需过多赘述具体实现细节.

public static class Matrix4x4
{
public static Matrix4x4 MultiplyMatrix4x4(Matrix4x4 lhs, Matrix4x4 rhs) {
// 矩阵乘法的具体实现
// 由于篇幅限制,此处省略详细步骤
return new Matrix4x4(...);
}
}

复制代码
    public static void CalculateObliqueMatrix(ref Matrix4x4 projection, Vector4 clipPlane)    
    {        
    	Vector4 q = projection.inverse * new Vector4(sgn(clipPlane.x), sgn(clipPlane.y), 1.0f, 1.0f);        
    	Vector4 c = clipPlane * (2.0F / (Vector4.Dot(clipPlane, q)));        
    	projection[2] = c.x - projection[3];        
    	projection[6] = c.y - projection[7];        
    	projection[10] = c.z - projection[11];        
    	projection[14] = c.w - projection[15];    
    }

Mirror Shader

获取MirrorCamera的RenderTarget,即MirrorCamera的截图效果。

复制代码
    inline float4 ComputeNonStereoScreenPos1(float4 pos)
     {        
    	 float4 o = pos * 0.5f;        
    	 o.xy = float2(o.x, o.y * _ProjectionParams.x) + o.w;        
    	 o.zw = pos.zw;        
    	 return o;   
    }

在Unity Shader库中定义了ComputeScreenPos函数的内部实现,在其之后使用tex2Dproj方法对纹理进行采样。

在这里插入图片描述

其中uniform float4 _ProjectionParams;
投影参数各值分别为如下含义:

  • x 等于 1;当投影翻转时,则 x 等于 -1。
  • y 即为 camera 的近裁剪平面。
  • z 即为 camera 的远裁剪平面。
  • w 等于 1 除以 远裁剪平面。
复制代码
    inline float4 ComputeScreenPos1(float4 pos, float d)
     {        
    	 float4 o = pos *0.5f;        
    	 o.xy = float2(o.x / d, o.y / d * _ProjectionParams.x) + 0.5f;        
    	 //o.xy = float2(o.x / o.w, o.y / o.w * 1) + 0.5f;       
    	  o.zw = pos.zw;        
    	  return o;   
    }

为了实现纹理采样:
fixed4 refl = tex2D(_ReflectionTex, i.refl.xy);
结果表明:

在这里插入图片描述

可以看到采样的有抖动的问题。
打开Wireframe

在这里插入图片描述

如下图:我们就可以看到其中的规律了。

在这里插入图片描述

如果应用 tex2D 函数进行采样,并且纹理贴图在面附近发生伸展的情况下,则会出现不规则且不确定的贴图采样扭曲现象。这是因为 tex2Dproj 在处理这类问题时更为稳定的原因之一。最后查阅一些 UNITY_PROJ_COORD 的定义。

复制代码
    #if defined(SHADER_API_PSP2)
    #define UNITY_BUGGY_TEX2DPROJ4
    #define UNITY_PROJ_COORD(a) (a).xyw
    #else
    #define UNITY_PROJ_COORD(a) a
    #endif

后续处理

uv扰动参数和噪声贴图

在这里插入图片描述

这里还要说明一种深度模糊的效果

附录:

uniform float4 _ScreenParams:屏幕参数:

  • x值代表屏幕宽度

  • y值代表屏幕高度

  • z值等于1加上1除以屏幕宽度

  • w值等于1加上1除以height(表示像素数量)

    1. Unity内置变换矩阵
在这里插入图片描述
  1. Githup 源码位置
    https://github.com/bennychao/UnityShaders

全部评论 (0)

还没有任何评论哟~