补齐备份工程打开依赖

This commit is contained in:
JSD\13999
2026-05-26 17:55:41 +08:00
parent e81881ad78
commit 43b4650ee3
433 changed files with 49783 additions and 3 deletions

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: bdbc0567055e3424da2363638a6ffd14
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@@ -0,0 +1,144 @@
fileFormatVersion: 2
guid: f88b6df342d5c4f4a969fb6eb4799d3e
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 11
mipmaps:
mipMapMode: 0
enableMipMap: 1
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 1
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
vTOnly: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: 1
aniso: 2
mipBias: 0
wrapU: 1
wrapV: 1
wrapW: 1
nPOTScale: 1
lightmap: 0
compressionQuality: 50
spriteMode: 0
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 0
alphaIsTransparency: 0
spriteTessellationDetail: -1
textureType: 0
textureShape: 1
singleChannelComponent: 0
flipbookRows: 1
flipbookColumns: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
ignorePngGamma: 0
applyGammaDecoding: 0
platformSettings:
- serializedVersion: 3
buildTarget: DefaultTexturePlatform
maxTextureSize: 64
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Standalone
maxTextureSize: 64
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: iPhone
maxTextureSize: 64
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Android
maxTextureSize: 64
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Windows Store Apps
maxTextureSize: 8192
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID:
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
spritePackingTag:
pSDRemoveMatte: 0
pSDShowRemoveMatteOption: 0
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

After

Width:  |  Height:  |  Size: 121 B

View File

@@ -0,0 +1,144 @@
fileFormatVersion: 2
guid: 27623e5a17b6fd44a9af57a733ee993a
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 11
mipmaps:
mipMapMode: 0
enableMipMap: 0
sRGBTexture: 0
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
vTOnly: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: 0
aniso: 2
mipBias: 0
wrapU: 0
wrapV: 0
wrapW: 0
nPOTScale: 1
lightmap: 0
compressionQuality: 50
spriteMode: 0
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 0
alphaIsTransparency: 0
spriteTessellationDetail: -1
textureType: 0
textureShape: 1
singleChannelComponent: 0
flipbookRows: 1
flipbookColumns: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
ignorePngGamma: 0
applyGammaDecoding: 0
platformSettings:
- serializedVersion: 3
buildTarget: DefaultTexturePlatform
maxTextureSize: 32
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 0
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Standalone
maxTextureSize: 32
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 0
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: iPhone
maxTextureSize: 32
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 0
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Android
maxTextureSize: 32
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 0
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Windows Store Apps
maxTextureSize: 8192
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID:
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
spritePackingTag:
pSDRemoveMatte: 0
pSDShowRemoveMatteOption: 0
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 76d974e53c74fd642a7607b4a9bbf0a4
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,128 @@
// WaterCausticsModules
// Copyright (c) 2021 Masataka Hakozaki
#if WCE_URP
using System.Collections.Generic;
using MH.WaterCausticsModules.Effect;
using UnityEngine;
using UnityEngine.Rendering;
namespace MH.WaterCausticsModules {
[ExecuteAlways]
[DisallowMultipleComponent]
[AddComponentMenu ("")]
internal class AtOnce : MonoBehaviour {
private WaterCausticsEffect _summoner;
private MeshRenderer _render;
internal MeshRenderer render => _render;
private void setRenderEnable (bool isOn) {
if (_render && _render.enabled != isOn) _render.enabled = isOn;
}
private bool _inited;
private AtOnce init (WaterCausticsEffect summoner, Material mat) {
_inited = true;
_summoner = summoner;
var mf = gameObject.AddComponent<MeshFilter> ();
mf.sharedMesh = getMesh ();
_render = gameObject.AddComponent<MeshRenderer> ();
_render.sharedMaterial = mat;
_render.shadowCastingMode = ShadowCastingMode.Off;
_render.lightProbeUsage = LightProbeUsage.Off;
_render.reflectionProbeUsage = ReflectionProbeUsage.Off;
_render.allowOcclusionWhenDynamic = true;
_render.receiveShadows = true;
updateTransform ();
// -- HideFlags --
gameObject.hideFlags = HideFlags.HideAndDontSave | HideFlags.HideInInspector;
// gameObject.hideFlags &= (~HideFlags.HideInHierarchy); // デバッグ用 Hierarchyで表示
// ---------------
return this;
}
private void OnDisable () {
setRenderEnable (false);
}
private void OnDestroy () {
destroy (ref __mesh);
}
private void LateUpdate () {
if (!_summoner || !_summoner.isActiveAndEnabled || _summoner.method != Method.AtOnce) {
setRenderEnable (false);
} else {
setRenderEnable (true);
updateTransform ();
}
}
private void updateTransform () {
if (gameObject.layer != _summoner.gameObject.layer)
gameObject.layer = _summoner.gameObject.layer;
var sumTra = _summoner.transform;
if (transform.parent != sumTra.parent)
transform.SetParent (sumTra.parent, worldPositionStays : false);
if (transform.localToWorldMatrix != sumTra.localToWorldMatrix) {
transform.localPosition = sumTra.localPosition;
transform.localRotation = sumTra.localRotation;
transform.localScale = sumTra.localScale;
}
}
private void Update () {
bool isLeaked = (!_inited || !_summoner || _summoner.atOnce != this);
if (isLeaked) destroy (gameObject);
}
// ----------------------------------------------------------- Mesh
private Mesh __mesh;
private Mesh getMesh () {
if (!__mesh) {
Mesh m = new Mesh ();
m.name = "WCEMeshForAtOnce";
m.vertices = new Vector3 [] { new Vector3 (-.5f, -.5f, -.5f), new Vector3 (.5f, -.5f, -.5f), new Vector3 (-.5f, .5f, -.5f), new Vector3 (.5f, .5f, -.5f), new Vector3 (-.5f, -.5f, .5f), new Vector3 (.5f, -.5f, .5f), new Vector3 (-.5f, .5f, .5f), new Vector3 (.5f, .5f, .5f), /* */ Vector3.zero, Vector3.zero, Vector3.zero, Vector3.zero, Vector3.zero, Vector3.zero, Vector3.zero, Vector3.zero };
m.triangles = new int [] { 2, 6, 7, 2, 7, 3, 0, 2, 3, 0, 3, 1, 1, 3, 7, 1, 7, 5, 0, 4, 6, 0, 6, 2, 4, 5, 7, 4, 7, 6, 0, 1, 5, 0, 5, 4, /* */ 15, 8, 9, 15, 9, 10, 15, 10, 11, 15, 11, 12, 15, 12, 13, 15, 13, 14 };
m.bounds = new Bounds (Vector3.zero, Vector3.one);
m.hideFlags = HideFlags.HideAndDontSave;
m.UploadMeshData (markNoLongerReadable: true);
__mesh = m;
}
return __mesh;
}
// ----------------------------------------------------------- Static
static internal AtOnce Create (WaterCausticsEffect summoner, Material mat) {
var name = "(WCE Renderer) (Deletable)";
var go = new GameObject (name);
go.SetActive (false); // ← Flags設定時にOnEnable,OnDisableが呼ばれる不具合の回避
var a = go.AddComponent<AtOnce> ().init (summoner, mat);
go.SetActive (true);
return a;
}
static internal void OnSummonerDestroyed (ref AtOnce a) {
if (a == null) return;
destroy (a.gameObject);
a = null;
}
static private void destroy<T> (ref T o) where T : Object {
if (o == null) return;
destroy (o);
o = null;
}
static private void destroy (Object o) {
if (o == null) return;
if (Application.isPlaying)
Destroy (o);
else
DestroyImmediate (o);
}
// -----------------------------------------------------------
}
}
#endif // End of WCE_URP

View File

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

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: eb81f73566a5654488dbc4e168ae6b26
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,97 @@
// WaterCausticsModules
// Copyright (c) 2021 Masataka Hakozaki
#if UNITY_EDITOR && (!WCE_URP || WCE_DEVELOPMENT)
using System.Collections.Generic;
using System.Linq;
using UnityEditor;
using UnityEngine;
#pragma warning disable 162
namespace MH.WaterCausticsModules {
/*------------------------------------------------------------------------
URP10.4以上のパッケージを持っていない場合にEffectモジュールを削除。
initializeOnLoad と インポート時に削除を試す
-------------------------------------------------------------------------*/
public class CheckRenderPipeline : AssetPostprocessor {
static private readonly string classFileName = $"{typeof(CheckRenderPipeline).Name}.cs";
#if WCE_DEVELOPMENT
[MenuItem ("WCM/TestDialog/DeleteEffectModuleDialog")]
static void dialogTest () => showDialogAndWarning ();
static private readonly bool isDeveloping = true;
#else
static private readonly bool isDeveloping = false;
#endif
[InitializeOnLoadMethod]
private static void initializeOnLoad () {
EditorApplication.delayCall += delayCall;
}
private static void delayCall () {
if (isDeveloping) return;
if (findAsset<EffectModuleRef> (out var asset, out var path)) {
if (asset.effectModule) {
var folderPath = AssetDatabase.GetAssetPath (asset.effectModule);
if (!string.IsNullOrEmpty (folderPath) && folderPath.EndsWith (Constant.EFFECT_FOLDER_NAME)) {
deleteEffectFolder (folderPath);
}
}
}
}
private static string s_folderPath;
static void OnPostprocessAllAssets (string [] imported, string [] deleted, string [] moved, string [] movedFrom) {
if (isDeveloping) return;
if (findAsset<EffectModuleRef> (out var asset, out var path) && asset.effectModule) {
var folderPath = AssetDatabase.GetAssetPath (asset.effectModule);
if (!string.IsNullOrEmpty (folderPath) && folderPath.EndsWith (Constant.EFFECT_FOLDER_NAME)) {
if (imported.Any (a => a.StartsWith (folderPath))) {
// Shaderファイルなどを先に削除 ※Shader Error回避
deleteWithoutMat (folderPath);
// フォルダの削除はDelayCallで行う ※MaterialPostprocessorでのNullエラー回避
s_folderPath = folderPath;
EditorApplication.delayCall += () => deleteEffectFolder (s_folderPath);
} else {
deleteEffectFolder (folderPath);
}
}
}
}
static void deleteWithoutMat (string folderPath) {
string [] guids = AssetDatabase.FindAssets ("", new [] { folderPath });
string [] paths = guids.Select (guid => AssetDatabase.GUIDToAssetPath (guid)).Where (p => p.EndsWith (".shader") || p.EndsWith (".asset") || p.EndsWith (".lighting")).ToArray ();
#if UNITY_2020_1_OR_NEWER
AssetDatabase.DeleteAssets (paths, new List<string> ());
#else
foreach (var p in paths) AssetDatabase.DeleteAsset (p);
#endif
}
static void deleteEffectFolder (string folderPath) {
if (isDeveloping || string.IsNullOrEmpty (folderPath)) return;
if (AssetDatabase.DeleteAsset (folderPath)) {
AssetDatabase.Refresh ();
showDialogAndWarning ();
}
}
static void showDialogAndWarning () {
// ----- Dialog表示
EditorUtility.DisplayDialog ("Effect module removed.", $"The Effect module of this asset was removed.\n\nBecause the UniversalRP package {Constant.REQUIRE_URP_VER} could not be detected in this project.\n\nSee the Manual for details.\n\n\n({Constant.ASSET_NAME})", "OK");
}
static private bool findAsset<T> (out T asset, out string path) where T : Object {
asset = null;
path = null;
var guids = AssetDatabase.FindAssets ($"t:{typeof (T).ToString()}", new [] { "Assets" }); // ※フォルダ名の最後にスラッシュがあると古いUnityでエラーになるので注意
if (guids.Length == 0) return false;
path = AssetDatabase.GUIDToAssetPath (guids [0]);
asset = AssetDatabase.LoadAssetAtPath<T> (path);
return asset != null;
}
}
}
#endif

View File

@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: 4373c16da8bab7841b9c9f883fd8ca5c
labels:
- WaterCausticsModules
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,67 @@
// WaterCausticsModules
// Copyright (c) 2021 Masataka Hakozaki
#if UNITY_EDITOR && WCE_URP
using System.Collections.Generic;
using UnityEditor;
using UnityEditor.Build;
using UnityEditor.Build.Reporting;
using UnityEditor.Rendering;
using UnityEngine;
using UnityEngine.Rendering;
namespace MH.WaterCausticsModules {
/*------------------------------------------------------------------------
Previewウィンドウでエフェクトを無効化
-------------------------------------------------------------------------*/
public class DisableInPreviewWindow : IPreprocessBuildWithReport, IPostprocessBuildWithReport {
private static readonly string KEYWORD = "_WCE_DISABLED";
public int callbackOrder => 1;
public void OnPreprocessBuild (BuildReport report) {
// ビルド前処理
disableEvent ();
}
public void OnPostprocessBuild (BuildReport report) {
// ビルド後処理
enableEvent ();
}
[InitializeOnLoadMethod]
static void OnInitialize () {
// Editor起動直後、プレイ開始時
enableEvent ();
}
static private void enableEvent () {
WaterCausticsEffectFeature.onCamRender -= onEnqueue;
WaterCausticsEffectFeature.onCamRender += onEnqueue;
}
static private void disableEvent () {
Shader.DisableKeyword (KEYWORD);
WaterCausticsEffectFeature.onCamRender -= onEnqueue;
}
static private void onEnqueue (Camera cam) {
if (cam.cameraType == CameraType.Preview)
Shader.EnableKeyword (KEYWORD);
else
Shader.DisableKeyword (KEYWORD);
}
public class ShaderPreprocessor : IPreprocessShaders {
// シェーダバリアント削除
public int callbackOrder => 1;
public void OnProcessShader (Shader shader, ShaderSnippetData snippet, IList<ShaderCompilerData> data) {
var deleteKeyword = new ShaderKeyword (DisableInPreviewWindow.KEYWORD);
for (var i = data.Count - 1; i >= 0; --i)
if (data [i].shaderKeywordSet.IsEnabled (deleteKeyword))
data.RemoveAt (i);
}
}
}
}
#endif

View File

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

View File

@@ -0,0 +1,17 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &11400000
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 276d321c87e0f494fb5e61d87eb50ad6, type: 3}
m_Name: EffectModuleRef
m_EditorClassIdentifier:
m_effectModule: {fileID: 102900000, guid: 557c32d7360c26949947ac9dd8c308fc, type: 3}
m_customFunc: {fileID: 102900000, guid: 5c458e7b6a8f6024aba7bed0ab7b3320, type: 3}
m_packageForASE: {fileID: 102900000, guid: cd1a5fad241143647aa5403add1f9fd8, type: 3}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 9e71d80f209a88447bb8a57499210fd2
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,25 @@
// WaterCausticsModules
// Copyright (c) 2021 Masataka Hakozaki
#if UNITY_EDITOR
using UnityEngine;
namespace MH.WaterCausticsModules {
#if WCE_DEVELOPMENT
[CreateAssetMenu]
#endif
public class EffectModuleRef : ScriptableObject {
// WaterCausticEffectフォルダ
[SerializeField] private Object m_effectModule;
internal Object effectModule => m_effectModule;
// ShaderFunctionsフォルダ
[SerializeField] private Object m_customFunc;
internal Object customFunc => m_customFunc;
// ForAmplifyShaderEditor.unitypackageファイル
[SerializeField] private Object m_packageForASE;
internal Object packageForASE => m_packageForASE;
}
}
#endif

View File

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

View File

@@ -0,0 +1,50 @@
// WaterCausticsModules
// Copyright (c) 2021 Masataka Hakozaki
#if UNITY_EDITOR && WCE_URP && AMPLIFY_SHADER_EDITOR
using UnityEditor;
using UnityEngine;
#pragma warning disable 162
namespace MH.WaterCausticsModules {
/*------------------------------------------------------------------------
AmplifyShaderEditorがある環境でアセットがインポートされた際、
AmplifyShaderEditor用のカスタムファンクションパッケージを自動インポート
-------------------------------------------------------------------------*/
public class ImportPackageForASE {
#if WCE_DEVELOPMENT
static private readonly bool isDeveloping = true;
#else
static private readonly bool isDeveloping = false;
#endif
[InitializeOnLoadMethod]
public static void registerCallback () {
AssetDatabase.importPackageCompleted -= importCompleted;
AssetDatabase.importPackageCompleted += importCompleted;
}
static void importCompleted (string packageName) {
if (isDeveloping) return;
if (Constant.CheckPackageName (packageName) && findAsset<EffectModuleRef> (out var asset, out var path) && asset.packageForASE) {
string packagePath = AssetDatabase.GetAssetPath (asset.packageForASE);
if (packagePath != null && packagePath.EndsWith (Constant.ASE_PACKAGE_NAME)) {
AssetDatabase.ImportPackage (packagePath, false);
AssetDatabase.DeleteAsset (packagePath);
AssetDatabase.Refresh ();
}
}
}
static private bool findAsset<T> (out T asset, out string path) where T : Object {
asset = null;
path = null;
var guids = AssetDatabase.FindAssets ($"t:{typeof (T).ToString()}", new [] { "Assets" });
if (guids.Length == 0) return false;
path = AssetDatabase.GUIDToAssetPath (guids [0]);
asset = AssetDatabase.LoadAssetAtPath<T> (path);
return asset != null;
}
}
}
#endif

