欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Unity 屏幕特效 之 分屏之 斜角(对角线) 分屏渲染不同相机画面功能的简单实现

程序员文章站 2022-05-24 23:53:58
...

Unity 屏幕特效 之 分屏之 斜角(对角线) 分屏渲染不同相机画面功能的简单实现

 

目录

Unity 屏幕特效 之 分屏之 斜角(对角线) 分屏渲染不同相机画面功能的简单实现

一、简介

二、关键技术

三、注意事项

四、效果预览

五、实现步骤

六、关键代码


 

一、简介

所谓屏幕后处理,简单来说就是渲染流水线的最后阶段,对由整个场景生成的一张图片进行处理,比如HDR,运动模糊等等效果,通过屏幕空间的后处理,可以整体改变整个游戏的风格或者效果。所以,要制作屏幕后处理,我们需要两样东西,一个是用于渲染后处理效果的shader,而另一个是我们需要调用这个渲染的脚本。
 

实现原理:

  •     斜角分屏,根据点再对角线的上或者下,进行分屏渲染

 

二、关键技术

1、在 Shader 中,根据数学公式得到 UV 对角线 上下的规律,进行斜角分屏渲染;  

 2、OnRenderImage函数每帧渲染完全部内容后执行,我们在每一帧设置Material的各项参数,通过Material.SetXXX("name",value)可以向shader中传递各种参数;

3、ceil 函数(向上求整), 返回大于或等于输入值的最小整数。

4、关键代码

// 斜角渲染不同相机的画面
// 斜角线有两条:y-x=0,y+x-1=0
// uv的 x y 值 带入上面斜角线,值大于0,在线上面,值小于 0 ,在线下面
if (_SpiltScreenMode) {
	col = tex2D(_MainTex, i.uv)*ceil(i.uv.x+i.uv.y -1)+tex2D(_SecondCameraTexture,i.uv)*ceil(1-i.uv.x-i.uv.y);
}
else{
	col = tex2D(_MainTex, i.uv)*ceil(i.uv.y-i.uv.x)+tex2D(_SecondCameraTexture,i.uv)*ceil(i.uv.x-i.uv.y);
}

 

三、注意事项

1、各种后处理效果可以叠加,这里的dest并不一定就是屏幕。不过后处理是很耗费性能的,一方面是pixel shader全屏幕overdraw,另一方面,一个rendertexture的内存占用很大,尤其是大分辨率手机上,多个后处理效果可能造成内存耗尽,程序崩溃;(不过网上有方式可以优化这个功能,到时候找找资料看看,在给大家试试哈,大家也可以自己先看看试试)

2、注意判断屏幕特效是否支持可以用;

3、注意参数值根据实际效果,合理调节;

 

四、效果预览

Unity 屏幕特效 之 分屏之 斜角(对角线) 分屏渲染不同相机画面功能的简单实现

 

五、实现步骤

简单原理图:

 

Unity 屏幕特效 之 分屏之 斜角(对角线) 分屏渲染不同相机画面功能的简单实现

 

具体实现步骤:

1、打开Unity,在场景中添加几个 Cube 和 camera

Unity 屏幕特效 之 分屏之 斜角(对角线) 分屏渲染不同相机画面功能的简单实现

 

2、其中,可以调整两个camer 位置和方向,进行不一样的渲染,MainCamera 和 Camera 的渲染如下

Unity 屏幕特效 之 分屏之 斜角(对角线) 分屏渲染不同相机画面功能的简单实现

Unity 屏幕特效 之 分屏之 斜角(对角线) 分屏渲染不同相机画面功能的简单实现

 

3、在工程中,新建两个脚本和Shader,Shader 实现分屏,脚本把屏幕数据传给Shader

Unity 屏幕特效 之 分屏之 斜角(对角线) 分屏渲染不同相机画面功能的简单实现

 

4、把脚本挂载到 MainCamera 上,并赋值

