一、Shader 篇 命名有改动
Shader "Car/VertexColorTransform" //顶点颜色变换
{
Properties
{
_MainColor("Main Color", Color) = (1,1,1,1)
//_CubeMap("Cube Map", CUBE) = ""{}
_ReflectAmount("Reflect Amount", Float) = 1
_RimColorMultiply("Rim Color Multiply", Float) = 0
_RimPower("Rim Power", Float) = 1
_ReflFresnelPower("Reflect Fresnel Power", Float) = 1
_ReflFresnelOffset("Reflect Fresnel Offset", Float) = 0
_WaveLength("Wave Length", Float) = 1
_WaveStrenth("Wave Strenth", Float) = 1
_WaveOffset("Wave Offset", Float) = 0
_StartPos("Start Position", Vector) = (0,0,0,0)
_TargetColor("Target Color", Color) = (1,1,1,1)
_OcclusionStrength("DarkColor Strength", Float) = 1
_OcclusionOffset("DarkColor Offset", Float) = 0
_FinalColorAdjust("FinalColorAdjust", Float) = 1.3
}
SubShader
{
Tags { "RenderType"="Opaque" "IgnoreProjector"="True"}
CGINCLUDE
#pragma vertex vert
#pragma fragment frag
#pragma fragmentoption ARB_precision_hint_fastest
#pragma exclude_renderers xbox360 ps3 flash d3d11_9x
fixed4 _MainColor;
samplerCUBE _CubeMap;
fixed _ReflectAmount;
half _ReflFresnelPower;
half _ReflFresnelOffset;
half _RimColorMultiply;
half _RimPower;
half _WaveLength;
half _WaveStrenth;
half _WaveOffset;
float4 _StartPos;
fixed4 _TargetColor;
fixed _OcclusionStrength;
float _OcclusionOffset;
float _FinalColorAdjust;
fixed4 _LightColor0;
struct VertexInput
{
float4 vertex:POSITION;
fixed3 normal:NORMAL;
};
struct VertexOutput
{
float4 pos:SV_POSITION;
fixed4 reflectDir:TEXCOORD0;
fixed rimMultiply:TEXCOORD2;
fixed3 transColor:TEXCOORD3;
float4 worldPos:TEXCOORD4;
};
VertexOutput vert(VertexInput v)
{
VertexOutput output;
//vertex offset
fixed pi = 3.1415926535898;
half dist = distance(_StartPos.xyz, mul(_Object2World, v.vertex).xyz);
half x = (_WaveOffset - dist) * _WaveLength;
half normalOffset = (sin(x + pi*0.5) + 1) * _WaveStrenth;
normalOffset = (x > -pi && x < pi) ? normalOffset : 0;
float4 worldPos = mul(_Object2World, v.vertex);
worldPos.xyz += float3(mul(_Object2World, fixed4(v.normal,0)).xyz) * normalOffset;
output.pos = mul(UNITY_MATRIX_VP, worldPos);
x = saturate(x*0.25+0.5);
output.transColor = lerp(_MainColor.rgb, _TargetColor.rgb, x);
output.worldPos = worldPos;
//light & color
fixed3 lightDir = normalize(_WorldSpaceLightPos0.xyz);
fixed3 normalDir = normalize(mul(_Object2World, float4(v.normal, 0)).xyz);
output.lightColor = _LightColor0.rgb * (dot(lightDir, normalDir) * 0.5 + 0.5) + UNITY_LIGHTMODEL_AMBIENT.rgb;
fixed3 viewDir = normalize(float3((_WorldSpaceCameraPos - mul(_Object2World, v.vertex)).xyz));
fixed NdotV = dot(normalDir, viewDir);
output.reflectDir.xyz = reflect(-viewDir, normalDir);
output.reflectDir.w = _ReflectAmount * pow(1-NdotV, _ReflFresnelPower) + _ReflFresnelOffset;
output.rimMultiply = pow(1-NdotV, _RimPower) * _RimColorMultiply;
return output;
}
fixed4 frag(VertexOutput i):COLOR
{
fixed4 c = fixed4(0,0,0,1);
fixed3 cubeColor = texCUBE(_CubeMap, i.reflectDir.xyz).rgb * i.reflectDir.w;
c.rgb = (i.transColor.rgb + cubeColor + i.transColor.rgb * i.rimMultiply) * i.lightColor;
//final color
c.rgb = c.rgb * saturate((i.worldPos.y + _OcclusionOffset) * _OcclusionStrength) * _FinalColorAdjust;
return c;
}
ENDCG
Pass
{
Tags{"LightMode"="ForwardBase"}
CGPROGRAM
#define UNITY_PASS_FORWARDBASE
#define multi_compile_fwdbase_fullshadows
ENDCG
}
}
}
二、线条生成
using UnityEngine;
using DG.Tweening;
public class RectMesh : PrimitiveBase
{
[SerializeField]
private float m_Width;
[SerializeField]
private float m_Length;
public enum PivotAlign { Left, Center, Right }
public PivotAlign widthAlign = PivotAlign.Center;//宽度方向的中心点
public PivotAlign lengthAlign = PivotAlign.Center;//长度方向的中心点
/// <summary>
/// 宽度
/// </summary>
public float width
{
get { return m_Width; }
set { m_Width = value; UpdateShape(); }
}
/// <summary>
/// 长度
/// </summary>
public float length
{
get { return m_Length; }
set { m_Length = value; UpdateShape(); }
}
/// <summary>
/// x方向的偏移
/// </summary>
public float offsetX
{
get { return offset.x; }
set { offset.x = value; UpdateShape(); }
}
protected override void UpdateShape()
{
if (cacheTransform == null || meshFilter == null)
{
Init();
}
Vector3 localPos = offset;
float w2 = m_Width * 0.5f;
float l2 = m_Length * 0.5f;
vertices = new Vector3[4];
float x0, z0, x1, z1, x2, z2, x3, z3;
x0 = z0 = x1 = z1 = x2 = z2 = x3 = z3 = 0;
switch (widthAlign)
{
case PivotAlign.Center:x0 = -w2;x1 = w2;x2 = -w2;x3 = w2;break;
case PivotAlign.Left:x0 = 0f;x1 = m_Width; x2 = 0f;x3 = m_Width;break;
case PivotAlign.Right:x0 = -m_Width;x1 = 0f;x2 = -m_Width;x3 = 0f;break;
}
switch(lengthAlign)
{
case PivotAlign.Center:z0 = -l2;z1 = -l2;z2=l2;z3 = l2;break;
case PivotAlign.Left:z0 = 0f;z1 = 0;z2 = m_Length;z3 = m_Length;break;
case PivotAlign.Right:z0 = -m_Length;z1 = -m_Length;z2 = 0f;z3 = 0f;break;
}
vertices[0].x = localPos.x + x0;
vertices[0].y = localPos.y;
vertices[0].z = localPos.z + z0;
vertices[1].x = localPos.x + x1;
vertices[1].y = localPos.y;
vertices[1].z = localPos.z + z1;
vertices[2].x = localPos.x + x2;
vertices[2].y = localPos.y;
vertices[2].z = localPos.z + z2;
vertices[3].x = localPos.x + x3;
vertices[3].y = localPos.y;
vertices[3].z = localPos.z + z3;
UpdateMesh();
}
protected override void InitMesh()
{
if (cacheTransform == null || meshFilter == null)
{
Init();
}
triangles = new int[] { 0, 2, 3, 0, 3, 1 };
uvs = new Vector2[4];
uvs[0].x = 0; uvs[0].y = 0;
uvs[1].x = 1; uvs[1].y = 0;
uvs[2].x = 0; uvs[2].y = 1;
normals = new Vector3[4];
normals[0].y = normals[1].y = normals[2].y = normals[3].y = 1;
UpdateShape();
}
public Tweener DoLength(float endValue, float duration, float delay)
{
return DOTween.To(() => length, x => length = x, endValue, duration).SetDelay(delay);
}
public Tween DoWidth(float endValue, float duration, float delay)
{
return DOTween.To(() => width, x => width = x, endValue, duration).SetDelay(delay);
}
}
using UnityEngine;
[RequireComponent(typeof(MeshFilter), typeof(MeshRenderer))][ExecuteInEditMode]
public class PrimitiveBase : MonoBehaviour
{
/// <summary>
/// 偏移
/// </summary>
public Vector3 offset;
protected MeshFilter meshFilter;
public Transform cacheTransform;
void Awake()
{
Init();
InitMesh();
}
protected void Init()
{
cacheTransform = transform;
meshFilter = GetComponent<MeshFilter>();
meshFilter.sharedMesh = new Mesh();
}
protected virtual void InitMesh()
{
}
protected Vector3[] vertices;
protected int[] triangles;
protected Vector2[] uvs;
protected Vector3[] normals;
protected void UpdateMesh()
{
if(meshFilter.sharedMesh == null)
{
meshFilter.sharedMesh = new Mesh();
}
meshFilter.sharedMesh.vertices = vertices;
meshFilter.sharedMesh.triangles = triangles;
meshFilter.sharedMesh.uv = uvs;
meshFilter.sharedMesh.normals = normals;
}
protected virtual void UpdateShape()
{
}
void OnValidate()
{
InitMesh();
}
}