昨天看到蛮牛上有个练手的文章,要求是实现unity斜边分屏,就是将屏幕分成两个三角形,分别显示两个照相机显示的内容,有些端游也出现过,而且网上也好像没有这样的例子,觉得有趣,就写了一个早上,实现了它,先上效果图:
上面的例子中,两个照相机对准的是同一个立方体,触摸右下角的区域则旋转立方体,触摸左上角则移动立方体,达到了简单的分屏控制效果。
简单说一下步骤:
1,创建两个照相机,一个作为主要相机。另外一个辅助相机是需要取得他的targettexture,;
2,在主相机中重写OnRenderImage方法;
3,创建一个材质,赋予一个shader,然后将此材质通过上述2中的OnRenderImage方法输出到最终显示。shader的作用为使得主相机的texture和辅助相机的targettexture根据需要显示在屏幕中的两个区域;
4,根据屏幕分辨率以及鼠标坐标,判断出鼠标处于哪部分区域,执行旋转或移动。
下面来详细实现一下以上步骤:
给Main Camera添加一个脚本,脚本代码如下:
using UnityEngine;
using System.Collections;
public class Test : MonoBehaviour {
public Camera cam;
public Material mat;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
}
void OnRenderImage(RenderTexture src, RenderTexture dest)
{
if (cam.targetTexture == null)
{
cam.targetTexture = new RenderTexture(cam.pixelWidth, cam.pixelHeight, 0); //根据主相机的宽高创建一个同样宽高的纹理,记录辅助相机的图像
}
mat.SetTexture("_OtherTex", cam.targetTexture);//传入辅助相机的纹理,shader中用到,具体见下面的shader代码
Graphics.Blit(src, dest, mat);
}
}
shader代码如下:
Shader "Custom/Shader" {
Properties {
_MainTex ("Base (RGB) Trans (A)", 2D) = "white" {}//主相机的纹理
_OtherTex ("Other Tex", 2D) = "white" {}<span style="white-space:pre"> </span>//辅助相机的纹理
}
SubShader {
Tags {"Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent"}
LOD 100
Cull Off<span style="white-space:pre"> </span>
Blend Off<span style="white-space:pre"> </span>//关闭混合
Pass {
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata_t {
float4 vertex : POSITION;
float2 texcoord : TEXCOORD0;
};
struct v2f {
float4 vertex : SV_POSITION;
half2 texcoord : TEXCOORD0;
};
sampler2D _MainTex;
sampler2D _OtherTex;
float4 _MainTex_ST;
v2f vert (appdata_t v)
{
v2f o;
o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
o.texcoord = TRANSFORM_TEX(v.texcoord, _MainTex);
return o;
}
fixed4 frag (v2f i) : SV_Target
{
half2 otherTexcoord = half2(i.texcoord.x, 1 - i.texcoord.y);<span style="white-space:pre"> </span>//本人也不清楚为什么外面传进来的rendertexture的纹理坐标的y会相反,所以自己动手用1来减去
fixed4 col = tex2D(_MainTex, i.texcoord)*ceil(i.texcoord.x + i.texcoord.y - 1) + tex2D(_OtherTex, otherTexcoord)*ceil(1 - i.texcoord.x - i.texcoord.y);
return col;
}
ENDCG
}
}
FallBack "Diffuse"
}
上面的shader的核心代码
fixed4 col = tex2D(_MainTex, i.texcoord)*ceil(i.texcoord.x + i.texcoord.y - 1) + tex2D(_OtherTex, otherTexcoord)*ceil(1 - i.texcoord.x - i.texcoord.y);
以上代码分为两部分,其实本质是依靠y = -x + 1这个公式来实现,需要点高中数学知识
经过上面两部,图形就已经为最终效果了,下面来实现分屏控制:
工程里创建一个空对象ControlObj(上图中有),给它添加代码,代码如下:
using UnityEngine;
using System.Collections;
public class Control : MonoBehaviour {
public Transform obj;
// Use this for initialization
Vector2 mousePos;
float screenWidth = Screen.width;
float screenHeight = Screen.height;
void Start () {
}
// Update is called once per frame
void Update () {
if (Input.GetMouseButtonDown(0))
{
mousePos = Input.mousePosition;
//Debug.Log("按下左键" + mousePos);
}
if (Input.GetMouseButton(0))
{
Debug.Log("移动左键");
//按照区域判断是移动还是旋转
float x = mousePos.x / screenWidth;
float y = mousePos.y / screenHeight;
if (y < x) updateObjRotation();
else updateObjPosition();
}
if (Input.GetMouseButtonUp(0))
{
Debug.Log("松开左键");
}
}
void updateObjRotation()
{
Debug.Log("更新物体旋转");
obj.rotation = Quaternion.AngleAxis(1, Vector3.up) * obj.rotation;
}
void updateObjPosition()
{
Debug.Log("更新物体位置");
obj.position = new Vector3(obj.position.x + 0.03f, obj.position.y, obj.position.z);
}
}
核心代码为:
<span style="white-space:pre"> </span> //按照区域判断是移动还是旋转
float x = mousePos.x / screenWidth;
float y = mousePos.y / screenHeight;
if (y < x) updateObjRotation();
else updateObjPosition();
这是使用了y = x这个公式;
由此大功告成