feat: 双Pass膨胀描边shader替代LineRenderer
- 新增 Custom/OutlineUnlit shader: Pass1膨胀描边(Cull Front)+Pass2内芯填充 - BlueOutline.mat: 蓝色描边+半透蓝填充 - TouchPositionHandler改用MeshRenderer.enabled闪烁 - 球体挂MeshRenderer+Outline材质,0.4s闪烁
This commit is contained in:
@@ -0,0 +1,32 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!21 &2100000
|
||||
Material:
|
||||
serializedVersion: 8
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: BlueOutline
|
||||
m_Shader: {fileID: 4800000, guid: 8f9df7221aff6471e9c94f9880c6b198, type: 3}
|
||||
m_Parent: {fileID: 0}
|
||||
m_ModifiedSerializedProperties: 0
|
||||
m_ValidKeywords: []
|
||||
m_InvalidKeywords: []
|
||||
m_LightmapFlags: 4
|
||||
m_EnableInstancingVariants: 0
|
||||
m_DoubleSidedGI: 0
|
||||
m_CustomRenderQueue: -1
|
||||
stringTagMap: {}
|
||||
disabledShaderPasses: []
|
||||
m_LockedProperties:
|
||||
m_SavedProperties:
|
||||
serializedVersion: 3
|
||||
m_TexEnvs: []
|
||||
m_Ints: []
|
||||
m_Floats:
|
||||
- _OutlineWidth: 0.08
|
||||
m_Colors:
|
||||
- _MainColor: {r: 0.09999997, g: 0.29999998, b: 0.8, a: 0.3}
|
||||
- _OutlineColor: {r: 0.19999996, g: 0.5, b: 1, a: 1}
|
||||
m_BuildTextureStacks: []
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ffca8dfc24bad4047b97aff00ba3497c
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 2100000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1210,7 +1210,7 @@ GameObject:
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
m_IsActive: 0
|
||||
--- !u!4 &30774413
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
/// 挂在 touchArray 的每个子球体上,点击时把 woman 移动到 womanPointArray 对应位置。
|
||||
/// 两个交叉圆环形成球形轮廓闪烁提示。
|
||||
/// 挂在 touchArray 子球体上。球体用双Pass膨胀描边shader(Custom/OutlineUnlit),
|
||||
/// 闪烁提示用户点击。点击后移动到对应位置并顺序显示下一个。
|
||||
/// </summary>
|
||||
public class TouchPositionHandler : MonoBehaviour
|
||||
{
|
||||
@@ -10,73 +10,20 @@ public class TouchPositionHandler : MonoBehaviour
|
||||
public GameObject womanObject;
|
||||
public GameObject nextTouchObject;
|
||||
|
||||
private LineRenderer _ringH; // 水平环
|
||||
private LineRenderer _ringV; // 垂直环
|
||||
private MeshRenderer _meshRenderer;
|
||||
|
||||
private void Start()
|
||||
{
|
||||
var mr = GetComponent<MeshRenderer>();
|
||||
if (mr != null) mr.enabled = false;
|
||||
|
||||
CreateCrossRings();
|
||||
StartCoroutine(BlinkRings());
|
||||
_meshRenderer = GetComponent<MeshRenderer>();
|
||||
StartCoroutine(BlinkMesh());
|
||||
}
|
||||
|
||||
private void CreateCrossRings()
|
||||
{
|
||||
float r = 0.15f;
|
||||
int segs = 32;
|
||||
float yOff = 0.05f;
|
||||
Color blue = new Color(0.2f, 0.5f, 1f);
|
||||
|
||||
// 水平环 —— 世界空间 XZ 平面
|
||||
var hGo = new GameObject("RingH");
|
||||
hGo.transform.SetParent(transform, false);
|
||||
_ringH = hGo.AddComponent<LineRenderer>();
|
||||
SetupRing(_ringH, blue);
|
||||
_ringH.useWorldSpace = true;
|
||||
_ringH.positionCount = segs;
|
||||
Vector3 center = transform.position + Vector3.up * yOff;
|
||||
for (int i = 0; i < segs; i++)
|
||||
{
|
||||
float a = i * 2f * Mathf.PI / segs;
|
||||
_ringH.SetPosition(i, center + new Vector3(Mathf.Cos(a) * r, 0, Mathf.Sin(a) * r));
|
||||
}
|
||||
|
||||
// 垂直环 —— 世界空间 XY 平面(竖起来)
|
||||
var vGo = new GameObject("RingV");
|
||||
vGo.transform.SetParent(transform, false);
|
||||
_ringV = vGo.AddComponent<LineRenderer>();
|
||||
SetupRing(_ringV, blue);
|
||||
_ringV.useWorldSpace = true;
|
||||
_ringV.positionCount = segs;
|
||||
for (int i = 0; i < segs; i++)
|
||||
{
|
||||
float a = i * 2f * Mathf.PI / segs;
|
||||
_ringV.SetPosition(i, center + new Vector3(Mathf.Cos(a) * r, Mathf.Sin(a) * r, 0));
|
||||
}
|
||||
|
||||
Debug.Log($"[TouchPosition] {name}: 交叉蓝环已创建 (r={r})");
|
||||
}
|
||||
|
||||
private void SetupRing(LineRenderer lr, Color c)
|
||||
{
|
||||
lr.loop = true;
|
||||
lr.startWidth = 0.06f;
|
||||
lr.endWidth = 0.06f;
|
||||
lr.material = new Material(Shader.Find("Unlit/Color"));
|
||||
lr.material.color = c;
|
||||
lr.startColor = c;
|
||||
lr.endColor = c;
|
||||
}
|
||||
|
||||
private System.Collections.IEnumerator BlinkRings()
|
||||
private System.Collections.IEnumerator BlinkMesh()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
bool on = !_ringH.enabled;
|
||||
if (_ringH != null) _ringH.enabled = on;
|
||||
if (_ringV != null) _ringV.enabled = on;
|
||||
if (_meshRenderer != null)
|
||||
_meshRenderer.enabled = !_meshRenderer.enabled;
|
||||
yield return new WaitForSeconds(0.4f);
|
||||
}
|
||||
}
|
||||
@@ -91,14 +38,9 @@ public class TouchPositionHandler : MonoBehaviour
|
||||
womanObject.transform.rotation = targetPosition.rotation;
|
||||
Debug.Log($"[TouchPosition] woman 移动到 {targetPosition.name}");
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogWarning($"[TouchPosition] {name}: 引用为空");
|
||||
}
|
||||
|
||||
StopAllCoroutines();
|
||||
if (_ringH != null) _ringH.enabled = false;
|
||||
if (_ringV != null) _ringV.enabled = false;
|
||||
if (_meshRenderer != null) _meshRenderer.enabled = false;
|
||||
|
||||
gameObject.SetActive(false);
|
||||
if (nextTouchObject != null)
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3341ac3659c134c929e8f36c5268188d
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,64 @@
|
||||
Shader "Custom/OutlineUnlit"
|
||||
{
|
||||
Properties
|
||||
{
|
||||
_MainColor ("Main Color", Color) = (0.1, 0.3, 0.8, 0.3)
|
||||
_OutlineColor ("Outline Color", Color) = (0.2, 0.5, 1, 1)
|
||||
_OutlineWidth ("Outline Width", Range(0, 0.3)) = 0.08
|
||||
}
|
||||
SubShader
|
||||
{
|
||||
Tags { "RenderType"="Transparent" "Queue"="Transparent" }
|
||||
Blend SrcAlpha OneMinusSrcAlpha
|
||||
ZWrite Off
|
||||
|
||||
// Pass 1: 膨胀描边
|
||||
Pass
|
||||
{
|
||||
Name "OUTLINE"
|
||||
Cull Front
|
||||
CGPROGRAM
|
||||
#pragma vertex vert
|
||||
#pragma fragment frag
|
||||
#include "UnityCG.cginc"
|
||||
|
||||
float _OutlineWidth;
|
||||
float4 _OutlineColor;
|
||||
|
||||
struct appdata { float4 vertex : POSITION; float3 normal : NORMAL; };
|
||||
struct v2f { float4 pos : SV_POSITION; };
|
||||
|
||||
v2f vert(appdata v)
|
||||
{
|
||||
v2f o;
|
||||
float3 n = normalize(v.normal);
|
||||
v.vertex.xyz += n * _OutlineWidth;
|
||||
o.pos = UnityObjectToClipPos(v.vertex);
|
||||
return o;
|
||||
}
|
||||
|
||||
fixed4 frag(v2f i) : SV_Target { return _OutlineColor; }
|
||||
ENDCG
|
||||
}
|
||||
|
||||
// Pass 2: 内芯填充
|
||||
Pass
|
||||
{
|
||||
Name "FILL"
|
||||
Cull Back
|
||||
CGPROGRAM
|
||||
#pragma vertex vert
|
||||
#pragma fragment frag
|
||||
#include "UnityCG.cginc"
|
||||
|
||||
float4 _MainColor;
|
||||
|
||||
struct appdata { float4 vertex : POSITION; };
|
||||
struct v2f { float4 pos : SV_POSITION; };
|
||||
|
||||
v2f vert(appdata v) { v2f o; o.pos = UnityObjectToClipPos(v.vertex); return o; }
|
||||
fixed4 frag(v2f i) : SV_Target { return _MainColor; }
|
||||
ENDCG
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8f9df7221aff6471e9c94f9880c6b198
|
||||
ShaderImporter:
|
||||
externalObjects: {}
|
||||
defaultTextures: []
|
||||
nonModifiableTextures: []
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user