unityzgy/.svn/pristine/e1/e15efb701484d0eb77d536363ebc4ae95efef87d.svn-base
ayuan9957 bf12e02276 feat: 多语言本地化系统 - 支持中/英/法/俄实时切换
- LocalizationManager: 新增翻译表(SetFormatted/SetDuration/LocalizeOperateMsg)
- LoginPanel: InputField placeholder本地化、字体颜色保持
- HistoryPanel: 用时数据本地化、placeholder本地化
- RecordDetailPanel: 操作详情消息本地化(LanguageChanged重建)
- AppraiseWindowBase: 评价等级本地化、操作消息重建
- EditorAppraiser: 所有评估消息改用InjectOperateMsgLocalized
- StudentOperateRecorder: 新增InjectOperateMsgLocalized方法
- LocalizationLanguageTestBar: 单例模式、ScreenSpaceOverlay筛选
- 字体切换时保留颜色和verticalOverflow
2026-07-16 10:05:59 +08:00

192 lines
8.4 KiB
Plaintext

// Material Colour Swap|Highlighters|40020
namespace VRTK.Highlighters
{
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
/// <summary>
/// The Material Colour Swap Highlighter is a basic implementation that simply swaps the texture colour for the given highlight colour.
/// </summary>
/// <remarks>
/// Due to the way the object material is interacted with, changing the material colour will break Draw Call Batching in Unity whilst the object is highlighted.
///
/// The Draw Call Batching will resume on the original material when the item is no longer highlighted.
///
/// This is the default highlighter that is applied to any script that requires a highlighting component (e.g. `VRTK_Interactable_Object`).
/// </remarks>
/// <example>
/// `VRTK/Examples/005_Controller_BasicObjectGrabbing` demonstrates the solid highlighting on the green cube, red cube and flying saucer when the controller touches it.
///
/// `VRTK/Examples/035_Controller_OpacityAndHighlighting` demonstrates the solid highlighting if the right controller collides with the green box or if any of the buttons are pressed.
/// </example>
[AddComponentMenu("VRTK/Scripts/Interactions/Highlighters/VRTK_MaterialColorSwapHighlighter")]
public class VRTK_MaterialColorSwapHighlighter : VRTK_BaseHighlighter
{
[Tooltip("The emission colour of the texture will be the highlight colour but this percent darker.")]
public float emissionDarken = 50f;
[Tooltip("A custom material to use on the highlighted object.")]
public Material customMaterial;
protected Dictionary<string, Material[]> originalSharedRendererMaterials = new Dictionary<string, Material[]>();
protected Dictionary<string, Material[]> originalRendererMaterials = new Dictionary<string, Material[]>();
protected Dictionary<string, Coroutine> faderRoutines;
protected bool resetMainTexture = false;
/// <summary>
/// The Initialise method sets up the highlighter for use.
/// </summary>
/// <param name="color">Not used.</param>
/// <param name="options">A dictionary array containing the highlighter options:\r * `&lt;'resetMainTexture', bool&gt;` - Determines if the default main texture should be cleared on highlight. `true` to reset the main default texture, `false` to not reset it.</param>
public override void Initialise(Color? color = null, Dictionary<string, object> options = null)
{
originalSharedRendererMaterials = new Dictionary<string, Material[]>();
originalRendererMaterials = new Dictionary<string, Material[]>();
faderRoutines = new Dictionary<string, Coroutine>();
resetMainTexture = GetOption<bool>(options, "resetMainTexture");
ResetHighlighter();
}
/// <summary>
/// The ResetHighlighter method stores the object's materials and shared materials prior to highlighting.
/// </summary>
public override void ResetHighlighter()
{
StoreOriginalMaterials();
}
/// <summary>
/// The Highlight method initiates the change of colour on the object and will fade to that colour (from a base white colour) for the given duration.
/// </summary>
/// <param name="color">The colour to highlight to.</param>
/// <param name="duration">The time taken to fade to the highlighted colour.</param>
public override void Highlight(Color? color, float duration = 0f)
{
if (color == null)
{
return;
}
ChangeToHighlightColor((Color)color, duration);
}
/// <summary>
/// The Unhighlight method returns the object back to it's original colour.
/// </summary>
/// <param name="color">Not used.</param>
/// <param name="duration">Not used.</param>
public override void Unhighlight(Color? color = null, float duration = 0f)
{
if (originalRendererMaterials == null)
{
return;
}
if (faderRoutines != null)
{
foreach (var fadeRoutine in faderRoutines)
{
StopCoroutine(fadeRoutine.Value);
}
faderRoutines.Clear();
}
foreach (Renderer renderer in GetComponentsInChildren<Renderer>(true))
{
var objectReference = renderer.gameObject.GetInstanceID().ToString();
if (!originalRendererMaterials.ContainsKey(objectReference))
{
continue;
}
renderer.materials = originalRendererMaterials[objectReference];
renderer.sharedMaterials = originalSharedRendererMaterials[objectReference];
}
}
protected virtual void StoreOriginalMaterials()
{
originalSharedRendererMaterials.Clear();
originalRendererMaterials.Clear();
foreach (Renderer renderer in GetComponentsInChildren<Renderer>(true))
{
var objectReference = renderer.gameObject.GetInstanceID().ToString();
originalSharedRendererMaterials[objectReference] = renderer.sharedMaterials;
originalRendererMaterials[objectReference] = renderer.materials;
renderer.sharedMaterials = originalSharedRendererMaterials[objectReference];
}
}
protected virtual void ChangeToHighlightColor(Color color, float duration = 0f)
{
foreach (Renderer renderer in GetComponentsInChildren<Renderer>(true))
{
var swapCustomMaterials = new Material[renderer.materials.Length];
for (int i = 0; i < renderer.materials.Length; i++)
{
var material = renderer.materials[i];
if (customMaterial)
{
material = customMaterial;
swapCustomMaterials[i] = material;
}
var faderRoutineID = material.GetInstanceID().ToString();
if (faderRoutines.ContainsKey(faderRoutineID) && faderRoutines[faderRoutineID] != null)
{
StopCoroutine(faderRoutines[faderRoutineID]);
faderRoutines.Remove(faderRoutineID);
}
material.EnableKeyword("_EMISSION");
if (resetMainTexture && material.HasProperty("_MainTex"))
{
//renderer.material.SetTexture("_MainTex", new Texture());
}
if (material.HasProperty("_Color"))
{
if (duration > 0f)
{
faderRoutines[faderRoutineID] = StartCoroutine(CycleColor(material, material.color, color, duration));
}
else
{
material.color = color;
if (material.HasProperty("_EmissionColor"))
{
material.SetColor("_EmissionColor", VRTK_SharedMethods.ColorDarken(color, emissionDarken));
}
}
}
}
if (customMaterial)
{
renderer.materials = swapCustomMaterials;
}
}
}
protected virtual IEnumerator CycleColor(Material material, Color startColor, Color endColor, float duration)
{
var elapsedTime = 0f;
while (elapsedTime <= duration)
{
elapsedTime += Time.deltaTime;
if (material.HasProperty("_Color"))
{
material.color = Color.Lerp(startColor, endColor, (elapsedTime / duration));
}
if (material.HasProperty("_EmissionColor"))
{
material.SetColor("_EmissionColor", Color.Lerp(startColor, VRTK_SharedMethods.ColorDarken(endColor, emissionDarken), (elapsedTime / duration)));
}
yield return null;
}
}
}
}