先解释一下标题,异形视频播放:不规则形状播放。先贴个图:
如图,背景图是正常的视频播放,三角形则是另一视频播放,不过是不规则的三角形。原理就是通过shader检测三个坐标点计算进行纹理的渲染,贴一下代码:
Shader代码:
Shader "Hidden/Triangle"
{
Properties
{
_MainTex ("MainTex", 2D) = "white" {}
_ViceTex ("ViceTex", 2D) = "white" {}
}
SubShader
{
Tags { "RenderType"="Transparent" "Queue"="Transparent" }
Cull Off ZWrite Off ZTest Always
Blend SrcAlpha OneMinusSrcAlpha
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
sampler2D _MainTex;
sampler2D _ViceTex;
vector points[3];
int pointNums = 0;
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};
float IsInSide(float3 uv,float3 point1,float3 point2,float3 point3)
{
//叉乘法:利用叉乘法判断一个点是否在三角形内
float3 a = point1 - uv;
float3 b = point2 - uv;
float3 c = point3 - uv;
float3 ab = cross(a,b);
float3 bc = cross(b,c);
float3 ca = cross(c,a);
float d1 = dot(ab,bc);
float d2 = dot(ab,ca);
float d3 = dot(bc,ca);
return (d1 > 0 && d2 > 0 && d3 > 0) || (d1 < 0 && d2 < 0 && d3 < 0);
}
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = v.uv;
return o;
}
fixed4 frag (v2f i) : SV_Target
{
float nums = step(3,pointNums);
float4 main = tex2D(_MainTex, i.uv);
float4 vice = tex2D(_ViceTex, i.uv);
float isInSide = IsInSide(float3(i.uv,0),points[0],points[1],points[2]);
//顶点小于3,return main;大于等于3 在判断是否在三角形内(isInSide),在 return main ,否 return vice
fixed4 col = lerp(main,lerp(main,vice,isInSide),nums);
return col;
}
ENDCG
}
}
}
C#代码:
using UnityEngine;
public class TriangleVideoPlayer : MonoBehaviour
{
/// <summary>
/// 三角形顶点
/// </summary>
private Vector4[] points;
/// <summary>
/// 材质球
/// </summary>
public Material material;
/// <summary>
/// 顶点数量
/// </summary>
private int nums;
/// <summary>
/// 圆心
/// </summary>
private Vector2 center;
void Start()
{
this.points = new Vector4[3];
this.center = Vector2.zero;
}
void Update()
{
this.UpdateParameter();
}
private void UpdateParameter()
{
if (Input.GetMouseButtonDown(0))
{
if (this.points[0] == null)
this.points[0] = new Vector4(Input.mousePosition.x / Screen.width, Input.mousePosition.y / Screen.height, 0f, 0f);
else if (this.points[1] == null)
this.points[1] = new Vector4(Input.mousePosition.x / Screen.width, Input.mousePosition.y / Screen.height, 0f, 0f);
else if (this.points[2] == null)
this.points[2] = new Vector4(Input.mousePosition.x / Screen.width, Input.mousePosition.y / Screen.height, 0f, 0f);
else
{
this.points[0] = this.points[1];
this.points[1] = this.points[2];
this.points[2] = new Vector4(Input.mousePosition.x / Screen.width, Input.mousePosition.y / Screen.height, 0f, 0f);
}
this.nums++;
this.nums = Mathf.Clamp(this.nums, 0, 3);
this.material.SetVectorArray("points", this.points);
this.material.SetInt("pointNums", this.nums);
}
}
}
这里解释一下shader代码中的IsInSide这个函数,其实是利用了叉乘法判断一个点是否在三角形内,关于叉乘法请自行搜索,通过IsInSide这个函数能区分出那一部分需要渲染主视频另一部分渲染副视频,视频部分是这样设置的:
由于两个视频有音频输出,为了好玩,设置了一下左右声道,如图:
这里用了VideoPlayer组件进行的视频播放,当然我能也可以换个思路利用常见的圆形进行视频不规则播放:
原理很简单,直接看源码:
Shader代码:
Shader "Hidden/Circle"
{
Properties
{
_MainTex ("MainTex", 2D) = "white" {}
_ViceTex ("ViceTex", 2D) = "white" {}
_CircleCenter("CircleCenter",Vector) = (0,0,0,0)
_Radius("Radius",Range(0,1)) = 0
}
SubShader
{
Tags{ "RenderType" = "Transparent" "Queue" = "Transparent" "IgnoreProjector" = "True" }
Cull Off ZWrite On ZTest Less
Blend SrcAlpha OneMinusSrcAlpha
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
sampler2D _MainTex;
sampler2D _ViceTex;
float4 _CircleCenter;
float _Radius;
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = v.uv;
return o;
}
fixed4 frag (v2f i) : SV_Target
{
//偏移至中心
float2 uv = i.uv - float2(_CircleCenter.x,_CircleCenter.y);
//适配屏幕宽高
uv *= float2(_ScreenParams.x / _ScreenParams.y,1);
//计算距离
float len = length(uv);
float4 main = tex2D(_MainTex, i.uv);
float4 vice = tex2D(_ViceTex,i.uv);
return lerp(main,vice,step(len,_Radius));
}
ENDCG
}
}
}
C#代码:
using UnityEngine;
public class CircleVideoPlayer : MonoBehaviour
{
/// <summary>
/// 圆心
/// </summary>
private Vector4 circleCenter;
/// <summary>
/// 材质球
/// </summary>
private Material material;
/// <summary>
/// 半径
/// </summary>
[Range(0,0.5f)]
public float radius;
void Start()
{
this.circleCenter = Vector4.zero;
this.material = this.GetComponent<MeshRenderer>().material;
this.SetMaterialParameter();
}
void Update()
{
this.Check();
this.SetMaterialParameter();
}
private void Check()
{
this.circleCenter = new Vector4(Input.mousePosition.x / Screen.width, Input.mousePosition.y / Screen.height, Input.mousePosition.z, 0);
if (Input.GetAxis("Mouse ScrollWheel") < 0)
this.radius -= Time.deltaTime;
else if (Input.GetAxis("Mouse ScrollWheel") > 0)
this.radius += Time.deltaTime;
this.radius = Mathf.Clamp(this.radius, 0, 0.5f);
}
/// <summary>
/// 设置材质球参数
/// </summary>
private void SetMaterialParameter()
{
this.material.SetVector("_CircleCenter", this.circleCenter);
this.material.SetFloat("_Radius", this.radius);
}
}
如果有需要的朋友,下载链接:
https://lanzous.com/b00nihunc
密码:9o4m
参考链接(这个是多边形):https://blog.csdn.net/zzlyw/article/details/53992048