View File

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

View File

@@ -0,0 +1,54 @@
// WaterCausticsModules
// Copyright (c) 2021 Masataka Hakozaki
#if UNITY_EDITOR && WCE_URP
using System.Collections.Generic;
using UnityEditor.Build;
using UnityEditor.Rendering;
using UnityEngine;
using UnityEngine.Rendering;
namespace MH.WaterCausticsModules {
/*------------------------------------------------------------------------
ビルド時シェーダバリアント削除
-------------------------------------------------------------------------*/
public class OptimizeShader : IPreprocessShaders {
public int callbackOrder => 1;
private readonly ShaderKeyword [] delKeys = {
new ShaderKeyword ("WCE_DEBUG_NORMAL"),
new ShaderKeyword ("WCE_DEBUG_DEPTH"),
new ShaderKeyword ("WCE_DEBUG_FACING"),
new ShaderKeyword ("WCE_DEBUG_CAUSTICS"),
new ShaderKeyword ("WCE_DEBUG_AREA"),
#if !WCE_URP_12_0 // URP12より下の場合
new ShaderKeyword ("_GBUFFER_NORMALS_OCT"),
new ShaderKeyword ("_LIGHT_LAYERS"),
new ShaderKeyword ("_LIGHT_COOKIES"),
#endif
#if !WCE_URP_14_0 // URP14より下の場合
new ShaderKeyword ("_FORWARD_PLUS"),
#endif
};
private bool hasDelKey (ShaderKeywordSet set) {
foreach (var key in delKeys)
if (set.IsEnabled (key))
return true;
return false;
}
public void OnProcessShader (Shader shader, ShaderSnippetData snippet, IList<ShaderCompilerData> data) {
// シェーダ名チェック
if (!shader.name.StartsWith (Constant.SHADER_NAME_HEADER)) return;
// キーを持っているか確認 & 削除
for (var i = data.Count - 1; i >= 0; --i) {
if (hasDelKey (data [i].shaderKeywordSet))
data.RemoveAt (i);
}
}
}
}
#endif

View File

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

View File

@@ -0,0 +1,40 @@
// WaterCausticsModules
// Copyright (c) 2021 Masataka Hakozaki
#if UNITY_EDITOR && WCE_URP
using System.Linq;
using UnityEditor;
using UnityEngine;
namespace MH.WaterCausticsModules {
/*------------------------------------------------------------------------
「missing SubGraph references」エラーを防ぐため、このスクリプトが移動した
ことを検知した際にShaderFunctionsフォルダを再インポート。
-------------------------------------------------------------------------*/
public class ReimportFunctions : AssetPostprocessor {
static private readonly string classFileName = $"{typeof (ReimportFunctions).Name}.cs";
static void OnPostprocessAllAssets (string [] imported, string [] deleted, string [] moved, string [] movedFrom) {
// ※移動時と名称変更時、フォルダは importedAssetsとmovedAssetsに入るので注意、アセットはmovedAssetsのみ
if (moved.Any (a => a.EndsWith (classFileName)) && !imported.Any (a => a.EndsWith (classFileName))) {
if (findAsset<EffectModuleRef> (out var asset, out var path) && asset.customFunc) {
var folderPath = AssetDatabase.GetAssetPath (asset.customFunc);
if (!string.IsNullOrEmpty (folderPath) && moved.Any (a => a == folderPath)) {
AssetDatabase.ImportAsset (folderPath, ImportAssetOptions.ImportRecursive);
}
}
}
}
static private bool findAsset<T> (out T asset, out string path) where T : Object {
asset = null;
path = null;
var guids = AssetDatabase.FindAssets ($"t:{typeof (T).ToString()}", new [] { "Assets" });
if (guids.Length == 0) return false;
path = AssetDatabase.GUIDToAssetPath (guids [0]);
asset = AssetDatabase.LoadAssetAtPath<T> (path);
return asset != null;
}
}
}
#endif

View File

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

View File

@@ -0,0 +1,15 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &11400000
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 71d38c23289312844bc6e88159ed75c7, type: 3}
m_Name: WaterCausticsEffectData
m_EditorClassIdentifier:
m_autoManageFeature: 1

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 062a4f28f6d145a4798a42cbe2bf6992
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,47 @@
// WaterCausticsModules
// Copyright (c) 2021 Masataka Hakozaki
#if UNITY_EDITOR && WCE_URP
using System.IO;
using UnityEditor;
using UnityEngine;
namespace MH.WaterCausticsModules {
public class WaterCausticsEffectData : ScriptableObject {
// ---------------------------------------------------------
[SerializeField] internal bool m_autoManageFeature = true;
internal bool AutoManageFeature => m_autoManageFeature;
// ---------------------------------------------------------
static private WaterCausticsEffectData _s_ins;
static internal WaterCausticsEffectData GetAsset () {
if (_s_ins) return _s_ins;
if (findAsset<WaterCausticsEffectData> (out var ins, out var path)) return _s_ins = ins;
return _s_ins = createAsset<WaterCausticsEffectData> ();
}
static private bool findAsset<T> (out T asset, out string path) where T : Object {
asset = null;
path = null;
var guids = AssetDatabase.FindAssets ($"t:{typeof (T).ToString()}", new [] { "Assets" });
if (guids.Length == 0) return false;
path = AssetDatabase.GUIDToAssetPath (guids [0]);
asset = AssetDatabase.LoadAssetAtPath<T> (path);
return asset != null;
}
static private T createAsset<T> () where T : ScriptableObject {
T asset = ScriptableObject.CreateInstance<T> ();
MonoScript mono = MonoScript.FromScriptableObject (asset);
string scriptPath = AssetDatabase.GetAssetPath (mono);
string folderPath = Path.GetDirectoryName (scriptPath).Replace ("\\", "/");
string path = $"{folderPath}/{Path.GetFileNameWithoutExtension (scriptPath)}.asset";
AssetDatabase.CreateAsset (asset, path);
AssetDatabase.SaveAssets ();
return asset;
}
// ---------------------------------------------------------
}
}
#endif

View File

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

View File

