mirror of
https://github.com/DeMuenu/MoonlightVRC.git
synced 2025-12-12 19:13:56 +00:00
@@ -1,15 +1,15 @@
|
||||
// Assets/Editor/PlayerPositionsToShaderPreview.cs
|
||||
// Assets/Editor/LightUpdaterPreview.cs
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using System.Collections.Generic;
|
||||
|
||||
[InitializeOnLoad]
|
||||
public static class PlayerPositionsToShaderPreview
|
||||
public static class LightUpdaterPreview
|
||||
{
|
||||
const double kTickInterval = 0.1; // seconds
|
||||
static double _nextTick;
|
||||
static readonly Dictionary<PlayerPositionsToShader, Cache> _cache = new Dictionary<PlayerPositionsToShader, Cache>();
|
||||
static readonly Dictionary<LightUpdater, Cache> _cache = new Dictionary<LightUpdater, Cache>();
|
||||
|
||||
struct Cache
|
||||
{
|
||||
@@ -21,7 +21,7 @@ public static class PlayerPositionsToShaderPreview
|
||||
public int size;
|
||||
}
|
||||
|
||||
static PlayerPositionsToShaderPreview()
|
||||
static LightUpdaterPreview()
|
||||
{
|
||||
EditorApplication.update += Update;
|
||||
EditorApplication.hierarchyChanged += ForceTick;
|
||||
@@ -53,18 +53,18 @@ public static class PlayerPositionsToShaderPreview
|
||||
SceneView.RepaintAll();
|
||||
}
|
||||
|
||||
static PlayerPositionsToShader[] FindAllInScene()
|
||||
static LightUpdater[] FindAllInScene()
|
||||
{
|
||||
#if UNITY_2023_1_OR_NEWER
|
||||
return Object.FindObjectsByType<PlayerPositionsToShader>(FindObjectsInactive.Exclude, FindObjectsSortMode.None);
|
||||
return Object.FindObjectsByType<LightUpdater>(FindObjectsInactive.Exclude, FindObjectsSortMode.None);
|
||||
#elif UNITY_2020_1_OR_NEWER
|
||||
return Object.FindObjectsOfType<PlayerPositionsToShader>(true);
|
||||
return Object.FindObjectsOfType<LightUpdater>(true);
|
||||
#else
|
||||
return Resources.FindObjectsOfTypeAll<PlayerPositionsToShader>();
|
||||
return Resources.FindObjectsOfTypeAll<LightUpdater>();
|
||||
#endif
|
||||
}
|
||||
|
||||
static void EnsureArrays(PlayerPositionsToShader src, int required)
|
||||
static void EnsureArrays(LightUpdater src, int required)
|
||||
{
|
||||
if (!_cache.TryGetValue(src, out var c) ||
|
||||
c.positions == null || c.colors == null || c.directions == null || c.types == null || c.shadowMapIndices == null ||
|
||||
@@ -83,7 +83,7 @@ public static class PlayerPositionsToShaderPreview
|
||||
}
|
||||
}
|
||||
|
||||
static void PushFromBehaviour(PlayerPositionsToShader src)
|
||||
static void PushFromBehaviour(LightUpdater src)
|
||||
{
|
||||
int max = Mathf.Max(1, src.maxLights);
|
||||
EnsureArrays(src, max);
|
||||
@@ -171,8 +171,8 @@ public static class PlayerPositionsToShaderPreview
|
||||
}
|
||||
}
|
||||
|
||||
[CustomEditor(typeof(PlayerPositionsToShader))]
|
||||
public class PlayerPositionsToShaderInspector : Editor
|
||||
[CustomEditor(typeof(LightUpdater))]
|
||||
public class LightUpdaterInspector : Editor
|
||||
{
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
@@ -186,7 +186,7 @@ public class PlayerPositionsToShaderInspector : Editor
|
||||
|
||||
if (GUILayout.Button("Refresh Now"))
|
||||
{
|
||||
PlayerPositionsToShaderPreview.ForceTick();
|
||||
LightUpdaterPreview.ForceTick();
|
||||
EditorApplication.QueuePlayerLoopUpdate();
|
||||
SceneView.RepaintAll();
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
// Assets/Lighting/Scripts/PlayerPositionsToShader.Editor.cs
|
||||
// Assets/Lighting/Scripts/LightUpdater.Editor.cs
|
||||
#if UNITY_EDITOR
|
||||
using UnityEngine;
|
||||
|
||||
public partial class PlayerPositionsToShader
|
||||
public partial class LightUpdater
|
||||
{
|
||||
public void Editor_BuildPreview(
|
||||
out Vector4[] positions,
|
||||
@@ -30,15 +30,24 @@ public partial class PlayerPositionsToShader
|
||||
|
||||
LightdataStorage data = t.GetComponent<LightdataStorage>();
|
||||
|
||||
// w = cosHalfAngle (0 for omni)
|
||||
float cosHalf = (data != null) ? data.GetCosHalfAngle() : 0f;
|
||||
|
||||
Vector3 pos = t.position;
|
||||
float range = (data != null) ? data.range * t.localScale.x : t.localScale.x;
|
||||
float range = 0;
|
||||
if (data.lightType == LightType.Sphere)
|
||||
{
|
||||
range = (data != null) ? data.range * t.localScale.x : t.localScale.x;
|
||||
}
|
||||
else
|
||||
{
|
||||
range = (data != null) ? Mathf.Cos(Mathf.Deg2Rad * ((data.spotAngleDeg * 0.5f) + Mathf.Max(data.range, 0))): 0f;
|
||||
}
|
||||
|
||||
// rgb = color, a = intensity (packed to match runtime/shader)
|
||||
Vector4 col = (data != null) ? data.GetFinalColor() : new Vector4(1f, 1f, 1f, 1f);
|
||||
float intensity = (data != null) ? data.intensity * t.localScale.x : 1f;
|
||||
|
||||
// w = cosHalfAngle (0 for omni)
|
||||
float cosHalf = (data != null) ? data.GetCosHalfAngle() : 0f;
|
||||
|
||||
// 0=Omni, 1=Spot, 2=Directional (your custom enum)
|
||||
int typeId = (data != null) ? data.GetTypeId() : 0;
|
||||
@@ -30,13 +30,13 @@ On PC, I haven't encountered any frame drops in the editor at all, even with 400
|
||||
|
||||
1. Clone the code into your project.
|
||||
|
||||
2. Add the `PlayerPositionsToShader` component to a GameObject in your scene:
|
||||
2. Add the `LightUpdater` component to a GameObject in your scene:
|
||||
- Tweak strength/intensity of the local and remote player if you want them to have an attached light.
|
||||
|
||||
3. For lights, attach `LightdataStorage` to a Transform and configure:
|
||||
- `range`, `type`, `color`, `intensity`, and `spotAngleDeg`.
|
||||
|
||||
4. Add the light transform to your `PlayerPositionsToShader` component's `otherLightSources` array.
|
||||
4. Add the light transform to your `LightUpdater` component's `otherLightSources` array.
|
||||
|
||||
5. Use one of the premade shaders on your material. Or, if you feel like it, use the provided .hlsl/.cginc in your own shader. You just need to copy everything surrounded by Moonlight comments, and apply it at the end of your shader.
|
||||
|
||||
@@ -44,8 +44,8 @@ On PC, I haven't encountered any frame drops in the editor at all, even with 400
|
||||
|
||||
## Editor preview
|
||||
|
||||
- While not in play mode, the editor helper `PlayerPositionsToShaderPreview` (EditorPreview/Editor/PlayerPositionsToShaderPreview.cs) and `ShadowcasterUpdaterPreview` (EditorPreview/Editor/ShadowcasterUpdaterPreview.cs) write the same property blocks to assigned Renderers so you can preview lighting effects in the Scene view. Those update 10 times a second.
|
||||
- The editor partial helper for building preview arrays is in `EditorPreview/PlayerPositionsToShader.Editor.cs`.
|
||||
- While not in play mode, the editor helper `LightUpdaterPreview` (EditorPreview/Editor/LightUpdaterPreview.cs) and `ShadowcasterUpdaterPreview` (EditorPreview/Editor/ShadowcasterUpdaterPreview.cs) write the same property blocks to assigned Renderers so you can preview lighting effects in the Scene view. Those update 10 times a second.
|
||||
- The editor partial helper for building preview arrays is in `EditorPreview/LightUpdater.Editor.cs`.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ using VRC.SDKBase;
|
||||
using VRC.Udon;
|
||||
using VRC.SDK3.Rendering;
|
||||
|
||||
public partial class PlayerPositionsToShader : UdonSharpBehaviour
|
||||
public partial class LightUpdater : UdonSharpBehaviour
|
||||
{
|
||||
[Header("Lightsources")]
|
||||
[Tooltip("Place Transforms here which should also emit Light (attach LightdataStorage to them).")]
|
||||
@@ -221,21 +221,29 @@ public partial class PlayerPositionsToShader : UdonSharpBehaviour
|
||||
Vector3 fwd = rot * Vector3.down;
|
||||
|
||||
|
||||
float cosHalf = (data != null) ? data.GetCosHalfAngle() : 0f;
|
||||
float Lightangle = (data != null) ? data.GetCosHalfAngle() : 0f;
|
||||
|
||||
Vector4 posTemp = new Vector4(pos.x, pos.y, pos.z, range);
|
||||
if (_positions[currentCount] != posTemp)
|
||||
Vector4 posTemp = Vector4.zero;
|
||||
if (data.lightType == LightType.Sphere)
|
||||
{
|
||||
_positions[currentCount] = posTemp;
|
||||
_positons_isDirty = true;
|
||||
posTemp = new Vector4(pos.x, pos.y, pos.z, range);
|
||||
}
|
||||
else
|
||||
{
|
||||
posTemp = new Vector4(pos.x, pos.y, pos.z, Mathf.Cos(Mathf.Deg2Rad * ((data.spotAngleDeg * 0.5f) + Mathf.Max(data.range, 0))));
|
||||
}
|
||||
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);
|
||||
Vector4 dirTemp = new Vector4(fwd.x, fwd.y, fwd.z, Lightangle);
|
||||
if (_directions[currentCount] != dirTemp)
|
||||
{
|
||||
_directions[currentCount] = dirTemp;
|
||||
@@ -11,10 +11,9 @@
|
||||
else if (_Udon_LightType[LightCounter] == 1) \
|
||||
{ \
|
||||
float invSq = _Udon_LightColors[LightCounter].a / max(1e-4, (distanceFromLight * invSqMul) * (distanceFromLight * invSqMul)); \
|
||||
float threshold = (-1 + _Udon_LightDirections[LightCounter].w / 180); \
|
||||
\
|
||||
contrib = min(dot(normalize(i.worldPos - Lightposition), -normalize(_Udon_LightDirections[LightCounter].xyz)), 0); \
|
||||
contrib= 1 - step(threshold, contrib); \
|
||||
contrib = dot(normalize(i.worldPos - Lightposition), normalize(_Udon_LightDirections[LightCounter].xyz)); \
|
||||
contrib = smoothstep(radius,_Udon_LightDirections[LightCounter].w, contrib); \
|
||||
\
|
||||
contrib = contrib * invSq; \
|
||||
dIntensity += contrib; \
|
||||
|
||||
237
Shader/Standard_Lightmap_2SP.shader
Normal file
237
Shader/Standard_Lightmap_2SP.shader
Normal file
@@ -0,0 +1,237 @@
|
||||
Shader "DeMuenu/World/Hoppou/Standard_Lightmap_2SP"
|
||||
{
|
||||
Properties
|
||||
{
|
||||
_MainTex ("Texture", 2D) = "white" {}
|
||||
_NormalMap ("Normal Map", 2D) = "bump" {}
|
||||
_NormalMapStrength ("Normal Map Strength", Range(0,1)) = 1
|
||||
_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
|
||||
|
||||
|
||||
//Moonlight
|
||||
_InverseSqareMultiplier ("Inverse Square Multiplier", Float) = 1
|
||||
_LightCutoffDistance ("Light Cutoff Distance", Float) = 100
|
||||
|
||||
_EnableShadowCasting ("Enable Shadowcasting", Float) = 0
|
||||
_BlurPixels ("Shadowcaster Blur Pixels", Float) = 0
|
||||
//Moonlight END
|
||||
|
||||
[Enum(UnityEngine.Rendering.CullMode)] _Cull ("Cull Mode", Float) = 2
|
||||
|
||||
|
||||
|
||||
}
|
||||
SubShader
|
||||
{
|
||||
Tags { "RenderType"="Opaque" }
|
||||
LOD 100
|
||||
Cull[_Cull]
|
||||
|
||||
Pass
|
||||
{
|
||||
CGPROGRAM
|
||||
#pragma vertex vert
|
||||
#pragma fragment frag
|
||||
#pragma multi_compile _ LIGHTMAP_ON
|
||||
#pragma multi_compile _ DIRLIGHTMAP_COMBINED
|
||||
|
||||
#include "UnityCG.cginc"
|
||||
#include "Includes/LightStrength.hlsl"
|
||||
#include "Includes/Lambert.hlsl"
|
||||
#include "Includes/DefaultSetup.hlsl"
|
||||
#include "Includes/Variables.hlsl"
|
||||
#include "Includes/Shadowcaster.cginc"
|
||||
|
||||
//Moonlight Defines
|
||||
#define MAX_LIGHTS 80 // >= maxPlayers in script
|
||||
//Moonlight Defines END
|
||||
|
||||
struct appdata
|
||||
{
|
||||
float4 vertex : POSITION;
|
||||
float2 uv : TEXCOORD0;
|
||||
float3 normal : NORMAL;
|
||||
float4 tangent : TANGENT;
|
||||
float2 uv2 : TEXCOORD1; // Lightmap UV
|
||||
};
|
||||
|
||||
struct v2f
|
||||
{
|
||||
float2 uv : TEXCOORD0;
|
||||
float2 uv2 : TEXCOORD1;
|
||||
float2 uvEmmis : TEXCOORD4;
|
||||
float4 vertex : SV_POSITION;
|
||||
float2 normUV : TEXCOORD5;
|
||||
float3 worldTangent : TEXCOORD6;
|
||||
float3 worldBitangent : TEXCOORD7;
|
||||
|
||||
//Moonlight
|
||||
float3 worldPos : TEXCOORD2;
|
||||
float3 worldNormal: TEXCOORD3;
|
||||
//Moonlight END
|
||||
|
||||
|
||||
#ifdef LIGHTMAP_ON
|
||||
float2 lmuv : TEXCOORD8;
|
||||
#endif
|
||||
|
||||
|
||||
};
|
||||
|
||||
sampler2D _MainTex;
|
||||
float4 _MainTex_ST;
|
||||
sampler2D _NormalMap;
|
||||
float4 _NormalMap_ST;
|
||||
float4 _Color;
|
||||
float _NormalMapStrength;
|
||||
|
||||
|
||||
|
||||
sampler2D _EmmisiveText;
|
||||
float4 _EmmisiveText_ST;
|
||||
float4 _EmmissiveColor;
|
||||
float _EmmissiveStrength;
|
||||
|
||||
|
||||
MoonlightGlobalVariables
|
||||
|
||||
|
||||
float4 _Udon_Plane_Origin_1; // xyz = origin (world), w unused
|
||||
float4 _Udon_Plane_Uinv_1; // xyz = Udir / (2*halfWidth)
|
||||
float4 _Udon_Plane_Vinv_1; // xyz = Vdir / (2*halfHeight)
|
||||
float4 _Udon_Plane_Normal_1; // xyz = unit normal
|
||||
|
||||
sampler2D _Udon_shadowCasterTex_1;
|
||||
float4 _Udon_shadowCasterColor_1;
|
||||
float4 _Udon_OutSideColor_1;
|
||||
float _Udon_MinBrightnessShadow_1;
|
||||
|
||||
float4 _Udon_Plane_Origin_2;
|
||||
float4 _Udon_Plane_Uinv_2;
|
||||
float4 _Udon_Plane_Vinv_2;
|
||||
float4 _Udon_Plane_Normal_2;
|
||||
|
||||
sampler2D _Udon_shadowCasterTex_2;
|
||||
float4 _Udon_shadowCasterColor_2;
|
||||
float4 _Udon_OutSideColor_2;
|
||||
float _Udon_MinBrightnessShadow_2;
|
||||
|
||||
float _BlurPixels;
|
||||
float4 _Udon_shadowCasterTex_1_TexelSize; // xy = 1/width, 1/height
|
||||
float4 _Udon_shadowCasterTex_2_TexelSize;
|
||||
|
||||
bool _EnableShadowCasting;
|
||||
|
||||
|
||||
|
||||
v2f vert (appdata v)
|
||||
{
|
||||
v2f o;
|
||||
o.vertex = UnityObjectToClipPos(v.vertex);
|
||||
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
|
||||
o.normUV = TRANSFORM_TEX(v.uv, _NormalMap);
|
||||
o.uvEmmis = TRANSFORM_TEX(v.uv, _EmmisiveText);
|
||||
|
||||
float3 nWS = UnityObjectToWorldNormal(v.normal);
|
||||
float3 tWS = normalize(UnityObjectToWorldDir(v.tangent.xyz));
|
||||
float3 bWS = normalize(cross(nWS, tWS) * v.tangent.w);
|
||||
|
||||
o.worldNormal = nWS;
|
||||
o.worldTangent = tWS;
|
||||
o.worldBitangent= bWS;
|
||||
|
||||
|
||||
//Moonlight Vertex
|
||||
float4 wp = mul(unity_ObjectToWorld, v.vertex);
|
||||
o.worldPos = wp.xyz;
|
||||
//o.worldNormal = UnityObjectToWorldNormal(v.normal);
|
||||
//Moonlight Vertex END
|
||||
|
||||
#ifdef LIGHTMAP_ON
|
||||
o.lmuv = v.uv2 * unity_LightmapST.xy + unity_LightmapST.zw;
|
||||
#endif
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
fixed4 frag (v2f i) : SV_Target
|
||||
{
|
||||
// sample the texture
|
||||
fixed4 col = tex2D(_MainTex, i.uv);
|
||||
fixed4 norm = tex2D(_NormalMap, i.normUV);
|
||||
|
||||
fixed4 emmis = tex2D(_EmmisiveText, i.uvEmmis);
|
||||
|
||||
|
||||
//Moonlight
|
||||
float3 nTS = UnpackNormal(norm);
|
||||
float3 NmapWS = normalize(i.worldTangent * nTS.x +
|
||||
i.worldBitangent * nTS.y +
|
||||
i.worldNormal * nTS.z);
|
||||
float3 N = normalize(lerp(normalize(i.worldNormal), NmapWS, saturate(_NormalMapStrength)));
|
||||
|
||||
OutLoopSetup(i, _Udon_PlayerCount) //defines count, N, dmax, dIntensity
|
||||
|
||||
[loop]
|
||||
for (int LightCounter = 0; LightCounter < MAX_LIGHTS; LightCounter++)
|
||||
{
|
||||
InLoopSetup(_Udon_LightPositions, LightCounter, count, i); //defines distanceFromLight, contrib
|
||||
|
||||
|
||||
//Lambertian diffuse
|
||||
Lambert(_Udon_LightPositions[LightCounter].xyz ,i, N); //defines NdotL
|
||||
|
||||
LightTypeCalculations(_Udon_LightColors, LightCounter, i, NdotL, dIntensity, _Udon_LightPositions[LightCounter].a, _Udon_LightPositions[LightCounter].xyz);
|
||||
|
||||
float4 ShadowCasterMult_1 = 1;
|
||||
float4 ShadowCasterMult_2 = 1;
|
||||
|
||||
if (((_Udon_ShadowMapIndex[LightCounter] > 0.5) && (_Udon_ShadowMapIndex[LightCounter] < 1.5) && (_EnableShadowCasting > 0.5)) || (_Udon_ShadowMapIndex[LightCounter] > 2.5 && _EnableShadowCasting))
|
||||
{
|
||||
float4 sc1 = SampleShadowcasterPlaneWS_Basis(
|
||||
_Udon_LightPositions[LightCounter].xyz, i.worldPos,
|
||||
_Udon_Plane_Origin_1.xyz, _Udon_Plane_Uinv_1.xyz, _Udon_Plane_Vinv_1.xyz, _Udon_Plane_Normal_1.xyz,
|
||||
_Udon_shadowCasterTex_1, _Udon_OutSideColor_1, _Udon_shadowCasterColor_1, _BlurPixels, _Udon_shadowCasterTex_1_TexelSize.xy);
|
||||
ShadowCasterMult_1 = max(sc1, _Udon_MinBrightnessShadow_1);
|
||||
}
|
||||
if (_Udon_ShadowMapIndex[LightCounter] > 1.5 && (_EnableShadowCasting > 0.5))
|
||||
{
|
||||
float4 sc2 = SampleShadowcasterPlaneWS_Basis(
|
||||
_Udon_LightPositions[LightCounter].xyz, i.worldPos,
|
||||
_Udon_Plane_Origin_2.xyz, _Udon_Plane_Uinv_2.xyz, _Udon_Plane_Vinv_2.xyz, _Udon_Plane_Normal_2.xyz,
|
||||
_Udon_shadowCasterTex_2, _Udon_OutSideColor_2, _Udon_shadowCasterColor_2, _BlurPixels, _Udon_shadowCasterTex_2_TexelSize.xy);
|
||||
ShadowCasterMult_2 = max(sc2, _Udon_MinBrightnessShadow_2);
|
||||
}
|
||||
|
||||
dmax = dmax + contrib * float4(LightColor, 1) * NdotL * ShadowCasterMult_1 * ShadowCasterMult_2;
|
||||
|
||||
}
|
||||
//dmax.xyz = min(dmax * dIntensity, 1.0);
|
||||
dmax.w = 1.0;
|
||||
|
||||
//Moonlight END
|
||||
|
||||
fixed3 lm = 0;
|
||||
#ifdef LIGHTMAP_ON
|
||||
// Decode handles RGBM/DoubleLDR and linear/gamma differences for you.
|
||||
lm = DecodeLightmap(UNITY_SAMPLE_TEX2D(unity_Lightmap, i.lmuv));
|
||||
|
||||
#ifdef DIRLIGHTMAP_COMBINED
|
||||
// Directional lightmaps add dominant direction; improves shading on normal-mapped/curved surfaces
|
||||
half4 dirTex = UNITY_SAMPLE_TEX2D_SAMPLER(unity_LightmapInd,unity_Lightmap, i.lmuv);
|
||||
lm = DecodeDirectionalLightmap(lm, dirTex, normalize(i.worldNormal));
|
||||
#endif
|
||||
#endif
|
||||
|
||||
return col * _Color * (dmax + float4(lm, 1)) + emmis * _EmmissiveStrength * _EmmissiveColor;
|
||||
}
|
||||
ENDCG
|
||||
}
|
||||
}
|
||||
|
||||
FallBack "Diffuse"
|
||||
}
|
||||
9
Shader/Standard_Lightmap_2SP.shader.meta
Normal file
9
Shader/Standard_Lightmap_2SP.shader.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: dcd9aab68ad0b484f8382cdb61ef0cb9
|
||||
ShaderImporter:
|
||||
externalObjects: {}
|
||||
defaultTextures: []
|
||||
nonModifiableTextures: []
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user