最近在看一个大佬的知乎专栏,并且自己跟着大佬的代码做了一遍,文章主要是关于图文混排的,所以写下这篇文章做个笔记。
代码主要包括两部分,一部分是shader的,用来生成材质,另一部分是C#代码,使用shader,做一定修改之后,两者结合能够在屏幕上生成任意颜色、任意大小的纯色区域。
首先是生成纯黑区域:
shader部分:
Shader "Custom/Learn" {
Properties
{
_MainTex("Base (RGB), Alpha (A)", 2D) = "white" {}
}
SubShader
{
LOD 200
Tags
{
"Queue" = "Transparent"
"IgnoreProjector" = "True"
"RenderType" = "Transparent"
}
Pass
{
Cull Off
Lighting Off
ZWrite On
Fog{ Mode Off }
Offset -1, -1
Blend SrcAlpha OneMinusSrcAlpha
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
sampler2D _MainTex;
float4 _MainTex_ST;
struct appdata_t
{
float4 vertex : POSITION;
float2 texcoord : TEXCOORD0;
fixed4 color : COLOR;
};
struct v2f
{
float4 vertex : SV_POSITION;
half2 texcoord : TEXCOORD0;
fixed4 color : COLOR;
};
v2f o;
v2f vert(appdata_t v)
{
o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
return o;
}
fixed4 frag(v2f IN) : COLOR
{
return float4(0,0,0,1);
}
ENDCG
}
}
Fallback" Diffuse "
}
关于shader部分我不懂,不过猜测v2f vert(appdata_t v),以及 fixed4 frag(v2f IN) : COLOR 是比较重要的部分。因为我们使用shader主要是定点着色已经最终成像。
其次是c#部分
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Black : MonoBehaviour {
public int width = 512;
public int height = 512;
public Color color = Color.black;
private MeshFilter meshFilter;
private MeshRenderer meshRender;
// Use this for initialization
void Start () {
Shader s = Shader.Find("Custom/Learn");
Material spriteMaterial = new Material(s);
//get meshFilter
meshFilter = gameObject.GetComponent<MeshFilter>();
if (meshFilter == null)
{
meshFilter = gameObject.AddComponent<MeshFilter>();
meshRender = gameObject.AddComponent<MeshRenderer>();
meshRender.sharedMaterial = spriteMaterial;
}
Fill();
}
// Update is called once per frame
void Fill () {
//得到网格对象
Mesh mesh = new Mesh();
meshFilter.mesh = mesh;
//三角形顶点的坐标数组
Vector3[] vertices = new Vector3[4];
//三角形顶点数组
int[] triangles = new int[6];
//颜色数组
Color[] colors = new Color[4];
//uv贴图数组
Vector2[] uv = new Vector2[4];
float glWidth = (float)width / 2;
float glHeight = (float)height / 2;
//以当前对象的中心坐标为准
vertices[0] = new Vector3(-glWidth, -glHeight, 0);
vertices[1] = new Vector3(-glWidth, glHeight, 0);
vertices[2] = new Vector3(glWidth, -glHeight, 0);
vertices[3] = new Vector3(glWidth, glHeight, 0);
//绑定顶点顺序
triangles[0] = 0;
triangles[1] = 2;
triangles[2] = 1;
triangles[3] = 2;
triangles[4] = 3;
triangles[5] = 1;
//设置顶点颜色
colors[0] = color;
colors[1] = color;
colors[2] = color;
colors[3] = color;
//绑定贴图UV
uv[0] = Vector2.zero;
uv[1] = Vector2.up;
uv[2] = Vector2.right;
uv[3] = Vector2.one;
//给mesh赋值
mesh.vertices = vertices;
mesh.triangles = triangles;
mesh.colors = colors;
mesh.uv = uv;
}
}
其中比较关键的是通过第一部分的shader生成material,之后自定义meshFilter进行着色。
在第二部分的代码中,我们通过把正方形或者说长方形(width != height时)风格城两个三角形进行处理,所以顶点坐标、颜色、uv贴图有四个,因为是四个顶点,而顶点数组却有六个,这是因为我们把四个顶点的长方形分割成了两个三角形从而有了六个顶点数据。
上述程序的不足在于color定死了是(0,0,0,1)即黑色,如果我们希望颜色为C#中color的颜色的话,我们需要做如下改变:
shader:
v2f o;
v2f vert(appdata_t v)
{
o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
o.color = v.color;
return o;
}
fixed4 frag(v2f IN) : COLOR
{
return IN.color;
}
ENDCG
从而使我们的返回COLOR不是固定的。
c#:
原博主在代码中实现更新的方式是在OnValidate()函数中调用Fill()函数进行更新。
private void OnValidate()
{
if (meshFilter && Application.isPlaying)
{
Fill();
}
}
在任何实时更新逻辑的函数中调用Fill()都有效,比如Update()、FixedUpdate()等。