@@ -0,0 +1,935 @@
// WaterCausticsModules
// Copyright (c) 2021 Masataka Hakozaki
#if UNITY_EDITOR && WCE_URP
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using MH.WaterCausticsModules.Effect;
using UnityEditor;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
namespace MH.WaterCausticsModules {
[CanEditMultipleObjects]
[CustomEditor (typeof (WaterCausticsEffect))]
public class WaterCausticsEffectEditor : Editor {
private SerializedProperty m_method;
private SerializedProperty m_normalSrc;
private SerializedProperty m_debugInfo;
private SerializedProperty m_debugMode;
private SerializedProperty m_useLayer;
private SerializedProperty m_renderLayerMask;
private SerializedProperty m_layerMask;
private SerializedProperty m_clipOutside;
private SerializedProperty m_texture;
private SerializedProperty m_textureChannel;
private SerializedProperty m_textureRotation;
private SerializedProperty m_texRotSinCos;
private SerializedProperty m_useRandomTiling;
private SerializedProperty m_tilingSeed;
private SerializedProperty m_tilingRotation;
private SerializedProperty m_tilingHardness;
private SerializedProperty m_intensity;
private SerializedProperty m_mainLit;
private SerializedProperty m_addLit;
private SerializedProperty m_colorShift;
private SerializedProperty m_colorShiftDir;
private SerializedProperty m_scale;
private SerializedProperty m_surfaceY;
private SerializedProperty m_surfFadeStart;
private SerializedProperty m_surfFadeEnd;
private SerializedProperty m_useDepthFade;
private SerializedProperty m_depthFadeStart;
private SerializedProperty m_depthFadeEnd;
private SerializedProperty m_useDistanceFade;
private SerializedProperty m_distanceFadeStart;
private SerializedProperty m_distanceFadeEnd;
private SerializedProperty m_litSaturation;
private SerializedProperty m_multiply;
private SerializedProperty m_normalAttenRate;
private SerializedProperty m_normalAtten;
private SerializedProperty m_transparentBackside;
private SerializedProperty m_backsideShadow;
private SerializedProperty m_shadowIntensity;
private SerializedProperty m_receiveShadows;
private SerializedProperty m_useMainLit;
private SerializedProperty m_useAddLit;
private SerializedProperty m_useImageMask;
private SerializedProperty m_imageMaskTexture;
private SerializedProperty m_stencilRef;
private SerializedProperty m_stencilReadMask;
private SerializedProperty m_stencilWriteMask;
private SerializedProperty m_stencilComp;
private SerializedProperty m_stencilPass;
private SerializedProperty m_stencilFail;
private SerializedProperty m_stencilZFail;
private SerializedProperty m_cullMode;
private SerializedProperty m_zWriteMode;
private SerializedProperty m_zTestMode;
private SerializedProperty m_depthOffsetFactor;
private SerializedProperty m_depthOffsetUnits;
private SerializedProperty m_shader;
private SerializedProperty m_noTexture;
private SerializedProperty m_useCustomFunc;
private SerializedProperty m_renderEvent;
private SerializedProperty m_renderEventAdjust;
private void prepProperties () {
if (m_method != null) return;
m_method = serializedObject.FindProperty ("m_method");
m_normalSrc = serializedObject.FindProperty ("m_normalSrc");
m_debugInfo = serializedObject.FindProperty ("m_debugInfo");
m_debugMode = serializedObject.FindProperty ("m_debugMode");
m_useLayer = serializedObject.FindProperty ("m_useLayer");
m_renderLayerMask = serializedObject.FindProperty ("m_renderLayerMask");
m_layerMask = serializedObject.FindProperty ("m_layerMask");
m_clipOutside = serializedObject.FindProperty ("m_clipOutside");
m_texture = serializedObject.FindProperty ("m_texture");
m_textureChannel = serializedObject.FindProperty ("m_textureChannel");
m_textureRotation = serializedObject.FindProperty ("m_textureRotation");
m_texRotSinCos = serializedObject.FindProperty ("m_texRotSinCos");
m_useRandomTiling = serializedObject.FindProperty ("m_useRandomTiling");
m_tilingSeed = serializedObject.FindProperty ("m_tilingSeed");
m_tilingRotation = serializedObject.FindProperty ("m_tilingRotation");
m_tilingHardness = serializedObject.FindProperty ("m_tilingHardness");
m_intensity = serializedObject.FindProperty ("m_intensity");
m_mainLit = serializedObject.FindProperty ("m_mainLit");
m_addLit = serializedObject.FindProperty ("m_addLit");
m_colorShift = serializedObject.FindProperty ("m_colorShift");
m_colorShiftDir = serializedObject.FindProperty ("m_colorShiftDir");
m_scale = serializedObject.FindProperty ("m_scale");
m_surfaceY = serializedObject.FindProperty ("m_surfaceY");
m_surfFadeStart = serializedObject.FindProperty ("m_surfFadeStart");
m_surfFadeEnd = serializedObject.FindProperty ("m_surfFadeEnd");
m_useDepthFade = serializedObject.FindProperty ("m_useDepthFade");
m_depthFadeStart = serializedObject.FindProperty ("m_depthFadeStart");
m_depthFadeEnd = serializedObject.FindProperty ("m_depthFadeEnd");
m_useDistanceFade = serializedObject.FindProperty ("m_useDistanceFade");
m_distanceFadeStart = serializedObject.FindProperty ("m_distanceFadeStart");
m_distanceFadeEnd = serializedObject.FindProperty ("m_distanceFadeEnd");
m_litSaturation = serializedObject.FindProperty ("m_litSaturation");
m_multiply = serializedObject.FindProperty ("m_multiply");
m_normalAttenRate = serializedObject.FindProperty ("m_normalAttenRate");
m_normalAtten = serializedObject.FindProperty ("m_normalAtten");
m_transparentBackside = serializedObject.FindProperty ("m_transparentBackside");
m_backsideShadow = serializedObject.FindProperty ("m_backsideShadow");
m_shadowIntensity = serializedObject.FindProperty ("m_shadowIntensity");
m_receiveShadows = serializedObject.FindProperty ("m_receiveShadows");
m_useMainLit = serializedObject.FindProperty ("m_useMainLit");
m_useAddLit = serializedObject.FindProperty ("m_useAddLit");
m_useImageMask = serializedObject.FindProperty ("m_useImageMask");
m_imageMaskTexture = serializedObject.FindProperty ("m_imageMaskTexture");
m_stencilRef = serializedObject.FindProperty ("m_stencilRef");
m_stencilReadMask = serializedObject.FindProperty ("m_stencilReadMask");
m_stencilWriteMask = serializedObject.FindProperty ("m_stencilWriteMask");
m_stencilComp = serializedObject.FindProperty ("m_stencilComp");
m_stencilPass = serializedObject.FindProperty ("m_stencilPass");
m_stencilFail = serializedObject.FindProperty ("m_stencilFail");
m_stencilZFail = serializedObject.FindProperty ("m_stencilZFail");
m_cullMode = serializedObject.FindProperty ("m_cullMode");
m_zWriteMode = serializedObject.FindProperty ("m_zWriteMode");
m_zTestMode = serializedObject.FindProperty ("m_zTestMode");
m_depthOffsetFactor = serializedObject.FindProperty ("m_depthOffsetFactor");
m_depthOffsetUnits = serializedObject.FindProperty ("m_depthOffsetUnits");
m_shader = serializedObject.FindProperty ("m_shader");
m_noTexture = serializedObject.FindProperty ("m_noTexture");
m_useCustomFunc = serializedObject.FindProperty ("m_useCustomFunc");
m_renderEvent = serializedObject.FindProperty ("m_renderEvent");
m_renderEventAdjust = serializedObject.FindProperty ("m_renderEventAdjust");
}
private SerializedObject _wceData;
private SerializedProperty m_autoManageFeature;
private SerializedObject prepWceData () {
if (_wceData == null)
_wceData = new SerializedObject (WaterCausticsEffectData.GetAsset ());
if (m_autoManageFeature == null) {
m_autoManageFeature = _wceData.FindProperty ("m_autoManageFeature");
}
_wceData.Update ();
return _wceData;
}
static readonly GUIContent [] _cullingEnumStr = {
new GUIContent ("Both"),
new GUIContent ("Back"),
new GUIContent ("Front"),
};
static readonly string descGenFromDepth = "[Generate from Depth] \nGenerate from _CameraDepthTexture generated by the system. This method is not good for smooth surfaces, but it does produce the correct normals.";
static readonly string descCamNormalTex = "[Camera Normals Tex] \nSampling _CameraNormalsTexture generated by the system. This is high quality, but may produce strange results with materials that do not support normal output.";
static readonly GUIContent [] _normalSrcStr = {
new GUIContent ("Generate from Depth (LQ)", $"{descGenFromDepth}\n\n{descCamNormalTex}"),
new GUIContent ("Camera Normals Tex (HQ)", $"{descGenFromDepth}\n\n{descCamNormalTex}"),
};
static readonly string [] _renderingLayerMaskNamesSpare = { "Layer1", "Layer2", "Layer3", "Layer4", "Layer5", "Layer6", "Layer7", "Layer8", "Layer9", "Layer10", "Layer11", "Layer12", "Layer13", "Layer14", "Layer15", "Layer16", "Layer17", "Layer18", "Layer19", "Layer20", "Layer21", "Layer22", "Layer23", "Layer24", "Layer25", "Layer26", "Layer27", "Layer28", "Layer29", "Layer30", "Layer31", "Layer32", };
private List<ScriptableRendererData> _rendererDataList;
private bool _hasGetRenderData;
protected virtual void OnEnable () {
foreach (var tar in targets.OfType<WaterCausticsEffect> ())
tar.VersionCheck ();
}
UniversalRenderPipelineAsset urpAsset => GraphicsSettings.currentRenderPipeline as UniversalRenderPipelineAsset;
public override void OnInspectorGUI () {
if (urpAsset) {
var wceData = prepWceData ();
prepProperties ();
serializedObject.Update ();
using (var check = new EditorGUI.ChangeCheckScope ()) {
drawProperties ();
serializedObject.ApplyModifiedProperties ();
wceData.ApplyModifiedProperties ();
if (check.changed) {
foreach (var tar in targets.OfType<WaterCausticsEffect> ())
tar.OnInspectorChanged ();
}
}
} else {
// -- URP設定が完了していない場合
onInspectorGUI_NotSettingYet ();
}
}
// -----------------------------------------------------------
readonly Color colorPinkBar = new Color (1f, 0.3f, 0.6f, 0.3f);
readonly Color colorPinkContent = new Color (1f, 0.3f, 0.6f, 1f);
readonly Color colorGreenContent = new Color (0.4f, 1f, 0.7f, 1f);
private float lineH = EditorGUIUtility.singleLineHeight + 2;
readonly float SPACE_SUB_TOP_5 = 5f;
readonly float SPACE_SUB_BTM_12 = 12f;
readonly float SPACE_MAIN_TOP_7 = 7f;
readonly float SPACE_MAIN_BTM_5 = 5f;
private Color _defaultGUIColor;
private void setLabelAreaWidth (float labelWidthMin, float valWidthMin) {
if (EditorGUIUtility.labelWidth < labelWidthMin)
EditorGUIUtility.labelWidth = labelWidthMin;
if (EditorGUIUtility.currentViewWidth - EditorGUIUtility.labelWidth < valWidthMin)
EditorGUIUtility.labelWidth = EditorGUIUtility.currentViewWidth - valWidthMin;
}
private void drawProperties () {
_defaultGUIColor = GUI.color;
storeIndentWidth ();
EditorGUIUtility.labelWidth += 6;
EditorGUI.indentLevel++;
setLabelAreaWidth (labelWidthMin: 140f, valWidthMin: 170f);
bool isEditingMultiObj = serializedObject.isEditingMultipleObjects;
bool isMethodEach = (m_method.enumValueIndex == (int) Method.EachMesh && !m_method.hasMultipleDifferentValues);
bool isMethodOnce = (m_method.enumValueIndex == (int) Method.AtOnce && !m_method.hasMultipleDifferentValues);
// ---------------------------------------------------------------------------------- System
// ------ RendererFeature
if (!_hasGetRenderData) {
_hasGetRenderData = true;
WaterCausticsEffectFeatureEditor.GetAllRendererData (out _rendererDataList);
if (WaterCausticsEffectData.GetAsset ().AutoManageFeature)
WaterCausticsEffectFeatureEditor.AddFeatureToAllRenderers (_rendererDataList, useUndo : false);
}
bool someRenderNotHasFeature = !WaterCausticsEffectFeatureEditor.CheckAllHasActiveFeature (_rendererDataList);
bool currentRenderNotHasFeature = someRenderNotHasFeature && !WaterCausticsEffectFeature.effective;
// ----------------------
if (expandMainGroup (m_method, true, "System", isPink : currentRenderNotHasFeature)) {
EditorGUILayout.Space (SPACE_MAIN_TOP_7);
// ------ RendererFeature
if (someRenderNotHasFeature) {
EditorGUI.indentLevel -= 1;
// labelWarning("To apply this effect, a Renderer Feature needs to be added to a Renderer.", 11);
using (new ColorScope (currentRenderNotHasFeature ? colorPinkContent : _defaultGUIColor)) {
string str = "To apply this effect, a Renderer Feature needs to be added to a Renderer.";
if (currentRenderNotHasFeature)
EditorGUILayout.HelpBox ($"The Renderer Feature has not been added or activated in the current Renderer.\n{str}", MessageType.Warning);
else
EditorGUILayout.HelpBox ($"The Renderer Feature has not been added or activated in some Renderers.\n{str}", MessageType.Warning);
EditorGUILayout.Space (2);
Rect rect = GUILayoutUtility.GetRect (0, 0);
rect.height = lineH;
rect.width *= 0.5f;
if (GUI.Button (rect, new GUIContent ("Select Renderer", "Search and select RendererData assets."), EditorStyles.miniButton)) {
// -- 選択ボタン
if (WaterCausticsEffectFeatureEditor.GetAllRendererData (out var list)) {
// -- 成功
WaterCausticsEffectFeatureEditor.SelectAndPing (list);
if (list.Count >= 2) {
var pathStr = WaterCausticsEffectFeatureEditor.AssetsToPathStr (list);
EditorApplication.delayCall += () => EditorApplication.delayCall += () =>
EditorUtility.DisplayDialog ("Multiple found.", $"Multiple RendererData assets found.\n\n{pathStr}", "OK");
}
} else {
// -- 見つからない
EditorUtility.DisplayDialog ("Not found.", $"Not found.", "OK");
}
}
rect.x += rect.width;
if (GUI.Button (rect, new GUIContent ("Fix It", "Add a Renderer Feature to Renderers."), EditorStyles.miniButton)) {
// -- 追加ボタン
if (WaterCausticsEffectFeatureEditor.AddFeatureToAllRenderers (useUndo: true)) {
// -- 成功
} else {
// -- 失敗
bool showURL = EditorUtility.DisplayDialog ("Failed", "Processing failed. Please add the Renderer Feature to Renderers manually.", "Open URP Manual", "Cancel");
if (showURL) Application.OpenURL (Constant.URL_HOW_TO_ADD_FEATURE);
}
}
EditorGUILayout.Space (lineH);
using (new ColorScope (_defaultGUIColor)) {
EditorGUILayout.Space (1);
if (labelLink (new GUIContent ("How to add Renderer Feature to Renderer", Constant.URL_HOW_TO_ADD_FEATURE), 10))
Application.OpenURL (Constant.URL_HOW_TO_ADD_FEATURE);
EditorGUILayout.Space (4);
}
EditorGUI.indentLevel += 1;
EditorGUILayout.Space (15);
}
}
// ----------------------
EditorGUILayout.PropertyField (m_method, new GUIContent ("Effect Method", "[At Once]\nDraws the effect at once using the camera's depth and normal texture. It can also be applied to objects with materials that are deformed by shaders. \n\n[Each Mesh]\nDraws effects to each mesh. Masking with layers and the surface to be drawn can be specified. However, it cannot be applied to objects with materials that deform with shaders. For such objects, embed custom function in the shader or use the At Once method."));
if (isMethodOnce) {
using (new IndentScope (-2f, 0f)) {
popup (m_normalSrc, _normalSrcStr, "Normal Data", $"How to get normal vector in world space.\n\n{descGenFromDepth}\n\n{descCamNormalTex}");
}
}
drawBoolAndValue (m_debugInfo, m_debugMode, true, new GUIContent ("Debug Info", "Display data for debugging. This is only valid on the editor.\n\n" +
$"[{DebugMode.Normal}]\nDisplays world-space normal data.\n\n" +
$"[{DebugMode.Depth}]\nDisplays the depth data.\n\n" +
$"[{DebugMode.Facing}]\nDisplays the plane facing the camera as bright.\n\n" +
$"[{DebugMode.Caustics}]\nDisplays only caustics effects.\n\n" +
$"[{DebugMode.LightArea}]\nDisplays the affected area by each light.\n\n" +
$"If some objects are not rendering correctly on At Once method with Camera Normals Tex, the object's material is outputting the wrong normals. Check the normals on this screen and modify the material (shader) of the object."));
EditorGUILayout.Space (SPACE_SUB_BTM_12);
// ---------------------------------------------------------------------------------- Influence Scope
if (expandSubGroup (m_useImageMask, true, "Influence Scope")) {
EditorGUILayout.Space (SPACE_SUB_TOP_5);
selectGameObjectLayer (new GUIContent ("Layer", "The layer in which this effect exists."));
if (isMethodEach) {
EditorGUILayout.PropertyField (m_layerMask, new GUIContent ("Layer Mask", "Specify the layer on which the effect will be drawn. Objects on unchecked layers will be ignored."));
}
if (isMethodEach) {
EditorGUILayout.PropertyField (m_clipOutside, new GUIContent ("Clip Outside", "Draw effects only inside the volume."));
}
drawBoolAndValue (m_useImageMask, m_imageMaskTexture, hide : true, new GUIContent ("Image Mask", "Masking with an image."));
if (isMethodEach) {
popup (m_cullMode, _cullingEnumStr, "Render Face", "Which face to draw.");
}
// EditorGUILayout.Space (2);
// if (isExpand (m_renderEventAdjust, false, new GUIContent ("Advanced", "Advanced Settings"))) {
// using (new IndentScope (0f, 0f)) {
EditorGUILayout.PropertyField (m_useCustomFunc, new GUIContent ("Custom Function", "Supports Custom Function for shader. \nTransmits the settings to the WaterCausticsEmissionSync function embedded in the shader. \nTurning this On will copy the settings to a global shader variable. \n\nIf there are multiple effects with this setting On in a scene, the last active effect will be used."));
{
// 描画タイミング設定
bool isExpanded = isExpand (m_renderEvent, true, new GUIContent (""));
EditorGUILayout.Space (-EditorGUIUtility.singleLineHeight - 2f);
string baseTimingName = splitCamelCase (((RenderPassEvent) m_renderEvent.intValue).ToString ());
int sysOpqTiming = (int) WaterCausticsEffect.SYS_OPAQUE_TEX_EVENT;
string sysOpqName = WaterCausticsEffect.SYS_OPAQUE_TEX_EVENT.ToString ();
string sysOpqDesc = $"{sysOpqName}({sysOpqTiming})";
string sysOpqDescPlusOne = $"{sysOpqName}+1 ({sysOpqTiming+1})";
string defaultTiming = WaterCausticsEffect.RENDER_EVENT.ToString ();
int defaultTimingAdj = WaterCausticsEffect.RENDER_EVENT_ADJ;
int baseTiming = m_renderEvent.intValue;
int adjTiming = m_renderEventAdjust.intValue;
int adjusted = baseTiming + adjTiming;
bool isHasDifVal = m_renderEvent.hasMultipleDifferentValues || m_renderEventAdjust.hasMultipleDifferentValues;
EditorGUILayout.LabelField (new GUIContent ("Draw Timing", $"Specifies the timing of drawing.\n\nTo display this effect on _CameraOpaqueTexture, it must be drawn before {sysOpqDesc}."), new GUIContent (isHasDifVal ? "-" : $"{baseTimingName} {(adjTiming < 0 ? "-" : "+")}{Mathf.Abs(adjTiming)} ({Mathf.Clamp(adjusted, 0, 1000)})"));
if (isExpanded) {
using (new IndentScope (-2f, 4f)) {
EditorGUILayout.PropertyField (m_renderEvent, new GUIContent ($"Render Event", $"Controls when the render executes. \n[Default: {defaultTiming}]"));
EditorGUILayout.PropertyField (m_renderEventAdjust, new GUIContent ("Adjustment", $"Controls when the render executes. This number is added to the Draw Timing above. \n[Default: {defaultTimingAdj}]"));
bool isEarly = (adjusted <= sysOpqTiming);
string warning = isEarly ? $"To use a value between 0 and 1 in the Multiply Color setting, set it after {sysOpqDescPlusOne}." :
$"To display this effect on _CameraOpaqueTexture, it must be drawn before {sysOpqDesc}.";
EditorGUILayout.HelpBox (new GUIContent (warning, ""), true);
}
}
}
if (isMethodOnce) {
var names = urpAsset.renderingLayerMaskNames;
if (names == null) names = _renderingLayerMaskNamesSpare;
bitMask (m_renderLayerMask, names, "Render Mask", "Rendering Layer Mask of this effect. It works as same as RenderingLayerMask of MeshRenderer.");
}
if (isMethodEach) {
if (isExpand (m_zTestMode, false, new GUIContent ("Depth Buffer", "Adjust Depth Testing and Depth Offset."))) {
using (new IndentScope (0, 2)) {
EditorGUILayout.PropertyField (m_zWriteMode, new GUIContent ("ZWrite", "Whether to write depth values to the depth buffer."));
EditorGUILayout.PropertyField (m_zTestMode, new GUIContent ("ZTest", "Comparison method with already existing depth values."));
EditorGUILayout.PropertyField (m_depthOffsetFactor, new GUIContent ("Offset Factor", "Offset Factor"));
EditorGUILayout.PropertyField (m_depthOffsetUnits, new GUIContent ("Offset Units", "Offset Units"));
}
}
EditorGUILayout.Space (2);
}
if (isExpand (m_stencilRef, false, new GUIContent ("Stencil Buffer", "The Stencil Buffer can be used to limit the objects to be drawn or used for subsequent effects."))) {
using (new IndentScope (0, 2)) {
EditorGUILayout.PropertyField (m_stencilRef, new GUIContent ("Ref", "Stencil Reference Value"));
EditorGUILayout.PropertyField (m_stencilReadMask, new GUIContent ("ReadMask", "Stencil Read Mask"));
EditorGUILayout.PropertyField (m_stencilWriteMask, new GUIContent ("WriteMask", "Stencil Write Mask"));
EditorGUILayout.PropertyField (m_stencilComp, new GUIContent ("Comp", "Stencil Compare Operation"));
EditorGUILayout.PropertyField (m_stencilPass, new GUIContent ("Pass", "Stencil Pass Operation"));
EditorGUILayout.PropertyField (m_stencilFail, new GUIContent ("Fail", "Stencil Fail Operation"));
EditorGUILayout.PropertyField (m_stencilZFail, new GUIContent ("ZFail", "Stencil Z Fail Operation"));
}
}
// }
// }
}
EditorGUILayout.Space (SPACE_SUB_BTM_12);
}
EditorGUILayout.Space (SPACE_MAIN_BTM_5);
// ---------------------------------------------------------------------------------- Effect Group
bool useTextureWarning = (m_texture.objectReferenceValue == null && isGameObjectOnScene () && !isEditingMultiObj);
if (expandMainGroup (m_texture, true, "Caustics Effect", isPink : useTextureWarning && m_texture.isExpanded)) {
EditorGUILayout.Space (SPACE_MAIN_TOP_7);
if (expandSubGroup (m_textureRotation, true, "Texture", isPink : useTextureWarning)) {
EditorGUILayout.Space (SPACE_SUB_TOP_5);
using (new ColorScope (useTextureWarning?colorPinkContent : GUI.color)) {
EditorGUILayout.PropertyField (m_texture, new GUIContent ("Caustics Texture", $"Set the RenderTexture specified as the output destination in the {typeof(WaterCausticsTexGenerator).Name}."));
if (!m_texture.hasMultipleDifferentValues) {
if (useTextureWarning) {
EditorGUILayout.Space (1);
EditorGUILayout.BeginHorizontal ();
GUILayout.FlexibleSpace ();
if (GUILayout.Button ("Search from this Scene", EditorStyles.miniButton, GUILayout.Width (150))) {
var gen = FindObjectsOfType<WaterCausticsTexGenerator> ().FirstOrDefault (g => g.renderTexture != null);
if (gen != null)
m_texture.objectReferenceValue = gen.renderTexture;
else
EditorUtility.DisplayDialog ("Not Found", $"There is no {typeof(WaterCausticsTexGenerator).Name} with active and having RenderTexture in this scene.", "OK");
}
EditorGUILayout.EndHorizontal ();
EditorGUILayout.Space (3);
} else {
var tex = m_texture.objectReferenceValue as Texture;
if (tex != null) {
EditorGUILayout.HelpBox ($"{tex.width}x{tex.height} / {tex.graphicsFormat}", MessageType.None);
EditorGUILayout.Space (3);
}
}
}
}
EditorGUILayout.PropertyField (m_textureChannel, new GUIContent ("Channel", "Channels to be used. Set to R if using R-channel only textures."));
using (var check = new EditorGUI.ChangeCheckScope ()) {
using (new IndentScope (0f, 0f, 1)) {
EditorGUILayout.PropertyField (m_textureRotation, new GUIContent ("Rotation", "Rotate the texture."));
drawDirMark (m_textureRotation, true);
}
if (check.changed) {
float rad = m_textureRotation.floatValue * Mathf.Deg2Rad;
m_texRotSinCos.vector2Value = new Vector2 (Mathf.Sin (rad), Mathf.Cos (rad));
}
}
EditorGUILayout.PropertyField (m_useRandomTiling, new GUIContent ("Random Tiling", "Use randomized hexagonal tiling. This reduces unnatural repetitions that appear on distant planes."));
if (m_useRandomTiling.boolValue) {
using (new IndentScope (-2f, 0f)) {
EditorGUILayout.PropertyField (m_tilingSeed, new GUIContent ("Seed", "Random seed value."));
EditorGUILayout.PropertyField (m_tilingHardness, new GUIContent ("Hardness", "Edge hardness."));
EditorGUILayout.PropertyField (m_tilingRotation, new GUIContent ("Rotation", "Rotate tiles randomly."));
}
}
EditorGUILayout.Space (SPACE_SUB_BTM_12);
}
if (expandSubGroup (m_scale, true, "Dimensions")) {
EditorGUILayout.Space (SPACE_SUB_TOP_5);
EditorGUILayout.PropertyField (m_scale, new GUIContent ("Scale", "Texture size at the height of the water surface."));
EditorGUILayout.PropertyField (m_surfaceY, new GUIContent ("Water Surface Y", "Height of the water surface. Y-axis. The projected position of the light is calculated with respect to this plane."));
EditorGUILayout.Space (4);
drawStartEndProp (m_surfFadeStart, m_surfFadeEnd, new GUIContent ("Surface Fade", "Attenuates light as it approaches the surface of the water."));
EditorGUILayout.PropertyField (m_useDepthFade, new GUIContent ("Depth Fade", "Attenuates light as depth increases."));
if (m_useDepthFade.boolValue) {
using (new IndentScope (-2f, 0f))
drawStartEndProp (m_depthFadeStart, m_depthFadeEnd, new GUIContent ("Range", "Attenuates light as depth increases."));
}
EditorGUILayout.PropertyField (m_useDistanceFade, new GUIContent ("Distance Fade", "Attenuates light as distance increases."));
if (m_useDistanceFade.boolValue) {
using (new IndentScope (-2f, 0f))
drawStartEndProp (m_distanceFadeStart, m_distanceFadeEnd, new GUIContent ("Range", "Attenuates light as distance increases."));
}
EditorGUILayout.Space (SPACE_SUB_BTM_12);
}
if (expandSubGroup (m_intensity, true, "Effect")) {
EditorGUILayout.Space (SPACE_SUB_TOP_5);
EditorGUILayout.PropertyField (m_intensity, new GUIContent ("Intensity", "Intensity of effect."));
using (new IndentScope (-1f, 1f)) {
drawBoolAndValue (m_useMainLit, m_mainLit, hide : true, new GUIContent ("Main Light", "Adjust the intensity of the main light. If the checkbox is Off, the main light calculation is skipped."));
drawBoolAndValue (m_useAddLit, m_addLit, hide : true, new GUIContent ("Additional Lights", "Adjust the intensity of the additional lights. If the check box is Off, the calculation of additional lights is skipped."));
}
EditorGUILayout.Space (2);
drawBoolAndValue (m_receiveShadows, m_shadowIntensity, hide : true, new GUIContent ("Shadow", "Strength of shadow. If the checkbox is unchecked, the shadow calculation is skipped. \n\nFor the At Once method, \"Transparent Receive Shadows\" in the URP settings must also be set to On."));
EditorGUILayout.Space (2);
EditorGUILayout.PropertyField (m_colorShift, new GUIContent ("Color Shift", "Amount of RGB channel shift."));
if (m_colorShift.floatValue > 0f) {
using (new IndentScope (-2f, 0f, 2)) {
EditorGUILayout.PropertyField (m_colorShiftDir, new GUIContent ("Direction", "Direction of shift for RGB channels."));
drawDirMark (m_colorShiftDir, true);
}
}
EditorGUILayout.Space (2);
EditorGUILayout.PropertyField (m_litSaturation, new GUIContent ("Light Color", "Color intensity of the light."));
EditorGUILayout.Space (2);
EditorGUILayout.PropertyField (m_multiply, new GUIContent ("Multiply Color", "Multiply by the screen color and then add. \nIf this value is 1 or 0, it is processed faster because it uses the shader's Blend function. Otherwise, _CameraOpaqueTexture is sampled and multiplied. If the Draw Timing setting is before _CameraOpaqueTexture is drawn, it is processed as 1."));
if (!isEditingMultiObj && (m_multiply.floatValue > 0f && m_multiply.floatValue < 1f) &&
((m_renderEvent.intValue + m_renderEventAdjust.intValue) <= (int) WaterCausticsEffect.SYS_OPAQUE_TEX_EVENT)
) {
// 描画タイミングが早すぎる場合警告
using (new IndentScope (0f, 0f)) {
EditorGUILayout.HelpBox (new GUIContent ("Only 0 or 1 is valid because the Draw Timing is too early.", "Draw Timing in Influence Scope settings is too early and _CameraOpaqueTexture does not exist, so it cannot be drawn with a setting between 0 and 1. Therefore, it is drawn as 1."), true);
}
}
EditorGUILayout.Space (3);
EditorGUILayout.PropertyField (m_normalAtten, new GUIContent ("Normal Attenuation", "Attenuation due to the angle between the normal and the light ray. \n[Default: 1]")); {
using (new IndentScope (-2f, 2f)) {
using (new DisableScope (m_normalAtten.floatValue > 0f)) {
EditorGUILayout.PropertyField (m_normalAttenRate, new GUIContent ("Rate", "Rate of normal attenuation. How quickly does the light fade. \n[Default: 1.5]"));
EditorGUILayout.PropertyField (m_transparentBackside, new GUIContent ("Transparent", "The intensity of light transmitted to the backside. \n[Default: 0]"));
}
using (new DisableScope (m_receiveShadows.boolValue && (m_normalAtten.floatValue < 1f || m_transparentBackside.floatValue > 0f))) {
EditorGUILayout.PropertyField (m_backsideShadow, new GUIContent ("Backside Shadow", "The intensity of shadow on the backside. \n[Default: 0]"));
}
}
}
EditorGUILayout.Space (SPACE_SUB_BTM_12);
}
}
EditorGUILayout.Space (SPACE_MAIN_BTM_5);
// ---------------------------------------------------------------------------------- Advanced Settings
if (expandMainGroup (m_backsideShadow, false, "Advanced Settings")) {
EditorGUILayout.Space (SPACE_MAIN_TOP_7);
if (expandSubGroup (m_normalAttenRate, false, "Renderer Feature")) {
EditorGUILayout.Space (SPACE_SUB_TOP_5);
using (var check = new EditorGUI.ChangeCheckScope ()) {
EditorGUILayout.PropertyField (m_autoManageFeature, new GUIContent ("Auto-Management", "Automatically manages Renderer Feature. It automatically adds the Renderer Feature for this effect to all Renderer Data in the project.\n\nIf this is turned off, it is required to manually add the Renderer Feature to the Renderer Data."));
if (check.changed && m_autoManageFeature.boolValue == true) {
WaterCausticsEffectFeatureEditor.AddFeatureToAllRenderers (useUndo: false);
}
if (!m_autoManageFeature.boolValue) {
EditorGUILayout.Space (1);
EditorGUI.indentLevel++;
EditorGUILayout.HelpBox ("To apply this effect, a Renderer Feature needs to be added to a Renderer.", MessageType.None);
EditorGUILayout.Space (1);
if (labelLink (new GUIContent ("How to add Renderer Feature to Renderer", Constant.URL_HOW_TO_ADD_FEATURE), 10, 2))
Application.OpenURL (Constant.URL_HOW_TO_ADD_FEATURE);
EditorGUI.indentLevel--;
}
}
EditorGUILayout.Space (SPACE_SUB_BTM_12);
}
}
EditorGUILayout.Space (SPACE_SUB_BTM_12);
EditorGUILayout.Space (SPACE_MAIN_BTM_5);
EditorGUILayout.Space (SPACE_MAIN_BTM_5);
EditorGUI.indentLevel--;
}
// ----------------------------------------------------------- Parts
private string splitCamelCase (string str) {
return Regex.Replace (
Regex.Replace (str, @"(\P{Ll})(\P{Ll}\p{Ll})", "$1 $2"), @"(\p{Ll})(\P{Ll})", "$1 $2");
}
private float _indentWidth;
private void storeIndentWidth () {
if (_indentWidth != 0f) return;
var x0 = EditorGUI.IndentedRect (Rect.zero).x;
EditorGUI.indentLevel++;
_indentWidth = EditorGUI.IndentedRect (Rect.zero).x - x0;
EditorGUI.indentLevel--;
}
private void drawBoolAndValue (SerializedProperty propBool, SerializedProperty propValue, bool hide, GUIContent label) {
EditorGUILayout.PropertyField (propBool, label);
var rect = GUILayoutUtility.GetLastRect ();
var labelW = EditorGUIUtility.labelWidth;
if (!hide || propBool.boolValue) {
using (new DisableScope (propBool.boolValue)) {
EditorGUIUtility.labelWidth += 25;
EditorGUI.PropertyField (rect, propValue, new GUIContent (" "));
}
}
EditorGUIUtility.labelWidth = labelW;
}
private void selectGameObjectLayer (GUIContent label) {
var gameObjects = targets.Select (t => (t as WaterCausticsEffect).gameObject).ToArray ();
var layers = gameObjects.Select (go => go.layer).Distinct ().ToArray ();
using (var check = new EditorGUI.ChangeCheckScope ()) {
EditorGUI.showMixedValue = (layers.Length != 1);
int newVal = EditorGUILayout.LayerField (label, layers [0]);
EditorGUI.showMixedValue = false;
if (check.changed) {
Undo.RecordObjects (gameObjects, "Changed Layer");
foreach (var go in gameObjects) {
go.layer = newVal;
EditorUtility.SetDirty (go);
}
if (layers.Length >= 2 && gameObjects.Length == Selection.objects.Length) {
// 上部のレイヤー表示Multiple(-)を更新するため選択中の場合は再選択
bool isSelected = true;
foreach (var o in gameObjects) {
if (!Selection.objects.Contains (o)) {
isSelected = false;
break;
}
}
if (isSelected) {
Selection.activeGameObject = null;
EditorApplication.delayCall += () => { Selection.objects = gameObjects; };
}
}
}
}
}
private void selectLayer (SerializedProperty prop, GUIContent label) {
using (var check = new EditorGUI.ChangeCheckScope ()) {
EditorGUI.showMixedValue = prop.hasMultipleDifferentValues;
var newVal = EditorGUILayout.LayerField (label, prop.intValue);
EditorGUI.showMixedValue = false;
if (check.changed)
prop.intValue = newVal;
}
}
private void drawStartEndProp (SerializedProperty propStt, SerializedProperty propEnd, GUIContent label) {
EditorGUILayout.LabelField (label);
var rect = GUILayoutUtility.GetLastRect ();
rect.x += EditorGUIUtility.labelWidth;
rect.width -= EditorGUIUtility.labelWidth;
drawStartEndPropInRect (rect, propStt, propEnd);
}
private void drawStartEndPropInRect (Rect rect, SerializedProperty propStt, SerializedProperty propEnd) {
bool isWide = (rect.width > 140);
float span = isWide ? 5f : 3f;
var rect2 = rect;
var rect3 = rect;
rect2.width = rect3.width = (rect.width - span) * 0.5f;
rect3.x += rect2.width + span;
var storeIndent = EditorGUI.indentLevel;
EditorGUI.indentLevel = 0;
var labelW = EditorGUIUtility.labelWidth;
using (var check = new EditorGUI.ChangeCheckScope ()) {
EditorGUI.showMixedValue = propStt.hasMultipleDifferentValues;
EditorGUIUtility.labelWidth = isWide? 32 : 10;
float newStt = EditorGUI.FloatField (rect2, isWide ? "Start" : "S", propStt.floatValue);
if (check.changed)
propStt.floatValue = Mathf.Clamp (newStt, 0, propEnd.floatValue);
}
using (var check = new EditorGUI.ChangeCheckScope ()) {
EditorGUI.showMixedValue = propEnd.hasMultipleDifferentValues;
EditorGUIUtility.labelWidth = isWide ? 26 : 10;
float newEnd = EditorGUI.FloatField (rect3, isWide ? "End" : "E", propEnd.floatValue);
if (check.changed)
propEnd.floatValue = Mathf.Max (newEnd, propStt.floatValue);
}
EditorGUI.showMixedValue = false;
EditorGUIUtility.labelWidth = labelW;
EditorGUI.indentLevel = storeIndent;
}
static private Color colorMulAlpha (Color c, float mulAlpha) => new Color (c.r, c.g, c.b, c.a * mulAlpha);
private void drawDirMark (SerializedProperty prop, bool isActive = true) {
EditorGUI.indentLevel--;
var rect = EditorGUI.IndentedRect (GUILayoutUtility.GetLastRect ());
drawDirMark (rect, prop, isActive);
EditorGUI.indentLevel++;
}
private void drawDirMark (Rect rect, SerializedProperty prop, bool isActive = true) {
rect.width = EditorGUIUtility.labelWidth;
Vector2 origin = new Vector2 (CIRCLE_R + 1, rect.height * 0.5f);
float dir = prop.floatValue;
Handles.color = colorMulAlpha (EditorStyles.label.normal.textColor, isActive ? 0.8f : 0.4f);
var tmpMatrix = Handles.matrix;
GUI.BeginClip (rect, origin, Vector2.zero, false);
Handles.matrix = tmpMatrix * Matrix4x4.Scale (Vector3.one * CIRCLE_R);
Handles.DrawAAPolyLine (Texture2D.whiteTexture, 1, circlePts);
if (!prop.hasMultipleDifferentValues) {
Handles.matrix = tmpMatrix * Matrix4x4.Rotate (Quaternion.Euler (0f, 0f, dir)) * Matrix4x4.Scale (Vector3.one * (CIRCLE_R - 0.5f));
Handles.DrawAAConvexPolygon (arrowAry);
}
Handles.matrix = tmpMatrix;
GUI.EndClip ();
}
static private Vector2 dirToVec (float dir) => new Vector2 (Mathf.Sin (dir * Mathf.Deg2Rad), -Mathf.Cos (dir * Mathf.Deg2Rad));
const float CIRCLE_R = 5f;
static readonly private Vector3 [] arrowAry = {
dirToVec (0),
dirToVec (150f),
dirToVec (170f),
dirToVec (-170f),
dirToVec (-150f),
};
static readonly private Vector3 [] circlePts = {
new Vector3 (-1f, 0f),
new Vector3 (-0.87f, -0.5f),
new Vector3 (-0.5f, -0.87f),
new Vector3 (0f, -1f),
new Vector3 (0.5f, -0.87f),
new Vector3 (0.87f, -0.5f),
new Vector3 (1f, 0f),
new Vector3 (0.87f, 0.5f),
new Vector3 (0.5f, 0.87f),
new Vector3 (0f, 1f),
new Vector3 (-0.5f, 0.87f),
new Vector3 (-0.87f, 0.5f),
new Vector3 (-1f, 0f),
};
bool isGameObjectOnScene () {
return (target as Component).gameObject.scene.IsValid ();
}
private void drawRectMain (bool isPink = false) {
Color color = isPink ? colorPinkBar : new Color (0f, 0f, 0f, 0.2f);
Rect rect = GUILayoutUtility.GetRect (0, 0);
rect.height = lineH;
rect.x -= _indentWidth + 4;
rect.width += _indentWidth + 8;
EditorGUI.DrawRect (rect, color);
}
private bool expandMainGroup (SerializedProperty prop, bool defOpen, string label, bool isPink = false) {
EditorGUI.indentLevel--;
drawRectMain (isPink);
bool expand = isExpand (prop, true, new GUIContent (label));
EditorGUI.indentLevel++;
return expand;
}
private bool expandSubGroup (SerializedProperty prop, bool defOpen, string label, bool isPink = false) {
Color color = isPink ? colorPinkBar : colorMulAlpha (EditorStyles.label.normal.textColor, 0.1f);
GUILayout.Label (" ");
Rect rect = GUILayoutUtility.GetLastRect ();
rect.y += 1f;
rect.x += 3f;
rect.width -= 3f;
Rect rect2 = rect;
rect2.x -= 14f;
rect2.width += 15f;
EditorGUI.DrawRect (rect2, color);
GUI.Label (rect, label);
if (prop == null) {
return true;
} else {
rect.x -= 14;
prop.isExpanded = EditorGUI.Foldout (rect, prop.isExpanded != defOpen, " ") != defOpen;
return prop.isExpanded != defOpen;
}
}
private void popup (SerializedProperty prop, GUIContent [] enumStr, string text, string tooltip) {
using (var check = new EditorGUI.ChangeCheckScope ()) {
EditorGUI.showMixedValue = prop.hasMultipleDifferentValues;
var newVal = EditorGUILayout.Popup (new GUIContent (text, tooltip), prop.enumValueIndex, enumStr);
EditorGUI.showMixedValue = false;
if (check.changed)
prop.enumValueIndex = newVal;
}
}
private void popup (SerializedProperty prop, string [] enumStr, string text, string tooltip) {
using (var check = new EditorGUI.ChangeCheckScope ()) {
EditorGUI.showMixedValue = prop.hasMultipleDifferentValues;
var newVal = EditorGUILayout.Popup (new GUIContent (text, tooltip), prop.enumValueIndex, enumStr);
EditorGUI.showMixedValue = false;
if (check.changed)
prop.enumValueIndex = newVal;
}
}
private void bitMask (SerializedProperty prop, string [] options, string text, string tooltip) {
using (var check = new EditorGUI.ChangeCheckScope ()) {
EditorGUI.showMixedValue = prop.hasMultipleDifferentValues;
int newVal = EditorGUILayout.MaskField (new GUIContent (text, tooltip), prop.intValue, options);
EditorGUI.showMixedValue = false;
if (check.changed) {
uint uintVal = unchecked ((uint) newVal);
prop.longValue = uintVal;
}
}
}
private bool isExpand (SerializedProperty prop, bool isDefaultOpen, GUIContent label) {
prop.isExpanded = EditorGUILayout.Foldout (prop.isExpanded != isDefaultOpen, label) != isDefaultOpen;
return prop.isExpanded != isDefaultOpen;
}
private bool isExpandMarkOnly (SerializedProperty prop, bool isDefaultOpen, float adjustX = 0f, float adjustY = 0f) {
var rect = GUILayoutUtility.GetLastRect ();
prop.isExpanded = EditorGUI.Foldout (rect, prop.isExpanded != isDefaultOpen, " ") != isDefaultOpen;
return prop.isExpanded != isDefaultOpen;
}
private void drawLine () {
Rect r = GUILayoutUtility.GetRect (0, 0);
Color col = colorMulAlpha (EditorStyles.label.normal.textColor, 0.09f);
EditorGUI.DrawRect (new Rect (r.x + 14f, r.y, r.width - 14f, 1f), col);
}
// ----------------------------------------------------------- Scope
private class AdjustLabelSpaceWidthScope : GUI.Scope {
private readonly float _store;
internal AdjustLabelSpaceWidthScope (float adjust) {
_store = EditorGUIUtility.labelWidth;
EditorGUIUtility.labelWidth += adjust;
}
protected override void CloseScope () {
EditorGUIUtility.labelWidth = _store;
}
}
private class LabelAndIndentScope : GUI.Scope {
private float _spaceBtm;
internal LabelAndIndentScope (GUIContent label, float spaceTop = 0f, float spaceMid = 2f, float spaceBtm = 0f) {
_spaceBtm = spaceBtm;
EditorGUILayout.Space (spaceTop);
EditorGUILayout.LabelField (label);
EditorGUILayout.Space (spaceMid);
EditorGUI.indentLevel++;
}
protected override void CloseScope () {
EditorGUI.indentLevel--;
EditorGUILayout.Space (_spaceBtm);
}
}
private class IndentScope : GUI.Scope {
private float _spaceBtm;
private int _indent;
internal IndentScope (float spaceTop = 3f, float spaceBtm = 10f, int indent = 1) {
_spaceBtm = spaceBtm;
_indent = indent;
EditorGUILayout.Space (spaceTop);
EditorGUI.indentLevel += indent;
}
protected override void CloseScope () {
EditorGUI.indentLevel -= _indent;
EditorGUILayout.Space (_spaceBtm);
}
}
private class DisableScope : GUI.Scope {
private readonly bool _tmp;
internal DisableScope (bool isActive = false) {
_tmp = isActive;
if (!_tmp) EditorGUI.BeginDisabledGroup (true);
}
protected override void CloseScope () {
if (!_tmp) EditorGUI.EndDisabledGroup ();
}
}
private class ColorScope : GUI.Scope {
private readonly Color _tmp;
internal ColorScope (Color color) {
_tmp = GUI.color;
GUI.color = color;
}
protected override void CloseScope () {
GUI.color = _tmp;
}
}
// ----------------------------------------------------------- URPパッケージは在るけれど 設定が完了していない場合
private bool isDark => EditorGUIUtility.isProSkin;
private GUIStyle _textStyle, _linkUrlStyle, _warningStyle;
private void prepStyle () {
if (_textStyle == null) {
_textStyle = new GUIStyle (EditorStyles.label);
_textStyle.wordWrap = true;
_textStyle.fontSize = 14;
_linkUrlStyle = new GUIStyle (_textStyle);
_linkUrlStyle.wordWrap = false;
_linkUrlStyle.normal.textColor = isDark ? new Color (0f, 0.8f, 1f, 1f) : new Color (0f, 0.4f, 0.8f, 1f);
_linkUrlStyle.hover.textColor = _linkUrlStyle.normal.textColor + Color.white * (isDark ? 0.3f : 0.2f);
_linkUrlStyle.stretchWidth = false;
_warningStyle = new GUIStyle (_textStyle);
_warningStyle.normal.textColor = isDark ? Color.white : new Color (0.8f, 0.1f, 0f, 1f);
_warningStyle.normal.background = Texture2D.whiteTexture;
}
}
private void onInspectorGUI_NotSettingYet () {
prepStyle ();
storeIndentWidth ();
EditorGUILayout.Space (50);
labelWarning ($"UniversalRP setup is not completed.");
EditorGUILayout.Space (10);
GUILayout.Label ($"Please refer to the Unity manual page to setup, or create a new project with the URP 3D template.", _textStyle);
EditorGUILayout.Space (10);
var urlA = "https://docs.unity3d.com/Packages/com.unity.render-pipelines.universal@12.0/manual/InstallURPIntoAProject.html";
if (labelLink (new GUIContent ("Unity URP Setup Manual", urlA)))
Application.OpenURL (urlA);
EditorGUILayout.Space (5);
var urlB = Constant.URL_MANUAL;
if (labelLink (new GUIContent ("Asset Manual", urlB)))
Application.OpenURL (urlB);
EditorGUILayout.Space (50);
}
void labelWarning (string text, int fontSize = 18) {
prepStyle ();
_warningStyle.fontSize = fontSize;
Color tmp = GUI.backgroundColor;
GUI.backgroundColor = isDark ? new Color (1f, 0.3f, 0.6f, 0.4f) : new Color (1f, 0.3f, 0.6f, 0.5f);
GUILayout.Label (text, _warningStyle);
GUI.backgroundColor = tmp;
}
private bool labelLink (GUIContent label, int fontSize = 14, int indent = 0, params GUILayoutOption [] options) {
prepStyle ();
_linkUrlStyle.fontSize = fontSize;
var rect = GUILayoutUtility.GetRect (label, _linkUrlStyle, options);
rect.x += indent * _indentWidth;
Handles.BeginGUI ();
Handles.color = _linkUrlStyle.normal.textColor;
Handles.DrawLine (new Vector3 (rect.xMin, rect.yMax), new Vector3 (rect.xMax, rect.yMax));
Handles.color = Color.white;
Handles.EndGUI ();
EditorGUIUtility.AddCursorRect (rect, MouseCursor.Link);
return GUI.Button (rect, label, _linkUrlStyle);
}
// -----------------------------------------------------------
}
}
#endif // End of WCE_URP

View File

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

View File

@@ -0,0 +1,207 @@
// WaterCausticsModules
// Copyright (c) 2021 Masataka Hakozaki
#if UNITY_EDITOR && WCE_URP
using System.Collections.Generic;
using System.IO;
using System.Linq;
using UnityEditor;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
namespace MH.WaterCausticsModules {
[CustomEditor (typeof (WaterCausticsEffectFeature), true)]
public class WaterCausticsEffectFeatureEditor : Editor {
private GUIStyle _style;
private void init () {
_style = new GUIStyle (EditorStyles.label);
_style.wordWrap = true;
_style.fontSize -= 1;
}
public override void OnInspectorGUI () {
if (_style == null) init ();
EditorGUILayout.Space (10);
string str = "This Renderer Function is required to apply WaterCausticsEffect.";
GUILayout.Label (str, _style);
}
//--------------------------------------------------------------------------------------------------------------
// static internal bool AddToCurrentRendererData (bool useUndo) {
// if (GetCurrentRendererData (out var dt))
// return AddFeatureToRenderer (dt, useUndo);
// return false;
// }
// static internal bool GetCurrentRendererData (out ScriptableRendererData dt) {
// dt = null;
// try {
// var urpAsset = GraphicsSettings.currentRenderPipeline as UniversalRenderPipelineAsset;
// var propertyInfo = typeof (UniversalRenderPipelineAsset).GetProperty ("scriptableRendererData", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
// if (propertyInfo == null) return false;
// dt = propertyInfo.GetValue (urpAsset) as ScriptableRendererData;
// return dt != null;
// } catch { }
// return false;
// }
public class ModificationProcessor : UnityEditor.AssetModificationProcessor {
// WaterCausticsEffectFeatureスクリプトが削除されるとき、登録済みのRendererFeatureを削除
// ※フォルダ削除時、中身のパスは渡されないので注意
private static AssetDeleteResult OnWillDeleteAsset (string deletePath, RemoveAssetOptions options) {
bool isDirectory = File.GetAttributes (deletePath).HasFlag (FileAttributes.Directory);
string scriptPath = getScriptPath<WaterCausticsEffectFeature> ();
if ((isDirectory && scriptPath.StartsWith (deletePath)) || deletePath == scriptPath) {
// RendererFeatureを削除
DeleteAllFeatures ();
}
return AssetDeleteResult.DidNotDelete;
}
}
static private string getScriptPath<T> () where T : ScriptableObject {
T asset = ScriptableObject.CreateInstance<T> ();
MonoScript mono = MonoScript.FromScriptableObject (asset);
string path = AssetDatabase.GetAssetPath (mono);
if (Application.isPlaying) Destroy (asset);
else DestroyImmediate (asset);
return path;
}
#if WCE_DEVELOPMENT
[MenuItem ("WCM/RendererFeatureTest/DeleteAllFeatures")]
#endif
static internal void DeleteAllFeatures () {
if (GetAllRendererData (out var list))
foreach (var dt in list)
DeleteFeature (dt);
}
static internal void DeleteFeature (ScriptableRendererData dt) {
if (!dt) return;
try {
// ※ TODO URPのバージョンが上がるたび処理方法に変更がないか要確認
if (dt.rendererFeatures.Any (a => a is WaterCausticsEffectFeature)) {
if (!EditorUtility.IsPersistent (dt)) return;
var feature = dt.rendererFeatures.FirstOrDefault (a => a is WaterCausticsEffectFeature);
AssetDatabase.RemoveObjectFromAsset (feature);
dt.rendererFeatures.Remove (feature);
dt.SetDirty ();
EditorUtility.SetDirty (dt);
saveAssetSafe (dt);
}
} catch { }
}
static private void saveAssetSafe (Object o) {
// ※AssetDatabase.SaveAssetIfDirty は Unity 2021.1.17、2020.3.16で追加されたので分岐
#if !UNITY_2020_3_OR_NEWER || UNITY_2020_3_0 || UNITY_2020_3_1 || UNITY_2020_3_2 || UNITY_2020_3_3 || UNITY_2020_3_4 || UNITY_2020_3_5 || UNITY_2020_3_6 || UNITY_2020_3_7 || UNITY_2020_3_8 || UNITY_2020_3_9 || UNITY_2020_3_10 || UNITY_2020_3_11 || UNITY_2020_3_12 || UNITY_2020_3_13 || UNITY_2020_3_14 || UNITY_2020_3_15 || UNITY_2021_1
AssetDatabase.SaveAssets ();
#else
AssetDatabase.SaveAssetIfDirty (o);
#endif
}
static internal bool AddFeatureToRenderer (ScriptableRendererData dt, bool useUndo) {
if (!dt) return false;
try {
if (dt.rendererFeatures.Any (a => a is WaterCausticsEffectFeature)) {
// -- すでにある場合 アクティブ化
var feature = dt.rendererFeatures.FirstOrDefault (a => a is WaterCausticsEffectFeature) as WaterCausticsEffectFeature;
//if (!feature.isActive) {
//if (useUndo) Undo.RegisterCompleteObjectUndo (feature, "Feature Set Active");
//feature.SetActive (true);
//EditorUtility.SetDirty (feature);
//saveAssetSafe (dt);
//}
WaterCausticsEffectFeature.OnAddedByScript ();
return true;
} else {
// -- まだ無い場合
// ※ TODO URPのバージョンが上がるたび処理方法に変更がないか要確認 10.9, 12.1, 14.0 OK
if (!EditorUtility.IsPersistent (dt)) return false;
var validateMethod = dt.GetType ().GetMethod ("ValidateRendererFeatures", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
if (validateMethod == null) return false;
var feature = ScriptableRendererFeature.CreateInstance<WaterCausticsEffectFeature> ();
feature.name = typeof (WaterCausticsEffect).Name;
if (useUndo) {
Undo.RegisterCreatedObjectUndo (feature, "Add Renderer Feature");
Undo.RegisterCompleteObjectUndo (dt, "Add Renderer Feature");
}
AssetDatabase.AddObjectToAsset (feature, dt);
dt.rendererFeatures.Add (feature);
validateMethod.Invoke (dt, null);
dt.SetDirty ();
EditorUtility.SetDirty (dt);
saveAssetSafe (dt);
WaterCausticsEffectFeature.OnAddedByScript ();
return true;
}
} catch { }
return false;
}
static internal bool CheckAllHasActiveFeature (List<ScriptableRendererData> list) {
return list != null && !list.Any (a => checkHasActiveFeature (a) == false);
}
static internal bool checkHasActiveFeature (ScriptableRendererData dt) {
return dt != null && dt.rendererFeatures.Any (a => a is WaterCausticsEffectFeature && a.isActive);
}
static internal bool AddFeatureToAllRenderers (out List<ScriptableRendererData> list, bool useUndo) {
if (GetAllRendererData (out list))
return AddFeatureToAllRenderers (list, useUndo);
return false;
}
#if WCE_DEVELOPMENT
[MenuItem ("WCM/RendererFeatureTest/AddFeatureToAllRenderers")]
#endif
static internal bool AddFeatureToAllRenderers () {
return AddFeatureToAllRenderers (useUndo: true);
}
static internal bool AddFeatureToAllRenderers (bool useUndo) {
if (GetAllRendererData (out var list))
return AddFeatureToAllRenderers (list, useUndo);
return false;
}
static internal bool AddFeatureToAllRenderers (List<ScriptableRendererData> list, bool useUndo) {
if (list == null) return false;
bool result = true;
foreach (var dt in list)
result &= AddFeatureToRenderer (dt, useUndo);
return result;
}
static internal bool GetAllRendererData (out List<ScriptableRendererData> list) {
list = new List<ScriptableRendererData> ();
var guids = AssetDatabase.FindAssets ($"t:{typeof(ScriptableRendererData).ToString()}", new [] { "Assets" });
if (guids.Length == 0) return false;
foreach (var guid in guids) {
var dt = AssetDatabase.LoadAssetAtPath<ScriptableRendererData> (AssetDatabase.GUIDToAssetPath (guid));
list.Add (dt);
}
return list.Count != 0;
}
static internal void SelectAndPing (List<ScriptableRendererData> list) {
Selection.objects = list.ToArray ();
foreach (var dt in list) EditorGUIUtility.PingObject (dt);
}
static internal string AssetsToPathStr (List<ScriptableRendererData> list) {
var str = "";
for (int i = 0; i < list.Count; i++)
str += $"{i+1}: {AssetDatabase.GetAssetPath (list [i])}\n";
return str;
}
//------------------------------------------------------------------------
}
}
#endif

View File

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

View File

@@ -0,0 +1,48 @@
// WaterCausticsModules
// Copyright (c) 2021 Masataka Hakozaki
#if UNITY_EDITOR && WCE_URP
using UnityEditor;
using UnityEngine;
namespace MH.WaterCausticsModules {
public class WaterCausticsEffectMenuItem {
[MenuItem ("GameObject/WaterCausticsModules/TexGen and Effect (with RenderTexture Asset)", false, 0)]
static public void CreateTexGenAndEffectPair () {
var texGen = WaterCausticsTexGeneratorMenuItem.CreateTexGeneratorWithRT ();
var effect = createEffectGO ();
effect.texture = texGen.renderTexture;
}
[MenuItem ("GameObject/WaterCausticsModules/Effect", false, 3)]
static public void CreateEffectGO () {
GameObject selectedGO = Selection.activeGameObject;
var effect = createEffectGO ();
var texGen = selectedGO?.GetComponent<WaterCausticsTexGenerator> ();
if (texGen == null)
texGen = Object.FindObjectOfType<WaterCausticsTexGenerator> ();
if (texGen != null)
effect.texture = texGen.renderTexture;
}
static private WaterCausticsEffect createEffectGO () {
var go = new GameObject ("WaterCausticsEffect");
Undo.RegisterCreatedObjectUndo (go, "Create WaterCausticsEffect");
var tra = go.transform;
if (Selection.activeGameObject != null) {
var baseTra = Selection.activeGameObject.transform;
tra.parent = baseTra.parent;
tra.SetSiblingIndex (baseTra.GetSiblingIndex () + 1);
}
tra.localPosition = Vector3.zero;
tra.localRotation = Quaternion.identity;
tra.localScale = Vector3.one * 3f;
Selection.activeObject = go;
Selection.activeObject = null;
Selection.activeObject = go;
return go.AddComponent<WaterCausticsEffect> ();
}
}
}
#endif

View File

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

View File

@@ -0,0 +1,15 @@
fileFormatVersion: 2
guid: e975b56feadc05a4a9da076c953ae619
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences:
- m_imageMaskTexture: {fileID: 2800000, guid: f88b6df342d5c4f4a969fb6eb4799d3e, type: 3}
- m_texture: {instanceID: 0}
- m_shader: {fileID: 4800000, guid: 348afebc23c3c6e4c8f05f2ea8f758fc, type: 3}
- m_noTexture: {fileID: 2800000, guid: 27623e5a17b6fd44a9af57a733ee993a, type: 3}
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,49 @@
// WaterCausticsModules
// Copyright (c) 2021 Masataka Hakozaki
#if WCE_URP
using System;
using UnityEngine;
using UnityEngine.Rendering.Universal;
namespace MH.WaterCausticsModules {
/*------------------------------------------------------------------------
This RendererFeature is used to stably apply WaterCausticsEffect to cameras
created by other effects.
For example, a mirror or water reflection effect may use a temporary camera
that is not placed in the scene, and the effect cannot be applied stably.
In that case, register this RendererFeature to the RendererData Asset.
The effect will be applied stably to all cameras.
このRendererFeatureは、他のエフェクトで作成されたカメラへWaterCausticsEffect
を安定的に適用するために使用します。
鏡や水面の反射エフェクトなどではシーンに配置されない一時的なカメラを使用する
場合があり、安定してエフェクトを適用出来ません。その場合はこの RendererFeature
を RendererData Asset に登録して下さい。安定してエフェクトが適用されるように
なります。
-------------------------------------------------------------------------*/
#if UNITY_2021_2_OR_NEWER
[DisallowMultipleRendererFeature ("WaterCausticsEffect (Renderer Feature)")]
#elif WCE_URP_10_8
[DisallowMultipleRendererFeature]
#endif
[HelpURL (Constant.URL_MANUAL)]
public class WaterCausticsEffectFeature : ScriptableRendererFeature {
static private WaterCausticsEffectFeature s_ins;
static public event Action<Camera> onCamRender;
static public event Action<ScriptableRenderer, Camera> onEnqueue;
static private int s_lastFrame;
static internal bool effective => (s_ins != null && s_ins.isActive && s_lastFrame >= Time.renderedFrameCount - 1);
static internal void OnAddedByScript () => s_lastFrame = Time.renderedFrameCount;
public override void Create () { }
public override void AddRenderPasses (ScriptableRenderer renderer, ref RenderingData rendData) {
s_ins = this;
s_lastFrame = Time.renderedFrameCount;
var cam = rendData.cameraData.camera;
onCamRender?.Invoke (cam);
onEnqueue?.Invoke (renderer, cam);
}
}
}
#endif

View File

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

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 5408d0311478d0c4984c6debe06c8308
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,522 @@
// WaterCausticsModules
// Copyright (c) 2021 Masataka Hakozaki
Shader "Hidden/WaterCausticsModules/Effect" {
Properties {
// --- Scope
_WCE_ClipOutside ("Clip Outside Volume", Int) = 1
_WCE_UseImageMask ("Use Image Mask", Int) = 0
[NoScaleOffset]_WCE_ImageMaskTex ("Texture", 2D) = "white" { }
[Enum(UnityEngine.Rendering.CullMode)] _CullMode ("Cull Mode", Int) = 2
// --- Texture
[NoScaleOffset]_WCE_CausticsTex ("Caustics Texture", 2D) = "black" { }
_WCE_TexChannels ("Channel", Vector) = (0, 1, 2, 0)
_WCE_TexRotateSinCos ("Rotation Sin and Cos", Vector) = (0, 1, 0, 0)
_WCE_TilingSeed ("Tiling Seed", Int) = -1
_WCE_TilingRot ("Tiling Rot", Float) = 0.02
_WCE_TilingHard ("Tiling Hard", Float) = 0.85
// --- Dimension
_WCE_Density ("Density", Float) = 0.2
_WCE_SurfaceY ("Water Surface Y", Float) = 2
_WCE_SurfFadeCoef ("Surface Fade Coef", Float) = 2
_WCE_SurfFadeStart ("Surface Fade Start", Float) = 0
_WCE_DepthFadeStart ("Depth Fade Start", Float) = 0
_WCE_DepthFadeCoef ("Depth Fade Coef", Float) = 0.01
_WCE_DistanceFadeStart ("Distance Fade Start", Float) = 0
_WCE_DistanceFadeCoef ("Distance Fade Coef", Float) = 0.01
// --- Effect
_WCE_IntensityMainLit ("Main Light Intensity", Range(0, 50)) = 1
_WCE_IntensityAddLit ("Additional Lights Intensity", Range(0, 50)) = 1
[ToggleOff(_RECEIVE_SHADOWS_OFF)] _RECEIVE_SHADOWS_OFF ("Receive Shadow", Float) = 1
_WCE_ShadowIntensity ("Shadow Intensity", Range(0, 1)) = 1
_WCE_ColorShift ("ColorShift", Vector) = (0.004, -0.001, 0, 0)
_WCE_LitSaturation ("Light Saturation", Range(0, 2)) = 0.2
_WCE_MultiplyByTex ("Multiply Color", Range(0, 1)) = 1
// --- Normal Atten
_WCE_NormalAtten ("Normal Atten Intensity", Range(0, 1)) = 1
_WCE_NormalAttenRate ("Normal Atten Rate", Range(1, 8)) = 2
_WCE_TransparentBack ("Transparent Backside", Range(0, 1)) = 0
_WCE_BacksideShadow ("Backside Shadow", Range(0, 1)) = 0
// --- Depth Buffer
_ZWrite ("ZWrite", Int) = 0
[Enum(UnityEngine.Rendering.CompareFunction)] _ZTest ("ZTest", Int) = 4
_OffsetFactor ("Offset Factor", float) = 0
_OffsetUnits ("Offset Units", float) = 0
// --- Stencil Buffer
_StencilRef ("Ref [0-255]", Range(0, 255)) = 0
_StencilReadMask ("Read Mask [0-255]", Range(0, 255)) = 255
_StencilWriteMask ("Write Mask [0-255]", Range(0, 255)) = 255
[Enum(UnityEngine.Rendering.CompareFunction)] _StencilComp ("Comp", Int) = 8
[Enum(UnityEngine.Rendering.StencilOp)] _StencilPass ("Pass", Int) = 0
[Enum(UnityEngine.Rendering.StencilOp)] _StencilFail ("ZFail", Int) = 0
[Enum(UnityEngine.Rendering.StencilOp)] _StencilZFail ("ZFail", Int) = 0
// --- Blend
[Enum(UnityEngine.Rendering.BlendMode)] _BlendSrcFactor ("SrcFactor", Int) = 1
[Enum(UnityEngine.Rendering.BlendMode)] _BlendDstFactor ("DstFactor", Int) = 1
// ※ Properties は SRPBatcher に必須
}
SubShader {
LOD 0
Tags { "RenderPipeline" = "UniversalPipeline" "RenderType" = "Transparent" "Queue" = "Transparent" "DisableBatching" = "True" "IgnoreProjector" = "True" }
Pass {
Name "WCE_EffectPass"
Tags { "LightMode" = "WCE_EffectPass" }
Blend [_BlendSrcFactor] [_BlendDstFactor]
ZWrite [_ZWrite]
ZTest [_ZTest]
Offset [_OffsetFactor], [_OffsetUnits]
Cull [_CullMode]
Stencil {
Ref [_StencilRef]
ReadMask [_StencilReadMask]
WriteMask [_StencilWriteMask]
Comp [_StencilComp]
Pass [_StencilPass]
Fail [_StencilFail]
ZFail [_StencilZFail]
}
HLSLPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma exclude_renderers d3d11_9x
#pragma target 3.5
#define WCE_EFFECT_SHADER
#define REQUIRE_OPAQUE_TEXTURE
#pragma multi_compile_local _ _WCE_ONE_PASS_NORMAL _WCE_ONE_PASS_DEPTH
#pragma multi_compile_local_fragment _ WCE_DEBUG_NORMAL WCE_DEBUG_DEPTH WCE_DEBUG_FACING WCE_DEBUG_CAUSTICS WCE_DEBUG_AREA
#if defined(_WCE_ONE_PASS_NORMAL) || defined(_WCE_ONE_PASS_DEPTH)
#define REQUIRE_DEPTH_TEXTURE
#if defined(_WCE_ONE_PASS_NORMAL)
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DeclareNormalsTexture.hlsl"
#endif
#else
#define WCE_EACH_MESH
#endif
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Version.hlsl"
#if VERSION_GREATER_EQUAL(11, 0)
#pragma multi_compile_fragment _ _MAIN_LIGHT_SHADOWS _MAIN_LIGHT_SHADOWS_CASCADE _MAIN_LIGHT_SHADOWS_SCREEN
#else
#pragma multi_compile_fragment _ _MAIN_LIGHT_SHADOWS
#pragma multi_compile_fragment _ _MAIN_LIGHT_SHADOWS_CASCADE
#endif
#pragma multi_compile_fragment _ _SHADOWS_SOFT
#pragma multi_compile_fragment _ _ADDITIONAL_LIGHTS
// ---- ※ URP14のDeferredで影が現れない問題応急処置
// ※ TODO URP14のバージョンが上がったら修正されたか要確認
#if UNITY_VERSION >= 202220 // Unity2022.2.0 URP14.0 以上
#if !defined(_RECEIVE_SHADOWS_OFF)
#define _ADDITIONAL_LIGHT_SHADOWS
#endif
#else
#pragma multi_compile_fragment _ _ADDITIONAL_LIGHT_SHADOWS
#endif
// ----
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/ShaderGraphFunctions.hlsl"
// ---- 使用しない
// #pragma multi_compile_fragment _ LIGHTMAP_ON
// #pragma multi_compile_fragment _ LIGHTMAP_SHADOW_MIXING
// #pragma multi_compile_fragment _ SHADOWS_SHADOWMASK
// #pragma multi_compile_fragment _ _MIXED_LIGHTING_SUBTRACTIVE
// ----
#if UNITY_VERSION >= 202120 // Unity2021.2.0 URP12.0 以上
#pragma multi_compile_fragment _ _GBUFFER_NORMALS_OCT
#pragma multi_compile_fragment _ _LIGHT_LAYERS
#pragma multi_compile_fragment _ _LIGHT_COOKIES
#endif
#if UNITY_VERSION >= 202220 // Unity2022.2.0 URP14.0 以上
#pragma multi_compile_fragment _ _FORWARD_PLUS
#endif
#pragma multi_compile_fog
#if defined(FOG_LINEAR) || defined(FOG_EXP) || defined(FOG_EXP2)
#define _USE_FOG
#endif
#include "WaterCausticsEffectCommon.hlsl"
#pragma multi_compile_local_fragment _ _RECEIVE_SHADOWS_OFF
struct appdata {
float4 vertex : POSITION;
#if defined(WCE_EACH_MESH)
float3 normal : NORMAL;
#else
uint vID : SV_VertexID;
#endif
UNITY_VERTEX_INPUT_INSTANCE_ID
};
struct v2f {
float4 posClip : SV_POSITION;
float4 posScrn : TEXCOORD0;
#if defined(WCE_EACH_MESH)
float3 posWld : TEXCOORD1;
float3 posEffect : TEXCOORD2;
float3 normalWS : TEXCOORD3;
#if defined(_USE_FOG)
float viewDepth : TEXCOORD4;
#endif
#endif
UNITY_VERTEX_OUTPUT_STEREO
};
CBUFFER_START(UnityPerMaterial)
float _WCE_Density;
int3 _WCE_TexChannels;
float2 _WCE_TexRotateSinCos;
int _WCE_TilingSeed;
float _WCE_TilingRot;
float _WCE_TilingHard;
float _WCE_SurfaceY;
float _WCE_SurfFadeStart;
float _WCE_SurfFadeCoef;
float _WCE_DepthFadeStart;
float _WCE_DepthFadeCoef;
float _WCE_DistanceFadeStart;
float _WCE_DistanceFadeCoef;
half _WCE_IntensityMainLit;
half _WCE_IntensityAddLit;
float2 _WCE_ColorShift;
half _WCE_LitSaturation;
half _WCE_MultiplyByTex;
half _WCE_NormalAtten;
half _WCE_NormalAttenRate;
half _WCE_TransparentBack;
half _WCE_BacksideShadow;
half _WCE_ShadowIntensity;
int _WCE_ClipOutside;
int _WCE_UseImageMask;
CBUFFER_END
#if defined(WCE_EACH_MESH)
CBUFFER_START(FrequentlyUpdateVariables)
float4x4 _WCE_WorldToObjMatrix;
CBUFFER_END
#endif
// ------------------------------------------------------------------------ Fill Clipped Hole
bool WCE_intersectPlaneAndLine(float3 ptA, float3 ptB, float3 planeP, float3 planeN, bool isAllowEndOnPlane, out float3 PT) {
float dotPA = dot(ptA - planeP, planeN);
float dotPB = dot(ptB - planeP, planeN);
bool isCross = (sign(dotPA) != sign(dotPB));
bool isPtOnPlane = (dotPA == 0 || dotPB == 0);
[branch] if (isCross && (isAllowEndOnPlane || !isPtOnPlane)) {
float3 AB = ptB - ptA;
float dif = abs(dotPA) + abs(dotPB);
float rate = abs(dotPA) / dif;
PT = ptA + AB * rate;
return true;
} else {
PT = float3(0, 0, 0);
return false;
}
}
float3 WCE_camDirWS() {
return -UNITY_MATRIX_V[2].xyz;
}
float3 WCE_viewDirWS(float3 posWS) {
return (unity_OrthoParams.w == 0) ? normalize(posWS - _WorldSpaceCameraPos) : WCE_camDirWS();
}
float3 WCE_viewDirRawWS(float3 posWS) {
return (unity_OrthoParams.w == 0) ? posWS - _WorldSpaceCameraPos : WCE_camDirWS();
}
float4 WCE_fillClippedHole(uint vID) {
const float3 pts[8] = {
float3(-0.5, -0.5, -0.5), float3(0.5, -0.5, -0.5), float3(-0.5, 0.5, -0.5), float3(0.5, 0.5, -0.5),
float3(-0.5, -0.5, 0.5), float3(0.5, -0.5, 0.5), float3(-0.5, 0.5, 0.5), float3(0.5, 0.5, 0.5),
};
const uint2 idxs [12] = {
uint2(0, 4), uint2(1, 5), uint2(2, 6), uint2(3, 7), uint2(0, 2), uint2(1, 3), uint2(4, 6), uint2(5, 7), uint2(0, 1), uint2(4, 5), uint2(2, 3), uint2(6, 7),
};
// ObliqueMatrix対応のためClipSpaceの端点からNearClipPlaneを得る
float near = UNITY_NEAR_CLIP_VALUE; // ← D3D11/Metal/Vulkan/Switch:1, GLCore/GLES:-1
float3 p0 = ComputeWorldSpacePosition(float4(0, 0, near, 1), UNITY_MATRIX_I_VP);
float3 p1 = ComputeWorldSpacePosition(float4(1, 0, near, 1), UNITY_MATRIX_I_VP);
float3 p2 = ComputeWorldSpacePosition(float4(0, 1, near, 1), UNITY_MATRIX_I_VP);
float3 planeN_WS = cross(p1 - p0, p2 - p0);
planeN_WS *= sign(dot(planeN_WS, -WCE_camDirWS()));
float3 planeN = TransformWorldToObjectNormal(planeN_WS, true);
float3 planeP = TransformWorldToObject(p0);
float3 rightV = TransformWorldToObjectDir(p1 - p0, true);
uint cnt = 0u;
float3 center = float3(0, 0, 0);
float4 intersectPts[6];
[unroll(12)] for (uint i = 0u; i < 12u; i++) {
float3 ptA = pts [idxs [i].x];
float3 ptB = pts [idxs [i].y];
float3 PT;
bool isIntersect = WCE_intersectPlaneAndLine(ptA, ptB, planeP, planeN, (i < 4), PT);
[branch] if (isIntersect) {
intersectPts [cnt].xyz = PT;
center += PT;
cnt++;
}
}
center /= cnt;
float3 outputPt = center;
[branch] if (cnt >= 3u && vID <= cnt) {
[unroll(6)] for (uint k = 0u; k < cnt; k++) {
// 時計回りにwを設定 -2+2
float3 v = normalize(intersectPts [k].xyz - center);
intersectPts [k].w = - (dot(v, rightV) - 1.0) * sign(dot(cross(v, rightV), planeN));
}
// ソート
[unroll(5)] for (uint m = 0u; m < cnt - 1u; m++) {
[unroll(5)] for (uint o = m + 1u; o < cnt; o++) {
[branch] if (intersectPts[m].w < intersectPts[o].w) {
float4 swap = intersectPts[m];
intersectPts[m] = intersectPts[o];
intersectPts[o] = swap;
}
}
}
outputPt = intersectPts[vID % cnt].xyz;
}
float4 posClip = TransformObjectToHClip(outputPt);
posClip.z = UNITY_NEAR_CLIP_VALUE * posClip.w;
return posClip;
}
// ------------------------------------------------------------------------ Vertex Shader
v2f vert(appdata v) {
v2f o = (v2f)0;
UNITY_SETUP_INSTANCE_ID(v);
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
#if defined(WCE_EACH_MESH)
// [Each Mesh]
float4 posClip = TransformObjectToHClip(v.vertex.xyz);
float3 posWld = TransformObjectToWorld(v.vertex.xyz);
float4 posScrn = ComputeScreenPos(posClip);
o.posClip = posClip;
o.posWld = posWld;
o.posScrn = posScrn;
o.posEffect = mul(_WCE_WorldToObjMatrix, float4(posWld, 1)).xyz;
o.normalWS = TransformObjectToWorldNormal(v.normal, true);
#if defined(_USE_FOG)
o.viewDepth = -TransformWorldToView(posWld).z;
#endif
#else
// [At Once]
float4 posClip;
[branch]if (v.vID < 8u) {
posClip = TransformObjectToHClip(v.vertex.xyz);
} else {
posClip = WCE_fillClippedHole(v.vID - 8u);
}
float4 posScrn = ComputeScreenPos(posClip);
o.posClip = posClip;
o.posScrn = posScrn;
#endif
return o;
}
// ------------------------------------------------------------------------ Reconstruct World Pos and Normal
float WCE_fixReversedZ(float Depth) {
#if UNITY_REVERSED_Z
return 1 - Depth;
#else
return Depth;
#endif
}
float3 WCE_reconstructPosWS(float2 screenUV, float rawDepth) {
#if !UNITY_REVERSED_Z
rawDepth = lerp(UNITY_NEAR_CLIP_VALUE, 1, rawDepth);
#endif
return ComputeWorldSpacePosition(screenUV, rawDepth, UNITY_MATRIX_I_VP);
}
bool WCE_checkOutside(float3 posES) {
return (abs(posES.x) > 0.5 || abs(posES.y) > 0.5 || abs(posES.z) > 0.5);
}
#if !defined(WCE_EACH_MESH)
#define RECONSTRUCT_NORMAL_HQ 1
half3 WCE_reconstructNormalWS(float2 screenUV, float3 posWS, float rdC) {
#if (!RECONSTRUCT_NORMAL_HQ)
return normalize(cross(ddy(posWS), ddx(posWS)));
#else
float2 offsetU = float2(_ScreenParams.z - 1, 0);
float2 offsetV = float2(0, _ScreenParams.w - 1);
float2 uvN = screenUV + offsetV;
float2 uvS = screenUV - offsetV;
float2 uvE = screenUV + offsetU;
float2 uvW = screenUV - offsetU;
float rdN = SampleSceneDepth(uvN);
float rdS = SampleSceneDepth(uvS);
float rdE = SampleSceneDepth(uvE);
float rdW = SampleSceneDepth(uvW);
float3 vV = abs(rdN - rdC) < abs(rdS - rdC) ? WCE_reconstructPosWS(uvN, rdN) - posWS : posWS - WCE_reconstructPosWS(uvS, rdS);
float3 vU = abs(rdE - rdC) < abs(rdW - rdC) ? WCE_reconstructPosWS(uvE, rdE) - posWS : posWS - WCE_reconstructPosWS(uvW, rdW);
return normalize(cross(vV, vU));
#endif
}
#endif
half3 WCE_getNormal(v2f IN, float2 screenUV, float3 posWS, float rawDepth) {
#if defined(WCE_EACH_MESH)
float3 normal = IN.normalWS; // VFACEセマンティクスでの向きの取得はメッシュのデータに不具合があると正しくないことがあるので廃止
normal *= -sign(dot(normal, WCE_viewDirRawWS(posWS)));
return normal;
#elif defined(_WCE_ONE_PASS_NORMAL)
float3 normal = SampleSceneNormals(screenUV);
#if VERSION_LOWER(10, 9) || (VERSION_GREATER_EQUAL(11, 0) && VERSION_LOWER(12, 0))
// ViewSpaceで保存されているURPのバージョン対応
normal.z *= -1;
normal = mul((float3x3)UNITY_MATRIX_I_V, normal).xyz;
normal = normalize(normal);
#endif
// normal *= -sign(dot(normal, WCE_viewDirWS(posWS))+0.07 );
normal *= -sign(dot(normal, WCE_viewDirRawWS(posWS)));
return normal;
#else
return WCE_reconstructNormalWS(screenUV, posWS, rawDepth);
#endif
}
// ------------------------------------------------------------------------ Fog (Oblique Projection Supported)
#if defined(_USE_FOG)
float WCE_computeFogFactorZ0ToFar(float z) {
#if defined(FOG_LINEAR)
return saturate(z * unity_FogParams.z + unity_FogParams.w);
#elif defined(FOG_EXP) || defined(FOG_EXP2)
return unity_FogParams.x * z;
#else
return 0;
#endif
}
float WCE_calcFog(float viewDepth) {
float nearToFarZ = max(viewDepth - _ProjectionParams.y, 0);
return ComputeFogIntensity(WCE_computeFogFactorZ0ToFar(nearToFarZ));
}
#endif
// ------------------------------------------------------------------------
#if defined(WCE_EACH_MESH)
// [Each Mesh]
#define WCE_clipOutside (_WCE_ClipOutside == 1)
#else
// [At Once]
#define WCE_clipOutside true
#endif
// ------------------------------------------------------------------------ Fragment
#define CLR_COL half4(0, 0, 0, 0)
TEXTURE2D(_WCE_CausticsTex);
TEXTURE2D(_WCE_ImageMaskTex);
SAMPLER(sampler_WCE_CausticsTex);
SAMPLER(sampler_WCE_ImageMaskTex);
half4 frag(v2f IN) : SV_Target {
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(IN);
// ---------- WorldPos
float2 screenUV = IN.posScrn.xy / IN.posScrn.w;
#if defined(WCE_EACH_MESH)
// [Each Mesh]
float3 posWS = IN.posWld;
float3 posES = IN.posEffect;
float rawDepth = 0.5;
#else
// [At Once]
float rawDepth = SampleSceneDepth(screenUV);
float3 posWS = WCE_reconstructPosWS(screenUV, rawDepth);
float3 posES = TransformWorldToObject(posWS);
#endif
// ---------- Debug Info
#if defined(WCE_DEBUG_NORMAL) || defined(WCE_DEBUG_DEPTH) || defined(WCE_DEBUG_FACING) || defined(WCE_DEBUG_CAUSTICS) || defined(WCE_DEBUG_AREA)
if ((WCE_clipOutside && WCE_checkOutside(posES)) || rawDepth == UNITY_RAW_FAR_CLIP_VALUE) discard;
#endif
#if defined(WCE_DEBUG_NORMAL)
return half4(pow(saturate(WCE_getNormal(IN, screenUV, posWS, rawDepth) * 0.5 + 0.5), 4) * 0.9, 1);
#elif defined(WCE_DEBUG_DEPTH)
float debugDepth = -TransformWorldToView(posWS).z * _ProjectionParams.w;
return half4(pow(abs(debugDepth), 0.7).xxx, 1);
#elif defined(WCE_DEBUG_FACING)
float3 n = WCE_getNormal(IN, screenUV, posWS, rawDepth);
float b = dot(-n, WCE_viewDirWS(posWS));
return half4((saturate(pow(abs(b), 2) * 0.5)).xxx, 1);
#elif defined(WCE_DEBUG_CAUSTICS)
_WCE_MultiplyByTex = 0;
#elif defined(WCE_DEBUG_AREA)
_WCE_MultiplyByTex = 0;
#endif
// ---------- Clip Outside
[branch] if ((WCE_clipOutside && WCE_checkOutside(posES)) || rawDepth == UNITY_RAW_FAR_CLIP_VALUE) return CLR_COL;
// ---------- Atten Start
float atten = 1; // halfだとVRシングルパスで不安定?
const float ATTEN_TH = 0.001;
// ---------- Fog
#if defined(_USE_FOG)
#if defined(WCE_EACH_MESH)
float viewDepth = IN.viewDepth;
#else
float viewDepth = -TransformWorldToView(posWS).z;
#endif
atten *= WCE_calcFog(viewDepth);
#endif
// ---------- Distance Fade
float3 viewDir = posWS - _WorldSpaceCameraPos; // ←ifに入れるとVR SinglePassでエラー
[branch] if (atten > ATTEN_TH && _WCE_DistanceFadeCoef > 0.0001f) {
atten *= smoothstep(0, 1, 1 - (length(viewDir) - _WCE_DistanceFadeStart) * _WCE_DistanceFadeCoef);
}
// ---------- Image Mask
[branch] if (atten > ATTEN_TH && _WCE_UseImageMask != 0) {
atten *= _WCE_ImageMaskTex.Sample(sampler_WCE_ImageMaskTex, posES.xz + 0.5).r;
}
// ---------- Atten End
[branch] if (atten <= ATTEN_TH) return CLR_COL;
_WCE_IntensityMainLit *= atten;
_WCE_IntensityAddLit *= atten;
// ---------- Normal
half3 normalWS = WCE_getNormal(IN, screenUV, posWS, rawDepth);
// ---------- Caustics
half3 c = WCE_EffectCore(posWS, normalWS, screenUV, _WCE_CausticsTex, sampler_WCE_CausticsTex, _WCE_TexRotateSinCos, _WCE_TexChannels, _WCE_TilingSeed, _WCE_TilingRot, _WCE_TilingHard, _WCE_Density, _WCE_SurfaceY, _WCE_SurfFadeStart, _WCE_SurfFadeCoef, _WCE_DepthFadeStart, _WCE_DepthFadeCoef, _WCE_IntensityMainLit, _WCE_IntensityAddLit, _WCE_ShadowIntensity, _WCE_ColorShift, _WCE_LitSaturation, _WCE_NormalAtten, _WCE_NormalAttenRate, _WCE_TransparentBack, _WCE_BacksideShadow);
// ---------- Multiply Opaque Tex
[branch] if (_WCE_MultiplyByTex > 0) {
c *= 1 - (1 - SHADERGRAPH_SAMPLE_SCENE_COLOR(screenUV)) * _WCE_MultiplyByTex;
}
return half4(c, 1);
}
ENDHLSL
}
}
Fallback "Hidden/InternalErrorShader"
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 348afebc23c3c6e4c8f05f2ea8f758fc
ShaderImporter:
externalObjects: {}
defaultTextures: []
nonModifiableTextures: []
preprocessorOverride: 0
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,377 @@
// WaterCausticsModules
// Copyright (c) 2021 Masataka Hakozaki
#ifndef WCE_COMMON_INCLUDED
#define WCE_COMMON_INCLUDED
#if defined(_LIGHT_COOKIES)
#pragma warning(disable : 3595) // ループ内勾配命令warning
#endif
#if !defined(SHADERGRAPH_PREVIEW)
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
#include "hextiling.hlsl"
#endif
#define WCE_LIT_DIR_MIN_Y 0.1
#if defined(WCE_USE_SAMPLER2D_INSTEAD_TEXTURE2D)
#define WCE_TEX_ARGS(texName) sampler2D texName
#define WCE_TEX_SAMPLE_GRAD(st, texName, uv, dx, dy) tex2Dgrad(st.texName, uv, dx, dy)
#define WCE_TEX_STRUCT(texName) sampler2D texName
#define WCE_TEX_STORE(st, texName) st.texName = texName
#else
#define WCE_TEX_ARGS(texName) TEXTURE2D(texName), SAMPLER(texName##SS)
#define WCE_TEX_SAMPLE_GRAD(st, texName, uv, dx, dy) SAMPLE_TEXTURE2D_GRAD(st.texName, st.texName##SS, uv, dx, dy)
#define WCE_TEX_STRUCT(texName) TEXTURE2D(texName); SAMPLER(texName##SS)
#define WCE_TEX_STORE(st, texName) st.texName = texName; st.texName##SS = texName##SS
#endif
struct WCE_SamplingData {
WCE_TEX_STRUCT(CausticsTex);
float3 pos;
float3 posDDX;
float3 posDDY;
int3 channel;
float2 colShift;
float2x2 rotMatrix;
bool useTiling;
uint tilingSeed;
float tilingRot;
float tilingHard;
float2 dx;
float2 dy;
};
struct WCE_Lit {
half3 dir;
half3 dirDDX;
half3 dirDDY;
half3 color;
half atten;
half shadow;
};
struct WCE_CommonData {
float3 posW;
float3 posWdX;
float3 posWdY;
half3 normWS;
float2 scrnUV;
half shadow;
half saturation;
half normAtten;
half normRate;
half transparent;
half backShadow;
float depthSign;
half depthFade;
uint layer;
float3 posOnSurf;
};
// Mainライト事前チェック 水面通過時、光線が上向き(1)か下向き(-1)か / RenderingLayerMaskチェック
void WCE_mainLitPreCheck(WCE_CommonData dt, out float signLitY, out bool result) {
#if defined(SHADERGRAPH_PREVIEW)
signLitY = -1;
result = true;
#else
Light l = GetMainLight();
signLitY = sign(l.direction.y);
#ifdef _LIGHT_LAYERS
result = (dt.depthSign == signLitY) && IsMatchingLightLayer(l.layerMask, dt.layer);
#else
result = (dt.depthSign == signLitY);
#endif
#endif
}
// Addライト事前チェック 水面通過時、光線が上向き(1)か下向き(-1)か / RenderingLayerMaskチェック
void WCE_addLitPreCheck(uint idx, WCE_CommonData dt, out float signLitY, out bool result) {
#if defined(SHADERGRAPH_PREVIEW)
signLitY = -1;
result = false;
#else
Light l = GetAdditionalLight(idx, dt.posOnSurf);
signLitY = sign(l.direction.y);
#ifdef _LIGHT_LAYERS
result = (dt.depthSign == signLitY) && IsMatchingLightLayer(l.layerMask, dt.layer);
#else
result = (dt.depthSign == signLitY);
#endif
#endif
}
// Main Light Data
void WCE_getMainLitData(WCE_CommonData dt, out WCE_Lit lit) {
lit = (WCE_Lit)0;
#if defined(SHADERGRAPH_PREVIEW)
lit.dir = normalize(half3(0, 1, -0.4));
lit.color = half3(1, 1, 1);
lit.atten = lit.shadow = 1;
#else
#if (defined(_MAIN_LIGHT_SHADOWS) || defined(_MAIN_LIGHT_SHADOWS_CASCADE) || defined(_MAIN_LIGHT_SHADOWS_SCREEN)) && !defined(_RECEIVE_SHADOWS_OFF)
#if defined(_MAIN_LIGHT_SHADOWS_SCREEN) && !defined(_SURFACE_TYPE_TRANSPARENT)
float4 shadowCoord = float4(dt.scrnUV.xy, 0, 1);
#else
float4 shadowCoord = TransformWorldToShadowCoord(dt.posW);
#endif
Light l = GetMainLight(shadowCoord, dt.posW, half4(1, 1, 1, 1));
#else
Light l = GetMainLight();
#endif
lit.dir = lit.dirDDX = lit.dirDDY = l.direction;
lit.color = l.color;
lit.atten = l.distanceAttenuation;
lit.shadow = l.shadowAttenuation;
#endif
}
// Additional Light Data
void WCE_getAddLitData(uint idx, WCE_CommonData dt, out WCE_Lit lit) {
lit = (WCE_Lit)0;
#if defined(SHADERGRAPH_PREVIEW)
lit.dir = lit.color = lit.dirDDX = lit.dirDDY = half3(0, -1, 0);
lit.atten = lit.shadow = 0;
#else
#if defined(_ADDITIONAL_LIGHT_SHADOWS) && !defined(_RECEIVE_SHADOWS_OFF)
Light l = GetAdditionalLight(idx, dt.posW, half4(1, 1, 1, 1));
#else
Light l = GetAdditionalLight(idx, dt.posW);
#endif
lit.dir = l.direction;
lit.color = l.color;
lit.atten = l.distanceAttenuation;
lit.shadow = l.shadowAttenuation;
lit.dirDDX = GetAdditionalLight(idx, dt.posWdX).direction;
lit.dirDDY = GetAdditionalLight(idx, dt.posWdY).direction;
#endif
}
// 水面付近減衰
half WCE_SurfFade(float depthAbs, float SurfFadeStart, float SurfFadeCoef) {
return saturate((depthAbs - SurfFadeStart) * SurfFadeCoef);
}
// 深さによる減衰
half WCE_depthFade(float depthAbs, float DepthFadeStart, float DepthFadeCoef) {
return saturate(1 - (depthAbs - DepthFadeStart) * DepthFadeCoef);
}
// ライト角度での減衰
half WCE_litDirAtten(half3 litDir) {
return saturate((abs(litDir.y) - WCE_LIT_DIR_MIN_Y) / (0.4 - WCE_LIT_DIR_MIN_Y));
}
// 減衰をまとめる
half WCE_calcAtten(WCE_CommonData dt, WCE_Lit lit, half dotLN) {
half dot = saturate(dotLN) + saturate(-dotLN) * dt.transparent;
dot = pow(abs(dot), dt.normRate);
dot = 1 - (1 - dot) * dt.normAtten;
half litDirAtten = WCE_litDirAtten(lit.dir);
return lit.atten * lit.shadow * dot * litDirAtten * dt.depthFade;
}
// 彩度調整
half3 WCE_adjustSaturation(half3 litColor, WCE_CommonData dt) {
half gray = dot(litColor, half3(0.299, 0.587, 0.114));
return lerp(gray.xxx, litColor, dt.saturation.xxx);
}
half3 WCE_sampleColGrad(WCE_SamplingData smpDt, float2 uvG) {
float2 uvR = uvG - smpDt.colShift;
float2 uvB = uvG + smpDt.colShift;
half3 c;
c.r = WCE_TEX_SAMPLE_GRAD(smpDt, CausticsTex, uvR, smpDt.dx, smpDt.dy)[smpDt.channel[0]];
c.g = WCE_TEX_SAMPLE_GRAD(smpDt, CausticsTex, uvG, smpDt.dx, smpDt.dy)[smpDt.channel[1]];
c.b = WCE_TEX_SAMPLE_GRAD(smpDt, CausticsTex, uvB, smpDt.dx, smpDt.dy)[smpDt.channel[2]];
return c;
}
half3 WCE_sampleRandomTiling(WCE_SamplingData smpDt, float2 uvG) {
#if defined(SHADERGRAPH_PREVIEW)
return WCE_sampleColGrad(smpDt, uvG);
#else
float2 uv1, uv2, uv3;
float3 w;
HEX_TILING_GetUV(uvG, smpDt.tilingRot, smpDt.tilingSeed, uv1, uv2, uv3, w);
half3 c1 = WCE_sampleColGrad(smpDt, uv1);
half3 c2 = WCE_sampleColGrad(smpDt, uv2);
half3 c3 = WCE_sampleColGrad(smpDt, uv3);
return HEX_TILING_MixColor(smpDt.tilingHard, c1, c2, c3, w);
#endif
}
// テクスチャサンプリング
half3 WCE_sampleCausticsTex(WCE_SamplingData smpDt, WCE_Lit lit, float signLitY) {
// ※litDir.yの絶対値がWCE_LIT_DIR_MIN_Y以下の場合はattenが0なので0除算は無視
// smpDt.posは水面基準の位置(Density乗算済み) yは深さ
float2 uvG = (lit.dir.xz / lit.dir.y) * smpDt.pos.y + smpDt.pos.xz;
float2 uvDDX = (lit.dirDDX.xz / lit.dirDDX.y) * smpDt.posDDX.y + smpDt.posDDX.xz;
float2 uvDDY = (lit.dirDDY.xz / lit.dirDDY.y) * smpDt.posDDY.y + smpDt.posDDY.xz;
uvG = mul(smpDt.rotMatrix, uvG);
smpDt.dx = mul(smpDt.rotMatrix, uvDDX) - uvG;
smpDt.dy = mul(smpDt.rotMatrix, uvDDY) - uvG;
uvG += signLitY * 0.05; // ←鏡面すぎると不自然なのでずらす
half3 c;
[branch] if (smpDt.useTiling) {
c = WCE_sampleRandomTiling(smpDt, uvG);
} else {
c = WCE_sampleColGrad(smpDt, uvG);
}
return c;
}
half WCE_calcShadowIntensity(WCE_Lit lit, half dotLN, WCE_CommonData dt) {
#if defined(_RECEIVE_SHADOWS_OFF)
return lit.shadow;
#else
return 1 - (1 - lit.shadow) * lerp(dt.backShadow * (1 - step(dt.transparent, 0) * step(1, dt.normAtten)), dt.shadow, step(0, dotLN));
#endif
}
uint WCE_getMeshRendLayer() {
#if defined(SHADERGRAPH_PREVIEW) || !defined(_LIGHT_LAYERS)
return 255;
#else
return GetMeshRenderingLightLayer();
#endif
}
half3 WCE_commonLitProcess(WCE_CommonData dt, WCE_SamplingData smpDt, half Intensity, WCE_Lit lit, float signLitY, half3 debugCol) {
half dotLN = dot(lit.dir, dt.normWS);
lit.shadow = WCE_calcShadowIntensity(lit, dotLN, dt);
half3 color = half3(0, 0, 0);
[branch] if (lit.atten * lit.shadow > 0) {
half atten = WCE_calcAtten(dt, lit, dotLN);
[branch] if (atten > 0) {
#if defined(WCE_DEBUG_AREA)
color = debugCol;
#else
half3 texColor = WCE_sampleCausticsTex(smpDt, lit, signLitY);
lit.color = WCE_adjustSaturation(lit.color, dt);
color = texColor * lit.color * atten * Intensity;
#endif
}
}
return color;
}
half3 WCE_addLitProcess(uint i, WCE_CommonData dt, WCE_SamplingData smpDt, half Intensity) {
WCE_Lit lit;
float signLitY;
bool checkResult;
half3 debugCol = half3(0, 0.1, 0);
WCE_addLitPreCheck(i, dt, /*out*/ signLitY, checkResult);
half3 color = half3(0, 0, 0);
[branch] if (checkResult) {
WCE_getAddLitData(i, dt, /*out*/ lit);
color = WCE_commonLitProcess(dt, smpDt, Intensity, lit, signLitY, debugCol);
}
return color;
}
// Main
half3 WCE_EffectCore(float3 WorldPos, half3 NormalWS, float2 ScreenUV, WCE_TEX_ARGS(CausticsTex), float2 TexRotSinCos, int3 TexChannels, int TilingSeed, float TilingRot, float TilingHard, float Density, float SurfY, float SurfFadeStart, float SurfFadeCoef, float DepthFadeStart, float DepthFadeCoef, half MainLitIntensity, half AddLitIntensity, half ShadowIntensity, float2 ColorShift, half LitSaturation, half NormalAtten, half NormalAttenRate, half TransparentBack, half BacksideShadow) {
#if defined(SHADERGRAPH_PREVIEW)
SurfY = 10;
SurfFadeStart = DepthFadeStart = DepthFadeCoef = AddLitIntensity = 0;
SurfFadeCoef = 1;
#endif
#if defined(_WCE_DISABLED)
return half3(0, 0, 0);
#else
WCE_CommonData dt;
dt.posW = WorldPos;
dt.posWdX = WorldPos + ddx(WorldPos);
dt.posWdY = WorldPos + ddy(WorldPos);
dt.normWS = NormalWS;
dt.scrnUV = ScreenUV;
dt.shadow = ShadowIntensity;
dt.saturation = LitSaturation;
dt.normAtten = NormalAtten;
dt.normRate = max(NormalAttenRate, 1);
dt.transparent = TransparentBack;
dt.backShadow = BacksideShadow;
float depth = SurfY - WorldPos.y;
float depthAbs = abs(depth);
dt.depthSign = sign(depth);
dt.depthFade = WCE_SurfFade(depthAbs, SurfFadeStart, SurfFadeCoef) * WCE_depthFade(depthAbs, DepthFadeStart, DepthFadeCoef);
dt.layer = WCE_getMeshRendLayer();
dt.posOnSurf = float3(WorldPos.x, SurfY, WorldPos.z);
WCE_SamplingData smpDt;
smpDt.useTiling = (TilingSeed >= 0);
smpDt.tilingSeed = asuint(TilingSeed);
smpDt.tilingRot = TilingRot;
smpDt.tilingHard = TilingHard;
smpDt.rotMatrix = float2x2(TexRotSinCos.y, -TexRotSinCos.x, TexRotSinCos.x, TexRotSinCos.y);
smpDt.colShift = mul(smpDt.rotMatrix, ColorShift);
smpDt.channel = TexChannels;
smpDt.pos = float3(dt.posW.x, depth, dt.posW.z) * Density;
smpDt.posDDX = float3(dt.posWdX.x, depth, dt.posWdX.z) * Density;
smpDt.posDDY = float3(dt.posWdY.x, depth, dt.posWdY.z) * Density;
WCE_TEX_STORE(smpDt, CausticsTex);
half3 color = half3(0, 0, 0);
[branch] if (MainLitIntensity > 0) {
float signLitY;
bool checkResult;
WCE_mainLitPreCheck(dt, /*out*/ signLitY, checkResult);
[branch] if (checkResult) {
WCE_Lit lit;
half3 debugCol = half3(0.2, 0, 0);
WCE_getMainLitData(dt, /*out*/ lit);
color = WCE_commonLitProcess(dt, smpDt, MainLitIntensity, lit, signLitY, debugCol);
}
}
#if !defined(SHADERGRAPH_PREVIEW)
#if defined(_ADDITIONAL_LIGHTS) || (defined(SHADERPASS) && (SHADERPASS == SHADERPASS_GBUFFER)) // Deferredは素通り
[branch] if (AddLitIntensity > 0) {
#if defined(_FORWARD_PLUS)
// [Forward+]
uint dirLitCnt = URP_FP_DIRECTIONAL_LIGHTS_COUNT;
[loop] for (uint i = 0; i < min(dirLitCnt, MAX_VISIBLE_LIGHTS); i++) {
color += WCE_addLitProcess(i, dt, smpDt, AddLitIntensity);
}
uint idx;
ClusterIterator iterator = ClusterInit(ScreenUV, WorldPos, 0);
[loop] while (ClusterNext(iterator, /*out*/ idx)) {
color += WCE_addLitProcess(idx + dirLitCnt, dt, smpDt, AddLitIntensity);
}
#else
// [Forward] & [Deferred]
uint pixelLitCnt = GetAdditionalLightsCount();
[loop] for (uint i = 0u; i < pixelLitCnt; i++) {
color += WCE_addLitProcess(i, dt, smpDt, AddLitIntensity);
}
#endif
}
#endif
#endif
return color;
#endif
}
#if defined(_LIGHT_COOKIES)
#pragma warning(enable : 3595) // ループ内勾配命令warning
#endif
#endif

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 3401e4fcc8ae3fa44926828d678fb61d
ShaderImporter:
externalObjects: {}
defaultTextures: []
nonModifiableTextures: []
preprocessorOverride: 0
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,95 @@
//
// Description : HexTilingFunction based on mmikk's hextile-demo
// Original : mmikk
// License : Copyright (c) 2022 mmikk
// Distributed under the MIT License. See LICENSE file.
// https://github.com/mmikk/hextile-demo/blob/main/LICENSE
// Edited by : M.Hakozaki
//
#ifndef HEX_TILING_INCLUDED
#define HEX_TILING_INCLUDED
uint lowBias32(uint x) {
// Best Integer Hash by FabriceNeyret2
// https://www.shadertoy.com/view/WttXWX#
x ^= x >> 16;
x *= 0x7feb352dU;
x ^= x >> 15;
x *= 0x846ca68bU;
x ^= x >> 16;
return x;
}
float2 HEX_TILING_hash3_2(int2 v, uint hashSeed) {
uint2 u = uint2(asuint(v));
uint x0 = u.x + (u.y << 16) + hashSeed;
uint x1 = (u.x << 16) + u.y + (hashSeed << 16);
return float2(lowBias32(x0), lowBias32(x1)) / float(0xffffffffU);
}
float2 HEX_TILING_hash1_2(uint hashSeed) {
return float2(hashSeed, lowBias32(hashSeed)) / float(0xffffffffU);
}
float2x2 HEX_TILING_getRot(float2 hash, float rot) {
const float M_PI = 3.14159;
float rad = (frac((hash.x + hash.y) * 65536) - 0.5) * M_PI * rot;
float c = cos(rad);
float s = sin(rad);
return float2x2(c, -s, s, c);
}
void HEX_TILING_GetUV(float2 uv, float rot, uint seed, out float2 uv1, out float2 uv2, out float2 uv3, out float3 w) {
const float TILE_SIZE = 1.3;
const float HEX_RATE = sqrt(3) * 0.5; // 0.86602... 六角形の縦横比
const float2x2 gridToSkewedGrid = float2x2(1 / HEX_RATE, 0, -0.5 / HEX_RATE, 1);
uint hashSeed = lowBias32(seed);
uv += HEX_TILING_hash1_2(hashSeed);
float2 skewedCoord = mul(gridToSkewedGrid, uv * TILE_SIZE);
int2 baseIdx = floor(skewedCoord);
float3 temp = float3(frac(skewedCoord), 0);
temp.z = 1 - temp.x - temp.y;
float s = step(0, -temp.z);
float s2 = 2 * s - 1;
int2 idx1 = baseIdx + int2(s, s);
int2 idx2 = baseIdx + int2(s, 1 - s);
int2 idx3 = baseIdx + int2(1 - s, s);
float2 hash1 = HEX_TILING_hash3_2(idx1, hashSeed);
float2 hash2 = HEX_TILING_hash3_2(idx2, hashSeed);
float2 hash3 = HEX_TILING_hash3_2(idx3, hashSeed);
float2x2 rot1 = HEX_TILING_getRot(hash1, rot);
float2x2 rot2 = HEX_TILING_getRot(hash2, rot);
float2x2 rot3 = HEX_TILING_getRot(hash3, rot);
uv1 = mul(uv, rot1) + hash1;
uv2 = mul(uv, rot2) + hash2;
uv3 = mul(uv, rot3) + hash3;
w.x = -temp.z * s2;
w.y = s - temp.y * s2;
w.z = s - temp.x * s2;
return;
}
float3 HEX_TILING_gain3(float3 w, float hardness) {
float k = log(1 - hardness) / log(0.5);
float3 s = 2 * step(0.5, w);
float3 m = 2 * (1 - s);
w = 0.5 * s + 0.25 * m * pow(max(0.0, s + w * m), k);
return w.xyz / (w.x + w.y + w.z);
}
half3 HEX_TILING_MixColor(float hardness, half3 c1, half3 c2, half3 c3, float3 w) {
half3 Lw = half3(0.299, 0.587, 0.114);
half3 Dw = half3(dot(c1, Lw), dot(c2, Lw), dot(c3, Lw));
Dw = lerp(1, Dw, 0.1);
w = Dw * pow(w, 7); // 7
w /= (w.x + w.y + w.z);
w = HEX_TILING_gain3(w, hardness);
return w.x * c1 + w.y * c2 + w.z * c3;
}
#endif

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 0b3dda1ff7ed7ad49aa545454b7a9d6e
ShaderImporter:
externalObjects: {}
defaultTextures: []
nonModifiableTextures: []
preprocessorOverride: 0
userData:
assetBundleName:
assetBundleVariant: