2026-04-24 버그수정 및 대사에 맞춘 캐릭터 동작

This commit is contained in:
2026-04-24 19:41:08 +09:00
parent 752b891a48
commit 9963eba810
273 changed files with 19320 additions and 206 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 888380afc233049ce9e618f9f36c8ba8
timeCreated: 1545593776
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 900
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,201 @@
using System;
using UnityEngine;
namespace HighlightPlus {
public enum HitFxMode {
Overlay = 0,
InnerGlow = 1,
LocalHit = 2
}
public enum HitFXTriggerMode {
Scripting = 0,
WhenHighlighted = 10
}
public partial class HighlightEffect : MonoBehaviour {
public static bool useUnscaledTime;
[NonSerialized]
public Transform currentHitTarget;
[NonSerialized]
public Vector3 currentHitLocalPosition;
[NonSerialized]
public Vector3 currentHitNormal;
public static float GetTime () {
return useUnscaledTime ? Time.unscaledTime : Time.time;
}
#region Hit FX handling
[Range(0, 1)] public float hitFxInitialIntensity;
public HitFxMode hitFxMode = HitFxMode.Overlay;
public HitFXTriggerMode hitFXTriggerMode = HitFXTriggerMode.Scripting;
public float hitFxFadeOutDuration = 0.25f;
[ColorUsage(true, true)] public Color hitFxColor = Color.white;
public float hitFxRadius = 0.5f;
float hitInitialIntensity;
float hitStartTime;
float hitFadeOutDuration;
Color hitColor;
bool hitActive;
Vector3 hitPosition;
float hitRadius;
/// <summary>
/// Performs a hit effect using default values
/// </summary>
public void HitFX () {
HitFX(hitFxColor, hitFxFadeOutDuration, hitFxInitialIntensity);
}
/// <summary>
/// Performs a hit effect localized at hit position and radius with default values
/// </summary>
public void HitFX (Vector3 position) {
HitFX(hitFxColor, hitFxFadeOutDuration, hitFxInitialIntensity, position, hitFxRadius);
}
/// <summary>
/// Performs a hit effect using desired color, fade out duration and optionally initial intensity (0-1)
/// </summary>
public void HitFX (Color color, float fadeOutDuration, float initialIntensity = 1f) {
hitInitialIntensity = initialIntensity;
hitFadeOutDuration = fadeOutDuration;
hitColor = color;
hitStartTime = GetTime();
hitActive = true;
if (overlay == 0) {
UpdateMaterialProperties();
}
}
/// <summary>
/// Performs a hit effect using desired color, fade out duration, initial intensity (0-1), hit position and radius of effect
/// </summary>
public void HitFX (Color color, float fadeOutDuration, float initialIntensity, Vector3 position, float radius) {
hitInitialIntensity = initialIntensity;
hitFadeOutDuration = fadeOutDuration;
hitColor = color;
hitStartTime = GetTime();
hitActive = true;
hitPosition = position;
hitRadius = radius;
if (overlay == 0) {
UpdateMaterialProperties();
}
}
#endregion
/// <summary>
/// Initiates the target FX on demand using predefined configuration (see targetFX... properties)
/// </summary>
public void TargetFX () {
targetFXStartTime = GetTime();
if (!_highlighted) {
highlighted = true;
}
if (!targetFX) {
targetFX = true;
UpdateMaterialProperties();
}
}
/// <summary>
/// Initiates the icon FX on demand using predefined configuration (see iconFX... properties)
/// </summary>
public void IconFX () {
iconFXStartTime = GetTime();
if (!_highlighted) {
highlighted = true;
}
if (!iconFX) {
iconFX = true;
UpdateMaterialProperties();
}
}
#region Label handling
[NonSerialized]
public HighlightLabel label;
void ReleaseLabel () {
label?.Release();
label = null;
}
void CheckLabel (bool disabling) {
// Enable label
bool shouldShowLabel = labelMode == LabelMode.Always || (_highlighted && labelMode == LabelMode.WhenHighlighted) || (labelShowInEditorMode && !Application.isPlaying);
shouldShowLabel = shouldShowLabel && !disabling && rmsCount != 0;
if (shouldShowLabel && labelEnabled) {
// Lazy initialization of label prefab
if (label == null && labelPrefab != null) {
label = HighlightLabelPoolManager.GetLabelInstance(labelPrefab);
}
if (label != null) {
label.ConfigureCanvas(labelRenderMode == LabelRenderMode.WorldSpace);
label.textLabel = labelText;
label.textColor = labelColor;
label.textSize = labelTextSize;
label.width = labelLineLength;
label.labelAlignment = labelAlignment;
label.labelRelativeAlignment = labelRelativeAlignment;
label.labelAlignmentTransform = labelAlignmentTransform;
label.labelMaxDistance = labelMaxDistance;
label.labelFadeStartDistance = labelFadeStartDistance;
label.labelScaleByDistance = labelScaleByDistance;
label.labelScaleMin = labelScaleMin;
label.labelScaleMax = labelScaleMax;
label.worldSpaceScale = labelWorldSpaceScale;
if (!label.isVisible) {
label.SetPosition(labelTarget == null ? target : labelTarget, Misc.vector3Zero, new Vector3(0, labelVerticalOffset, 0), labelViewportOffset);
label.Show();
}
}
}
else if (!labelEnabled) {
ReleaseLabel();
#if UNITY_EDITOR
if (!Application.isPlaying) {
HighlightLabelPoolManager.DestroySceneLabels();
}
#endif
}
else if (label != null) {
label.Hide();
}
}
public void SetHitPosition (Transform target, Vector3 localPosition, Vector3 offsetWS, Vector3 normalWS) {
if (labelEnabled && labelFollowCursor && label != null) {
label.SetPosition(target, localPosition, offsetWS);
}
currentHitTarget = target;
currentHitLocalPosition = localPosition;
currentHitNormal = normalWS;
}
/// <summary>
/// Recreates label
/// </summary>
public void RefreshLabel () {
HighlightLabelPoolManager.DestroySceneLabels();
CheckLabel(false);
}
#endregion
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: e749f80d0d29a49d49d6e0f4752065cd
timeCreated: 1542876337
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,90 @@
using UnityEngine;
using UnityEngine.Rendering;
using System.Collections.Generic;
namespace HighlightPlus {
public enum BlockerTargetOptions {
OnlyThisObject,
Children,
LayerInChildren
}
[DefaultExecutionOrder(100)]
[ExecuteInEditMode]
public class HighlightEffectBlocker : MonoBehaviour {
public BlockerTargetOptions include = BlockerTargetOptions.OnlyThisObject;
public LayerMask layerMask = -1;
public string nameFilter;
public bool useRegEx;
public bool blockOutlineAndGlow = true;
public bool blockOverlay = true;
List<Renderer> renderers;
void OnEnable () {
Refresh();
HighlightPlusRenderPassFeature.RegisterBlocker(this);
}
void OnDisable () {
HighlightPlusRenderPassFeature.UnregisterBlocker(this);
}
public void Refresh() {
if (renderers == null) {
renderers = new List<Renderer>();
} else {
renderers.Clear();
}
switch (include) {
case BlockerTargetOptions.OnlyThisObject:
Renderer r = GetComponent<Renderer>();
if (r != null) renderers.Add(r);
return;
case BlockerTargetOptions.Children:
GetComponentsInChildren<Renderer>(true, renderers);
break;
case BlockerTargetOptions.LayerInChildren:
Renderer[] childRenderers = GetComponentsInChildren<Renderer>(true);
for (int k = 0; k < childRenderers.Length; k++) {
Renderer cr = childRenderers[k];
if (cr != null && ((1 << cr.gameObject.layer) & layerMask) != 0) {
renderers.Add(cr);
}
}
break;
}
if (!string.IsNullOrEmpty(nameFilter)) {
for (int k = renderers.Count - 1; k >= 0; k--) {
string objName = renderers[k].name;
if (useRegEx) {
if (!System.Text.RegularExpressions.Regex.IsMatch(objName, nameFilter)) {
renderers.RemoveAt(k);
}
} else if (!objName.Contains(nameFilter)) {
renderers.RemoveAt(k);
}
}
}
}
public void BuildCommandBuffer (CommandBuffer cmd, Material mat) {
if (renderers == null) return;
int renderersCount = renderers.Count;
for (int k=0;k<renderersCount;k++) {
Renderer r = renderers[k];
if (r == null || !r.enabled || !r.gameObject.activeInHierarchy) continue;
int submeshCount = r.sharedMaterials.Length;
for (int i = 0; i < submeshCount; i++) {
cmd.DrawRenderer(r, mat, i);
}
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e1449eaee17884bf3ad10a841cab981b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,278 @@
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Rendering;
namespace HighlightPlus {
public partial class HighlightEffect : MonoBehaviour {
static readonly List<HighlightSeeThroughOccluder> occluders = new List<HighlightSeeThroughOccluder>();
static readonly Dictionary<Camera, int> occludersFrameCount = new Dictionary<Camera, int>();
static Material fxMatSeeThroughOccluder, fxMatDepthWrite;
static RaycastHit[] hits;
/// <summary>
/// True if the see-through is cancelled by an occluder using raycast method
/// </summary>
public bool IsSeeThroughOccluded(Camera cam) {
if (rms == null) return false;
// Compute bounds
Bounds bounds = new Bounds();
for (int r = 0; r < rms.Length; r++) {
if (rms[r].renderer != null) {
if (bounds.size.x == 0) {
bounds = rms[r].renderer.bounds;
} else {
bounds.Encapsulate(rms[r].renderer.bounds);
}
}
}
Vector3 pos = bounds.center;
Vector3 camPos = cam.transform.position;
Vector3 offset = pos - camPos;
float maxDistance = Vector3.Distance(pos, camPos);
if (hits == null || hits.Length == 0) {
hits = new RaycastHit[64];
}
int occludersCount = occluders.Count;
int hitCount = Physics.BoxCastNonAlloc(pos - offset, bounds.extents * 0.9f, offset.normalized, hits, Quaternion.identity, maxDistance);
for (int k = 0; k < hitCount; k++) {
for (int j = 0; j < occludersCount; j++) {
if (hits[k].collider.transform == occluders[j].transform) {
return true;
}
}
}
return false;
}
public static void RegisterOccluder(HighlightSeeThroughOccluder occluder) {
if (!occluders.Contains(occluder)) {
occluders.Add(occluder);
}
}
public static void UnregisterOccluder(HighlightSeeThroughOccluder occluder) {
if (occluders.Contains(occluder)) {
occluders.Remove(occluder);
}
}
/// <summary>
/// Test see-through occluders.
/// </summary>
/// <param name="cam">The camera to be tested</param>
/// <returns>Returns true if there's no raycast-based occluder cancelling the see-through effect</returns>
public bool RenderSeeThroughOccluders(CommandBuffer cb, Camera cam) {
int occludersCount = occluders.Count;
if (occludersCount == 0 || rmsCount == 0) return true;
bool useRayCastCheck = false;
// Check if raycast method is needed
for (int k = 0; k < occludersCount; k++) {
HighlightSeeThroughOccluder occluder = occluders[k];
if (occluder == null || !occluder.isActiveAndEnabled) continue;
if (occluder.mode == OccluderMode.BlocksSeeThrough && occluder.detectionMethod == DetectionMethod.RayCast) {
useRayCastCheck = true;
break;
}
}
if (useRayCastCheck) {
if (IsSeeThroughOccluded(cam)) return false;
}
// do not render see-through occluders more than once this frame per camera (there can be many highlight effect scripts in the scene, we only need writing to stencil once)
int lastFrameCount;
occludersFrameCount.TryGetValue(cam, out lastFrameCount);
int currentFrameCount = Time.frameCount;
if (currentFrameCount == lastFrameCount) return true;
occludersFrameCount[cam] = currentFrameCount;
if (fxMatSeeThroughOccluder == null) {
InitMaterial(ref fxMatSeeThroughOccluder, ref shaderSeeThroughOccluder, "HighlightPlus/Geometry/SeeThroughOccluder");
if (fxMatSeeThroughOccluder == null) return true;
}
if (fxMatDepthWrite == null) {
InitMaterial(ref fxMatDepthWrite, ref shaderDepthWrite, "HighlightPlus/Geometry/JustDepth");
if (fxMatDepthWrite == null) return true;
}
for (int k = 0; k < occludersCount; k++) {
HighlightSeeThroughOccluder occluder = occluders[k];
if (occluder == null || !occluder.isActiveAndEnabled) continue;
if (occluder.detectionMethod == DetectionMethod.Stencil) {
if (occluder.meshData == null) continue;
int meshDataLength = occluder.meshData.Length;
// Per renderer
for (int m = 0; m < meshDataLength; m++) {
// Per submesh
Renderer renderer = occluder.meshData[m].renderer;
if (renderer.isVisible) {
for (int s = 0; s < occluder.meshData[m].subMeshCount; s++) {
cb.DrawRenderer(renderer, occluder.mode == OccluderMode.BlocksSeeThrough ? fxMatSeeThroughOccluder : fxMatDepthWrite, s);
}
}
}
}
}
return true;
}
bool CheckOcclusion(Camera cam) {
if (!perCameraOcclusionData.TryGetValue(cam, out PerCameraOcclusionData occlusionData)) {
occlusionData = new PerCameraOcclusionData();
perCameraOcclusionData[cam] = occlusionData;
}
float now = GetTime();
int frameCount = Time.frameCount; // ensure all cameras are checked this frame
if (now - occlusionData.checkLastTime < seeThroughOccluderCheckInterval && Application.isPlaying && occlusionData.occlusionRenderFrame != frameCount) return occlusionData.lastOcclusionTestResult;
occlusionData.cachedOccluders.Clear();
occlusionData.cachedOccluderCollider = null;
if (rms == null || rms.Length == 0 || rms[0].renderer == null) return false;
occlusionData.checkLastTime = now;
occlusionData.occlusionRenderFrame = frameCount;
Vector3 camPos = cam.transform.position;
if (seeThroughOccluderCheckIndividualObjects) {
for (int r = 0; r < rms.Length; r++) {
if (rms[r].renderer != null) {
Bounds bounds = rms[r].renderer.bounds;
Vector3 pos = bounds.center;
float maxDistance = Vector3.Distance(pos, camPos);
if (Physics.BoxCast(pos, bounds.extents * seeThroughOccluderThreshold, (camPos - pos).normalized, out RaycastHit hitInfo, Quaternion.identity, maxDistance, seeThroughOccluderMask)) {
occlusionData.cachedOccluderCollider = hitInfo.collider;
occlusionData.lastOcclusionTestResult = true;
return true;
}
}
}
occlusionData.lastOcclusionTestResult = false;
return false;
} else {
// Compute combined bounds
Bounds bounds = rms[0].renderer.bounds;
for (int r = 1; r < rms.Length; r++) {
if (rms[r].renderer != null) {
bounds.Encapsulate(rms[r].renderer.bounds);
}
}
Vector3 pos = bounds.center;
float maxDistance = Vector3.Distance(pos, camPos);
occlusionData.lastOcclusionTestResult = Physics.BoxCast(pos, bounds.extents * seeThroughOccluderThreshold, (camPos - pos).normalized, out RaycastHit hitInfo, Quaternion.identity, maxDistance, seeThroughOccluderMask);
occlusionData.cachedOccluderCollider = hitInfo.collider;
return occlusionData.lastOcclusionTestResult;
}
}
const int MAX_OCCLUDER_HITS = 50;
static RaycastHit[] occluderHits;
void AddWithoutRepetition(List<Renderer> target, List<Renderer> source, LayerMask layerMask) {
int sourceCount = source.Count;
for (int k = 0; k < sourceCount; k++) {
Renderer entry = source[k];
if (entry != null && !target.Contains(entry) && ValidRenderer(entry) && ((1<<entry.gameObject.layer) & layerMask) != 0) {
target.Add(entry);
}
}
}
void CheckOcclusionAccurate(CommandBuffer cbuf, Camera cam) {
if (!perCameraOcclusionData.TryGetValue(cam, out PerCameraOcclusionData occlusionData)) {
occlusionData = new PerCameraOcclusionData();
perCameraOcclusionData[cam] = occlusionData;
}
float now = GetTime();
int frameCount = Time.frameCount; // ensure all cameras are checked this frame
bool reuse = now - occlusionData.checkLastTime < seeThroughOccluderCheckInterval && Application.isPlaying && occlusionData.occlusionRenderFrame != frameCount;
if (!reuse) {
occlusionData.cachedOccluders.Clear();
occlusionData.cachedOccluderCollider = null;
if (rms == null || rms.Length == 0 || rms[0].renderer == null) return;
occlusionData.checkLastTime = now;
occlusionData.occlusionRenderFrame = frameCount;
Quaternion quaternionIdentity = Quaternion.identity;
Vector3 camPos = cam.transform.position;
if (occluderHits == null || occluderHits.Length < MAX_OCCLUDER_HITS) {
occluderHits = new RaycastHit[MAX_OCCLUDER_HITS];
}
if (seeThroughOccluderCheckIndividualObjects) {
for (int r = 0; r < rms.Length; r++) {
if (rms[r].renderer != null) {
Bounds bounds = rms[r].renderer.bounds;
Vector3 pos = bounds.center;
float maxDistance = Vector3.Distance(pos, camPos);
int numOccluderHits = Physics.BoxCastNonAlloc(pos, bounds.extents * seeThroughOccluderThreshold, (camPos - pos).normalized, occluderHits, quaternionIdentity, maxDistance, seeThroughOccluderMask);
for (int k = 0; k < numOccluderHits; k++) {
occluderHits[k].collider.transform.root.GetComponentsInChildren(tempRR);
AddWithoutRepetition(occlusionData.cachedOccluders, tempRR, seeThroughOccluderMask);
}
}
}
} else {
// Compute combined bounds
Bounds bounds = rms[0].renderer.bounds;
for (int r = 1; r < rms.Length; r++) {
if (rms[r].renderer != null) {
bounds.Encapsulate(rms[r].renderer.bounds);
}
}
Vector3 pos = bounds.center;
float maxDistance = Vector3.Distance(pos, camPos);
int numOccluderHits = Physics.BoxCastNonAlloc(pos, bounds.extents * seeThroughOccluderThreshold, (camPos - pos).normalized, occluderHits, quaternionIdentity, maxDistance, seeThroughOccluderMask);
for (int k = 0; k < numOccluderHits; k++) {
occluderHits[k].collider.transform.root.GetComponentsInChildren(tempRR);
AddWithoutRepetition(occlusionData.cachedOccluders, tempRR, seeThroughOccluderMask);
}
}
}
// render occluders
int occluderRenderersCount = occlusionData.cachedOccluders.Count;
if (occluderRenderersCount > 0) {
for (int k = 0; k < occluderRenderersCount; k++) {
Renderer r = occlusionData.cachedOccluders[k];
if (r != null) {
cbuf.DrawRenderer(r, fxMatSeeThroughMask);
}
}
}
}
public void GetOccluders(Camera camera, List<Transform> occluders) {
occluders.Clear();
if (perCameraOcclusionData.TryGetValue(camera, out PerCameraOcclusionData occlusionData)) {
if (occlusionData.cachedOccluderCollider != null) {
occluders.Add(occlusionData.cachedOccluderCollider.transform);
return;
}
foreach (Renderer r in occlusionData.cachedOccluders) {
if (r != null) {
occluders.Add(r.transform);
}
}
}
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: d0bc1f04199a64e66ae9630062b3a6ad
timeCreated: 1542876337
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,330 @@
using System;
using TMPro;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.UI;
namespace HighlightPlus {
[ExecuteAlways]
public partial class HighlightLabel : MonoBehaviour {
public Camera cam;
[NonSerialized]
public Transform target;
[NonSerialized]
public Vector3 localPosition;
[NonSerialized]
public Vector3 worldOffset;
[NonSerialized]
public Vector2 viewportOffset;
[NonSerialized]
public bool isVisible;
[NonSerialized]
public LabelAlignment labelAlignment = LabelAlignment.Auto;
[NonSerialized]
public bool labelRelativeAlignment;
[NonSerialized]
public Transform labelAlignmentTransform;
public GameObject labelPrefab;
internal bool isPooled;
[NonSerialized]
public bool isWorldSpace;
[NonSerialized]
public float worldSpaceScale = 0.01f;
static Material uiAlwaysOnTopMaterial;
static int zTestModeID;
Canvas canvas;
Image line;
TextMeshProUGUI text;
RectTransform panel;
CanvasGroup canvasGroup;
[NonSerialized]
public float labelMaxDistance = 250f;
[NonSerialized]
public float labelFadeStartDistance = 200f;
[NonSerialized]
public bool labelScaleByDistance;
[NonSerialized]
public float labelScaleMin = 1f;
[NonSerialized]
public float labelScaleMax = 1f;
[NonSerialized]
public float highlightAlpha = 1f;
public virtual float alpha {
get {
return highlightAlpha;
}
set {
highlightAlpha = value;
}
}
public virtual Color textColor {
get {
return text?.color ?? Color.white;
}
set {
if (text != null) {
text.color = value;
}
}
}
public virtual string textLabel {
get {
return text?.text ?? "";
}
set {
if (text != null) {
text.text = value;
}
}
}
public virtual float textSize {
get {
return text?.fontSize ?? 14;
}
set {
if (text != null) {
text.fontSize = value;
}
}
}
public virtual float width {
get {
return text?.rectTransform.sizeDelta.x ?? 200;
}
set {
if (text == null) return;
if (text.rectTransform != null) {
Vector2 currentSize = text.rectTransform.sizeDelta;
if (currentSize.x != value) {
text.rectTransform.sizeDelta = new Vector2(value, currentSize.y);
}
}
RectTransform panelRectTransform = panel.GetComponent<RectTransform>();
if (panelRectTransform != null) {
Vector2 currentSize = panelRectTransform.sizeDelta;
if (currentSize.x != value) {
panelRectTransform.sizeDelta = new Vector2(value, currentSize.y);
}
}
}
}
void Awake () {
canvas = GetComponent<Canvas>();
line = GetComponentInChildren<Image>();
text = GetComponentInChildren<TextMeshProUGUI>();
panel = transform.GetChild(0).GetComponentInChildren<RectTransform>();
canvasGroup = GetComponent<CanvasGroup>();
if (zTestModeID == 0) {
zTestModeID = Shader.PropertyToID("_ZTestMode");
}
}
/// <summary>
/// Configures the label Canvas render mode for screen space or world space rendering.
/// </summary>
public void ConfigureCanvas(bool worldSpace) {
if (isWorldSpace == worldSpace) return;
isWorldSpace = worldSpace;
if (canvas == null) return;
if (worldSpace) {
canvas.renderMode = RenderMode.WorldSpace;
canvas.worldCamera = cam;
SetAlwaysOnTop(true);
} else {
canvas.renderMode = RenderMode.ScreenSpaceOverlay;
SetAlwaysOnTop(false);
}
}
void SetAlwaysOnTop(bool enabled) {
// UI Image (the connecting line)
if (line != null) {
if (enabled) {
if (uiAlwaysOnTopMaterial == null) {
uiAlwaysOnTopMaterial = new Material(Shader.Find("UI/Default"));
uiAlwaysOnTopMaterial.SetFloat(ShaderParams.ZTest, (float)CompareFunction.Always);
}
line.material = uiAlwaysOnTopMaterial;
} else {
line.material = null;
}
}
// TextMeshPro text
if (text != null) {
text.fontMaterial.SetFloat(zTestModeID, (float)(enabled ? CompareFunction.Always : CompareFunction.LessEqual));
}
}
/// <summary>
/// Return the label to the pool
/// </summary>
public virtual void ReturnToPool () {
if (!isPooled) return;
gameObject.SetActive(false);
HighlightLabelPoolManager.ReturnToPool(this);
}
public virtual void SetPosition(Transform target, Vector3 localPosition, Vector3 worldOffset, Vector2 viewportOffset = default) {
this.target = target;
this.localPosition = localPosition;
this.worldOffset = worldOffset;
this.viewportOffset = viewportOffset;
}
public virtual void UpdatePosition () {
if (panel == null || text == null) return;
if (cam == null) {
cam = Camera.main;
if (cam == null) return;
}
if (target == null) return;
Vector3 worldPosition = target.TransformPoint(localPosition);
Vector3 worldWithOffset = worldPosition + worldOffset;
// Distance-based visibility & scaling (common to both modes)
float distanceToCam = Vector3.Distance(cam.transform.position, worldWithOffset);
float visibleAlpha = 1f;
if (labelMaxDistance > 0f && distanceToCam > labelMaxDistance) {
if (canvasGroup != null) canvasGroup.alpha = 0f;
return;
}
if (labelFadeStartDistance > 0f && labelMaxDistance > labelFadeStartDistance && distanceToCam > labelFadeStartDistance) {
float t = (distanceToCam - labelFadeStartDistance) / (labelMaxDistance - labelFadeStartDistance);
visibleAlpha = Mathf.Clamp01(1f - t);
}
if (canvasGroup != null) {
canvasGroup.alpha = highlightAlpha * visibleAlpha;
}
if (isWorldSpace) {
UpdatePositionWorldSpace(worldWithOffset, distanceToCam);
} else {
UpdatePositionScreenSpace(worldWithOffset, distanceToCam);
}
}
void UpdatePositionWorldSpace(Vector3 worldWithOffset, float distanceToCam) {
// Position canvas in world space
transform.position = worldWithOffset;
// Billboard: face camera
transform.rotation = cam.transform.rotation;
// Scale: base worldSpaceScale + optional distance scaling
float scale = worldSpaceScale;
if (labelScaleByDistance && labelMaxDistance > 0f) {
float tScale = Mathf.Clamp01(distanceToCam / labelMaxDistance);
scale *= Mathf.Lerp(labelScaleMax, labelScaleMin, tScale);
}
transform.localScale = new Vector3(scale, scale, scale);
// Panel keeps identity transform in world space mode
panel.localScale = Vector3.one;
panel.localPosition = Vector3.zero;
}
void UpdatePositionScreenSpace(Vector3 worldWithOffset, float distanceToCam) {
// If anchor point is outside of view, hide label without changing active state
Vector3 vp = cam.WorldToViewportPoint(worldWithOffset);
bool onScreen = vp.z > 0f && vp.x >= 0f && vp.x <= 1f && vp.y >= 0f && vp.y <= 1f;
if (!onScreen) {
if (canvasGroup != null) {
canvasGroup.alpha = 0f;
}
return;
}
if (labelScaleByDistance && labelMaxDistance > 0f) {
float tScale = Mathf.Clamp01(distanceToCam / labelMaxDistance);
float scale = Mathf.Lerp(labelScaleMax, labelScaleMin, tScale);
panel.localScale = new Vector3(scale, scale, 1f);
} else {
panel.localScale = Vector3.one;
}
Vector3 screenPosition = cam.WorldToScreenPoint(worldWithOffset);
// Apply viewport offset in screen space (normalized -1 to 1 range)
screenPosition.x += viewportOffset.x * Screen.width;
screenPosition.y += viewportOffset.y * Screen.height;
panel.position = screenPosition;
bool flip = false;
if (labelRelativeAlignment && labelAlignmentTransform != null) {
Vector3 dirToCam = (cam.transform.position - labelAlignmentTransform.position).normalized;
float dot = Vector3.Dot(labelAlignmentTransform.forward, dirToCam);
flip = dot > 0;
}
if (labelAlignment == LabelAlignment.Left) {
panel.pivot = flip ? Vector2.zero : Vector2.right;
text.alignment = flip ? TextAlignmentOptions.BottomRight : TextAlignmentOptions.BottomLeft;
} else if (labelAlignment == LabelAlignment.Right) {
panel.pivot = flip ? Vector2.right : Vector2.zero;
text.alignment = flip ? TextAlignmentOptions.BottomLeft : TextAlignmentOptions.BottomRight;
} else if (labelAlignment == LabelAlignment.Auto && panel.position.x + width * 2f > cam.pixelWidth * 0.95f) {
panel.pivot = Vector2.right;
text.alignment = TextAlignmentOptions.BottomLeft;
} else {
panel.pivot = Vector2.zero;
text.alignment = TextAlignmentOptions.BottomRight;
}
}
/// <summary>
/// Show the label
/// </summary>
public virtual void Show () {
isVisible = true;
#if UNITY_EDITOR
if (!Application.isPlaying) {
HighlightLabelPoolManager.Refresh();
}
#endif
}
/// <summary>
/// Hide the label
/// </summary>
public virtual void Hide () {
if (this == null) return;
gameObject.SetActive(false);
isVisible = false;
}
/// <summary>
/// Hide & destroy the label
/// </summary>
public virtual void Release () {
if (this == null) return;
Hide();
if (isPooled) {
ReturnToPool();
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0e63182d0d6a34016b819144ebdd9188
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,135 @@
using System.Collections.Generic;
using UnityEngine;
namespace HighlightPlus {
[ExecuteAlways]
[DefaultExecutionOrder(-100)]
public class HighlightLabelPoolManager : MonoBehaviour {
private static HighlightLabelPoolManager instance;
private static readonly Dictionary<GameObject, Queue<HighlightLabel>> labelPools = new Dictionary<GameObject, Queue<HighlightLabel>>();
private static readonly HashSet<HighlightLabel> activeLabels = new HashSet<HighlightLabel>();
private static readonly int initialPoolSize = 5;
const string LABEL_INSTANCE_NAME = "Highlight Plus Label";
const string LABEL_POOL_NAME = "Highlight Plus Label Pool Manager";
[RuntimeInitializeOnLoadMethod]
static void DomainReloadDisabledSupport () {
DestroySceneLabels();
}
void OnEnable () {
if (instance == null) {
instance = this;
} else if (instance != this) {
DestroyImmediate(gameObject);
}
ClearPools();
}
void OnDestroy () {
if (instance == this) {
instance = null;
}
labelPools.Clear();
activeLabels.Clear();
}
public static void DestroySceneLabels () {
if (instance != null) {
DestroyImmediate(instance.gameObject);
instance = null;
}
ClearPools();
}
static void ClearPools () {
if (instance != null) {
for (int i = instance.transform.childCount - 1; i >= 0; i--) {
Transform child = instance.transform.GetChild(i);
if (child != null) {
DestroyImmediate(child.gameObject);
}
}
}
labelPools.Clear();
activeLabels.Clear();
}
private static void InitializePool (GameObject prefab) {
if (!labelPools.ContainsKey(prefab)) {
labelPools[prefab] = new Queue<HighlightLabel>();
for (int i = 0; i < initialPoolSize; i++) {
CreatePooledLabel(prefab);
}
}
}
private static HighlightLabel CreatePooledLabel (GameObject prefab) {
GameObject labelInstanceGO = Instantiate(prefab);
labelInstanceGO.name = LABEL_INSTANCE_NAME;
labelInstanceGO.hideFlags = HideFlags.DontSave;
labelInstanceGO.transform.SetParent(instance.transform, false);
HighlightLabel labelInstance = labelInstanceGO.GetComponentInChildren<HighlightLabel>();
labelInstance.labelPrefab = prefab;
labelInstance.isPooled = true;
labelInstanceGO.SetActive(false);
labelPools[prefab].Enqueue(labelInstance);
return labelInstance;
}
public static HighlightLabel GetLabelInstance (GameObject prefab) {
if (instance == null) {
GameObject go = new GameObject(LABEL_POOL_NAME);
go.hideFlags = HideFlags.DontSave;
instance = go.AddComponent<HighlightLabelPoolManager>();
}
// Initialize pool if needed
InitializePool(prefab);
// Try to get from pool
HighlightLabel labelInstance = null;
while (labelInstance == null && labelPools[prefab].Count > 0) {
labelInstance = labelPools[prefab].Dequeue();
}
if (labelInstance != null) {
activeLabels.Add(labelInstance);
return labelInstance;
}
// Create new instance if pool is empty
HighlightLabel newLabel = CreatePooledLabel(prefab);
activeLabels.Add(newLabel);
return newLabel;
}
public static void ReturnToPool (HighlightLabel label) {
if (label.labelPrefab != null && labelPools.ContainsKey(label.labelPrefab)) {
labelPools[label.labelPrefab].Enqueue(label);
activeLabels.Remove(label);
}
}
public static void Refresh () {
if (instance == null) return;
instance.LateUpdate();
}
void LateUpdate () {
foreach (var label in activeLabels) {
if (label == null) continue;
if (label.isVisible) {
label.UpdatePosition();
if (!label.gameObject.activeSelf) {
label.gameObject.SetActive(true);
}
}
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a7d255a67ae894a2c87031baca521c15
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,590 @@
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
namespace HighlightPlus {
[RequireComponent(typeof(HighlightEffect))]
[DefaultExecutionOrder(100)]
[HelpURL("https://kronnect.com/docs/highlight-plus/")]
public class HighlightManager : MonoBehaviour {
[Tooltip("Enables highlight when pointer is over this object.")]
[SerializeField]
bool _highlightOnHover = true;
public bool highlightOnHover {
get { return _highlightOnHover; }
set {
if (_highlightOnHover != value) {
_highlightOnHover = value;
if (!_highlightOnHover) {
if (currentEffect != null) {
Highlight(false);
}
}
}
}
}
public LayerMask layerMask = -1;
public Camera raycastCamera;
public RayCastSource raycastSource = RayCastSource.MousePosition;
[Tooltip("Objects in this layer mask will block the highlight if they are between the camera and the target.")]
public LayerMask blockingLayerMask = -1;
[Tooltip("Minimum distance for target.")]
public float minDistance;
[Tooltip("Maximum distance for target. 0 = infinity")]
public float maxDistance;
[Tooltip("Blocks interaction if pointer is over an UI element")]
public bool respectUI = true;
[Tooltip("Unhighlights the object when the pointer is over a UI element")]
public bool unhighlightOnUI;
[Tooltip("If the object will be selected by clicking with mouse or tapping on it.")]
public bool selectOnClick;
[Tooltip("Optional profile for objects selected by clicking on them")]
public HighlightProfile selectedProfile;
[Tooltip("Profile to use when object is selected and highlighted.")]
public HighlightProfile selectedAndHighlightedProfile;
[Tooltip("Automatically deselects other previously selected objects")]
public bool singleSelection;
[Tooltip("Toggles selection on/off when clicking object")]
public bool toggle;
[Tooltip("Keeps current selection when clicking outside of any selectable object")]
public bool keepSelection = true;
HighlightEffect baseEffect, currentEffect;
Transform currentObject;
RaycastHit2D[] hitInfo2D;
static RaycastHit blockingHit;
readonly List<RaycastResult> cachedRaycastResults = new List<RaycastResult>();
PointerEventData cachedPointerEventData;
EventSystem cachedEventSystem;
public readonly static List<HighlightEffect> selectedObjects = new List<HighlightEffect>();
public event OnObjectSelectionEvent OnObjectSelected;
public event OnObjectSelectionEvent OnObjectUnSelected;
public event OnObjectHighlightEvent OnObjectHighlightStart;
public event OnObjectHighlightEvent OnObjectHighlightStay;
public event OnObjectHighlightEvent OnObjectHighlightEnd;
public event OnObjectClickEvent OnObjectClicked;
public static int lastTriggerFrame;
static HighlightManager _instance;
public static HighlightManager instance {
get {
if (_instance == null) {
_instance = Misc.FindObjectOfType<HighlightManager>();
}
return _instance;
}
}
[RuntimeInitializeOnLoadMethod]
static void DomainReloadDisabledSupport () {
selectedObjects.Clear();
lastTriggerFrame = 0;
_instance = null;
}
void OnEnable () {
currentObject = null;
currentEffect = null;
if (baseEffect == null) {
if (!TryGetComponent(out baseEffect)) {
baseEffect = gameObject.AddComponent<HighlightEffect>();
}
}
if (raycastCamera == null) {
raycastCamera = GetCamera();
if (raycastCamera == null) {
Debug.LogError("Highlight Manager: no camera found!");
}
}
hitInfo2D = new RaycastHit2D[1];
InputProxy.Init();
}
void OnDisable () {
SwitchesObject(null);
internal_DeselectAll();
}
void Update () {
if (raycastCamera == null)
return;
#if ENABLE_INPUT_SYSTEM && !ENABLE_LEGACY_INPUT_MANAGER
if (respectUI) {
EventSystem es = EventSystem.current;
if (es == null) {
es = CreateEventSystem();
}
cachedRaycastResults.Clear();
if (cachedPointerEventData == null || cachedEventSystem != es) {
cachedPointerEventData = new PointerEventData(es);
cachedEventSystem = es;
}
Vector3 cameraPos = raycastCamera.transform.position;
if (raycastSource == RayCastSource.MousePosition) {
cachedPointerEventData.position = InputProxy.mousePosition;
} else {
cachedPointerEventData.position = new Vector2(raycastCamera.pixelWidth * 0.5f, raycastCamera.pixelHeight * 0.5f);
}
es.RaycastAll(cachedPointerEventData, cachedRaycastResults);
int hitCount = cachedRaycastResults.Count;
// check UI blocker
bool blocked = false;
for (int k = 0; k < hitCount; k++) {
RaycastResult rr = cachedRaycastResults[k];
if (rr.module is UnityEngine.UI.GraphicRaycaster) {
blocked = true;
break;
}
}
if (blocked) {
if (unhighlightOnUI && currentEffect != null && currentEffect.highlighted) {
currentEffect.SetHighlighted(false);
}
return;
}
// compute blocking ray for distance checks
Ray blockingRay;
if (raycastSource == RayCastSource.MousePosition) {
blockingRay = raycastCamera.ScreenPointToRay(InputProxy.mousePosition);
} else {
blockingRay = new Ray(raycastCamera.transform.position, raycastCamera.transform.forward);
}
float uiBlockingDistance = GetBlockingDistance(blockingRay, maxDistance > 0 ? maxDistance : raycastCamera.farClipPlane);
// look for our gameobject
for (int k = 0; k < hitCount; k++) {
RaycastResult rr = cachedRaycastResults[k];
float distance = Vector3.Distance(rr.worldPosition, cameraPos);
if (distance < minDistance || (maxDistance > 0 && distance > maxDistance) || distance > uiBlockingDistance) continue;
GameObject theGameObject = rr.gameObject;
if ((layerMask & (1 << rr.gameObject.layer)) == 0) continue;
// is this object state controller by Highlight Trigger?
HighlightTrigger trigger = theGameObject.GetComponent<HighlightTrigger>();
if (trigger != null) return;
UpdateHitPosition(theGameObject.transform, rr.worldPosition, Misc.vector3Zero);
// Toggles selection
Transform t = theGameObject.transform;
if (InputProxy.GetMouseButtonDown(0)) {
if (selectOnClick) {
ToggleSelection(t, !toggle);
}
} else
// Check if the object has a Highlight Effect
if (t != currentObject) {
SwitchesObject(t);
}
}
}
// if not blocked by UI and no hit found, fallback to raycast (required if no PhysicsRaycaster is present on the camera)
#endif
Ray ray;
{
#if !(ENABLE_INPUT_SYSTEM && !ENABLE_LEGACY_INPUT_MANAGER)
Vector2 screenPos = raycastSource == RayCastSource.MousePosition ? (Vector2)InputProxy.mousePosition : new Vector2(raycastCamera.pixelWidth * 0.5f, raycastCamera.pixelHeight * 0.5f);
if (!CanInteractAt(screenPos)) {
if (unhighlightOnUI && currentEffect != null && currentEffect.highlighted) {
currentEffect.SetHighlighted(false);
}
return;
}
#endif
if (raycastSource == RayCastSource.MousePosition) {
ray = raycastCamera.ScreenPointToRay(InputProxy.mousePosition);
}
else {
ray = new Ray(raycastCamera.transform.position, raycastCamera.transform.forward);
}
}
VerifyHighlightStay();
float blockingDistance = GetBlockingDistance(ray, maxDistance > 0 ? maxDistance : raycastCamera.farClipPlane);
RaycastHit hitInfo;
if (Physics.Raycast(ray, out hitInfo, maxDistance > 0 ? maxDistance : raycastCamera.farClipPlane, layerMask) && Vector3.Distance(hitInfo.point, ray.origin) >= minDistance && hitInfo.distance <= blockingDistance) {
Transform t = hitInfo.collider.transform;
// is this object state controller by Highlight Trigger?
if (t.TryGetComponent(out HighlightTrigger _)) {
return;
}
// Toggles selection
if (InputProxy.GetMouseButtonDown(0)) {
if (selectOnClick) {
ToggleSelection(t, !toggle);
}
}
else
// Check if the object has a Highlight Effect
if (t != currentObject) {
SwitchesObject(t);
}
UpdateHitPosition(t, hitInfo.point, hitInfo.normal);
return;
}
else // check sprites
if (Physics2D.GetRayIntersectionNonAlloc(ray, hitInfo2D, maxDistance > 0 ? maxDistance : raycastCamera.farClipPlane, layerMask) > 0 && Vector3.Distance(hitInfo2D[0].point, ray.origin) >= minDistance && Vector3.Distance(hitInfo2D[0].point, ray.origin) <= blockingDistance) {
Transform t = hitInfo2D[0].collider.transform;
// is this object state controller by Highlight Trigger?
if (t.TryGetComponent(out HighlightTrigger _)) {
return;
}
// Toggles selection
if (InputProxy.GetMouseButtonDown(0)) {
if (selectOnClick) {
ToggleSelection(t, !toggle);
}
}
else
// Check if the object has a Highlight Effect
if (t != currentObject) {
SwitchesObject(t);
}
UpdateHitPosition(t, hitInfo2D[0].point, Misc.vector3Zero);
return;
}
// no hit
if (selectOnClick && !keepSelection && InputProxy.GetMouseButtonDown(0) && lastTriggerFrame < Time.frameCount) {
internal_DeselectAll();
}
SwitchesObject(null);
}
#if ENABLE_INPUT_SYSTEM && !ENABLE_LEGACY_INPUT_MANAGER
EventSystem CreateEventSystem() {
GameObject eo = new GameObject("Event System created by Highlight Plus", typeof(EventSystem), typeof(UnityEngine.InputSystem.UI.InputSystemUIInputModule));
return eo.GetComponent<EventSystem>();
}
#endif
void VerifyHighlightStay () {
if (currentObject == null || currentEffect == null || !currentEffect.highlighted) return;
if (OnObjectHighlightStay != null && !OnObjectHighlightStay(currentObject.gameObject)) {
SwitchesObject(null);
}
}
void SwitchesObject (Transform newObject) {
if (currentEffect != null) {
if (highlightOnHover) {
Highlight(false);
}
currentEffect = null;
}
currentObject = newObject;
if (newObject == null) return;
if (newObject.TryGetComponent(out HighlightTrigger ht) && ht.enabled) {
return;
}
if (!newObject.TryGetComponent(out HighlightEffect otherEffect)) {
// Check if there's a parent highlight effect that includes this object
HighlightEffect parentEffect = newObject.GetComponentInParent<HighlightEffect>();
if (parentEffect != null && parentEffect.Includes(newObject)) {
currentEffect = parentEffect;
if (highlightOnHover) {
Highlight(true);
}
return;
}
}
currentEffect = otherEffect != null ? otherEffect : baseEffect;
baseEffect.enabled = currentEffect == baseEffect;
currentEffect.SetTarget(currentObject);
if (highlightOnHover) {
Highlight(true);
}
}
void UpdateHitPosition (Transform target, Vector3 positionWS, Vector3 normalWS) {
if (currentEffect == null) return;
Vector3 localPosition = target.InverseTransformPoint(positionWS);
currentEffect.SetHitPosition(target, localPosition, Misc.vector3Zero, normalWS);
if (InputProxy.GetMouseButtonDown(0) && OnObjectClicked != null) {
OnObjectClicked(target.gameObject, positionWS, normalWS);
}
}
#if !(ENABLE_INPUT_SYSTEM && !ENABLE_LEGACY_INPUT_MANAGER)
bool CanInteractAt (Vector2 screenPosition) {
if (!respectUI) return true;
EventSystem es = EventSystem.current;
if (es == null) return true;
if (Application.isMobilePlatform && InputProxy.touchCount > 0) {
if (es.IsPointerOverGameObject(InputProxy.GetFingerIdFromTouch(0))) {
return false;
}
if (raycastSource == RayCastSource.CameraDirection) {
return !IsUIAtScreenPosition(es, screenPosition);
}
return true;
}
if (raycastSource == RayCastSource.MousePosition) {
return !es.IsPointerOverGameObject(-1);
}
return !IsUIAtScreenPosition(es, screenPosition);
}
bool IsUIAtScreenPosition (EventSystem es, Vector2 screenPosition) {
cachedRaycastResults.Clear();
if (cachedPointerEventData == null || cachedEventSystem != es) {
cachedPointerEventData = new PointerEventData(es);
cachedEventSystem = es;
}
cachedPointerEventData.position = screenPosition;
es.RaycastAll(cachedPointerEventData, cachedRaycastResults);
int hitCount = cachedRaycastResults.Count;
for (int k = 0; k < hitCount; k++) {
RaycastResult rr = cachedRaycastResults[k];
if (rr.module is UnityEngine.UI.GraphicRaycaster) {
return true;
}
}
return false;
}
#endif
float GetBlockingDistance (Ray ray, float maxRayDistance) {
if (blockingLayerMask == 0) return float.MaxValue;
if (Physics.Raycast(ray, out blockingHit, maxRayDistance, blockingLayerMask)) {
return blockingHit.distance + 0.01f;
}
return float.MaxValue;
}
void ToggleSelection (Transform t, bool forceSelection) {
if (t == null) return;
// We need a highlight effect on each selected object
HighlightEffect hb = t.GetComponent<HighlightEffect>();
if (hb == null) {
HighlightEffect parentEffect = t.GetComponentInParent<HighlightEffect>();
if (parentEffect != null && parentEffect.Includes(t)) {
hb = parentEffect;
if (hb.previousSettings == null) {
hb.previousSettings = ScriptableObject.CreateInstance<HighlightProfile>();
}
hb.previousSettings.Save(hb);
}
else {
hb = t.gameObject.AddComponent<HighlightEffect>();
hb.camerasLayerMask = baseEffect.camerasLayerMask;
hb.ignoreObjectVisibility = baseEffect.ignoreObjectVisibility;
hb.reflectionProbes = baseEffect.reflectionProbes;
hb.normalsOption = baseEffect.normalsOption;
hb.optimizeSkinnedMesh = baseEffect.optimizeSkinnedMesh;
hb.GPUInstancing = baseEffect.GPUInstancing;
hb.previousSettings = ScriptableObject.CreateInstance<HighlightProfile>();
// copy default highlight effect settings from this manager into this highlight plus component
hb.previousSettings.Save(baseEffect);
hb.previousSettings.Load(hb);
}
}
bool currentState = hb.isSelected;
bool newState = forceSelection ? true : !currentState;
if (newState == currentState) return;
if (newState) {
if (OnObjectSelected != null && !OnObjectSelected(t.gameObject)) return;
}
else {
if (OnObjectUnSelected != null && !OnObjectUnSelected(t.gameObject)) return;
}
if (singleSelection) {
internal_DeselectAll();
}
currentEffect = hb;
currentEffect.isSelected = newState;
baseEffect.enabled = false;
if (currentEffect.isSelected) {
if (currentEffect.previousSettings == null) {
currentEffect.previousSettings = ScriptableObject.CreateInstance<HighlightProfile>();
}
hb.previousSettings.Save(hb);
if (!selectedObjects.Contains(currentEffect)) {
selectedObjects.Add(currentEffect);
}
}
else {
if (currentEffect.previousSettings != null) {
currentEffect.previousSettings.Load(hb);
}
if (selectedObjects.Contains(currentEffect)) {
selectedObjects.Remove(currentEffect);
}
}
Highlight(newState);
}
void Highlight (bool state) {
if (currentEffect == null) return;
if (state) {
if (!currentEffect.highlighted) {
if (OnObjectHighlightStart != null && currentEffect.target != null) {
if (!OnObjectHighlightStart(currentEffect.target.gameObject)) {
currentObject = null; // allows re-checking so it keeps checking with the event
return;
}
}
}
}
else {
if (currentEffect.highlighted) {
if (OnObjectHighlightEnd != null && currentEffect.target != null) {
OnObjectHighlightEnd(currentEffect.target.gameObject);
}
}
}
if (selectOnClick || currentEffect.isSelected) {
if (currentEffect.isSelected) {
if (state && selectedAndHighlightedProfile != null) {
selectedAndHighlightedProfile.Load(currentEffect);
}
else if (selectedProfile != null) {
selectedProfile.Load(currentEffect);
}
else {
currentEffect.previousSettings.Load(currentEffect);
}
if (currentEffect.highlighted && currentEffect.fading != HighlightEffect.FadingState.FadingOut) {
currentEffect.UpdateMaterialProperties();
}
else {
currentEffect.SetHighlighted(true);
}
return;
}
else if (!highlightOnHover) {
currentEffect.SetHighlighted(false);
return;
}
}
currentEffect.SetHighlighted(state);
}
public static Camera GetCamera () {
Camera raycastCamera = Camera.main;
if (raycastCamera == null) {
raycastCamera = Misc.FindObjectOfType<Camera>();
}
return raycastCamera;
}
void internal_DeselectAll () {
int count = selectedObjects.Count;
for (int k = 0; k < count; k++) {
HighlightEffect hb = selectedObjects[k];
if (hb != null && hb.gameObject != null) {
if (OnObjectUnSelected != null) {
if (!OnObjectUnSelected(hb.gameObject)) continue;
}
hb.RestorePreviousHighlightEffectSettings();
hb.isSelected = false;
hb.SetHighlighted(false);
}
}
selectedObjects.Clear();
}
/// <summary>
/// Deselects any selected object in the scene
/// </summary>
public static void DeselectAll () {
if (instance != null) {
_instance.internal_DeselectAll();
return;
}
foreach (HighlightEffect hb in selectedObjects) {
if (hb != null && hb.gameObject != null) {
hb.RestorePreviousHighlightEffectSettings();
hb.isSelected = false;
hb.SetHighlighted(false);
}
}
selectedObjects.Clear();
}
/// <summary>
/// Unselects all objects in the scene
/// </summary>
public void UnselectObjects () {
DeselectAll();
}
/// <summary>
/// Manually causes highlight manager to select an object
/// </summary>
public void SelectObject (Transform t) {
ToggleSelection(t, true);
}
/// <summary>
/// Manually causes highlight manager to select multiple objects
/// </summary>
/// <param name="objects">Array of objects to select</param>
public void SelectObjects (Transform[] objects) {
foreach (var obj in objects) {
SelectObject(obj);
}
}
public void SelectObjects (List<Transform> objects) {
foreach (var obj in objects) {
SelectObject(obj);
}
}
/// <summary>
/// Manually causes highlight manager to toggle selection on an object
/// </summary>
public void ToggleObject (Transform t) {
ToggleSelection(t, false);
}
/// <summary>
/// Manually causes highlight manager to unselect an object
/// </summary>
public void UnselectObject (Transform t) {
if (t == null) return;
HighlightEffect hb = t.GetComponent<HighlightEffect>();
if (hb == null) return;
if (hb.isSelected) {
ToggleSelection(t, false);
}
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: af4d46fd89b9543e5be2358ac0c9ced0
timeCreated: 1542876337
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,359 @@
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Experimental.Rendering;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
#if UNITY_2023_3_OR_NEWER
using UnityEngine.Rendering.RenderGraphModule;
#endif
namespace HighlightPlus {
public class HighlightPlusRenderPassFeature : ScriptableRendererFeature {
class HighlightPass : ScriptableRenderPass {
class PassData {
public Camera camera;
#if UNITY_2022_1_OR_NEWER
public RTHandle colorTarget, depthTarget;
#else
public RenderTargetIdentifier colorTarget, depthTarget;
#endif
#if UNITY_2023_3_OR_NEWER
public TextureHandle colorTexture, depthTexture;
#endif
public bool clearStencil;
public CommandBuffer cmd;
}
readonly PassData passData = new PassData();
// far objects render first
class DistanceComparer : IComparer<HighlightEffect> {
public Vector3 camPos;
public int Compare (HighlightEffect e1, HighlightEffect e2) {
if (e1.sortingPriority < e2.sortingPriority) return -1;
if (e1.sortingPriority > e2.sortingPriority) return 1;
Vector3 e1Pos = e1.transform.position;
float dx1 = e1Pos.x - camPos.x;
float dy1 = e1Pos.y - camPos.y;
float dz1 = e1Pos.z - camPos.z;
float distE1 = dx1 * dx1 + dy1 * dy1 + dz1 * dz1 + e1.sortingOffset;
Vector3 e2Pos = e2.transform.position;
float dx2 = e2Pos.x - camPos.x;
float dy2 = e2Pos.y - camPos.y;
float dz2 = e2Pos.z - camPos.z;
float distE2 = dx2 * dx2 + dy2 * dy2 + dz2 * dz2 + e2.sortingOffset;
if (distE1 > distE2) return -1;
if (distE1 < distE2) return 1;
return 0;
}
}
public bool usesCameraOverlay;
ScriptableRenderer renderer;
RenderTextureDescriptor cameraTextureDescriptor;
static DistanceComparer effectDistanceComparer = new DistanceComparer();
static Comparison<HighlightEffect> cachedEffectComparisonDelegate;
bool clearStencil;
static RenderTextureDescriptor sourceDesc;
static Material blockerOutlineAndGlowMat, blockerOverlayMat, blockerAllMat;
public void Setup (HighlightPlusRenderPassFeature passFeature, ScriptableRenderer renderer) {
this.renderPassEvent = passFeature.renderPassEvent;
this.clearStencil = passFeature.clearStencil;
this.renderer = renderer;
ConfigureInput(ScriptableRenderPassInput.Depth);
}
#if !UNITY_6000_4_OR_NEWER
#if UNITY_2023_3_OR_NEWER
[Obsolete]
#endif
public override void Configure (CommandBuffer cmd, RenderTextureDescriptor cameraTextureDescriptor) {
this.cameraTextureDescriptor = cameraTextureDescriptor;
}
#if UNITY_2023_3_OR_NEWER
[Obsolete]
#endif
public override void Execute (ScriptableRenderContext context, ref RenderingData renderingData) {
#if UNITY_2022_1_OR_NEWER
RTHandle cameraColorTarget = renderer.cameraColorTargetHandle;
RTHandle cameraDepthTarget = renderer.cameraDepthTargetHandle;
#else
RenderTargetIdentifier cameraColorTarget = renderer.cameraColorTarget;
RenderTargetIdentifier cameraDepthTarget = renderer.cameraDepthTarget;
#endif
#if !UNITY_2021_2_OR_NEWER
// In Unity 2021.2, when MSAA > 1, cameraDepthTarget is no longer cameraColorTarget
if (!usesCameraOverlay && (cameraTextureDescriptor.msaaSamples > 1 || cam.cameraType == CameraType.SceneView)) {
cameraDepthTarget = cameraColorTarget;
}
#endif
passData.clearStencil = clearStencil;
passData.camera = renderingData.cameraData.camera;
passData.colorTarget = cameraColorTarget;
passData.depthTarget = cameraDepthTarget;
sourceDesc = renderingData.cameraData.cameraTargetDescriptor;
CommandBuffer cmd = CommandBufferPool.Get("Highlight Plus");
cmd.Clear();
passData.cmd = cmd;
ExecutePass(passData);
context.ExecuteCommandBuffer(cmd);
CommandBufferPool.Release(cmd);
}
#endif
static void ExecutePass (PassData passData) {
int count = HighlightEffect.effects.Count;
HighlightEffect.effects.RemoveAll(t => t == null);
count = HighlightEffect.effects.Count;
if (count == 0) return;
Camera cam = passData.camera;
int camLayer = 1 << cam.gameObject.layer;
CameraType camType = cam.cameraType;
if (!HighlightEffect.customSorting && ((camType == CameraType.Game && (sortFrameCount++) % 10 == 0) || !Application.isPlaying)) {
effectDistanceComparer.camPos = cam.transform.position;
if (cachedEffectComparisonDelegate == null) {
cachedEffectComparisonDelegate = effectDistanceComparer.Compare;
}
HighlightEffect.effects.Sort(cachedEffectComparisonDelegate);
}
bool outlineOccludersPending = outlineAndGlowOccluders.Count > 0;
HighlightEffect.focusRendered = false;
for (int k = 0; k < count; k++) {
HighlightEffect effect = HighlightEffect.effects[k];
if (!(effect.ignoreObjectVisibility || effect.isVisible)) continue;
if (!effect.isActiveAndEnabled) continue;
if (camType == CameraType.Reflection && !effect.reflectionProbes) continue;
if ((effect.camerasLayerMask & camLayer) == 0) continue;
if (outlineOccludersPending) {
outlineOccludersPending = false;
foreach (HighlightEffectBlocker blocker in outlineAndGlowOccluders) {
if (blocker != null && blocker.isActiveAndEnabled) {
int stencilOp = 0;
if (blocker.blockOutlineAndGlow) stencilOp += 2;
if (blocker.blockOverlay) stencilOp += 4;
if (stencilOp == 2) {
if (blockerOutlineAndGlowMat == null) {
blockerOutlineAndGlowMat = Resources.Load<Material>("HighlightPlus/HighlightBlockerOutlineAndGlow");
}
blocker.BuildCommandBuffer(passData.cmd, blockerOutlineAndGlowMat);
}
else if (stencilOp == 4) {
if (blockerOverlayMat == null) {
blockerOverlayMat = Resources.Load<Material>("HighlightPlus/HighlightBlockerOverlay");
}
blocker.BuildCommandBuffer(passData.cmd, blockerOverlayMat);
}
else if (stencilOp == 6) {
if (blockerAllMat == null) {
blockerAllMat = Resources.Load<Material>("HighlightPlus/HighlightUIMask");
}
blocker.BuildCommandBuffer(passData.cmd, blockerAllMat);
}
}
}
}
effect.SetCommandBuffer(passData.cmd);
effect.BuildCommandBuffer(passData.camera, passData.colorTarget, passData.depthTarget, passData.clearStencil, ref sourceDesc);
passData.clearStencil = false;
}
}
#if UNITY_2023_3_OR_NEWER
public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer frameData) {
UniversalCameraData cameraData = frameData.Get<UniversalCameraData>();
if (IsDepthOnlyTarget(cameraData.cameraTargetDescriptor)) {
return;
}
UniversalResourceData resourceData = frameData.Get<UniversalResourceData>();
if (!resourceData.activeColorTexture.IsValid()) {
return;
}
using (var builder = renderGraph.AddUnsafePass<PassData>("Highlight Plus Pass RG", out var passData)) {
builder.AllowPassCulling(false);
passData.clearStencil = clearStencil;
passData.camera = cameraData.camera;
passData.colorTexture = resourceData.activeColorTexture;
passData.depthTexture = resourceData.activeDepthTexture;
builder.UseTexture(resourceData.activeColorTexture, AccessFlags.ReadWrite);
builder.UseTexture(resourceData.activeDepthTexture, AccessFlags.Read);
builder.UseTexture(resourceData.cameraDepthTexture, AccessFlags.Read);
sourceDesc = cameraData.cameraTargetDescriptor;
builder.SetRenderFunc((PassData passData, UnsafeGraphContext context) => {
CommandBuffer cmd = CommandBufferHelpers.GetNativeCommandBuffer(context.cmd);
passData.cmd = cmd;
passData.colorTarget = passData.colorTexture;
passData.depthTarget = passData.depthTexture;
ExecutePass(passData);
});
}
}
#endif
}
HighlightPass renderPass;
public RenderPassEvent renderPassEvent = RenderPassEvent.AfterRenderingTransparents;
[Tooltip("Clears stencil buffer before rendering highlight effects. This option can solve compatibility issues with shaders that also use stencil buffers.")]
public bool clearStencil;
/// <summary>
/// Makes the effects visible in Edit mode.
/// </summary>
[Tooltip("If enabled, effects will be visible also in Edit mode (when not in Play mode).")]
public bool previewInEditMode = true;
/// <summary>
/// Makes the effects visible in Scene View.
/// </summary>
[Tooltip("If enabled, effects will be visible also in Scene View.")]
public bool showInSceneView = true;
/// <summary>
/// Makes the effects visible in Edit mode.
/// </summary>
[Tooltip("If enabled, effects will be visible also in Preview camera (preview camera shown when a camera is selected in Editor).")]
public bool showInPreviewCamera;
public static bool installed;
public static bool showingInEditMode;
public static List<HighlightEffectBlocker> outlineAndGlowOccluders = new List<HighlightEffectBlocker>();
public static int sortFrameCount;
const string PREVIEW_CAMERA_NAME = "Preview";
void OnDisable () {
installed = false;
}
public override void Create () {
renderPass = new HighlightPass();
VRCheck.Init();
}
// This method is called when setting up the renderer once per-camera.
public override void AddRenderPasses (ScriptableRenderer renderer, ref RenderingData renderingData) {
if (HighlightEffect.effects.Count == 0) return;
showingInEditMode = previewInEditMode;
Camera cam = renderingData.cameraData.camera;
#if UNITY_EDITOR
if (!previewInEditMode && !Application.isPlaying) {
return;
}
CameraType camType = cam.cameraType;
if (camType == CameraType.SceneView && !showInSceneView) {
return;
}
if (!showInPreviewCamera && (camType == CameraType.Preview || cam.name.StartsWith(PREVIEW_CAMERA_NAME))) {
return;
}
#endif
if (IsDepthOnlyTarget(renderingData.cameraData.cameraTargetDescriptor)) {
return;
}
#if UNITY_2019_4_OR_NEWER
if (renderingData.cameraData.renderType == CameraRenderType.Base) {
renderPass.usesCameraOverlay = cam.GetUniversalAdditionalCameraData().cameraStack.Count > 0;
}
#endif
renderPass.Setup(this, renderer);
renderer.EnqueuePass(renderPass);
installed = true;
}
static Material sBlockerOutlineAndGlowMat, sBlockerOverlayMat, sBlockerAllMat;
public static void RenderBlockers(CommandBuffer cmd) {
int count = outlineAndGlowOccluders.Count;
if (count == 0) return;
for (int i = 0; i < count; i++) {
HighlightEffectBlocker blocker = outlineAndGlowOccluders[i];
if (blocker == null || !blocker.isActiveAndEnabled) continue;
int stencilOp = 0;
if (blocker.blockOutlineAndGlow) stencilOp += 2;
if (blocker.blockOverlay) stencilOp += 4;
if (stencilOp == 2) {
if (sBlockerOutlineAndGlowMat == null) {
sBlockerOutlineAndGlowMat = Resources.Load<Material>("HighlightPlus/HighlightBlockerOutlineAndGlow");
}
blocker.BuildCommandBuffer(cmd, sBlockerOutlineAndGlowMat);
} else if (stencilOp == 4) {
if (sBlockerOverlayMat == null) {
sBlockerOverlayMat = Resources.Load<Material>("HighlightPlus/HighlightBlockerOverlay");
}
blocker.BuildCommandBuffer(cmd, sBlockerOverlayMat);
} else if (stencilOp == 6) {
if (sBlockerAllMat == null) {
sBlockerAllMat = Resources.Load<Material>("HighlightPlus/HighlightUIMask");
}
blocker.BuildCommandBuffer(cmd, sBlockerAllMat);
}
}
}
public static void RegisterBlocker (HighlightEffectBlocker occluder) {
if (!outlineAndGlowOccluders.Contains(occluder)) {
outlineAndGlowOccluders.Add(occluder);
}
}
public static void UnregisterBlocker (HighlightEffectBlocker occluder) {
outlineAndGlowOccluders.Remove(occluder);
}
static bool IsDepthOnlyTarget(in RenderTextureDescriptor descriptor) {
if (descriptor.colorFormat == RenderTextureFormat.Depth) {
return true;
}
#if UNITY_2019_1_OR_NEWER
if (descriptor.graphicsFormat == GraphicsFormat.None) {
return true;
}
#endif
return false;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 473a86c9e274347dfbdde619584cebe9
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,829 @@
using System;
using UnityEngine;
using UnityEngine.Serialization;
namespace HighlightPlus {
[CreateAssetMenu(menuName = "Highlight Plus Profile", fileName = "Highlight Plus Profile", order = 100)]
[HelpURL("https://kronnect.com/docs/highlight-plus/")]
public class HighlightProfile : ScriptableObject {
[Tooltip("Different options to specify which objects are affected by this Highlight Effect component.")]
public TargetOptions effectGroup = TargetOptions.Children;
[Tooltip("The layer that contains the affected objects by this effect when effectGroup is set to LayerMask.")]
public LayerMask effectGroupLayer = -1;
[Tooltip("Only include objects whose names contains this text.")]
public string effectNameFilter;
[Tooltip("Use RegEx to determine if an object name matches the effectNameFilter.")]
public bool effectNameUseRegEx;
[Tooltip("Exclude objects that already have a Highlight Effect component when using Include options.")]
public bool excludeObjectsWithHighlightEffect;
[Tooltip("Combine meshes of all objects in this group affected by Highlight Effect reducing draw calls.")]
public bool combineMeshes;
[Tooltip("The alpha threshold for transparent cutout objects. Pixels with alpha below this value will be discarded.")]
[Range(0, 1)]
public float alphaCutOff;
[Tooltip("Optional custom texture property name used for alpha clipping; if not found, falls back to _BaseMap or _MainTex.")]
public string alphaCutOffTextureName;
[Tooltip("If back facing triangles are ignored.Backfaces triangles are not visible but you may set this property to false to force highlight effects to act on those triangles as well.")]
public bool cullBackFaces = true;
[Tooltip("Normals handling option:\nPreserve original: use original mesh normals.\nSmooth: average normals to produce a smoother outline/glow mesh based effect.\nReorient: recomputes normals based on vertex direction to centroid.")]
public NormalsOption normalsOption;
public float fadeInDuration;
public float fadeOutDuration;
[Tooltip("Fades out effects based on distance to camera")]
public bool cameraDistanceFade;
[Tooltip("The closest distance particles can get to the camera before they fade from the camera's view.")]
public float cameraDistanceFadeNear;
[Tooltip("The farthest distance particles can get away from the camera before they fade from the camera's view.")]
public float cameraDistanceFadeFar = 1000;
[Tooltip("Keeps the outline/glow size unaffected by object distance.")]
public bool constantWidth = true;
[Tooltip("Increases the screen coverage for the outline/glow to avoid cuts when using cloth or vertex shader that transform mesh vertices")]
public int extraCoveragePixels;
[Tooltip("Minimum width when the constant width option is not used")]
[Range(0, 1)]
public float minimumWidth;
[Range(0, 1)]
[Tooltip("Intensity of the overlay effect. A value of 0 disables the overlay completely.")]
public float overlay;
public OverlayMode overlayMode = OverlayMode.WhenHighlighted;
[ColorUsage(showAlpha: false, hdr: true)] public Color overlayColor = Color.yellow;
public float overlayAnimationSpeed = 1f;
[Range(0, 1)]
public float overlayMinIntensity = 0.5f;
[Range(0, 1)]
[Tooltip("Controls the blending or mix of the overlay color with the natural colors of the object.")]
public float overlayBlending = 1.0f;
[Tooltip("Optional overlay texture.")]
public Texture2D overlayTexture;
public TextureUVSpace overlayTextureUVSpace;
public float overlayTextureScale = 1f;
public Vector2 overlayTextureScrolling;
public Visibility overlayVisibility = Visibility.Normal;
[Tooltip("Controls the blend mode of the overlay effect.")]
public OverlayBlendMode overlayBlendMode = OverlayBlendMode.AlphaBlending;
[Tooltip("Optional overlay pattern texture.")]
public OverlayPattern overlayPattern = OverlayPattern.None;
public Vector2 overlayPatternScrolling;
[Tooltip("Scale of the overlay pattern")]
[Range(1f, 100f)]
public float overlayPatternScale = 10f;
[Tooltip("Size/Thickness of the overlay pattern")]
[Range(0.01f, 1f)]
public float overlayPatternSize = 0.15f;
[Tooltip("Softness of the overlay pattern")]
[Range(0.01f, 0.5f)]
public float overlayPatternSoftness = 0.02f;
[Tooltip("Rotation angle for the overlay pattern in degrees")]
[Range(-180f, 180f)]
public float overlayPatternRotation = 0f;
[Range(0, 1)]
[Tooltip("Intensity of the outline. A value of 0 disables the outline completely.")]
public float outline = 1f;
[ColorUsage(true, true)] public Color outlineColor = Color.black;
public ColorStyle outlineColorStyle = ColorStyle.SingleColor;
[GradientUsage(hdr: true, ColorSpace.Linear)] public Gradient outlineGradient;
public bool outlineGradientInLocalSpace;
[Range(1, 3)]
public int outlineBlurPasses = 2;
public float outlineWidth = 0.45f;
public QualityLevel outlineQuality = QualityLevel.High;
public OutlineEdgeMode outlineEdgeMode = OutlineEdgeMode.Exterior;
public float outlineEdgeThreshold = 0.995f;
[Tooltip("Controls how quickly the outline effect scales down with distance when constant width is disabled. Lower values make the effect fade faster with distance.")]
public float outlineDistanceScaleBias = 25f;
public float outlineSharpness = 1f;
[Range(1, 8)]
[Tooltip("Reduces the quality of the outline but improves performance a bit.")]
public int outlineDownsampling = 1;
public ContourStyle outlineContourStyle = ContourStyle.AroundVisibleParts;
public float outlineGradientKnee = 0.4f;
public float outlineGradientPower = 8f;
[Tooltip("Enables stylized outline effect.")]
public bool outlineStylized;
[Tooltip("Pattern texture used for the stylized outline effect.")]
public Texture2D outlinePattern;
[Tooltip("Scale of the pattern texture.")]
public float outlinePatternScale = 0.3f;
[Tooltip("Threshold for the pattern texture.")]
[Range(0, 1)]
public float outlinePatternThreshold = 0.3f;
[Tooltip("Distortion amount for the pattern texture.")]
[Range(0, 1.5f)]
public float outlinePatternDistortionAmount = 0.5f;
[Tooltip("Stop motion scale for the distortion effect.")]
public float outlinePatternStopMotionScale = 5f;
[Tooltip("Distortion texture used for the stylized outline effect.")]
public Texture2D outlinePatternDistortionTexture;
[Tooltip("Adds a empty margin between the outline mesh and the effects")]
[Range(0, 1)]
public float padding;
[Tooltip("Makes the outline pixelated. A value of 0 disables pixelation. Higher values produce bigger pixels.")]
[Range(0, 32)]
public int outlinePixelation;
[Tooltip("Enables dashed outline effect.")]
public bool outlineDashed;
[Tooltip("Width of the dashed outline.")]
[Range(0, 1)]
public float outlineDashWidth = 0.5f;
[Tooltip("Gap of the dashed outline.")]
[Range(0, 1)]
public float outlineDashGap = 0.3f;
[Tooltip("Speed of the dashed outline.")]
public float outlineDashSpeed = 2f;
public Visibility outlineVisibility = Visibility.Normal;
[Tooltip("If enabled, this object won't combine the outline with other objects.")]
public bool outlineIndependent;
[Tooltip("Select the mask mode used with this effect.")]
public MaskMode outlineMaskMode = MaskMode.Stencil;
[Range(0, 5)]
[Tooltip("The intensity of the outer glow effect. A value of 0 disables the glow completely.")]
public float glow;
public float glowWidth = 0.4f;
public QualityLevel glowQuality = QualityLevel.High;
public BlurMethod glowBlurMethod = BlurMethod.Gaussian;
public bool glowHighPrecision = true;
[Tooltip("Controls how quickly the glow effect scales down with distance when constant width is disabled. Lower values make the effect fade faster with distance.")]
public float glowDistanceScaleBias = 25f;
[Range(1, 8)]
[Tooltip("Reduces the quality of the glow but improves performance a bit.")]
public int glowDownsampling = 2;
[ColorUsage(true, true)] public Color glowHQColor = new Color(0.64f, 1f, 0f, 1f);
[Tooltip("When enabled, outer glow renders with dithering. When disabled, glow appears as a solid color.")]
[Range(0, 1)]
public float glowDithering = 1;
public GlowDitheringStyle glowDitheringStyle = GlowDitheringStyle.Pattern;
[Tooltip("Seed for the dithering effect")]
public float glowMagicNumber1 = 0.75f;
[Tooltip("Another seed for the dithering effect that combines with first seed to create different patterns")]
public float glowMagicNumber2 = 0.5f;
public float glowAnimationSpeed = 1f;
public Visibility glowVisibility = Visibility.Normal;
public GlowBlendMode glowBlendMode = GlowBlendMode.Additive;
[Tooltip("Blends glow passes one after another. If this option is disabled, glow passes won't overlap (in this case, make sure the glow pass 1 has a smaller offset than pass 2, etc.)")]
public bool glowBlendPasses = true;
public GlowPassData[] glowPasses;
[Tooltip("Select the mask mode used with this effect.")]
public MaskMode glowMaskMode = MaskMode.Stencil;
[Tooltip("Makes the glow pixelated. A value of 0 disables pixelation. Higher values produce bigger pixels.")]
[Range(0, 32)]
public int glowPixelation;
[Range(0, 5f)]
[Tooltip("The intensity of the inner glow effect. A value of 0 disables the glow completely.")]
public float innerGlow;
[Range(0, 2)]
public float innerGlowWidth = 1f;
public float innerGlowPower = 1f;
public InnerGlowBlendMode innerGlowBlendMode = InnerGlowBlendMode.Additive;
[ColorUsage(true, true)] public Color innerGlowColor = Color.white;
public Visibility innerGlowVisibility = Visibility.Normal;
[Range(0, 1)]
[Tooltip("Intensity of the focus effect. A value of 0 disables the focus effect completely.")]
public float focus;
[Tooltip("Color and transparency of the focus dim overlay.")]
public Color focusColor = new Color(0, 0, 0, 0.9412f);
[Range(0, 1)]
[Tooltip("Optional background blur intensity for the focus effect.")]
public float focusBlur;
[Range(1, 8)]
[Tooltip("Downsampling factor for the focus blur. Higher values improve performance at the cost of quality.")]
public int focusBlurDownsampling = 2;
[Range(0, 1)]
[Tooltip("Desaturation intensity for the focus background. A value of 1 makes the background fully grayscale.")]
public float focusDesaturation;
[Tooltip("Enables the targetFX effect. This effect draws an animated sprite over the object.")]
public bool targetFX;
[Tooltip("Style of the target FX effect.")]
public TargetFXStyle targetFXStyle = TargetFXStyle.Texture;
[Tooltip("Width of the frame when using Frame style.")]
[Range(0.001f, 0.5f)]
public float targetFXFrameWidth = 0.1f;
[Tooltip("Length of the frame corners when using Frame style.")]
[Range(0.1f, 1f)]
public float targetFXCornerLength = 0.25f;
[Tooltip("Minimum opacity of the frame when using Frame style.")]
[Range(0, 1)]
public float targetFXFrameMinOpacity;
public Texture2D targetFXTexture;
[ColorUsage(true, true)] public Color targetFXColor = Color.white;
public float targetFXRotationSpeed = 50f;
public float targetFXRotationAngle;
public float targetFXInitialScale = 4f;
public float targetFXEndScale = 1.5f;
[Tooltip("Makes target scale relative to object renderer bounds.")]
public bool targetFXScaleToRenderBounds;
[Tooltip("Makes target FX effect square")]
public bool targetFXSquare = true;
[Tooltip("Places target FX sprite at the bottom of the highlighted object.")]
public bool targetFXAlignToGround;
[Tooltip("Max distance from the center of the highlighted object to the ground.")]
public float targetFXGroundMaxDistance = 15f;
public LayerMask targetFXGroundLayerMask = -1;
[Tooltip("Fade out effect with altitude")]
public float targetFXFadePower = 32;
[Tooltip("Enable to render a single target FX effect at the center of the enclosing bounds")]
public bool targetFXUseEnclosingBounds;
[Tooltip("Optional world space offset for the position of the targetFX effect")]
public Vector3 targetFXOffset;
[Tooltip("If enabled, the target FX effect will be centered on the hit position")]
public bool targetFxCenterOnHitPosition;
[Tooltip("If enabled, the target FX effect will align to the hit normal")]
public bool targetFxAlignToNormal;
public float targetFXTransitionDuration = 0.5f;
[Tooltip("0 = stay forever")]
public float targetFXStayDuration = 1.5f;
public Visibility targetFXVisibility = Visibility.AlwaysOnTop;
[Tooltip("If the ground is transparent, the effect won't work. You can set this property to the altitude of the transparent ground to force the effect to render at this altitude.")]
public float targetFXGroundMinAltitude = -1000;
[Tooltip("Enables the iconFX effect. This effect draws an animated object over the object.")]
public bool iconFX;
public IconAssetType iconFXAssetType;
public GameObject iconFXPrefab;
public Mesh iconFXMesh;
[ColorUsage(true, true)] public Color iconFXLightColor = Color.white;
[ColorUsage(true, true)] public Color iconFXDarkColor = Color.gray;
public float iconFXRotationSpeed = 50f;
public IconAnimationOption iconFXAnimationOption = IconAnimationOption.None;
public float iconFXAnimationAmount = 0.1f;
public float iconFXAnimationSpeed = 3f;
public float iconFXScale = 1f;
[Tooltip("Makes target scale relative to object renderer bounds.")]
public bool iconFXScaleToRenderBounds;
[Tooltip("Optional world space offset for the position of the iconFX effect")]
public Vector3 iconFXOffset = new Vector3(0, 1, 0);
public float iconFXTransitionDuration = 0.5f;
[Tooltip("0 = stay forever")]
public float iconFXStayDuration = 1.5f;
[Tooltip("Enables the label effect. This effect shows a text label over the object.")]
public bool labelEnabled;
[Tooltip("Screen Space renders the label as a 2D overlay. World Space renders the label in 3D, suitable for VR.")]
public LabelRenderMode labelRenderMode = LabelRenderMode.ScreenSpace;
[Tooltip("The text to display in the label")]
public string labelText = "Label";
[Tooltip("The size of the label text")]
public float labelTextSize = 14;
[ColorUsage(true, true)] public Color labelColor = Color.white;
[Tooltip("The prefab to use for the label. Must contain a Canvas and TextMeshProUGUI component.")]
public GameObject labelPrefab;
public float labelVerticalOffset;
public Vector2 labelViewportOffset;
[Tooltip("The horizontal offset of the label with respect to the object bounds")]
[FormerlySerializedAs("lineLength")]
public float labelLineLength = 200;
[Tooltip("If enabled, the label will follow the cursor when hovering the object")]
public bool labelFollowCursor = true;
public LabelMode labelMode = LabelMode.WhenHighlighted;
[Tooltip("If enabled, the label will be shown in editor mode (non playing)")]
public bool labelShowInEditorMode = true;
[Tooltip("Controls the alignment of the label relative to the target object on screen.")]
public LabelAlignment labelAlignment = LabelAlignment.Auto;
[Tooltip("Enables relative alignment based on the forward direction of the alignment transform.")]
public bool labelRelativeAlignment;
[Tooltip("The transform used for relative alignment direction.")]
public Transform labelAlignmentTransform;
[Tooltip("Maximum distance from camera where the label is visible (units). Default 250.")]
public float labelMaxDistance = 250f;
[Tooltip("Distance at which label starts fading out (units). 0 disables fading.")]
public float labelFadeStartDistance = 200f;
[Tooltip("Enable distance-based scaling of label Canvas.")]
public bool labelScaleByDistance;
[Tooltip("Minimum scale when at max distance (0..1 typically). Default 1.")]
public float labelScaleMin = 1f;
[Tooltip("Maximum scale when near camera. Default 1.")]
public float labelScaleMax = 1f;
[Tooltip("Base scale of the label in World Space mode. Adjust to match desired apparent size.")]
public float labelWorldSpaceScale = 0.01f;
[Tooltip("See-through mode for this Highlight Effect component.")]
public SeeThroughMode seeThrough = SeeThroughMode.Never;
[Tooltip("This mask setting let you specify which objects will be considered as occluders and cause the see-through effect for this Highlight Effect component. For example, you assign your walls to a different layer and specify that layer here, so only walls and not other objects, like ground or ceiling, will trigger the see-through effect.")]
public LayerMask seeThroughOccluderMask = -1;
[Tooltip("Uses stencil buffers to ensure pixel-accurate occlusion test. If this option is disabled, only physics raycasting is used to test for occlusion.")]
public bool seeThroughOccluderMaskAccurate;
[Tooltip("A multiplier for the occluder volume size which can be used to reduce the actual size of occluders when Highlight Effect checks if they're occluding this object.")]
[Range(0.01f, 0.9f)] public float seeThroughOccluderThreshold = 0.4f;
[Tooltip("The interval of time between occlusion tests.")]
public float seeThroughOccluderCheckInterval = 1f;
[Tooltip("If enabled, occlusion test is performed for each children element. If disabled, the bounds of all children is combined and a single occlusion test is performed for the combined bounds.")]
public bool seeThroughOccluderCheckIndividualObjects;
[Tooltip("Shows the see-through effect only if the occluder if at this 'offset' distance from the object.")]
public float seeThroughDepthOffset;
[Tooltip("Hides the see-through effect if the occluder is further than this distance from the object (0 = infinite)")]
public float seeThroughMaxDepth;
[Tooltip("Fade-out width near Max Depth (0 keeps hard clip)")]
public float seeThroughFadeRange;
[Range(0, 5f)] public float seeThroughIntensity = 0.8f;
[Range(0, 1)] public float seeThroughTintAlpha = 0.5f;
public Color seeThroughTintColor = Color.red;
[Range(0, 1)] public float seeThroughNoise = 1f;
[Range(0, 1)] public float seeThroughBorder;
public Color seeThroughBorderColor = Color.black;
public float seeThroughBorderWidth = 0.45f;
[Tooltip("Only display the border instead of the full see-through effect.")]
public bool seeThroughBorderOnly;
[Tooltip("This option clears the stencil buffer after rendering the see-through effect which results in correct rendering order and supports other stencil-based effects that render afterwards.")]
public bool seeThroughOrdered;
[Tooltip("Optional see-through mask effect texture.")]
public Texture2D seeThroughTexture;
public TextureUVSpace seeThroughTextureUVSpace;
public float seeThroughTextureScale = 1f;
[Tooltip("The order by which children objects are rendered by the see-through effect")]
public SeeThroughSortingMode seeThroughChildrenSortingMode = SeeThroughSortingMode.Default;
[Range(0, 1)] public float hitFxInitialIntensity;
public HitFxMode hitFxMode = HitFxMode.Overlay;
public HitFXTriggerMode hitFXTriggerMode = HitFXTriggerMode.Scripting;
public float hitFxFadeOutDuration = 0.25f;
[ColorUsage(true, true)] public Color hitFxColor = Color.white;
public float hitFxRadius = 0.5f;
public void Load (HighlightEffect effect) {
effect.effectGroup = effectGroup;
effect.effectGroupLayer = effectGroupLayer;
effect.effectNameFilter = effectNameFilter;
effect.effectNameUseRegEx = effectNameUseRegEx;
effect.excludeObjectsWithHighlightEffect = excludeObjectsWithHighlightEffect;
effect.combineMeshes = combineMeshes;
effect.alphaCutOff = alphaCutOff;
effect.alphaCutOffTextureName = alphaCutOffTextureName;
effect.cullBackFaces = cullBackFaces;
effect.padding = padding;
effect.normalsOption = normalsOption;
effect.fadeInDuration = fadeInDuration;
effect.fadeOutDuration = fadeOutDuration;
effect.cameraDistanceFade = cameraDistanceFade;
effect.cameraDistanceFadeFar = cameraDistanceFadeFar;
effect.cameraDistanceFadeNear = cameraDistanceFadeNear;
effect.constantWidth = constantWidth;
effect.extraCoveragePixels = extraCoveragePixels;
effect.minimumWidth = minimumWidth;
effect.overlay = overlay;
effect.overlayMode = overlayMode;
effect.overlayColor = overlayColor;
effect.overlayAnimationSpeed = overlayAnimationSpeed;
effect.overlayMinIntensity = overlayMinIntensity;
effect.overlayBlending = overlayBlending;
effect.overlayTexture = overlayTexture;
effect.overlayTextureUVSpace = overlayTextureUVSpace;
effect.overlayTextureScale = overlayTextureScale;
effect.overlayTextureScrolling = overlayTextureScrolling;
effect.overlayVisibility = overlayVisibility;
effect.overlayBlendMode = overlayBlendMode;
effect.overlayPattern = overlayPattern;
effect.overlayPatternScrolling = overlayPatternScrolling;
effect.overlayPatternScale = overlayPatternScale;
effect.overlayPatternSize = overlayPatternSize;
effect.overlayPatternSoftness = overlayPatternSoftness;
effect.overlayPatternRotation = overlayPatternRotation;
effect.outline = outline;
effect.outlineColor = outlineColor;
effect.outlineColorStyle = outlineColorStyle;
effect.outlineGradient = outlineGradient;
effect.outlineGradientInLocalSpace = outlineGradientInLocalSpace;
effect.outlineWidth = outlineWidth;
effect.outlineBlurPasses = outlineBlurPasses;
effect.outlineQuality = outlineQuality;
effect.outlineEdgeMode = outlineEdgeMode;
effect.outlineEdgeThreshold = outlineEdgeThreshold;
effect.outlineDistanceScaleBias = outlineDistanceScaleBias;
effect.outlineSharpness = outlineSharpness;
effect.outlineDownsampling = outlineDownsampling;
effect.outlineVisibility = outlineVisibility;
effect.outlineIndependent = outlineIndependent;
effect.outlineContourStyle = outlineContourStyle;
effect.outlineMaskMode = outlineMaskMode;
effect.outlineStylized = outlineStylized;
effect.outlinePattern = outlinePattern;
effect.outlinePatternScale = outlinePatternScale;
effect.outlinePatternThreshold = outlinePatternThreshold;
effect.outlinePatternDistortionTexture = outlinePatternDistortionTexture;
effect.outlinePatternDistortionAmount = outlinePatternDistortionAmount;
effect.outlinePatternStopMotionScale = outlinePatternStopMotionScale;
effect.outlineDashed = outlineDashed;
effect.outlineDashWidth = outlineDashWidth;
effect.outlineDashGap = outlineDashGap;
effect.outlineDashSpeed = outlineDashSpeed;
effect.outlineGradientKnee = outlineGradientKnee;
effect.outlineGradientPower = outlineGradientPower;
effect.outlinePixelation = outlinePixelation;
effect.glow = glow;
effect.glowWidth = glowWidth;
effect.glowQuality = glowQuality;
effect.glowBlurMethod = glowBlurMethod;
effect.glowHighPrecision = glowHighPrecision;
effect.glowDistanceScaleBias = glowDistanceScaleBias;
effect.glowDownsampling = glowDownsampling;
effect.glowHQColor = glowHQColor;
effect.glowDithering = glowDithering;
effect.glowDitheringStyle = glowDitheringStyle;
effect.glowMagicNumber1 = glowMagicNumber1;
effect.glowMagicNumber2 = glowMagicNumber2;
effect.glowAnimationSpeed = glowAnimationSpeed;
effect.glowVisibility = glowVisibility;
effect.glowBlendMode = glowBlendMode;
effect.glowBlendPasses = glowBlendPasses;
effect.glowPasses = GetGlowPassesCopy(glowPasses);
effect.glowMaskMode = glowMaskMode;
effect.glowPixelation = glowPixelation;
effect.innerGlow = innerGlow;
effect.innerGlowWidth = innerGlowWidth;
effect.innerGlowPower = innerGlowPower;
effect.innerGlowColor = innerGlowColor;
effect.innerGlowBlendMode = innerGlowBlendMode;
effect.innerGlowVisibility = innerGlowVisibility;
effect.focus = focus;
effect.focusColor = focusColor;
effect.focusBlur = focusBlur;
effect.focusBlurDownsampling = focusBlurDownsampling;
effect.focusDesaturation = focusDesaturation;
effect.targetFX = targetFX;
effect.targetFXColor = targetFXColor;
effect.targetFXInitialScale = targetFXInitialScale;
effect.targetFXEndScale = targetFXEndScale;
effect.targetFXScaleToRenderBounds = targetFXScaleToRenderBounds;
effect.targetFXAlignToGround = targetFXAlignToGround;
effect.targetFXGroundMaxDistance = targetFXGroundMaxDistance;
effect.targetFXGroundLayerMask = targetFXGroundLayerMask;
effect.targetFXFadePower = targetFXFadePower;
effect.targetFXRotationSpeed = targetFXRotationSpeed;
effect.targetFXRotationAngle = targetFXRotationAngle;
effect.targetFXStayDuration = targetFXStayDuration;
effect.targetFXTexture = targetFXTexture;
effect.targetFXTransitionDuration = targetFXTransitionDuration;
effect.targetFXVisibility = targetFXVisibility;
effect.targetFXUseEnclosingBounds = targetFXUseEnclosingBounds;
effect.targetFXSquare = targetFXSquare;
effect.targetFXOffset = targetFXOffset;
effect.targetFxCenterOnHitPosition = targetFxCenterOnHitPosition;
effect.targetFxAlignToNormal = targetFxAlignToNormal;
effect.targetFXStyle = targetFXStyle;
effect.targetFXFrameWidth = targetFXFrameWidth;
effect.targetFXCornerLength = targetFXCornerLength;
effect.targetFXFrameMinOpacity = targetFXFrameMinOpacity;
effect.targetFXGroundMinAltitude = targetFXGroundMinAltitude;
effect.iconFX = iconFX;
effect.iconFXAssetType = iconFXAssetType;
effect.iconFXPrefab = iconFXPrefab;
effect.iconFXMesh = iconFXMesh;
effect.iconFXLightColor = iconFXLightColor;
effect.iconFXDarkColor = iconFXDarkColor;
effect.iconFXAnimationOption = iconFXAnimationOption;
effect.iconFXAnimationAmount = iconFXAnimationAmount;
effect.iconFXAnimationSpeed = iconFXAnimationSpeed;
effect.iconFXScale = iconFXScale;
effect.iconFXScaleToRenderBounds = iconFXScaleToRenderBounds;
effect.iconFXOffset = iconFXOffset;
effect.iconFXRotationSpeed = iconFXRotationSpeed;
effect.iconFXStayDuration = iconFXStayDuration;
effect.iconFXTransitionDuration = iconFXTransitionDuration;
effect.seeThrough = seeThrough;
effect.seeThroughOccluderMask = seeThroughOccluderMask;
effect.seeThroughOccluderMaskAccurate = seeThroughOccluderMaskAccurate;
effect.seeThroughOccluderThreshold = seeThroughOccluderThreshold;
effect.seeThroughOccluderCheckInterval = seeThroughOccluderCheckInterval;
effect.seeThroughOccluderCheckIndividualObjects = seeThroughOccluderCheckIndividualObjects;
effect.seeThroughIntensity = seeThroughIntensity;
effect.seeThroughTintAlpha = seeThroughTintAlpha;
effect.seeThroughTintColor = seeThroughTintColor;
effect.seeThroughNoise = seeThroughNoise;
effect.seeThroughBorder = seeThroughBorder;
effect.seeThroughBorderColor = seeThroughBorderColor;
effect.seeThroughBorderWidth = seeThroughBorderWidth;
effect.seeThroughBorderOnly = seeThroughBorderOnly;
effect.seeThroughDepthOffset = seeThroughDepthOffset;
effect.seeThroughMaxDepth = seeThroughMaxDepth;
effect.seeThroughFadeRange = seeThroughFadeRange;
effect.seeThroughOrdered = seeThroughOrdered;
effect.seeThroughTexture = seeThroughTexture;
effect.seeThroughTextureScale = seeThroughTextureScale;
effect.seeThroughTextureUVSpace = seeThroughTextureUVSpace;
effect.seeThroughChildrenSortingMode = seeThroughChildrenSortingMode;
effect.hitFxInitialIntensity = hitFxInitialIntensity;
effect.hitFxMode = hitFxMode;
effect.hitFXTriggerMode = hitFXTriggerMode;
effect.hitFxFadeOutDuration = hitFxFadeOutDuration;
effect.hitFxColor = hitFxColor;
effect.hitFxRadius = hitFxRadius;
effect.labelEnabled = labelEnabled;
effect.labelRenderMode = labelRenderMode;
effect.labelText = labelText;
effect.labelTextSize = labelTextSize;
effect.labelColor = labelColor;
effect.labelPrefab = labelPrefab;
effect.labelVerticalOffset = labelVerticalOffset;
effect.labelViewportOffset = labelViewportOffset;
effect.labelLineLength = labelLineLength;
effect.labelMaxDistance = labelMaxDistance;
effect.labelFadeStartDistance = labelFadeStartDistance;
effect.labelScaleByDistance = labelScaleByDistance;
effect.labelScaleMin = labelScaleMin;
effect.labelScaleMax = labelScaleMax;
effect.labelWorldSpaceScale = labelWorldSpaceScale;
effect.labelFollowCursor = labelFollowCursor;
effect.labelMode = labelMode;
effect.labelAlignment = labelAlignment;
effect.labelShowInEditorMode = labelShowInEditorMode;
effect.labelRelativeAlignment = labelRelativeAlignment;
effect.labelAlignmentTransform = labelAlignmentTransform;
effect.UpdateMaterialProperties();
}
public void Save (HighlightEffect effect) {
effectGroup = effect.effectGroup;
effectGroupLayer = effect.effectGroupLayer;
effectNameFilter = effect.effectNameFilter;
effectNameUseRegEx = effect.effectNameUseRegEx;
excludeObjectsWithHighlightEffect = effect.excludeObjectsWithHighlightEffect;
combineMeshes = effect.combineMeshes;
alphaCutOff = effect.alphaCutOff;
alphaCutOffTextureName = effect.alphaCutOffTextureName;
cullBackFaces = effect.cullBackFaces;
padding = effect.padding;
normalsOption = effect.normalsOption;
fadeInDuration = effect.fadeInDuration;
fadeOutDuration = effect.fadeOutDuration;
cameraDistanceFade = effect.cameraDistanceFade;
cameraDistanceFadeFar = effect.cameraDistanceFadeFar;
cameraDistanceFadeNear = effect.cameraDistanceFadeNear;
constantWidth = effect.constantWidth;
extraCoveragePixels = effect.extraCoveragePixels;
minimumWidth = effect.minimumWidth;
overlay = effect.overlay;
overlayMode = effect.overlayMode;
overlayColor = effect.overlayColor;
overlayAnimationSpeed = effect.overlayAnimationSpeed;
overlayMinIntensity = effect.overlayMinIntensity;
overlayBlending = effect.overlayBlending;
overlayTexture = effect.overlayTexture;
overlayTextureUVSpace = effect.overlayTextureUVSpace;
overlayTextureScale = effect.overlayTextureScale;
overlayTextureScrolling = effect.overlayTextureScrolling;
overlayVisibility = effect.overlayVisibility;
overlayBlendMode = effect.overlayBlendMode;
overlayPattern = effect.overlayPattern;
overlayPatternScrolling = effect.overlayPatternScrolling;
overlayPatternScale = effect.overlayPatternScale;
overlayPatternSize = effect.overlayPatternSize;
overlayPatternSoftness = effect.overlayPatternSoftness;
overlayPatternRotation = effect.overlayPatternRotation;
outline = effect.outline;
outlineColor = effect.outlineColor;
outlineColorStyle = effect.outlineColorStyle;
outlineGradient = effect.outlineGradient;
outlineGradientInLocalSpace = effect.outlineGradientInLocalSpace;
outlineWidth = effect.outlineWidth;
outlineBlurPasses = effect.outlineBlurPasses;
outlineQuality = effect.outlineQuality;
outlineEdgeMode = effect.outlineEdgeMode;
outlineEdgeThreshold = effect.outlineEdgeThreshold;
outlineDistanceScaleBias = effect.outlineDistanceScaleBias;
outlineSharpness = effect.outlineSharpness;
outlineDownsampling = effect.outlineDownsampling;
outlineVisibility = effect.outlineVisibility;
outlineIndependent = effect.outlineIndependent;
outlineContourStyle = effect.outlineContourStyle;
outlineMaskMode = effect.outlineMaskMode;
outlineStylized = effect.outlineStylized;
outlinePattern = effect.outlinePattern;
outlinePatternScale = effect.outlinePatternScale;
outlinePatternThreshold = effect.outlinePatternThreshold;
outlinePatternDistortionTexture = effect.outlinePatternDistortionTexture;
outlinePatternDistortionAmount = effect.outlinePatternDistortionAmount;
outlinePatternStopMotionScale = effect.outlinePatternStopMotionScale;
outlineDashed = effect.outlineDashed;
outlineDashWidth = effect.outlineDashWidth;
outlineDashGap = effect.outlineDashGap;
outlineDashSpeed = effect.outlineDashSpeed;
outlineGradientKnee = effect.outlineGradientKnee;
outlineGradientPower = effect.outlineGradientPower;
outlinePixelation = effect.outlinePixelation;
glow = effect.glow;
glowWidth = effect.glowWidth;
glowQuality = effect.glowQuality;
glowHighPrecision = effect.glowHighPrecision;
glowBlurMethod = effect.glowBlurMethod;
glowDistanceScaleBias = effect.glowDistanceScaleBias;
glowDownsampling = effect.glowDownsampling;
glowHQColor = effect.glowHQColor;
glowDithering = effect.glowDithering;
glowDitheringStyle = effect.glowDitheringStyle;
glowMagicNumber1 = effect.glowMagicNumber1;
glowMagicNumber2 = effect.glowMagicNumber2;
glowAnimationSpeed = effect.glowAnimationSpeed;
glowVisibility = effect.glowVisibility;
glowBlendMode = effect.glowBlendMode;
glowBlendPasses = effect.glowBlendPasses;
glowPasses = GetGlowPassesCopy(effect.glowPasses);
glowMaskMode = effect.glowMaskMode;
glowPixelation = effect.glowPixelation;
innerGlow = effect.innerGlow;
innerGlowWidth = effect.innerGlowWidth;
innerGlowPower = effect.innerGlowPower;
innerGlowColor = effect.innerGlowColor;
innerGlowBlendMode = effect.innerGlowBlendMode;
innerGlowVisibility = effect.innerGlowVisibility;
focus = effect.focus;
focusColor = effect.focusColor;
focusBlur = effect.focusBlur;
focusBlurDownsampling = effect.focusBlurDownsampling;
focusDesaturation = effect.focusDesaturation;
targetFX = effect.targetFX;
targetFXColor = effect.targetFXColor;
targetFXInitialScale = effect.targetFXInitialScale;
targetFXEndScale = effect.targetFXEndScale;
targetFXScaleToRenderBounds = effect.targetFXScaleToRenderBounds;
targetFXAlignToGround = effect.targetFXAlignToGround;
targetFXGroundMaxDistance = effect.targetFXGroundMaxDistance;
targetFXGroundLayerMask = effect.targetFXGroundLayerMask;
targetFXFadePower = effect.targetFXFadePower;
targetFXRotationSpeed = effect.targetFXRotationSpeed;
targetFXRotationAngle = effect.targetFXRotationAngle;
targetFXStayDuration = effect.targetFXStayDuration;
targetFXTexture = effect.targetFXTexture;
targetFXTransitionDuration = effect.targetFXTransitionDuration;
targetFXVisibility = effect.targetFXVisibility;
targetFXUseEnclosingBounds = effect.targetFXUseEnclosingBounds;
targetFXSquare = effect.targetFXSquare;
targetFXOffset = effect.targetFXOffset;
targetFxCenterOnHitPosition = effect.targetFxCenterOnHitPosition;
targetFxAlignToNormal = effect.targetFxAlignToNormal;
targetFXStyle = effect.targetFXStyle;
targetFXFrameWidth = effect.targetFXFrameWidth;
targetFXCornerLength = effect.targetFXCornerLength;
targetFXFrameMinOpacity = effect.targetFXFrameMinOpacity;
targetFXGroundMinAltitude = effect.targetFXGroundMinAltitude;
iconFX = effect.iconFX;
iconFXAssetType = effect.iconFXAssetType;
iconFXPrefab = effect.iconFXPrefab;
iconFXMesh = effect.iconFXMesh;
iconFXLightColor = effect.iconFXLightColor;
iconFXDarkColor = effect.iconFXDarkColor;
iconFXAnimationOption = effect.iconFXAnimationOption;
iconFXAnimationAmount = effect.iconFXAnimationAmount;
iconFXAnimationSpeed = effect.iconFXAnimationSpeed;
iconFXScaleToRenderBounds = effect.iconFXScaleToRenderBounds;
iconFXScale = effect.iconFXScale;
iconFXOffset = effect.iconFXOffset;
iconFXRotationSpeed = effect.iconFXRotationSpeed;
iconFXStayDuration = effect.iconFXStayDuration;
iconFXTransitionDuration = effect.iconFXTransitionDuration;
seeThrough = effect.seeThrough;
seeThroughOccluderMask = effect.seeThroughOccluderMask;
seeThroughOccluderMaskAccurate = effect.seeThroughOccluderMaskAccurate;
seeThroughOccluderThreshold = effect.seeThroughOccluderThreshold;
seeThroughOccluderCheckInterval = effect.seeThroughOccluderCheckInterval;
seeThroughOccluderCheckIndividualObjects = effect.seeThroughOccluderCheckIndividualObjects;
seeThroughIntensity = effect.seeThroughIntensity;
seeThroughTintAlpha = effect.seeThroughTintAlpha;
seeThroughTintColor = effect.seeThroughTintColor;
seeThroughNoise = effect.seeThroughNoise;
seeThroughBorder = effect.seeThroughBorder;
seeThroughBorderColor = effect.seeThroughBorderColor;
seeThroughBorderWidth = effect.seeThroughBorderWidth;
seeThroughDepthOffset = effect.seeThroughDepthOffset;
seeThroughBorderOnly = effect.seeThroughBorderOnly;
seeThroughMaxDepth = effect.seeThroughMaxDepth;
seeThroughFadeRange = effect.seeThroughFadeRange;
seeThroughOrdered = effect.seeThroughOrdered;
seeThroughTexture = effect.seeThroughTexture;
seeThroughTextureScale = effect.seeThroughTextureScale;
seeThroughTextureUVSpace = effect.seeThroughTextureUVSpace;
seeThroughChildrenSortingMode = effect.seeThroughChildrenSortingMode;
hitFxInitialIntensity = effect.hitFxInitialIntensity;
hitFxMode = effect.hitFxMode;
hitFXTriggerMode = effect.hitFXTriggerMode;
hitFxFadeOutDuration = effect.hitFxFadeOutDuration;
hitFxColor = effect.hitFxColor;
hitFxRadius = effect.hitFxRadius;
labelEnabled = effect.labelEnabled;
labelRenderMode = effect.labelRenderMode;
labelText = effect.labelText;
labelTextSize = effect.labelTextSize;
labelColor = effect.labelColor;
labelPrefab = effect.labelPrefab;
labelVerticalOffset = effect.labelVerticalOffset;
labelViewportOffset = effect.labelViewportOffset;
labelLineLength = effect.labelLineLength;
labelMaxDistance = effect.labelMaxDistance;
labelFadeStartDistance = effect.labelFadeStartDistance;
labelScaleByDistance = effect.labelScaleByDistance;
labelScaleMin = effect.labelScaleMin;
labelScaleMax = effect.labelScaleMax;
labelWorldSpaceScale = effect.labelWorldSpaceScale;
labelFollowCursor = effect.labelFollowCursor;
labelMode = effect.labelMode;
labelAlignment = effect.labelAlignment;
labelShowInEditorMode = effect.labelShowInEditorMode;
labelRelativeAlignment = effect.labelRelativeAlignment;
labelAlignmentTransform = effect.labelAlignmentTransform;
}
GlowPassData[] GetGlowPassesCopy (GlowPassData[] glowPasses) {
if (glowPasses == null) {
return new GlowPassData[0];
}
GlowPassData[] pd = new GlowPassData[glowPasses.Length];
for (int k = 0; k < glowPasses.Length; k++) {
pd[k].alpha = glowPasses[k].alpha;
pd[k].color = glowPasses[k].color;
pd[k].offset = glowPasses[k].offset;
}
return pd;
}
public void OnValidate () {
outlineGradientKnee = Mathf.Max(0f, outlineGradientKnee);
outlineGradientPower = Mathf.Max(0f, outlineGradientPower);
outlineEdgeThreshold = Mathf.Clamp01(outlineEdgeThreshold);
outlineSharpness = Mathf.Max(outlineSharpness, 1f);
outlineDistanceScaleBias = Mathf.Max(1, outlineDistanceScaleBias);
extraCoveragePixels = Mathf.Max(0, extraCoveragePixels);
glowWidth = Mathf.Max(0, glowWidth);
glowAnimationSpeed = Mathf.Max(0, glowAnimationSpeed);
glowDistanceScaleBias = Mathf.Max(1, glowDistanceScaleBias);
outlineDistanceScaleBias = Mathf.Max(1, outlineDistanceScaleBias);
overlayAnimationSpeed = Mathf.Max(0, overlayAnimationSpeed);
innerGlowPower = Mathf.Max(1f, innerGlowPower);
seeThroughDepthOffset = Mathf.Max(0, seeThroughDepthOffset);
seeThroughMaxDepth = Mathf.Max(0, seeThroughMaxDepth);
seeThroughFadeRange = Mathf.Max(0, seeThroughFadeRange);
seeThroughBorderWidth = Mathf.Max(0, seeThroughBorderWidth);
targetFXFadePower = Mathf.Max(0, targetFXFadePower);
cameraDistanceFadeNear = Mathf.Max(0, cameraDistanceFadeNear);
cameraDistanceFadeFar = Mathf.Max(0, cameraDistanceFadeFar);
iconFXScale = Mathf.Max(0, iconFXScale);
iconFXAnimationAmount = Mathf.Max(0, iconFXAnimationAmount);
iconFXAnimationSpeed = Mathf.Max(0, iconFXAnimationSpeed);
outlinePatternScale = Mathf.Max(0, outlinePatternScale);
outlinePatternDistortionAmount = Mathf.Max(0, outlinePatternDistortionAmount);
outlinePatternThreshold = Mathf.Max(0, outlinePatternThreshold);
outlinePatternStopMotionScale = Mathf.Max(1, outlinePatternStopMotionScale);
if (glowPasses == null || glowPasses.Length == 0) {
glowPasses = new GlowPassData[4];
glowPasses[0] = new GlowPassData() { offset = 4, alpha = 0.1f, color = new Color(0.64f, 1f, 0f, 1f) };
glowPasses[1] = new GlowPassData() { offset = 3, alpha = 0.2f, color = new Color(0.64f, 1f, 0f, 1f) };
glowPasses[2] = new GlowPassData() { offset = 2, alpha = 0.3f, color = new Color(0.64f, 1f, 0f, 1f) };
glowPasses[3] = new GlowPassData() { offset = 1, alpha = 0.4f, color = new Color(0.64f, 1f, 0f, 1f) };
}
if (labelPrefab == null) {
labelPrefab = Resources.Load<GameObject>("HighlightPlus/Label");
}
labelLineLength = Mathf.Max(0, labelLineLength);
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 8e9253636bf2648bd813257f451f8486
timeCreated: 1549831900
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,7 @@
using UnityEngine;
namespace HighlightPlus {
public class HighlightRoot : MonoBehaviour {
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 802672b6bc327458dae0bb9eee8c9ca2
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,80 @@
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace HighlightPlus {
public struct MeshData {
public Renderer renderer;
public int subMeshCount;
}
public enum OccluderMode {
BlocksSeeThrough,
TriggersSeeThrough
}
public enum DetectionMethod {
Stencil = 0,
RayCast = 1
}
[ExecuteInEditMode]
public class HighlightSeeThroughOccluder : MonoBehaviour {
public OccluderMode mode = OccluderMode.BlocksSeeThrough;
public DetectionMethod detectionMethod = DetectionMethod.Stencil;
[NonSerialized]
public MeshData[] meshData;
List<Renderer> rr;
void OnEnable () {
if (gameObject.activeInHierarchy) {
Init();
}
}
void Init() {
if (mode == OccluderMode.BlocksSeeThrough && detectionMethod == DetectionMethod.RayCast) {
HighlightEffect.RegisterOccluder(this);
return;
}
if (rr == null) {
rr = new List<Renderer>();
} else {
rr.Clear();
}
GetComponentsInChildren(rr);
int rrCount = rr.Count;
meshData = new MeshData[rrCount];
for (int k = 0; k < rrCount; k++) {
meshData[k].renderer = rr[k];
meshData[k].subMeshCount = 1;
if (rr[k] is MeshRenderer) {
MeshFilter mf = rr[k].GetComponent<MeshFilter>();
if (mf != null && mf.sharedMesh != null) {
meshData[k].subMeshCount = mf.sharedMesh.subMeshCount;
}
} else if (rr[k] is SkinnedMeshRenderer) {
SkinnedMeshRenderer smr = (SkinnedMeshRenderer)rr[k];
if (smr.sharedMesh != null) {
meshData[k].subMeshCount = smr.sharedMesh.subMeshCount;
}
}
}
if (rrCount > 0) {
HighlightEffect.RegisterOccluder(this);
}
}
void OnDisable () {
HighlightEffect.UnregisterOccluder(this);
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 8dd965ceab19c4729a9dabd8aeb2972a
timeCreated: 1542876337
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,553 @@
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
namespace HighlightPlus {
public enum TriggerMode {
ColliderEventsOnlyOnThisObject = 0,
RaycastOnThisObjectAndChildren = 1,
Volume = 2
}
public enum RayCastSource {
MousePosition = 0,
CameraDirection = 1
}
[RequireComponent(typeof(HighlightEffect))]
[ExecuteInEditMode]
[HelpURL("https://kronnect.com/docs/highlight-plus/")]
public class HighlightTrigger : MonoBehaviour {
[Tooltip("Enables highlight when pointer is over this object.")]
public bool highlightOnHover = true;
[Tooltip("Used to trigger automatic highlighting including children objects.")]
#if ENABLE_INPUT_SYSTEM
public TriggerMode triggerMode = TriggerMode.RaycastOnThisObjectAndChildren;
#else
public TriggerMode triggerMode = TriggerMode.ColliderEventsOnlyOnThisObject;
#endif
public Camera raycastCamera;
public RayCastSource raycastSource = RayCastSource.MousePosition;
public LayerMask raycastLayerMask = -1;
[Tooltip("Objects in this layer mask will block the highlight if they are between the camera and the target.")]
public LayerMask blockingLayerMask = -1;
[Tooltip("Minimum distance for target.")]
public float minDistance;
[Tooltip("Maximum distance for target. 0 = infinity")]
public float maxDistance;
[Tooltip("Blocks interaction if pointer is over an UI element")]
public bool respectUI = true;
[Tooltip("Unhighlights the object when the pointer is over a UI element")]
public bool unhighlightOnUI;
public LayerMask volumeLayerMask;
const int MAX_RAYCAST_HITS = 100;
[Tooltip("If the object will be selected by clicking with mouse or tapping on it.")]
public bool selectOnClick;
[Tooltip("Profile to use when object is selected by clicking on it.")]
public HighlightProfile selectedProfile;
[Tooltip("Profile to use whtn object is selected and highlighted.")]
public HighlightProfile selectedAndHighlightedProfile;
[Tooltip("Automatically deselects any other selected object prior selecting this one")]
public bool singleSelection;
[Tooltip("Toggles selection on/off when clicking object")]
public bool toggle;
[Tooltip("Keeps current selection when clicking outside of any selectable object")]
public bool keepSelection = true;
[NonSerialized] public Collider[] colliders;
[NonSerialized] public Collider2D[] colliders2D;
public bool hasColliders => colliders != null && colliders.Length > 0;
public bool hasColliders2D => colliders2D != null && colliders2D.Length > 0;
UnityEngine.Object currentCollider;
static RaycastHit[] hits;
static RaycastHit2D[] hits2D;
static RaycastHit blockingHit;
HighlightEffect hb;
public HighlightEffect highlightEffect { get { return hb; } }
public event OnObjectSelectionEvent OnObjectSelected;
public event OnObjectSelectionEvent OnObjectUnSelected;
public event OnObjectHighlightEvent OnObjectHighlightStart;
public event OnObjectHighlightEvent OnObjectHighlightStay;
public event OnObjectHighlightEvent OnObjectHighlightEnd;
public event OnObjectClickEvent OnObjectClicked;
TriggerMode currentTriggerMode;
[RuntimeInitializeOnLoadMethod]
static void DomainReloadDisabledSupport () {
HighlightManager.selectedObjects.Clear();
}
void OnEnable () {
Init();
}
private void OnValidate () {
if (currentTriggerMode != triggerMode) {
UpdateTriggers();
}
}
void UpdateTriggers () {
currentTriggerMode = triggerMode;
if (currentTriggerMode == TriggerMode.RaycastOnThisObjectAndChildren) {
colliders = GetComponentsInChildren<Collider>();
colliders2D = GetComponentsInChildren<Collider2D>();
if (hits == null || hits.Length != MAX_RAYCAST_HITS) {
hits = new RaycastHit[MAX_RAYCAST_HITS];
}
if (hits2D == null || hits2D.Length != MAX_RAYCAST_HITS) {
hits2D = new RaycastHit2D[MAX_RAYCAST_HITS];
}
if (Application.isPlaying) {
StopAllCoroutines();
if (isActiveAndEnabled) {
StartCoroutine(DoRayCast());
}
}
}
}
public void Init () {
if (raycastCamera == null) {
raycastCamera = HighlightManager.GetCamera();
}
UpdateTriggers();
if (hb == null) {
hb = GetComponent<HighlightEffect>();
}
InputProxy.Init();
}
void Start () {
UpdateTriggers();
if (triggerMode == TriggerMode.RaycastOnThisObjectAndChildren) {
if (raycastCamera == null) {
raycastCamera = HighlightManager.GetCamera();
if (raycastCamera == null) {
Debug.LogError("Highlight Trigger on " + gameObject.name + ": no camera found!");
}
}
}
else {
if (!TryGetComponent(out Collider _)) {
if (TryGetComponent(out MeshFilter _)) {
gameObject.AddComponent<MeshCollider>();
}
}
}
}
IEnumerator DoRayCast () {
yield return null;
WaitForEndOfFrame w = new WaitForEndOfFrame();
while (triggerMode == TriggerMode.RaycastOnThisObjectAndChildren) {
if (raycastCamera == null || !isActiveAndEnabled) {
yield return null;
continue;
}
int hitCount;
bool hit = false;
#if ENABLE_INPUT_SYSTEM && !ENABLE_LEGACY_INPUT_MANAGER
if (respectUI) {
EventSystem es = EventSystem.current;
if (es == null) {
es = CreateEventSystem();
}
List<RaycastResult> raycastResults = new List<RaycastResult>();
PointerEventData eventData = new PointerEventData(es);
Vector3 cameraPos = raycastCamera.transform.position;
if (raycastSource == RayCastSource.MousePosition) {
eventData.position = InputProxy.mousePosition;
} else {
eventData.position = new Vector2(raycastCamera.pixelWidth * 0.5f, raycastCamera.pixelHeight * 0.5f);
}
es.RaycastAll(eventData, raycastResults);
hitCount = raycastResults.Count;
// check UI blocker
bool blocked = false;
for (int k = 0; k < hitCount; k++) {
RaycastResult rr = raycastResults[k];
if (rr.module is UnityEngine.UI.GraphicRaycaster) {
blocked = true;
break;
}
}
if (blocked) {
if (unhighlightOnUI && hb.highlighted) {
hb.SetHighlighted(false);
}
yield return null;
continue;
}
// look for our gameobject
for (int k = 0; k < hitCount; k++) {
RaycastResult rr = raycastResults[k];
float distance = Vector3.Distance(rr.worldPosition, cameraPos);
if (distance < minDistance || (maxDistance > 0 && distance > maxDistance)) continue;
GameObject theGameObject = rr.gameObject;
for (int c = 0; c < colliders.Length; c++) {
if (colliders[c].gameObject == theGameObject) {
Collider theCollider = colliders[c];
hit = true;
UpdateHitPosition(theCollider.transform, rr.worldPosition);
if (selectOnClick && InputProxy.GetMouseButtonDown(0)) {
ToggleSelection();
break;
} else if (theCollider != currentCollider) {
SwitchCollider(theCollider);
k = hitCount;
break;
}
}
}
}
}
// if not blocked by UI and no hit found, fallback to raycast (required if no PhysicsRaycaster is present on the camera)
#endif
Ray ray;
{
#if !(ENABLE_INPUT_SYSTEM && !ENABLE_LEGACY_INPUT_MANAGER)
Vector2 screenPos = raycastSource == RayCastSource.MousePosition ? (Vector2)InputProxy.mousePosition : new Vector2(raycastCamera.pixelWidth * 0.5f, raycastCamera.pixelHeight * 0.5f);
if (!CanInteractAt(screenPos)) {
if (unhighlightOnUI && hb.highlighted) {
hb.SetHighlighted(false);
}
yield return null;
continue;
}
#endif
if (raycastSource == RayCastSource.MousePosition) {
ray = raycastCamera.ScreenPointToRay(InputProxy.mousePosition);
}
else {
ray = new Ray(raycastCamera.transform.position, raycastCamera.transform.forward);
}
}
VerifyHighlightStay();
bool isMouseButonDown = InputProxy.GetMouseButtonDown(0);
float blockingDistance = GetBlockingDistance(ray, maxDistance > 0 ? maxDistance : float.MaxValue);
if (hasColliders2D) {
if (maxDistance > 0) {
hitCount = Physics2D.GetRayIntersectionNonAlloc(ray, hits2D, maxDistance, raycastLayerMask);
}
else {
hitCount = Physics2D.GetRayIntersectionNonAlloc(ray, hits2D, float.MaxValue, raycastLayerMask);
}
for (int k = 0; k < hitCount; k++) {
float hitDistance = Vector3.Distance(hits2D[k].point, ray.origin);
if (hitDistance < minDistance || hitDistance > blockingDistance) continue;
Collider2D theCollider = hits2D[k].collider;
int colliders2DCount = colliders2D.Length;
for (int c = 0; c < colliders2DCount; c++) {
if (colliders2D[c] == theCollider) {
hit = true;
UpdateHitPosition(hits2D[k].transform, hits2D[k].point);
if (selectOnClick && isMouseButonDown) {
ToggleSelection();
break;
}
else if (theCollider != currentCollider) {
SwitchCollider(theCollider);
k = hitCount;
break;
}
}
}
}
}
if (hasColliders) {
if (maxDistance > 0) {
hitCount = Physics.RaycastNonAlloc(ray, hits, maxDistance, raycastLayerMask);
}
else {
hitCount = Physics.RaycastNonAlloc(ray, hits, float.MaxValue, raycastLayerMask);
}
for (int k = 0; k < hitCount; k++) {
float hitDistance = hits[k].distance;
if (hitDistance < minDistance || hitDistance > blockingDistance) continue;
Collider theCollider = hits[k].collider;
int collidersCount = colliders.Length;
for (int c = 0; c < collidersCount; c++) {
if (colliders[c] == theCollider) {
hit = true;
UpdateHitPosition(hits[k].transform, hits[k].point);
if (selectOnClick && isMouseButonDown) {
ToggleSelection();
break;
}
else if (theCollider != currentCollider) {
SwitchCollider(theCollider);
k = hitCount;
break;
}
}
}
}
}
if (!hit && currentCollider != null) {
SwitchCollider(null);
}
if (selectOnClick && isMouseButonDown && !keepSelection && !hit) {
yield return w; // wait for other potential triggers to act
if (HighlightManager.lastTriggerFrame < Time.frameCount) {
if (OnObjectUnSelected != null) OnObjectUnSelected(gameObject);
HighlightManager.DeselectAll();
}
}
yield return null;
}
}
#if ENABLE_INPUT_SYSTEM && !ENABLE_LEGACY_INPUT_MANAGER
EventSystem CreateEventSystem() {
GameObject eo = new GameObject("Event System created by Highlight Plus", typeof(EventSystem), typeof(UnityEngine.InputSystem.UI.InputSystemUIInputModule));
return eo.GetComponent<EventSystem>();
}
#endif
void VerifyHighlightStay () {
if (hb == null || !hb.highlighted) return;
if (OnObjectHighlightStay != null && !OnObjectHighlightStay(hb.gameObject)) {
SwitchCollider(null);
}
}
void SwitchCollider (UnityEngine.Object newCollider) {
if (!highlightOnHover && !hb.isSelected) return;
currentCollider = newCollider;
if (currentCollider != null) {
Highlight(true);
}
else {
Highlight(false);
}
}
bool CanInteract () {
return CanInteractAt(InputProxy.mousePosition);
}
bool CanInteractAt (Vector2 screenPosition) {
if (!respectUI) return true;
EventSystem es = EventSystem.current;
if (es == null) return true;
if (Application.isMobilePlatform && InputProxy.touchCount > 0) {
if (es.IsPointerOverGameObject(InputProxy.GetFingerIdFromTouch(0))) {
return false;
}
if (raycastSource == RayCastSource.CameraDirection) {
return !IsUIAtScreenPosition(es, screenPosition);
}
return true;
}
if (raycastSource == RayCastSource.MousePosition) {
if (es.IsPointerOverGameObject(-1)) return false;
return true;
}
return !IsUIAtScreenPosition(es, screenPosition);
}
bool IsUIAtScreenPosition (EventSystem es, Vector2 screenPosition) {
List<RaycastResult> raycastResults = new List<RaycastResult>();
PointerEventData eventData = new PointerEventData(es);
eventData.position = screenPosition;
es.RaycastAll(eventData, raycastResults);
int hitCount = raycastResults.Count;
for (int k = 0; k < hitCount; k++) {
RaycastResult rr = raycastResults[k];
if (rr.module is UnityEngine.UI.GraphicRaycaster) {
return true;
}
}
return false;
}
float GetBlockingDistance (Ray ray, float maxRayDistance) {
if (blockingLayerMask == 0) return float.MaxValue;
if (hasColliders2D) {
RaycastHit2D hit2D = Physics2D.Raycast(ray.origin, ray.direction, maxRayDistance, blockingLayerMask);
if (hit2D.collider != null) {
return hit2D.distance + 0.01f;
}
}
if (Physics.Raycast(ray, out blockingHit, maxRayDistance, blockingLayerMask)) {
return blockingHit.distance + 0.01f;
}
return float.MaxValue;
}
void OnMouseDown () {
if (isActiveAndEnabled && triggerMode == TriggerMode.ColliderEventsOnlyOnThisObject) {
if (!CanInteract()) return;
if (selectOnClick && InputProxy.GetMouseButtonDown(0)) {
ToggleSelection();
return;
}
Highlight(true);
}
}
void OnMouseEnter () {
if (isActiveAndEnabled && triggerMode == TriggerMode.ColliderEventsOnlyOnThisObject) {
if (!CanInteract()) return;
Highlight(true);
}
}
void OnMouseExit () {
if (isActiveAndEnabled && triggerMode == TriggerMode.ColliderEventsOnlyOnThisObject) {
if (!CanInteract()) return;
Highlight(false);
}
}
void OnMouseOver () {
if (hb == null || !hb.labelEnabled) return;
Ray ray = raycastCamera.ScreenPointToRay(InputProxy.mousePosition);
if (Physics.Raycast(ray, out RaycastHit hit)) {
UpdateHitPosition(hit.transform, hit.point);
}
else {
UpdateHitPosition(transform, transform.position);
}
}
void Highlight (bool state) {
if (state) {
if (!hb.highlighted) {
if (OnObjectHighlightStart != null && hb.target != null) {
if (!OnObjectHighlightStart(hb.target.gameObject)) {
currentCollider = null;
return;
}
}
}
}
else {
if (hb.highlighted) {
if (OnObjectHighlightEnd != null && hb.target != null) {
OnObjectHighlightEnd(hb.target.gameObject);
}
}
}
if (selectOnClick || hb.isSelected) {
if (hb.isSelected) {
if (state && selectedAndHighlightedProfile != null) {
selectedAndHighlightedProfile.Load(hb);
}
else if (selectedProfile != null) {
selectedProfile.Load(hb);
}
else if (hb.previousSettings != null) {
hb.previousSettings.Load(hb);
}
if (hb.highlighted) {
hb.UpdateMaterialProperties();
}
else {
hb.SetHighlighted(true);
}
return;
}
else if (!highlightOnHover) {
hb.SetHighlighted(false);
return;
}
}
hb.SetHighlighted(state);
}
void UpdateHitPosition (Transform target, Vector3 positionWS = default, Vector3 normalWS = default) {
if (hb == null) return;
Vector3 localPosition = target.InverseTransformPoint(positionWS);
hb.SetHitPosition(target, localPosition, Misc.vector3Zero, normalWS);
if (InputProxy.GetMouseButtonDown(0) && OnObjectClicked != null) {
OnObjectClicked(target.gameObject, positionWS, normalWS);
}
}
void ToggleSelection () {
HighlightManager.lastTriggerFrame = Time.frameCount;
bool newState = toggle ? !hb.isSelected : true;
if (newState) {
if (OnObjectSelected != null && !OnObjectSelected(gameObject)) return;
}
else {
if (OnObjectUnSelected != null && !OnObjectUnSelected(gameObject)) return;
}
if (singleSelection && newState) {
HighlightManager.DeselectAll();
}
hb.isSelected = newState;
if (newState && !HighlightManager.selectedObjects.Contains(hb)) {
HighlightManager.selectedObjects.Add(hb);
}
else if (!newState && HighlightManager.selectedObjects.Contains(hb)) {
HighlightManager.selectedObjects.Remove(hb);
}
if (hb.isSelected) {
if (hb.previousSettings == null) {
hb.previousSettings = ScriptableObject.CreateInstance<HighlightProfile>();
}
hb.previousSettings.Save(hb);
}
else {
hb.RestorePreviousHighlightEffectSettings();
}
Highlight(true);
}
public void OnTriggerEnter (Collider other) {
if (triggerMode == TriggerMode.Volume) {
if ((volumeLayerMask & (1 << other.gameObject.layer)) != 0) {
Highlight(true);
}
}
}
public void OnTriggerExit (Collider other) {
if (triggerMode == TriggerMode.Volume) {
if ((volumeLayerMask & (1 << other.gameObject.layer)) != 0) {
Highlight(false);
}
}
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 5009cbb7e54994bb586cde7a70f34e6b
timeCreated: 1542876337
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,90 @@
using UnityEngine;
#if ENABLE_INPUT_SYSTEM && !ENABLE_LEGACY_INPUT_MANAGER
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;
using EnhancedTouch = UnityEngine.InputSystem.EnhancedTouch;
#endif
namespace HighlightPlus {
public static class InputProxy {
#if ENABLE_INPUT_SYSTEM && !ENABLE_LEGACY_INPUT_MANAGER
static Vector3 lastPointerPosition;
public static void Init() {
if (!EnhancedTouch.EnhancedTouchSupport.enabled) {
EnhancedTouch.EnhancedTouchSupport.Enable();
}
}
public static Vector3 mousePosition {
get {
if (touchCount > 0) {
lastPointerPosition = EnhancedTouch.Touch.activeTouches[0].screenPosition;
} else {
Mouse m = Mouse.current;
if (m != null) {
lastPointerPosition = m.position.ReadValue();
}
}
return lastPointerPosition;
}
}
public static bool GetMouseButtonDown(int buttonIndex) {
if (touchCount > 0) {
return EnhancedTouch.Touch.activeTouches[0].phase == UnityEngine.InputSystem.TouchPhase.Began;
} else {
Mouse m = Mouse.current;
if (m == null) return false;
switch (buttonIndex) {
case 1: return m.rightButton.wasPressedThisFrame;
case 2: return m.middleButton.wasPressedThisFrame;
default: return m.leftButton.wasPressedThisFrame;
}
}
}
public static int touchCount { get { return EnhancedTouch.Touch.activeTouches.Count; } }
public static int GetFingerIdFromTouch(int touchIndex) {
EnhancedTouch.Touch touch = EnhancedTouch.Touch.activeTouches[touchIndex];
return touch.finger.index;
}
public static bool GetKeyDown(string name) {
return ((KeyControl)Keyboard.current[name]).wasPressedThisFrame;
}
#else
public static void Init() {}
public static Vector3 mousePosition {
get {
return Input.mousePosition;
}
}
public static bool GetMouseButtonDown(int buttonIndex) {
return Input.GetMouseButtonDown(buttonIndex);
}
public static int touchCount {
get { return Input.touchCount; }
}
public static int GetFingerIdFromTouch(int touchIndex) {
return Input.GetTouch(touchIndex).fingerId;
}
public static bool GetKeyDown(string name) {
return Input.GetKeyDown(name);
}
#endif
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 22dd181849f53482686b5c26304410c2
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,41 @@
using UnityEngine;
using System;
namespace HighlightPlus {
public class Misc {
public static Vector2 vector2Zero = new Vector2(0, 0);
public static Vector2 vector2One = new Vector2(1, 1);
public static Vector3 vector3Zero = new Vector3(0, 0, 0);
public static Vector3 vector3Max = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue);
public static Vector3 vector3Min = new Vector3(float.MinValue, float.MinValue, float.MinValue);
public static T FindObjectOfType<T>(bool includeInactive = false) where T : UnityEngine.Object {
#if UNITY_2023_1_OR_NEWER
return UnityEngine.Object.FindAnyObjectByType<T>(includeInactive ? FindObjectsInactive.Include : FindObjectsInactive.Exclude);
#else
return UnityEngine.Object.FindObjectOfType<T>(includeInactive);
#endif
}
public static UnityEngine.Object[] FindObjectsOfType(Type type, bool includeInactive = false) {
#if UNITY_2023_1_OR_NEWER
return UnityEngine.Object.FindObjectsByType(type, includeInactive ? FindObjectsInactive.Include : FindObjectsInactive.Exclude, FindObjectsSortMode.None);
#else
return UnityEngine.Object.FindObjectsOfType(type, includeInactive);
#endif
}
public static T[] FindObjectsOfType<T>(bool includeInactive = false) where T : UnityEngine.Object {
#if UNITY_2023_1_OR_NEWER
return UnityEngine.Object.FindObjectsByType<T>(includeInactive ? FindObjectsInactive.Include : FindObjectsInactive.Exclude, FindObjectsSortMode.None);
#else
return UnityEngine.Object.FindObjectsOfType<T>(includeInactive);
#endif
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a87ac1812c2d44355a6c2acddcdd42ea
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,47 @@
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Rendering;
namespace HighlightPlus {
public static class RenderingUtils {
static Mesh _fullScreenMesh;
static Mesh fullscreenMesh {
get {
if (_fullScreenMesh != null) {
return _fullScreenMesh;
}
float num = 1f;
float num2 = 0f;
Mesh val = new Mesh();
_fullScreenMesh = val;
_fullScreenMesh.SetVertices(new List<Vector3> {
new Vector3 (-1f, -1f, 0f),
new Vector3 (-1f, 1f, 0f),
new Vector3 (1f, -1f, 0f),
new Vector3 (1f, 1f, 0f)
});
_fullScreenMesh.SetUVs(0, new List<Vector2> {
new Vector2 (0f, num2),
new Vector2 (0f, num),
new Vector2 (1f, num2),
new Vector2 (1f, num)
});
_fullScreenMesh.SetIndices(new int[6] { 0, 1, 2, 2, 1, 3 }, (MeshTopology)0, 0, false);
_fullScreenMesh.UploadMeshData(true);
return _fullScreenMesh;
}
}
static Matrix4x4 matrix4x4Identity = Matrix4x4.identity;
public static void FullScreenBlit(CommandBuffer cmd, RenderTargetIdentifier source, RenderTargetIdentifier destination, Material material, int passIndex) {
destination = new RenderTargetIdentifier(destination, 0, CubemapFace.Unknown, -1);
cmd.SetRenderTarget(destination);
cmd.SetGlobalTexture(ShaderParams.MainTex, source);
cmd.DrawMesh(fullscreenMesh, matrix4x4Identity, material, 0, passIndex);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 95fcf366e400b4f79938bee11ff1ddc0
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,147 @@
using UnityEngine;
namespace HighlightPlus {
public static class ShaderParams {
// general uniforms
public static int Cull = Shader.PropertyToID("_Cull");
public static int BlurScale = Shader.PropertyToID("_BlurScale");
public static int BlurScaleFirstHoriz = Shader.PropertyToID("_BlurScaleFirstHoriz");
public static int Speed = Shader.PropertyToID("_Speed");
public static int ConstantWidth = Shader.PropertyToID("_ConstantWidth");
public static int MinimumWidth = Shader.PropertyToID("_MinimumWidth");
public static int CutOff = Shader.PropertyToID("_CutOff");
public static int ZTest = Shader.PropertyToID("_ZTest");
public static int Flip = Shader.PropertyToID("_Flip");
public static int Debug = Shader.PropertyToID("_Debug");
public static int Color = Shader.PropertyToID("_Color");
public static int MainTex = Shader.PropertyToID("_MainTex");
public static int BaseMap = Shader.PropertyToID("_BaseMap");
public static int BaseMapST = Shader.PropertyToID("_BaseMap_ST");
public static int BlendSrc = Shader.PropertyToID("_BlendSrc");
public static int BlendDst = Shader.PropertyToID("_BlendDst");
public static int FadeFactor = Shader.PropertyToID("_HP_Fade");
public static int Padding = Shader.PropertyToID("_Padding");
public static int ResampleScale = Shader.PropertyToID("_ResampleScale");
public static int NoiseTex = Shader.PropertyToID("_NoiseTex");
public static int Pixelation = Shader.PropertyToID("_Pixelation");
// outline uniforms
public static int OutlineWidth = Shader.PropertyToID("_OutlineWidth");
public static int OutlineZTest = Shader.PropertyToID("_OutlineZTest");
public static int OutlineDirection = Shader.PropertyToID("_OutlineDirection");
public static int OutlineColor = Shader.PropertyToID("_OutlineColor");
public static int OutlineVertexWidth = Shader.PropertyToID("_OutlineVertexWidth");
public static int OutlineGradientTex = Shader.PropertyToID("_OutlineGradientTex");
public static int OutlineVertexData = Shader.PropertyToID("_OutlineVertexData");
public static int OutlineStencilComp = Shader.PropertyToID("_OutlineStencilComp");
public static int OutlineEdgeThreshold = Shader.PropertyToID("_EdgeThreshold");
public static int OutlineSharpness = Shader.PropertyToID("_OutlineSharpness");
// glow uniforms
public static int GlowZTest = Shader.PropertyToID("_GlowZTest");
public static int GlowStencilComp = Shader.PropertyToID("_GlowStencilComp");
public static int GlowStencilOp = Shader.PropertyToID("_GlowStencilOp");
public static int GlowDirection = Shader.PropertyToID("_GlowDirection");
public static int Glow = Shader.PropertyToID("_Glow");
public static int GlowColor = Shader.PropertyToID("_GlowColor");
public static int Glow2 = Shader.PropertyToID("_Glow2");
// see-through uniforms
public static int SeeThrough = Shader.PropertyToID("_SeeThrough");
public static int SeeThroughNoise = Shader.PropertyToID("_SeeThroughNoise");
public static int SeeThroughBorderWidth = Shader.PropertyToID("_SeeThroughBorderWidth");
public static int SeeThroughBorderConstantWidth = Shader.PropertyToID("_SeeThroughBorderConstantWidth");
public static int SeeThroughTintColor = Shader.PropertyToID("_SeeThroughTintColor");
public static int SeeThroughBorderColor = Shader.PropertyToID("_SeeThroughBorderColor");
public static int SeeThroughStencilRef = Shader.PropertyToID("_SeeThroughStencilRef");
public static int SeeThroughStencilComp = Shader.PropertyToID("_SeeThroughStencilComp");
public static int SeeThroughStencilPassOp = Shader.PropertyToID("_SeeThroughStencilPassOp");
public static int SeeThroughDepthOffset = Shader.PropertyToID("_SeeThroughDepthOffset");
public static int SeeThroughMaxDepth = Shader.PropertyToID("_SeeThroughMaxDepth");
public static int SeeThroughFadeRange = Shader.PropertyToID("_SeeThroughFadeRange");
public static int SeeThroughTexture = Shader.PropertyToID("_SeeThroughTexture");
public static int SeeThroughTextureScale = Shader.PropertyToID("_SeeThroughTextureScale");
// inner glow uniforms
public static int InnerGlowData = Shader.PropertyToID("_InnerGlowData");
public static int InnerGlowZTest = Shader.PropertyToID("_InnerGlowZTest");
public static int InnerGlowColor = Shader.PropertyToID("_InnerGlowColor");
public static int InnerGlowBlendMode = Shader.PropertyToID("_InnerGlowBlendMode");
// mask uniforms (not declared in Properties so globals take effect over material defaults)
public static int MaskStencilRef = Shader.PropertyToID("_MaskStencilRef");
public static int MaskWriteMask = Shader.PropertyToID("_MaskWriteMask");
// focus uniforms
public static int FocusColor = Shader.PropertyToID("_FocusColor");
public static int FocusBlurTex = Shader.PropertyToID("_FocusBlurTex");
public static int FocusBlurRT = Shader.PropertyToID("_HPFocusBlurRT");
public static int FocusBlurTempRT = Shader.PropertyToID("_HPFocusBlurTempRT");
public static int FocusDesaturation = Shader.PropertyToID("_FocusDesaturation");
// overlay uniforms
public static int OverlayData = Shader.PropertyToID("_OverlayData");
public static int OverlayBackColor = Shader.PropertyToID("_OverlayBackColor");
public static int OverlayColor = Shader.PropertyToID("_OverlayColor");
public static int OverlayHitPosData = Shader.PropertyToID("_OverlayHitPosData");
public static int OverlayHitStartTime = Shader.PropertyToID("_OverlayHitStartTime");
public static int OverlayTexture = Shader.PropertyToID("_OverlayTexture");
public static int OverlayTextureScrolling = Shader.PropertyToID("_OverlayTextureScrolling");
public static int OverlayZTest = Shader.PropertyToID("_OverlayZTest");
public static int OverlayPatternScrolling = Shader.PropertyToID("_OverlayPatternScrolling");
public static int OverlayPatternData = Shader.PropertyToID("_OverlayPatternData");
public static int OverlayBlendDst = Shader.PropertyToID("_OverlayBlendDst");
// target uniforms
public static int TargetFXRenderData = Shader.PropertyToID("_TargetFXRenderData");
public static int TargetFXFrameData = Shader.PropertyToID("_TargetFXFrameData");
public static int GlowRT = Shader.PropertyToID("_HPComposeGlowFinal");
public static int OutlineRT = Shader.PropertyToID("_HPComposeOutlineFinal");
// icon uniforms
public static int IconFXDarkColor = Shader.PropertyToID("_DarkColor");
// custom vertex transform
public static int VertexTransformMode = Shader.PropertyToID("_HP_VertexTransformMode");
// pattern uniforms
public static int PatternTex = Shader.PropertyToID("_PatternTex");
public static int DistortionTex = Shader.PropertyToID("_DistortionTex");
public static int PatternData = Shader.PropertyToID("_PatternData");
// dashed outline
public static int DashData = Shader.PropertyToID("_DashData");
// outline gradient
public static int OutlineGradientData = Shader.PropertyToID("_OutlineGradientData");
// keywords
public const string SKW_ALPHACLIP = "HP_ALPHACLIP";
public const string SKW_OUTLINE_GRADIENT_WS = "HP_OUTLINE_GRADIENT_WS";
public const string SKW_OUTLINE_GRADIENT_LS = "HP_OUTLINE_GRADIENT_LS";
public const string SKW_ALL_EDGES = "HP_ALL_EDGES";
public const string SKW_DEPTHCLIP = "HP_DEPTHCLIP";
public const string SKW_DEPTHCLIP_INV = "HP_DEPTHCLIP_INV";
public const string SKW_DEPTH_OFFSET = "HP_DEPTH_OFFSET";
public const string SKW_TEXTURE_TRIPLANAR = "HP_TEXTURE_TRIPLANAR";
public const string SKW_TEXTURE_TRIPLANAR_LOCAL = "HP_TEXTURE_TRIPLANAR_LOCAL";
public const string SKW_TEXTURE_SCREENSPACE = "HP_TEXTURE_SCREENSPACE";
public const string SKW_TEXTURE_OBJECTSPACE = "HP_TEXTURE_OBJECTSPACE";
public const string SKW_SEETHROUGH_ONLY_BORDER = "HP_SEETHROUGH_ONLY_BORDER";
public const string SKW_MASK_CUTOUT = "HP_MASK_CUTOUT";
public const string SKW_DITHER_BLUENOISE = "HP_DITHER_BLUENOISE";
public const string SKW_OUTLINE_STYLIZED = "HP_STYLIZED";
public const string SKW_OUTLINE_DASHED = "HP_DASHED";
public const string SKW_TARGET_FRAME = "HP_TARGET_FRAME";
public const string SKW_TARGET_INWARD_CORNERS = "HP_TARGET_INWARD_CORNERS";
public const string SKW_TARGET_CROSS = "HP_TARGET_CROSS";
public const string SKW_PATTERN_POLKADOTS = "HP_PATTERN_POLKADOTS";
public const string SKW_PATTERN_GRID = "HP_PATTERN_GRID";
public const string SKW_PATTERN_STAGGERED_LINES = "HP_PATTERN_STAGGERED_LINES";
public const string SKW_PATTERN_ZIGZAG = "HP_PATTERN_ZIGZAG";
public const string SKW_SOURCE_SOLID_COLOR = "SOURCE_SOLID_COLOR";
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0c43adc34509547febe8181a2de00da5
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,62 @@
// Comment this line to disable usage of XR module
#define ENABLE_XR
using System.Collections.Generic;
using UnityEngine;
#if ENABLE_XR
using UnityEngine.XR;
#endif
namespace HighlightPlus {
static class VRCheck {
public static bool isActive;
public static bool isVrRunning;
#if !ENABLE_XR
static bool IsActive() {
return false;
}
static bool IsVrRunning() {
return false;
}
#else
static readonly List<XRDisplaySubsystemDescriptor> displaysDescs = new List<XRDisplaySubsystemDescriptor>();
static readonly List<XRDisplaySubsystem> displays = new List<XRDisplaySubsystem>();
static bool IsActive() {
displaysDescs.Clear();
SubsystemManager.GetSubsystemDescriptors(displaysDescs);
// If there are registered display descriptors that is a good indication that VR is most likely "enabled"
return displaysDescs.Count > 0;
}
static bool IsVrRunning() {
bool vrIsRunning = false;
displays.Clear();
SubsystemManager.GetSubsystems(displays);
foreach (var displaySubsystem in displays) {
if (displaySubsystem.running) {
vrIsRunning = true;
break;
}
}
return vrIsRunning;
}
#endif
public static void Init() {
isActive = IsActive();
isVrRunning = IsVrRunning();
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c5a7be65460ba4182b08a8f602571e25
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: