裸眼 3D Shader 和相机脚本

Quilt Shader

修改自 https://www.shadertoy.com/view/XcdBRr https://www.shadertoy.com/view/3tBGDR

Shader "Custom/QuiltShader"
{
    Properties
    {
        _MainTex("Base Texture", 2D) = "white" { }
        _NumViews("Number of Views", Float) = 1.0
        _QuiltSize("Quilt Size", Vector) = (1.0, 1.0, 1.0, 1.0)
        _ScreenWidth("Screen Width", Float) = 1440.0
        _ScreenHeight("Screen Height", Float) = 2560.0
        _Obliquity("Obliquity", Float) = 0.10516
        _LineNumber("Line Number", Float) = 19.6401
        _Center("Center", Float) = -0.43532609939575195
        _InvView("Inv View", Float) = 0.0
        _RenderAsQuilt("Render As Quilt", Int) = 0
    }

        SubShader
        {
            Tags { "RenderType" = "Opaque" }
            Pass
            {
                CGPROGRAM
                #pragma vertex vert
                #pragma fragment frag
                #include "UnityCG.cginc"

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

                struct v2f
                {
                    float4 pos : POSITION;
                    float2 uv : TEXCOORD0;
                };

                float _ScreenWidth;
                float _ScreenHeight;
                float _Obliquity;
                float _LineNumber;
                float _Center;
                float _InvView;
                float _NumViews;
                float4 _QuiltSize;
                sampler2D _MainTex;
                float _RenderAsQuilt;

                // quilt 的纹理坐标计算
                float2 texArr(float3 uvz)
                {
                    float z = floor(uvz.z * _NumViews);
                    float x = (fmod(z, _QuiltSize.x) + uvz.x) / _QuiltSize.x;
                    float y = (floor(z / _QuiltSize.x) + uvz.y) / _QuiltSize.y;
                    return float2(x, y);
                }


                // GLSL 兼容函数
                #define glsl_mod(x,y) (((x)-(y)*floor((x)/(y))))

                // Vertex shader
                v2f vert(appdata_t v)
                {
                    v2f o;
                    o.pos = UnityObjectToClipPos(v.vertex);
                    o.uv = v.uv;
                    return o;
                }

                // Fragment shader
                float4 frag(v2f i) : SV_Target
                {
                    // Constants
                    float subp = 1.0 / (_ScreenWidth * 3.0);
                    float3 rgb = float3(0.0, 0.0, 0.0);
                    float2 uv = i.uv;

                    if (_RenderAsQuilt == 1)
                    {
                        // 渲染为 quilt 拼图
                        rgb = tex2D(_MainTex, uv).rgb;
                    }
                    else
                    {
                        // 渲染为光栅图
                        for (int chan = 0; chan < 3; ++chan)
                        {
                            float z = (uv.x + float(chan) * subp + uv.y * (-_Obliquity * (_ScreenHeight / _ScreenWidth))) * ((_ScreenWidth * 3.0) / _LineNumber) - _Center;
                            z = glsl_mod(z + ceil(abs(z)), 1.0);
                            z = (1.0 - _InvView) * z + _InvView * (1.0 - z);

                            float2 iuv = texArr(float3(uv, z));

                            rgb[chan] = tex2D(_MainTex, iuv)[chan];
                        }
                    }

                    
                    return float4(rgb, 1.0); // 返回最终颜色
                }
                ENDCG
            }
        }
        FallBack "Diffuse"
}

相机脚本

using UnityEngine;

public class MultiCameraQuiltRenderer : MonoBehaviour
{
    [Range(0f, 0.05f)]
    public float CameraDistance = 0.01f;

    [Range(0f, 1f)]
    public float RotationAngle = 0.5f;

    public int quiltGridX = 7; // 横向格子数
    public int quiltGridY = 7; // 纵向格子数
    public RenderTexture quiltTexture; // 拼接渲染结果的 RenderTexture
    public Camera cameraPrefab; // 摄像机预制体

    private Camera[,] cameras; // 用于存储所有摄像机的二维数组

    void Start()
    {
        Debug.Log("displays connected: " + Display.displays.Length);
        // Display.displays[0] 是主要的默认显示器
        // 检查并激活每个显示器

        for (int i = 1; i < Display.displays.Length; i++)
        {
            Display.displays[i].Activate();
        }



        // 创建一个RenderTexture用于拼接所有摄像机的视图
        //quiltTexture = new RenderTexture(1024 * quiltGridX, 1024 * quiltGridY, 24);
        //quiltTexture.wrapMode = TextureWrapMode.Clamp;
        //quiltTexture.Create();

        // 初始化摄像机数组
        cameras = new Camera[quiltGridX, quiltGridY];

        int camId = 0;

        // 创建并配置摄像机
        for (int y = 0; y < quiltGridY; y++)
        {
            for (int x = 0; x < quiltGridX; x++)
            {
                // 创建摄像机
                Camera cam = Instantiate(cameraPrefab, transform);
                cam.enabled = true;
                cam.targetTexture = quiltTexture;  // 设置为同一个目标RenderTexture
                cam.transform.position = new Vector3(CameraDistance * 20 + camId * -CameraDistance, 0, 0);
                camId++;

                // 计算视口位置
                float viewportX =  (float)x / quiltGridX ;
                float viewportY = (float)y / quiltGridY;
                float viewportWidth = 1f / quiltGridX;
                float viewportHeight = 1f / quiltGridY;

                // 设置摄像机的视口 (Viewport)
                cam.rect = new Rect(viewportX, viewportY, viewportWidth, viewportHeight);

                // 存储摄像机
                cameras[x, y] = cam;
            }
        }
    }

    private void Update()
    {
        int camId = 0;
        //更新摄像机位置
        for (int y = 0; y < quiltGridY; y++)
        {
            for (int x = 0; x < quiltGridX; x++)
            {
                cameras[x,y].transform.position = new Vector3(CameraDistance * 20 + camId * -CameraDistance, 0, 0);

                //根据位置轻微旋转
                cameras[x, y].transform.eulerAngles = new Vector3(0, -20 * RotationAngle + camId * RotationAngle, 0);


                camId++;
            }
        }
    }

    void OnGUI()
    {
        // 以GUI形式显示拼接后的 RenderTexture
        //GUI.DrawTexture(new Rect(0, 0, Screen.width, Screen.height), quiltTexture);
        
    }
}