裸眼 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);
}
}