mirror of
https://github.com/DeMuenu/MoonlightVRC.git
synced 2025-12-12 11:12:47 +00:00
Initial commit
This commit is contained in:
2
.gitattributes
vendored
Normal file
2
.gitattributes
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
# Auto detect text files and perform LF normalization
|
||||
* text=auto
|
||||
8
EditorPreview.meta
Normal file
8
EditorPreview.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2a124e3c4f76d5c4694c91508af58fba
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
EditorPreview/Editor.meta
Normal file
8
EditorPreview/Editor.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9ee398d1bd8711f4e9424187553d2877
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
159
EditorPreview/Editor/PlayerPositionsToShaderPreview.cs
Normal file
159
EditorPreview/Editor/PlayerPositionsToShaderPreview.cs
Normal file
@@ -0,0 +1,159 @@
|
||||
// Assets/Editor/PlayerPositionsToShaderPreview.cs
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using System.Collections.Generic;
|
||||
|
||||
[InitializeOnLoad]
|
||||
public static class PlayerPositionsToShaderPreview
|
||||
{
|
||||
const double kTickInterval = 0.1; // seconds
|
||||
static double _nextTick;
|
||||
static readonly MaterialPropertyBlock _mpb = new MaterialPropertyBlock();
|
||||
static readonly Dictionary<PlayerPositionsToShader, Cache> _cache = new Dictionary<PlayerPositionsToShader, Cache>();
|
||||
|
||||
struct Cache
|
||||
{
|
||||
public Vector4[] positions;
|
||||
public Vector4[] colors;
|
||||
public Vector4[] directions;
|
||||
public float[] types;
|
||||
public int size;
|
||||
}
|
||||
|
||||
static PlayerPositionsToShaderPreview()
|
||||
{
|
||||
EditorApplication.update += Update;
|
||||
EditorApplication.hierarchyChanged += ForceTick;
|
||||
Undo.undoRedoPerformed += ForceTick;
|
||||
Selection.selectionChanged += ForceTick;
|
||||
}
|
||||
|
||||
public static void ForceTick() => _nextTick = 0;
|
||||
|
||||
static void Update()
|
||||
{
|
||||
#if UNITY_2019_1_OR_NEWER
|
||||
if (EditorApplication.isPlayingOrWillChangePlaymode) return;
|
||||
#else
|
||||
if (EditorApplication.isPlaying) return;
|
||||
#endif
|
||||
double now = EditorApplication.timeSinceStartup;
|
||||
if (now < _nextTick) return;
|
||||
_nextTick = now + kTickInterval;
|
||||
|
||||
var behaviours = FindAllInScene();
|
||||
foreach (var b in behaviours)
|
||||
{
|
||||
if (b == null || !b.isActiveAndEnabled) continue;
|
||||
if (EditorUtility.IsPersistent(b)) continue; // skip assets
|
||||
PushFromUdonBehaviour(b);
|
||||
}
|
||||
|
||||
SceneView.RepaintAll();
|
||||
}
|
||||
|
||||
static PlayerPositionsToShader[] FindAllInScene()
|
||||
{
|
||||
#if UNITY_2023_1_OR_NEWER
|
||||
return Object.FindObjectsByType<PlayerPositionsToShader>(FindObjectsInactive.Exclude, FindObjectsSortMode.None);
|
||||
#elif UNITY_2020_1_OR_NEWER
|
||||
return Object.FindObjectsOfType<PlayerPositionsToShader>(true);
|
||||
#else
|
||||
return Resources.FindObjectsOfTypeAll<PlayerPositionsToShader>();
|
||||
#endif
|
||||
}
|
||||
|
||||
static void EnsureArrays(PlayerPositionsToShader src, int required)
|
||||
{
|
||||
if (!_cache.TryGetValue(src, out var c) ||
|
||||
c.positions == null || c.colors == null || c.directions == null || c.types == null ||
|
||||
c.size != required)
|
||||
{
|
||||
c = new Cache
|
||||
{
|
||||
positions = new Vector4[required],
|
||||
colors = new Vector4[required],
|
||||
directions = new Vector4[required],
|
||||
types = new float[required],
|
||||
size = required
|
||||
};
|
||||
_cache[src] = c;
|
||||
}
|
||||
}
|
||||
|
||||
static void PushFromUdonBehaviour(PlayerPositionsToShader src)
|
||||
{
|
||||
int max = Mathf.Max(1, src.maxLights);
|
||||
EnsureArrays(src, max);
|
||||
|
||||
var c = _cache[src];
|
||||
var positions = c.positions;
|
||||
var colors = c.colors;
|
||||
var directions = c.directions;
|
||||
var types = c.types;
|
||||
|
||||
for (int i = 0; i < max; i++)
|
||||
{
|
||||
positions[i] = Vector4.zero;
|
||||
colors[i] = Vector4.zero;
|
||||
directions[i] = Vector4.zero;
|
||||
types[i] = 0f;
|
||||
}
|
||||
|
||||
// 🔗 Use the Editor-side function defined on the partial class
|
||||
int count = 0;
|
||||
try
|
||||
{
|
||||
src.Editor_BuildPreview(out positions, out colors, out directions, out types, out count);
|
||||
// replace cache arrays if sizes changed
|
||||
if (positions.Length != c.size) EnsureArrays(src, positions.Length);
|
||||
_cache[src] = new Cache { positions = positions, colors = colors, directions = directions, types = types, size = positions.Length };
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Ultra-safe fallback: nothing to push if the method signature changes unexpectedly
|
||||
count = 0;
|
||||
}
|
||||
|
||||
var rds = src.targets ?? System.Array.Empty<Renderer>();
|
||||
for (int r = 0; r < rds.Length; r++)
|
||||
{
|
||||
var rd = rds[r];
|
||||
if (rd == null) continue;
|
||||
|
||||
rd.GetPropertyBlock(_mpb);
|
||||
|
||||
if (!string.IsNullOrEmpty(src.positionsProperty)) _mpb.SetVectorArray(src.positionsProperty, positions);
|
||||
if (!string.IsNullOrEmpty(src.colorProperty)) _mpb.SetVectorArray(src.colorProperty, colors);
|
||||
if (!string.IsNullOrEmpty(src.directionsProperty)) _mpb.SetVectorArray(src.directionsProperty, directions);
|
||||
if (!string.IsNullOrEmpty(src.typeProperty)) _mpb.SetFloatArray (src.typeProperty, types);
|
||||
if (!string.IsNullOrEmpty(src.countProperty)) _mpb.SetFloat (src.countProperty, count);
|
||||
|
||||
rd.SetPropertyBlock(_mpb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[CustomEditor(typeof(PlayerPositionsToShader))]
|
||||
public class PlayerPositionsToShaderInspector : Editor
|
||||
{
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
DrawDefaultInspector();
|
||||
GUILayout.Space(6);
|
||||
using (new EditorGUI.DisabledScope(true))
|
||||
{
|
||||
EditorGUILayout.LabelField("Edit-Mode Preview", EditorStyles.boldLabel);
|
||||
EditorGUILayout.LabelField("Updates ~10×/s using \"Other Transforms\" as emitters.");
|
||||
}
|
||||
|
||||
if (GUILayout.Button("Refresh Now"))
|
||||
{
|
||||
PlayerPositionsToShaderPreview.ForceTick();
|
||||
EditorApplication.QueuePlayerLoopUpdate();
|
||||
SceneView.RepaintAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
11
EditorPreview/Editor/PlayerPositionsToShaderPreview.cs.meta
Normal file
11
EditorPreview/Editor/PlayerPositionsToShaderPreview.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2eac5e5df0d18524e84022a091ada4f5
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
53
EditorPreview/PlayerPositionsToShader.Editor.cs
Normal file
53
EditorPreview/PlayerPositionsToShader.Editor.cs
Normal file
@@ -0,0 +1,53 @@
|
||||
// Assets/Lighting/Scripts/PlayerPositionsToShader.Editor.cs
|
||||
#if UNITY_EDITOR
|
||||
using UnityEngine;
|
||||
|
||||
public partial class PlayerPositionsToShader
|
||||
{
|
||||
public void Editor_BuildPreview(
|
||||
out Vector4[] positions,
|
||||
out Vector4[] colors,
|
||||
out Vector4[] directions,
|
||||
out float[] types,
|
||||
out int count)
|
||||
{
|
||||
int max = Mathf.Max(1, maxLights);
|
||||
|
||||
positions = new Vector4[max];
|
||||
colors = new Vector4[max];
|
||||
directions = new Vector4[max];
|
||||
types = new float[max];
|
||||
count = 0;
|
||||
|
||||
// ✅ Avoid Array.Empty<T>(); just guard the loop
|
||||
if (otherLightSources != null)
|
||||
{
|
||||
for (int i = 0; i < otherLightSources.Length && count < max; i++)
|
||||
{
|
||||
Transform t = otherLightSources[i];
|
||||
if (t == null || !t.gameObject.activeInHierarchy) continue;
|
||||
|
||||
LightdataStorage data = t.GetComponent<LightdataStorage>();
|
||||
|
||||
Vector3 pos = t.position;
|
||||
float range = (data != null) ? data.range * t.localScale.x : t.localScale.x;
|
||||
Vector4 col = (data != null) ? data.GetFinalColor() : new Vector4(1f, 1f, 1f, 1f);
|
||||
float intens = (data != null) ? data.intensity * t.localScale.x : 1f;
|
||||
float cosHalf = (data != null) ? data.GetCosHalfAngle() : 1f;
|
||||
int typeId = (data != null) ? data.GetTypeId() : 0;
|
||||
|
||||
|
||||
Quaternion rot = t.rotation;
|
||||
Vector3 fwd = rot * Vector3.down;
|
||||
|
||||
positions[count] = new Vector4(pos.x, pos.y, pos.z, range);
|
||||
colors[count] = new Vector4(col.x, col.y, col.z, intens);
|
||||
directions[count] = new Vector4(fwd.x, fwd.y, fwd.z, data.spotAngleDeg);
|
||||
types[count] = (float)typeId;
|
||||
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
11
EditorPreview/PlayerPositionsToShader.Editor.cs.meta
Normal file
11
EditorPreview/PlayerPositionsToShader.Editor.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 93398d31d2739524dad37ec5e916b222
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Scripts.meta
Normal file
8
Scripts.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 23121b67c238da34e9055714600bb22a
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
48
Scripts/LightdataStorage.cs
Normal file
48
Scripts/LightdataStorage.cs
Normal file
@@ -0,0 +1,48 @@
|
||||
using UdonSharp;
|
||||
using UnityEngine;
|
||||
using VRC.SDKBase;
|
||||
using VRC.Udon;
|
||||
|
||||
|
||||
|
||||
public enum LightType { Sphere, Spot }
|
||||
|
||||
[UdonBehaviourSyncMode(BehaviourSyncMode.None)]
|
||||
public class LightdataStorage : UdonSharpBehaviour
|
||||
{
|
||||
|
||||
[Header("Type")]
|
||||
[Tooltip("Select the logical light type for this source.")]
|
||||
public LightType lightType = LightType.Sphere;
|
||||
|
||||
|
||||
[Header("Light Settings")]
|
||||
|
||||
public float range = 5f;
|
||||
|
||||
|
||||
|
||||
[ColorUsage(true, true)] // (showAlpha: true, HDR: true)
|
||||
public Color color = Color.white;
|
||||
|
||||
[Tooltip("Intensity multiplier applied to the color (kept separate so you can tweak brightness without changing hue).")]
|
||||
public float intensity = 1f;
|
||||
|
||||
[Header("Spotlight Shape")]
|
||||
[Tooltip("0 = omni (no cone)")]
|
||||
public float spotAngleDeg = 0f;
|
||||
|
||||
// Convert to a Vector4 for your shader upload
|
||||
public Vector4 GetFinalColor()
|
||||
{
|
||||
return new Vector4(color.r * intensity, color.g * intensity, color.b * intensity, color.a);
|
||||
}
|
||||
|
||||
public float GetCosHalfAngle()
|
||||
{
|
||||
if (spotAngleDeg <= 0f) return 0f;
|
||||
return Mathf.Cos(Mathf.Deg2Rad * (spotAngleDeg * 0.5f));
|
||||
}
|
||||
|
||||
public int GetTypeId() => (int)lightType; // Omni=0, Spot=1, Directional=2
|
||||
}
|
||||
11
Scripts/LightdataStorage.cs.meta
Normal file
11
Scripts/LightdataStorage.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d87e774841a8cbf4fa961c9076c880bf
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
280
Scripts/PlayerPositionsToShader.cs
Normal file
280
Scripts/PlayerPositionsToShader.cs
Normal file
@@ -0,0 +1,280 @@
|
||||
using System;
|
||||
using UdonSharp;
|
||||
using Unity.Mathematics;
|
||||
using UnityEngine;
|
||||
using VRC.SDKBase;
|
||||
using VRC.Udon;
|
||||
|
||||
public partial class PlayerPositionsToShader : UdonSharpBehaviour
|
||||
{
|
||||
[Header("Lightsources")]
|
||||
[Tooltip("Place Transforms here which should also emit Light (attach LightdataStorage to them).")]
|
||||
public Transform[] otherLightSources;
|
||||
|
||||
[Header("Renderers that use a supported shader")]
|
||||
public Renderer[] targets;
|
||||
|
||||
[Header("Strength")]
|
||||
[Tooltip("Local player light range")]
|
||||
public float lightStrengthLocal = 10f;
|
||||
|
||||
[Tooltip("Remote players light range")]
|
||||
public float lightStrengthRemote = 5f;
|
||||
|
||||
[Tooltip("Players light intensity")]
|
||||
public float playerLightIntensity = 5f;
|
||||
public float remoteLightIntensity = 2f;
|
||||
|
||||
|
||||
[Header("Shader property names (advanced users)")]
|
||||
[Tooltip("Vector4 array: xyz = position, w = range")]
|
||||
public string positionsProperty = "_PlayerPositions";
|
||||
|
||||
[Tooltip("Actual array count")]
|
||||
public string countProperty = "_PlayerCount";
|
||||
|
||||
[Tooltip("RGBA array: rgb = color, a = intensity")]
|
||||
public string colorProperty = "_LightColors";
|
||||
|
||||
[Tooltip("Vector4 array: xyz = direction, w = spot in degrees")]
|
||||
public string directionsProperty = "_LightDirections";
|
||||
|
||||
[Tooltip("float array: light type (1=area, 2=cone, etc)")]
|
||||
public string typeProperty = "_LightType";
|
||||
|
||||
[Header("Max Lights (advanced users)")]
|
||||
[Tooltip("Hard cap / array size. 80 = default cap")]
|
||||
public int maxLights = 80;
|
||||
|
||||
|
||||
|
||||
// Internals
|
||||
private Vector4[] _positions;
|
||||
private bool _positons_isDirty = false;
|
||||
private Vector4[] _lightColors;
|
||||
private bool _lightColors_isDirty = false;
|
||||
private Vector4[] _directions;
|
||||
private bool _directions_isDirty = false;
|
||||
|
||||
private float[] _TypeArray;
|
||||
private bool _TypeArray_isDirty = false;
|
||||
|
||||
private VRCPlayerApi[] _players;
|
||||
private MaterialPropertyBlock _mpb;
|
||||
|
||||
public int currentCount { get; private set; }
|
||||
|
||||
void Start()
|
||||
{
|
||||
if (maxLights < 1) maxLights = 1;
|
||||
|
||||
_positions = new Vector4[maxLights];
|
||||
_lightColors = new Vector4[maxLights];
|
||||
_directions = new Vector4[maxLights];
|
||||
_TypeArray = new float[maxLights];
|
||||
|
||||
_players = new VRCPlayerApi[maxLights];
|
||||
_mpb = new MaterialPropertyBlock();
|
||||
|
||||
UpdateData();
|
||||
PushToRenderers();
|
||||
}
|
||||
|
||||
void LateUpdate()
|
||||
{
|
||||
UpdateData();
|
||||
PushToRenderers();
|
||||
}
|
||||
|
||||
private void UpdateData()
|
||||
{
|
||||
currentCount = VRCPlayerApi.GetPlayerCount();
|
||||
|
||||
|
||||
VRCPlayerApi.GetPlayers(_players);
|
||||
|
||||
// --- Players as light sources ---
|
||||
for (int i = 0; i < currentCount && currentCount < maxLights; i++)
|
||||
{
|
||||
VRCPlayerApi p = _players[i];
|
||||
if (Utilities.IsValid(p))
|
||||
{
|
||||
Vector3 pos = p.GetPosition();
|
||||
float lightRange = p.isLocal ? lightStrengthLocal : lightStrengthRemote;
|
||||
float intensity = p.isLocal ? playerLightIntensity : remoteLightIntensity;
|
||||
|
||||
|
||||
Vector4 posTemp = new Vector4(pos.x, pos.y + 1f, pos.z, lightRange);
|
||||
if (_positions[i] != posTemp)
|
||||
{
|
||||
_positions[i] = posTemp;
|
||||
_positons_isDirty = true;
|
||||
}
|
||||
|
||||
Vector4 colorTemp = new Vector4(1f, 1f, 1f, intensity);
|
||||
if (_lightColors[i] != colorTemp)
|
||||
{
|
||||
_lightColors[i] = colorTemp;
|
||||
_lightColors_isDirty = true;
|
||||
}
|
||||
|
||||
|
||||
//Quaternion rot = p.GetRotation(); //We skip this for players, as they have round lights
|
||||
Vector3 fwd = Vector3.up;
|
||||
Vector4 TempDir = new Vector4(fwd.x, fwd.y, fwd.z, 10f);
|
||||
if (_directions[i] != TempDir)
|
||||
{
|
||||
_directions[i] = new Vector4(TempDir.x, TempDir.y, TempDir.z, 10f);
|
||||
_directions_isDirty = true;
|
||||
}
|
||||
|
||||
if (_TypeArray[i] != 0f)
|
||||
{
|
||||
_TypeArray[i] = 0f;
|
||||
_TypeArray_isDirty = true;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_positions[i] != Vector4.zero)
|
||||
{
|
||||
_positions[i] = Vector4.zero;
|
||||
_positons_isDirty = true;
|
||||
}
|
||||
if (_lightColors[i] != Vector4.zero)
|
||||
{
|
||||
_lightColors[i] = Vector4.zero;
|
||||
_lightColors_isDirty = true;
|
||||
}
|
||||
if (_directions[i] != Vector4.zero)
|
||||
{
|
||||
_directions[i] = Vector4.zero;
|
||||
_directions_isDirty = true;
|
||||
}
|
||||
if (_TypeArray[i] != 0f)
|
||||
{
|
||||
_TypeArray[i] = 0f;
|
||||
_TypeArray_isDirty = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --- Scene light sources ---
|
||||
if (otherLightSources != null)
|
||||
{
|
||||
for (int j = 0; j < otherLightSources.Length && currentCount < maxLights; j++)
|
||||
{
|
||||
Transform t = otherLightSources[j];
|
||||
if (t == null || !t.gameObject.activeInHierarchy) continue;
|
||||
|
||||
LightdataStorage data = t.GetComponent<LightdataStorage>();
|
||||
|
||||
Vector3 pos = t.position;
|
||||
float range = (data != null) ? data.range * t.localScale.x: t.localScale.x;
|
||||
|
||||
// NOTE: we pack intensity into color.w (to match your current shader usage)
|
||||
Vector4 col = (data != null) ? data.GetFinalColor() : new Vector4(1f, 1f, 1f, 1f);
|
||||
float intensity = (data != null) ? data.intensity * t.localScale.x : 1f;
|
||||
|
||||
//Vector3 fwd = new Vector3(t.localRotation.x, t.localRotation.y, t.localRotation.z);
|
||||
|
||||
Quaternion rot = t.rotation;
|
||||
Vector3 fwd = rot * Vector3.down;
|
||||
|
||||
|
||||
float cosHalf = (data != null) ? data.GetCosHalfAngle() : 0f;
|
||||
|
||||
Vector4 posTemp = new Vector4(pos.x, pos.y, pos.z, range);
|
||||
if (_positions[currentCount] != posTemp)
|
||||
{
|
||||
_positions[currentCount] = posTemp;
|
||||
_positons_isDirty = true;
|
||||
}
|
||||
Vector4 colorTemp = new Vector4(col.x, col.y, col.z, intensity);
|
||||
if (_lightColors[currentCount] != colorTemp)
|
||||
{
|
||||
_lightColors[currentCount] = colorTemp;
|
||||
_lightColors_isDirty = true;
|
||||
}
|
||||
Vector4 dirTemp = new Vector4(fwd.x, fwd.y, fwd.z, cosHalf);
|
||||
if (_directions[currentCount] != dirTemp)
|
||||
{
|
||||
_directions[currentCount] = dirTemp;
|
||||
_directions_isDirty = true;
|
||||
}
|
||||
|
||||
// ✅ Use your custom enum id (Omni=0, Spot=1, Directional=2)
|
||||
int typeId = (data != null) ? data.GetTypeId() : 0;
|
||||
if (_TypeArray[currentCount] != (float)typeId)
|
||||
{
|
||||
_TypeArray[currentCount] = (float)typeId;
|
||||
_TypeArray_isDirty = true;
|
||||
}
|
||||
|
||||
currentCount++;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = currentCount; i < maxLights; i++)
|
||||
{
|
||||
if (_positions[i] != Vector4.zero)
|
||||
{
|
||||
_positions[i] = Vector4.zero;
|
||||
_positons_isDirty = true;
|
||||
}
|
||||
|
||||
if (_lightColors[i] != Vector4.zero)
|
||||
{
|
||||
_lightColors[i] = Vector4.zero;
|
||||
_lightColors_isDirty = true;
|
||||
}
|
||||
|
||||
if (_directions[i] != Vector4.zero)
|
||||
{
|
||||
_directions[i] = Vector4.zero;
|
||||
_directions_isDirty = true;
|
||||
}
|
||||
|
||||
if (_TypeArray[i] != 0f)
|
||||
{
|
||||
_TypeArray[i] = 0f;
|
||||
_TypeArray_isDirty = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void PushToRenderers()
|
||||
{
|
||||
if (targets == null || targets.Length == 0) return;
|
||||
|
||||
// Snapshot which things are dirty this frame
|
||||
bool pushPositions = _positons_isDirty;
|
||||
bool pushColors = _lightColors_isDirty;
|
||||
bool pushDirs = _directions_isDirty;
|
||||
bool pushTypes = _TypeArray_isDirty && !string.IsNullOrEmpty(typeProperty);
|
||||
|
||||
for (int r = 0; r < targets.Length; r++)
|
||||
{
|
||||
Renderer rd = targets[r];
|
||||
if (!Utilities.IsValid(rd)) continue;
|
||||
|
||||
rd.GetPropertyBlock(_mpb);
|
||||
|
||||
if (pushPositions) _mpb.SetVectorArray(positionsProperty, _positions);
|
||||
if (pushColors) _mpb.SetVectorArray(colorProperty, _lightColors);
|
||||
if (pushDirs) _mpb.SetVectorArray(directionsProperty, _directions);
|
||||
if (pushTypes) _mpb.SetFloatArray(typeProperty, _TypeArray);
|
||||
|
||||
_mpb.SetFloat(countProperty, currentCount);
|
||||
rd.SetPropertyBlock(_mpb);
|
||||
}
|
||||
|
||||
// Only now mark them clean
|
||||
if (pushPositions) { _positons_isDirty = false; Debug.Log("Updated Positions"); }
|
||||
if (pushColors) { _lightColors_isDirty = false; Debug.Log("Updated LightColors"); }
|
||||
if (pushDirs) { _directions_isDirty = false; Debug.Log("Updated Directions"); }
|
||||
if (pushTypes) { _TypeArray_isDirty = false; Debug.Log("Updated TypeArray"); }
|
||||
}
|
||||
}
|
||||
11
Scripts/PlayerPositionsToShader.cs.meta
Normal file
11
Scripts/PlayerPositionsToShader.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ae77287fea761ef4d9c2f38c0d71d901
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Shader.meta
Normal file
8
Shader.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7b1f08ce8e71a3342a43990e3fb8a9dc
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
190
Shader/BlendinShader.shader
Normal file
190
Shader/BlendinShader.shader
Normal file
@@ -0,0 +1,190 @@
|
||||
Shader "DeMuenu/World/Hoppou/RevealStandart"
|
||||
{
|
||||
Properties
|
||||
{
|
||||
_MainTex ("Texture", 2D) = "white" {}
|
||||
_MultTex ("Multiply Texture", 2D) = "white" {}
|
||||
_MultiplicatorTex ("Multiply Texture Strength", Range(0,3)) = 0
|
||||
_Color ("Color", Color) = (1,1,1,1)
|
||||
|
||||
_EmmisiveText ("Emmissive Texture", 2D) = "white" {}
|
||||
_EmmissiveColor ("Emmissive Color", Color) = (1,1,1,1)
|
||||
_EmmissiveStrength ("Emmissive Strength", Range(0,10)) = 0
|
||||
|
||||
|
||||
//MoonsLight
|
||||
_InverseSqareMultiplier ("Inverse Square Multiplier", Float) = 1
|
||||
_LightCutoffDistance ("Light Cutoff Distance", Float) = 100
|
||||
//MoonsLight END
|
||||
|
||||
|
||||
|
||||
}
|
||||
SubShader
|
||||
{
|
||||
Tags { "RenderType"="Opaque" }
|
||||
LOD 100
|
||||
|
||||
Pass
|
||||
{
|
||||
CGPROGRAM
|
||||
#pragma vertex vert
|
||||
#pragma fragment frag
|
||||
|
||||
#include "UnityCG.cginc"
|
||||
|
||||
//MoonsLight Defines
|
||||
#define MAX_LIGHTS 80 // >= maxPlayers in script
|
||||
//MoonsLight Defines END
|
||||
|
||||
struct appdata
|
||||
{
|
||||
float4 vertex : POSITION;
|
||||
float2 uv : TEXCOORD0;
|
||||
float3 normal : NORMAL;
|
||||
};
|
||||
|
||||
struct v2f
|
||||
{
|
||||
float2 uv : TEXCOORD0;
|
||||
float2 uv2 : TEXCOORD1;
|
||||
float2 uvEmmis : TEXCOORD4;
|
||||
//UNITY_FOG_COORDS(1)
|
||||
float4 vertex : SV_POSITION;
|
||||
|
||||
//MoonsLight
|
||||
float3 worldPos : TEXCOORD2;
|
||||
float3 worldNormal: TEXCOORD3;
|
||||
|
||||
//MoonsLight END
|
||||
|
||||
|
||||
};
|
||||
|
||||
sampler2D _MainTex;
|
||||
float4 _MainTex_ST;
|
||||
sampler2D _MultTex;
|
||||
float4 _MultTex_ST;
|
||||
float _MultiplicatorTex;
|
||||
float4 _Color;
|
||||
|
||||
|
||||
sampler2D _EmmisiveText;
|
||||
float4 _EmmisiveText_ST;
|
||||
float4 _EmmissiveColor;
|
||||
float _EmmissiveStrength;
|
||||
|
||||
|
||||
//MoonsLight variables
|
||||
float _InverseSqareMultiplier;
|
||||
float _LightCutoffDistance;
|
||||
|
||||
float4 _LightPositions[MAX_LIGHTS]; // xyz = position
|
||||
float4 _LightColors[MAX_LIGHTS]; // xyz = position
|
||||
float4 _LightDirections[MAX_LIGHTS]; // xyz = direction, w = cos(halfAngle)
|
||||
float _LightType[MAX_LIGHTS]; // 0 = sphere, 1 = cone
|
||||
float _PlayerCount; // set via SetFloat
|
||||
//MoonsLight variables END
|
||||
|
||||
|
||||
v2f vert (appdata v)
|
||||
{
|
||||
v2f o;
|
||||
o.vertex = UnityObjectToClipPos(v.vertex);
|
||||
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
|
||||
o.uv2 = TRANSFORM_TEX(v.uv, _MultTex);
|
||||
o.uvEmmis = TRANSFORM_TEX(v.uv, _EmmisiveText);
|
||||
|
||||
|
||||
//MoonsLight Vertex
|
||||
float4 wp = mul(unity_ObjectToWorld, v.vertex);
|
||||
o.worldPos = wp.xyz;
|
||||
o.worldNormal = UnityObjectToWorldNormal(v.normal);
|
||||
//MoonsLight Vertex END
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
fixed4 frag (v2f i) : SV_Target
|
||||
{
|
||||
// sample the texture
|
||||
fixed4 col = tex2D(_MainTex, i.uv);
|
||||
fixed4 mult = tex2D(_MultTex, i.uv2);
|
||||
col = lerp(col, mult, _MultiplicatorTex);
|
||||
fixed4 emmis = tex2D(_EmmisiveText, i.uvEmmis);
|
||||
|
||||
|
||||
//MoonsLight
|
||||
int count = (int)_PlayerCount;
|
||||
|
||||
float3 N = normalize(i.worldNormal); //for lambertian diffuse
|
||||
// Example: compute distance to nearest player
|
||||
float4 dmax = float4(0,0,0,1);
|
||||
float dIntensity = 0;
|
||||
[loop]
|
||||
for (int idx = 0; idx < MAX_LIGHTS; idx++)
|
||||
{
|
||||
if (idx >= count) break;
|
||||
float radius = _LightPositions[idx].a;
|
||||
float3 q = _LightPositions[idx].xyz;
|
||||
|
||||
float distanceFromLight = length(i.worldPos - q);
|
||||
if (distanceFromLight > _LightCutoffDistance) continue;
|
||||
|
||||
float sd = 0.0;
|
||||
float contrib = 0.0;
|
||||
|
||||
|
||||
float invSqMul = max(1e-4, _InverseSqareMultiplier);
|
||||
|
||||
|
||||
//Lambertian diffuse
|
||||
float3 L = normalize(q - i.worldPos); // q = light position
|
||||
float NdotL = saturate(dot(N, L) * 0.5 + 0.5); // one-sided Lambert
|
||||
if (NdotL <= 0) continue;
|
||||
|
||||
if(_LightType[idx] == 0)
|
||||
{
|
||||
float invSq = _LightColors[idx].a / max(1e-4, max(0, max(1, distanceFromLight - radius) * invSqMul) * max(0, max(1, distanceFromLight - radius) * invSqMul));
|
||||
contrib = invSq;
|
||||
//contrib = contrib * step(-distance(i.worldPos, q), -1 + radius * 1); // 0 if outside sphere
|
||||
dIntensity += contrib * NdotL;
|
||||
}
|
||||
else if (_LightType[idx] == 1)
|
||||
{
|
||||
float invSq = _LightColors[idx].a / max(1e-4, (distanceFromLight * invSqMul) * (distanceFromLight * invSqMul));
|
||||
float threshold = (-1 + _LightDirections[idx].w / 180);
|
||||
|
||||
contrib = min(dot(normalize(i.worldPos - q), -normalize(_LightDirections[idx].xyz)), 0);
|
||||
contrib= 1 - step(threshold, contrib);
|
||||
|
||||
contrib = contrib * invSq;
|
||||
dIntensity += contrib * NdotL;
|
||||
}
|
||||
float3 LightColor = _LightColors[idx].xyz; // * NormalDirMult;
|
||||
|
||||
|
||||
|
||||
dmax = dmax + contrib * float4(LightColor, 1) * NdotL; // accumulate light contributions
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
//dmax.xyz = min(dmax * dIntensity, 1.0);
|
||||
dmax.w = 1.0;
|
||||
dmax = dmax;
|
||||
|
||||
|
||||
//MoonsLight END
|
||||
|
||||
|
||||
return col * _Color * dmax + emmis * _EmmissiveStrength * _EmmissiveColor;
|
||||
}
|
||||
ENDCG
|
||||
}
|
||||
}
|
||||
|
||||
FallBack "Diffuse"
|
||||
}
|
||||
9
Shader/BlendinShader.shader.meta
Normal file
9
Shader/BlendinShader.shader.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 10b36b8f1c13f5947ba9527616152cdb
|
||||
ShaderImporter:
|
||||
externalObjects: {}
|
||||
defaultTextures: []
|
||||
nonModifiableTextures: []
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
83
Shader/GhostWhiteShader.shader
Normal file
83
Shader/GhostWhiteShader.shader
Normal file
@@ -0,0 +1,83 @@
|
||||
Shader "DeMuenu/World/Hoppou/GhostWhite"
|
||||
{
|
||||
Properties
|
||||
{
|
||||
_MainTex ("Texture", 2D) = "white" {}
|
||||
_Color ("Color", Color) = (1,1,1,1)
|
||||
_EmmissiveColor ("Emmissive Color", Color) = (1,1,1,1)
|
||||
_EmmissiveStrength ("Emmissive Strength", Range(0,10)) = 0
|
||||
|
||||
_BaseColor ("Base Color", Color) = (0.06,0.08,0.1,1)
|
||||
_FresnelColor ("Fresnel Color", Color) = (0.3,0.7,1,1)
|
||||
_Power ("Fresnel Power", Range(0.1, 8)) = 3
|
||||
_Intensity ("Fresnel Intensity", Range(0, 4)) = 1
|
||||
}
|
||||
SubShader
|
||||
{
|
||||
Tags { "RenderType"="Opaque" }
|
||||
LOD 100
|
||||
|
||||
Pass
|
||||
{
|
||||
CGPROGRAM
|
||||
#pragma vertex vert
|
||||
#pragma fragment frag
|
||||
// make fog work
|
||||
#pragma multi_compile_fog
|
||||
|
||||
#include "UnityCG.cginc"
|
||||
|
||||
struct appdata
|
||||
{
|
||||
float4 vertex : POSITION;
|
||||
float3 normal : NORMAL;
|
||||
float2 uv : TEXCOORD0;
|
||||
};
|
||||
|
||||
struct v2f
|
||||
{
|
||||
float2 uv : TEXCOORD0;
|
||||
float4 vertex : SV_POSITION;
|
||||
float3 worldNormal : TEXCOORD2;
|
||||
float3 worldViewDir : TEXCOORD1;
|
||||
};
|
||||
|
||||
sampler2D _MainTex;
|
||||
float4 _MainTex_ST;
|
||||
fixed4 _Color;
|
||||
fixed4 _EmmissiveColor;
|
||||
float _EmmissiveStrength;
|
||||
fixed4 _BaseColor, _FresnelColor;
|
||||
float _Power, _Intensity;
|
||||
|
||||
v2f vert (appdata v)
|
||||
{
|
||||
v2f o;
|
||||
o.vertex = UnityObjectToClipPos(v.vertex);
|
||||
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
|
||||
o.worldNormal = UnityObjectToWorldNormal(v.normal);
|
||||
float3 worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
|
||||
o.worldViewDir = _WorldSpaceCameraPos - worldPos;
|
||||
return o;
|
||||
}
|
||||
|
||||
fixed4 frag (v2f i) : SV_Target
|
||||
{
|
||||
float3 N = normalize(i.worldNormal);
|
||||
float3 V = normalize(i.worldViewDir);
|
||||
// Schlick-style rim: (1 - N·V)^power
|
||||
float fresnel = pow(1.0 - saturate(dot(N, V)), _Power);
|
||||
|
||||
// sample the texture
|
||||
fixed4 col = tex2D(_MainTex, i.uv) * _Color ;
|
||||
|
||||
|
||||
col = float4(col.rgb + _FresnelColor.rgb * (fresnel * _Intensity), 1);
|
||||
|
||||
// apply fog
|
||||
return col + (_EmmissiveColor * _EmmissiveStrength);
|
||||
}
|
||||
ENDCG
|
||||
}
|
||||
}
|
||||
}
|
||||
9
Shader/GhostWhiteShader.shader.meta
Normal file
9
Shader/GhostWhiteShader.shader.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0914d1e38b9fb9748b943666168cb363
|
||||
ShaderImporter:
|
||||
externalObjects: {}
|
||||
defaultTextures: []
|
||||
nonModifiableTextures: []
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
186
Shader/LitParticles.shader
Normal file
186
Shader/LitParticles.shader
Normal file
@@ -0,0 +1,186 @@
|
||||
Shader "DeMuenu/World/Hoppou/Particles/LitParticles"
|
||||
{
|
||||
Properties
|
||||
{
|
||||
_MainTex ("Texture", 2D) = "white" {}
|
||||
_Color ("Color", Color) = (1,1,1,1)
|
||||
|
||||
|
||||
//MoonsLight
|
||||
_InverseSqareMultiplier ("Inverse Square Multiplier", Float) = 1
|
||||
_LightCutoffDistance ("Light Cutoff Distance", Float) = 100
|
||||
//MoonsLight END
|
||||
|
||||
|
||||
|
||||
}
|
||||
SubShader
|
||||
{
|
||||
Tags { "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" "PreviewType"="Plane" }
|
||||
Blend SrcAlpha One
|
||||
Cull Off
|
||||
Lighting Off
|
||||
ZWrite Off
|
||||
LOD 100
|
||||
|
||||
Pass
|
||||
{
|
||||
CGPROGRAM
|
||||
#pragma vertex vert
|
||||
#pragma fragment frag
|
||||
|
||||
#define MAX_LIGHTS 80 // >= maxPlayers in script
|
||||
|
||||
#include "UnityCG.cginc"
|
||||
|
||||
|
||||
|
||||
struct appdata
|
||||
{
|
||||
float4 vertex : POSITION;
|
||||
float2 uv : TEXCOORD0;
|
||||
|
||||
float4 color : COLOR;
|
||||
|
||||
float3 normal : NORMAL;
|
||||
|
||||
};
|
||||
|
||||
struct v2f
|
||||
{
|
||||
float2 uv : TEXCOORD0;
|
||||
float4 vertex : SV_POSITION;
|
||||
//MoonsLight
|
||||
float3 worldPos : TEXCOORD2;
|
||||
|
||||
float4 color : COLOR;
|
||||
|
||||
float3 worldNormal: TEXCOORD3;
|
||||
//MoonsLight END
|
||||
};
|
||||
|
||||
sampler2D _MainTex;
|
||||
float4 _MainTex_ST;
|
||||
sampler2D _MultTex;
|
||||
float4 _MultTex_ST;
|
||||
float4 _Color;
|
||||
|
||||
|
||||
sampler2D _EmmisiveText;
|
||||
float4 _EmmisiveText_ST;
|
||||
float4 _EmmissiveColor;
|
||||
float _EmmissiveStrength;
|
||||
|
||||
|
||||
//MoonsLight
|
||||
float _InverseSqareMultiplier;
|
||||
float _LightCutoffDistance;
|
||||
|
||||
float4 _LightPositions[MAX_LIGHTS]; // xyz = position
|
||||
float4 _LightColors[MAX_LIGHTS]; // xyz = position
|
||||
float4 _LightDirections[MAX_LIGHTS]; // xyz = direction, w = cos(halfAngle)
|
||||
float _LightType[MAX_LIGHTS]; // 0 = sphere, 1 = cone
|
||||
float _PlayerCount; // set via SetFloat
|
||||
//MoonsLight END
|
||||
|
||||
|
||||
v2f vert (appdata v)
|
||||
{
|
||||
v2f o;
|
||||
o.vertex = UnityObjectToClipPos(v.vertex);
|
||||
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
|
||||
|
||||
|
||||
//MoonsLight
|
||||
float4 wp = mul(unity_ObjectToWorld, v.vertex);
|
||||
o.worldPos = wp.xyz;
|
||||
o.color = v.color;
|
||||
o.worldNormal = UnityObjectToWorldNormal(v.normal);
|
||||
//MoonsLight END
|
||||
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
fixed4 frag (v2f i) : SV_Target
|
||||
{
|
||||
// sample the texture
|
||||
fixed4 col = tex2D(_MainTex, i.uv);
|
||||
|
||||
|
||||
//MoonsLight
|
||||
int count = (int)_PlayerCount;
|
||||
|
||||
float3 N = normalize(i.worldNormal); //for lambertian diffuse
|
||||
// Example: compute distance to nearest player
|
||||
float4 dmax = float4(0,0,0,1);
|
||||
float dIntensity = 0;
|
||||
[loop]
|
||||
for (int idx = 0; idx < MAX_LIGHTS; idx++)
|
||||
{
|
||||
if (idx >= count) break;
|
||||
float radius = _LightPositions[idx].a;
|
||||
float3 q = _LightPositions[idx].xyz;
|
||||
|
||||
float distanceFromLight = length(i.worldPos - q);
|
||||
if (distanceFromLight > _LightCutoffDistance) continue;
|
||||
|
||||
float sd = 0.0;
|
||||
float contrib = 0.0;
|
||||
|
||||
|
||||
float invSqMul = max(1e-4, _InverseSqareMultiplier);
|
||||
|
||||
|
||||
//Lambertian diffuse
|
||||
float3 L = normalize(q - i.worldPos); // q = light position
|
||||
float NdotL = saturate(dot(N, L) * 0.5 + 0.5); // one-sided Lambert
|
||||
if (NdotL <= 0) continue;
|
||||
|
||||
if(_LightType[idx] == 0)
|
||||
{
|
||||
float invSq = _LightColors[idx].a / max(1e-4, max(0, max(1, distanceFromLight - radius) * invSqMul) * max(0, max(1, distanceFromLight - radius) * invSqMul));
|
||||
contrib = invSq;
|
||||
//contrib = contrib * step(-distance(i.worldPos, q), -1 + radius * 1); // 0 if outside sphere
|
||||
dIntensity += contrib * NdotL;
|
||||
}
|
||||
else if (_LightType[idx] == 1)
|
||||
{
|
||||
float invSq = _LightColors[idx].a / max(1e-4, (distanceFromLight * invSqMul) * (distanceFromLight * invSqMul));
|
||||
float threshold = (-1 + _LightDirections[idx].w / 180);
|
||||
|
||||
contrib = min(dot(normalize(i.worldPos - q), -normalize(_LightDirections[idx].xyz)), 0);
|
||||
contrib= 1 - step(threshold, contrib);
|
||||
|
||||
contrib = contrib * invSq;
|
||||
dIntensity += contrib * NdotL;
|
||||
}
|
||||
float3 LightColor = _LightColors[idx].xyz; // * NormalDirMult;
|
||||
|
||||
|
||||
|
||||
dmax = dmax + contrib * float4(LightColor, 1) * NdotL; // accumulate light contributions
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
//dmax.xyz = min(dmax * dIntensity, 1.0);
|
||||
dmax.w = 1.0;
|
||||
dmax = dmax;
|
||||
|
||||
|
||||
//MoonsLight END
|
||||
|
||||
|
||||
|
||||
return col * _Color * min(dmax, 1.0) * i.color;
|
||||
|
||||
}
|
||||
ENDCG
|
||||
}
|
||||
}
|
||||
|
||||
FallBack "Diffuse"
|
||||
}
|
||||
9
Shader/LitParticles.shader.meta
Normal file
9
Shader/LitParticles.shader.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3ee874bc1f0a27c4caf078bd17d5c0c7
|
||||
ShaderImporter:
|
||||
externalObjects: {}
|
||||
defaultTextures: []
|
||||
nonModifiableTextures: []
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
90
Shader/MoonsLight.cingc
Normal file
90
Shader/MoonsLight.cingc
Normal file
@@ -0,0 +1,90 @@
|
||||
#ifndef MOONSLIGHT_INCLUDED
|
||||
#define MOONSLIGHT_INCLUDED
|
||||
|
||||
// You can override this before including if TEXCOORD2 is taken:
|
||||
// #define MOONSLIGHT_TEXCOORD TEXCOORD4
|
||||
#ifndef MOONSLIGHT_TEXCOORD
|
||||
#define MOONSLIGHT_TEXCOORD TEXCOORD2
|
||||
#endif
|
||||
|
||||
// Pick a safe max for your target hardware.
|
||||
#ifndef MAX_LIGHTS
|
||||
#define MAX_LIGHTS 80
|
||||
#endif
|
||||
|
||||
#include "UnityCG.cginc"
|
||||
|
||||
// ---------- Uniforms (set from script as Global/Material arrays) ----------
|
||||
uniform float4 _LightPositions[MAX_LIGHTS]; // xyz = pos, w = radius
|
||||
uniform float4 _LightColors[MAX_LIGHTS]; // xyz = rgb (not normalized), w = intensity scalar
|
||||
uniform float4 _LightDirections[MAX_LIGHTS]; // xyz = dir, w = half-angle in degrees (cone)
|
||||
uniform float _LightType[MAX_LIGHTS]; // 0 = sphere, 1 = cone
|
||||
uniform float _PlayerCount;
|
||||
|
||||
// ---------- Helpers you can inject into your v2f / vertex ----------
|
||||
#define MOONSLIGHT_V2F_MEMBERS float3 worldPos : MOONSLIGHT_TEXCOORD;
|
||||
|
||||
inline void MoonsLight_FillV2F(float4 vertexOS, out float3 worldPos)
|
||||
{
|
||||
worldPos = mul(unity_ObjectToWorld, vertexOS).xyz;
|
||||
}
|
||||
|
||||
// ---------- Core lighting (return value is 0..1 rgba contribution) ----------
|
||||
inline float4 MoonsLight_Accumulate(float3 worldPos, float3 worldNormal)
|
||||
{
|
||||
float3 N = normalize(worldNormal);
|
||||
float4 accum = float4(0,0,0,1);
|
||||
float dIntensity = 0.0;
|
||||
|
||||
int count = (int)_PlayerCount;
|
||||
|
||||
[loop]
|
||||
for (int idx = 0; idx < MAX_LIGHTS; idx++)
|
||||
{
|
||||
if (idx >= count) break;
|
||||
|
||||
float3 q = _LightPositions[idx].xyz;
|
||||
float radius = _LightPositions[idx].w;
|
||||
|
||||
float3 L = normalize(q - worldPos);
|
||||
float NdotL = saturate(dot(N, L) * 0.5 + 0.5); // one-sided Lambert
|
||||
float contrib = 0.0;
|
||||
|
||||
if (_LightType[idx] == 0.0)
|
||||
{
|
||||
// Sphere (SDF-ish falloff reused from your code)
|
||||
float sd = length(worldPos - q) - radius;
|
||||
sd = lerp(1.0, -sd, step(0.0, sd));
|
||||
contrib = min(1.0, max(max(sd, max(0.01, _LightColors[idx].a) / (sd * sd)), 0.01));
|
||||
dIntensity += contrib * NdotL;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Cone (directional spot)
|
||||
float threshold = (-1 + _LightDirections[idx].w / 180.0);
|
||||
contrib = min(dot(normalize(worldPos - q), -normalize(_LightDirections[idx].xyz)), 0.0);
|
||||
contrib = 1.0 - step(threshold, contrib);
|
||||
float distanceFromLight = length(worldPos - q);
|
||||
contrib = min(1.0, contrib * (max(0.01, _LightColors[idx].a) / (distanceFromLight * distanceFromLight)));
|
||||
dIntensity += contrib * NdotL;
|
||||
}
|
||||
|
||||
float3 lightRgb = normalize(_LightColors[idx].xyz);
|
||||
accum += contrib * float4(lightRgb, 1.0);
|
||||
}
|
||||
|
||||
accum.xyz = normalize(accum.xyz);
|
||||
accum.xyz = min(accum.xyz * dIntensity, 1.0);
|
||||
accum.w = 1.0;
|
||||
return min(accum, 1.0);
|
||||
}
|
||||
|
||||
// Optional: reuse your camera-distance fade
|
||||
inline float4 MoonsLight_ApplyDistanceFade(float4 color, float3 worldPos, float distanceFadeMultiplier, float distanceMin)
|
||||
{
|
||||
float dist = length(_WorldSpaceCameraPos.xyz - worldPos) / 100.0;
|
||||
color.xyz *= min(1.0, max(distanceMin, max(0.0, 1.0 - abs(dist) * distanceFadeMultiplier)));
|
||||
return color;
|
||||
}
|
||||
|
||||
#endif // MOONSLIGHT_INCLUDED
|
||||
7
Shader/MoonsLight.cingc.meta
Normal file
7
Shader/MoonsLight.cingc.meta
Normal file
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 76476ee372212af4e9094c2e42bc3cc5
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
216
Shader/Water.shader
Normal file
216
Shader/Water.shader
Normal file
@@ -0,0 +1,216 @@
|
||||
Shader "DeMuenu/World/Hoppou/Water"
|
||||
{
|
||||
Properties
|
||||
{
|
||||
_MainTex ("Texture", 2D) = "white" {}
|
||||
_Color ("Color", Color) = (1,1,1,0.5)
|
||||
_NormalMap ("Normal Map", 2D) = "bump" {}
|
||||
_NormalMapStrength1 ("Normal Map Strength", Range(0,1)) = 1
|
||||
_NormalMapStrength2 ("Normal Map Strength 2", Range(0,1)) = 0.5
|
||||
_NormalMap2Tiling ("Normal Map 2 Tiling", Float) = 2
|
||||
_NormalMapScrollSpeed ("Normal Map Scroll Speed", Float) = 0.1
|
||||
_NormalMapScrollSpeed2 ("Normal Map 2 Scroll Speed", Float) = 0.05
|
||||
|
||||
//MoonsLight
|
||||
_InverseSqareMultiplier ("Inverse Square Multiplier", Float) = 1
|
||||
_LightCutoffDistance ("Light Cutoff Distance", Float) = 100
|
||||
|
||||
_SpecPower ("Spec Power", Range(4,256)) = 64
|
||||
_SpecIntensity ("Spec Intensity", Range(0,10)) = 1
|
||||
_AmbientFloor ("Ambient Floor", Range(0,1)) = 0.08
|
||||
|
||||
_F0 ("F0", Range(0,1)) = 0.02
|
||||
_FresnelPower ("Fresnel Power", Range(1,8)) = 5
|
||||
_ReflectionStrength ("Reflection Strength", Range(0,1)) = 0.7
|
||||
//MoonsLight END
|
||||
}
|
||||
SubShader
|
||||
{
|
||||
Tags { "Queue"="Transparent" "RenderType"="Transparent" }
|
||||
LOD 100
|
||||
Blend SrcAlpha OneMinusSrcAlpha
|
||||
ZWrite Off
|
||||
|
||||
Pass
|
||||
{
|
||||
CGPROGRAM
|
||||
#pragma vertex vert
|
||||
#pragma fragment frag
|
||||
|
||||
#include "UnityCG.cginc"
|
||||
|
||||
//MoonsLight Defines
|
||||
#define MAX_LIGHTS 80 // >= maxPlayers in script
|
||||
//MoonsLight Defines END
|
||||
|
||||
struct appdata
|
||||
{
|
||||
float4 vertex : POSITION;
|
||||
float2 uv : TEXCOORD0;
|
||||
float3 normal : NORMAL;
|
||||
};
|
||||
|
||||
struct v2f
|
||||
{
|
||||
float2 uv : TEXCOORD0;
|
||||
float2 uvnorm : TEXCOORD1;
|
||||
float4 vertex : SV_POSITION;
|
||||
|
||||
//MoonsLight
|
||||
float3 worldPos : TEXCOORD2;
|
||||
float3 worldNormal: TEXCOORD3;
|
||||
//MoonsLight END
|
||||
};
|
||||
|
||||
sampler2D _MainTex;
|
||||
float4 _MainTex_ST;
|
||||
float4 _Color;
|
||||
sampler2D _NormalMap;
|
||||
float4 _NormalMap_ST;
|
||||
float _NormalMapStrength1;
|
||||
float _NormalMapStrength2;
|
||||
float _NormalMap2Tiling;
|
||||
float _NormalMapScrollSpeed;
|
||||
float _NormalMapScrollSpeed2;
|
||||
|
||||
|
||||
//MoonsLight variables
|
||||
float _InverseSqareMultiplier;
|
||||
float _LightCutoffDistance;
|
||||
|
||||
float4 _LightPositions[MAX_LIGHTS]; // xyz = position
|
||||
float4 _LightColors[MAX_LIGHTS]; // xyz = position
|
||||
float4 _LightDirections[MAX_LIGHTS]; // xyz = direction, w = cos(halfAngle)
|
||||
float _LightType[MAX_LIGHTS]; // 0 = sphere, 1 = cone
|
||||
float _PlayerCount; // set via SetFloat
|
||||
|
||||
//Watershader specific
|
||||
float _SpecPower, _SpecIntensity;
|
||||
float3 _AmbientFloor;
|
||||
|
||||
|
||||
float _F0, _FresnelPower, _ReflectionStrength;
|
||||
|
||||
inline float SchlickFresnel(float NoV, float F0, float power)
|
||||
{
|
||||
float f = pow(saturate(1.0 - NoV), power);
|
||||
return saturate(F0 + (1.0 - F0) * f);
|
||||
}
|
||||
//MoonsLight variables END
|
||||
|
||||
v2f vert (appdata v)
|
||||
{
|
||||
v2f o;
|
||||
o.vertex = UnityObjectToClipPos(v.vertex);
|
||||
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
|
||||
o.uvnorm = TRANSFORM_TEX(v.uv, _NormalMap);
|
||||
//MoonsLight Vertex
|
||||
float4 wp = mul(unity_ObjectToWorld, v.vertex);
|
||||
o.worldPos = wp.xyz;
|
||||
o.worldNormal = UnityObjectToWorldNormal(v.normal);
|
||||
//MoonsLight Vertex END
|
||||
return o;
|
||||
}
|
||||
|
||||
fixed4 frag (v2f i) : SV_Target
|
||||
{
|
||||
// sample the texture
|
||||
fixed4 col = tex2D(_MainTex, i.uv);
|
||||
fixed4 norm = tex2D(_NormalMap, i.uvnorm + float2(0, _NormalMapScrollSpeed * sin(_Time.y)));
|
||||
fixed4 norm2 = tex2D(_NormalMap, i.uvnorm * _NormalMap2Tiling + float2(_NormalMapScrollSpeed2 * sin(_Time.y), 0));
|
||||
float3 NormalOffset1 = UnpackNormal(norm).xyz;
|
||||
float3 NormalOffset2 = UnpackNormal(norm2).xyz;
|
||||
|
||||
//MoonsLight
|
||||
int count = (int)_PlayerCount;
|
||||
|
||||
float3 N = normalize(i.worldNormal + NormalOffset1 * _NormalMapStrength1 + NormalOffset2 * _NormalMapStrength2); //for lambertian diffuse
|
||||
|
||||
|
||||
//Waterspecific
|
||||
float3 V = normalize(_WorldSpaceCameraPos - i.worldPos);
|
||||
float3 R = reflect(-V, N); //for reflection vector
|
||||
//Waterspecific END
|
||||
//return float4(R,1);
|
||||
|
||||
|
||||
|
||||
|
||||
// Example: compute distance to nearest player
|
||||
float4 dmax = float4(0,0,0,1);
|
||||
float dIntensity = 0;
|
||||
[loop]
|
||||
for (int idx = 0; idx < MAX_LIGHTS; idx++)
|
||||
{
|
||||
if (idx >= count) break;
|
||||
float radius = _LightPositions[idx].a;
|
||||
float3 q = _LightPositions[idx].xyz;
|
||||
|
||||
float distanceFromLight = length(i.worldPos - q);
|
||||
if (distanceFromLight > _LightCutoffDistance) continue;
|
||||
|
||||
float sd = 0.0;
|
||||
float contrib = 0.0;
|
||||
|
||||
|
||||
float invSqMul = max(1e-4, _InverseSqareMultiplier);
|
||||
|
||||
|
||||
//Lambertian diffuse
|
||||
float3 L = normalize(q - i.worldPos); // q = light position
|
||||
float NdotL = saturate(dot(N, L) * 0.5 + 0.5); // one-sided Lambert
|
||||
if (NdotL <= 0) continue;
|
||||
|
||||
if(_LightType[idx] == 0)
|
||||
{
|
||||
float invSq = _LightColors[idx].a / max(1e-4, max(0, max(1, distanceFromLight - radius) * invSqMul) * max(0, max(1, distanceFromLight - radius) * invSqMul));
|
||||
contrib = invSq;
|
||||
//contrib = contrib * step(-distance(i.worldPos, q), -1 + radius * 1); // 0 if outside sphere
|
||||
dIntensity += contrib * NdotL;
|
||||
}
|
||||
else if (_LightType[idx] == 1)
|
||||
{
|
||||
float invSq = _LightColors[idx].a / max(1e-4, (distanceFromLight * invSqMul) * (distanceFromLight * invSqMul));
|
||||
float threshold = (-1 + _LightDirections[idx].w / 180);
|
||||
|
||||
contrib = min(dot(normalize(i.worldPos - q), -normalize(_LightDirections[idx].xyz)), 0);
|
||||
contrib= 1 - step(threshold, contrib);
|
||||
|
||||
contrib = contrib * invSq;
|
||||
dIntensity += contrib * NdotL;
|
||||
}
|
||||
float3 LightColor = _LightColors[idx].xyz; // * NormalDirMult;
|
||||
|
||||
//Watershader specific
|
||||
//float fres = Schlick(saturate(dot(N, V)), _F0, _FresnelPower);
|
||||
float3 R = reflect(-V, N);
|
||||
float spec = pow(saturate(dot(R, L)), _SpecPower);
|
||||
//return float4(spec, spec, spec,1);
|
||||
dmax.rgb += _LightColors[idx].rgb * contrib + _LightColors[idx].rgb * _SpecIntensity * spec * contrib;
|
||||
dmax.a -= _SpecIntensity * spec;
|
||||
//dmax = dmax + contrib * float4(LightColor, 1); // accumulate light contributions
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
//dmax.xyz = min(dmax * dIntensity, 1.0);
|
||||
|
||||
float NoV = saturate(dot(N, V));
|
||||
float fres = SchlickFresnel(NoV, _F0, _FresnelPower);
|
||||
|
||||
dmax.w = 1.0;
|
||||
dmax.a = dmax.a * _ReflectionStrength * fres;
|
||||
|
||||
|
||||
//MoonsLight END
|
||||
|
||||
|
||||
|
||||
// Final color
|
||||
return col * _Color * dmax ;
|
||||
}
|
||||
ENDCG
|
||||
}
|
||||
}
|
||||
}
|
||||
9
Shader/Water.shader.meta
Normal file
9
Shader/Water.shader.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b99615b9af356d248a6940b9961c417a
|
||||
ShaderImporter:
|
||||
externalObjects: {}
|
||||
defaultTextures: []
|
||||
nonModifiableTextures: []
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user