Unity 屏幕特效 之 分屏之 斜角(对角线) 分屏渲染不同相机画面功能的简单实现

 

5、运行场景,效果如上

Unity 屏幕特效 之 分屏之 斜角(对角线) 分屏渲染不同相机画面功能的简单实现

 

六、关键代码

1、ShaderSpiltScreen.shader

Shader "Unlit/ShaderSpiltScreen"
{
    Properties
    {
        _MainTex ("主camera的渲染图", 2D) = "white" {}
		_SecondCameraTexture("第二个camera的渲染图",2D)="white"{}
		[MaterialToggle]_SpiltScreenMode("屏幕分屏模式切换",float) = 1
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag


            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
          
                float4 vertex : SV_POSITION;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;
			sampler2D _SecondCameraTexture;
            float4 _SecondCameraTexture_ST;
			bool _SpiltScreenMode;

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
        
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
				fixed4 col;
				
				// 斜角渲染不同相机的画面
				// 斜角线有两条:y-x=0,y+x-1=0
				// uv的 x y 值 带入上面斜角线,值大于0,在线上面,值小于 0 ,在线下面
                if (_SpiltScreenMode) {
					col = tex2D(_MainTex, i.uv)*ceil(i.uv.x+i.uv.y -1)+tex2D(_SecondCameraTexture,i.uv)*ceil(1-i.uv.x-i.uv.y);
				}
				else{
					col = tex2D(_MainTex, i.uv)*ceil(i.uv.y-i.uv.x)+tex2D(_SecondCameraTexture,i.uv)*ceil(i.uv.x-i.uv.y);
				}

			

                return col;
            }
            ENDCG
        }
    }
}

 

2、SpiltScreen.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class SpiltScreen : ScreenPostEffectBase
{
    public bool _SpiltScreenMode = true;
    public Camera _SecondCamera;

    void OnRenderImage(RenderTexture sourceTexture, RenderTexture destTexture)
    {
        if (_Material != null)
        {
            if (_SecondCamera.targetTexture == null) {
                ////根据主相机的宽高创建一个同样宽高的纹理,记录辅助相机的图像
                _SecondCamera.targetTexture = new RenderTexture(_SecondCamera.pixelWidth,_SecondCamera.pixelHeight,0);
            }
            _Material.SetTexture("_SecondCameraTexture", _SecondCamera.targetTexture);
            _Material.SetInt("_SpiltScreenMode", _SpiltScreenMode?1:0);

            //Debug.Log(_SpiltScreenMode ? 1 : 0);

            Graphics.Blit(sourceTexture, destTexture, _Material);
        }
        else
        {
            Graphics.Blit(sourceTexture, destTexture);
        }
    }
}

 

3、ScreenPostEffectBase.cs

using UnityEngine;

//非运行时也触发效果
[ExecuteInEditMode]
//屏幕后处理特效一般都需要绑定在摄像机上
[RequireComponent(typeof(Camera))]
//提供一个后处理的基类,主要功能在于直接通过Inspector面板拖入shader,生成shader对应的材质
public class ScreenPostEffectBase : MonoBehaviour
{

    //Inspector面板上直接拖入
    public Shader shader = null;
    private Material _material = null;
    public Material _Material
    {
        get
        {
            if (_material == null)
                _material = GenerateMaterial(shader);
            return _material;
        }
    }

    //根据shader创建用于屏幕特效的材质
    protected Material GenerateMaterial(Shader shader)
    {
        // 系统是否支持
        if (!SystemInfo.supportsImageEffects)
        {
            return null;
        }

        if (shader == null)
            return null;
        //需要判断shader是否支持
        if (shader.isSupported == false)
            return null;
        Material material = new Material(shader);
        material.hideFlags = HideFlags.DontSave;
        if (material)
            return material;
        return null;
    }

    void OnDisable()
    {
        if (_material != null)
        {
            DestroyImmediate(_material);
        }
    }

}