Organized folder structure;

Added new SSS Lut Baker;
Removed old SubsurfaceLookupTextureIntegrator;
This commit is contained in:
2025-03-16 15:13:06 +09:00
parent 4ce84572d0
commit b2136e1ff4
22 changed files with 352 additions and 130 deletions

View File

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

View File

@@ -0,0 +1,103 @@
#pragma kernel CSMain
#pragma multi_compile_local _ _PRODUCTION
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl"
float _ScatterRadius;
float _Intensity;
int _SampleCount;
int _ApplyTonemap;
uint _TextureSize;
RWTexture2D<float4> _SSSLut;
static const float VARIANCE[6] =
{
0.0064,
0.0484,
0.1870,
0.5670,
1.9900,
7.4100
};
static const float3 WEIGHTS[6] =
{
float3(0.233, 0.455, 0.649),
float3(0.100, 0.336, 0.344),
float3(0.118, 0.198, 0.000),
float3(0.113, 0.007, 0.007),
float3(0.358, 0.004, 0.000),
float3(0.078, 0.000, 0.000)
};
float Gaussian(float v, float r)
{
return rcp(2.0 * PI * v) * exp((-r * r) / (2.0 * v));
}
float3 RadianceScatter(float r)
{
float3 result = 0.0;
for (int i = 0; i < 6; i++)
{
result += WEIGHTS[i] * Gaussian(VARIANCE[i], r);
}
return result;
}
float3 IntegrateDiffuseScattering_Ring(float theta, float r)
{
float x = -HALF_PI;
float increment = PI / _SampleCount;
float3 totalScatter = 0;
float3 totalWeight = 0;
while (x < HALF_PI)
{
float diffuse = saturate(cos(theta + x));
float distance = abs(2.0 * r * sin(x / 2.0));
float3 radiance = RadianceScatter(distance);
totalScatter += radiance * diffuse;
totalWeight += radiance;
x += increment;
}
return totalScatter / totalWeight;
}
float3 FilmicTonemap(float3 color)
{
return (color * (6.2 * color + 0.5)) / (color * (6.2 * color + 1.7) + 0.06);
}
[numthreads(8,8,1)]
void CSMain (uint3 id : SV_DispatchThreadID)
{
if (id.x > _TextureSize || id.y > _TextureSize)
{
return;
}
float2 uv = id.xy / float2(_TextureSize, _TextureSize);
#if UNITY_UV_STARTS_AT_TOP && _PRODUCTION
uv.y = 1.0 - uv.y;
#endif
float theta = acos(uv.x * 2.0 - 1.0);
float r = rcp(max(uv.y, 0.001) * _ScatterRadius);
float3 scatter = IntegrateDiffuseScattering_Ring(theta, r) * _Intensity;
if (_ApplyTonemap == 1)
{
scatter = FilmicTonemap(scatter);
}
_SSSLut[id.xy] = float4(scatter, 1.0);
}

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 7bf3d5f03d1a012489a8f673afe8a6b3
ComputeShaderImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,170 @@
using System.IO;
using UnityEditor;
using UnityEngine;
using UnityEngine.Experimental.Rendering;
using UnityEngine.Rendering;
using UnityEngine.UIElements;
namespace Misaki.HdrpToon.Editor
{
internal class SSSLutBakerView : UnityEditor.EditorWindow
{
public enum Quality
{
[InspectorName("64")]
UltraLow = 64,
[InspectorName("128")]
VeryLow = 128,
[InspectorName("256")]
Low = 256,
[InspectorName("512")]
Medium = 512,
[InspectorName("1024")]
High = 1024,
[InspectorName("2048")]
VeryHigh = 2048,
[InspectorName("4096")]
UltraHigh = 4096,
}
private const int _PREVIEW_SIZE = 128;
[SerializeField]
private VisualTreeAsset _visualAsset;
[SerializeField]
private ComputeShader _bakerShader;
private RenderTexture _previewTexture;
private RenderTextureDescriptor _previewDescriptor;
public float scatterRadius = 1.0f;
public float intensity = 1.0f;
public Quality sampleCount = Quality.Low;
public bool applyTonemap = true;
public Quality outputResolution = Quality.Medium;
public int outputQuality = 100;
[MenuItem("Tools/UTS/SSS LUT Baker")]
private static void ShowWindow()
{
var window = GetWindow<SSSLutBakerView>(true, "SSS LUT Baker");
window.minSize = new Vector2(400, 650);
window.ShowUtility();
}
private void OnEnable()
{
_previewDescriptor = new RenderTextureDescriptor
{
width = _PREVIEW_SIZE,
height = _PREVIEW_SIZE,
volumeDepth = 1,
dimension = TextureDimension.Tex2D,
depthBufferBits = 0,
msaaSamples = 1,
graphicsFormat = GraphicsFormat.R8G8B8A8_UNorm,
enableRandomWrite = true,
sRGB = false,
useMipMap = false,
};
_previewTexture = RenderTexture.GetTemporary(_previewDescriptor);
}
private bool GenerateSSSLut(RenderTexture texture, int textureSize, bool production)
{
if (_bakerShader == null || !texture.enableRandomWrite)
{
return false;
}
_bakerShader.SetFloat("_ScatterRadius", scatterRadius);
_bakerShader.SetFloat("_Intensity", intensity);
_bakerShader.SetInt("_SampleCount", (int)sampleCount);
_bakerShader.SetInt("_ApplyTonemap", applyTonemap ? 1 : 0);
_bakerShader.SetInt("_TextureSize", textureSize);
_bakerShader.SetKeyword(new LocalKeyword(_bakerShader, "_PRODUCTION"), production);
_bakerShader.SetTexture(0, "_SSSLut", texture);
const int groupSizeX = 8;
const int groupSizeY = 8;
var threadGroupX = (textureSize + (groupSizeX - 1)) / groupSizeX;
var threadGroupY = (textureSize + (groupSizeY - 1)) / groupSizeY;
_bakerShader.Dispatch(0, threadGroupX, threadGroupY, 1);
return true;
}
private void BakePreview()
{
GenerateSSSLut(_previewTexture, _PREVIEW_SIZE, false);
}
private void Bake()
{
var outputPath = EditorUtility.SaveFilePanel("Export Texture", Application.dataPath, "SSS Lut", "jpg");
if (string.IsNullOrEmpty(outputPath))
{
return;
}
var outputDescriptor = _previewDescriptor;
outputDescriptor.width = (int)outputResolution;
outputDescriptor.height = (int)outputResolution;
var tempTexture = RenderTexture.GetTemporary(outputDescriptor);
var tempTexture2D = new Texture2D(outputDescriptor.width, outputDescriptor.height, TextureFormat.RGB24, false, true);
try
{
if (!GenerateSSSLut(tempTexture, (int)outputResolution, true))
{
return;
}
RenderTexture.active = tempTexture;
tempTexture2D.ReadPixels(new Rect(0, 0, outputDescriptor.width, outputDescriptor.height), 0, 0);
tempTexture2D.Apply();
RenderTexture.active = null;
File.WriteAllBytes(outputPath, tempTexture2D.EncodeToJPG(outputQuality));
AssetDatabase.Refresh();
}
finally
{
RenderTexture.ReleaseTemporary(tempTexture);
DestroyImmediate(tempTexture2D);
}
}
private void CreateGUI()
{
if (_visualAsset == null)
{
return;
}
var visualTree = _visualAsset.Instantiate();
visualTree.StretchToParentSize();
visualTree.dataSource = this;
var previewImage = visualTree.Q<Image>("preview-image");
previewImage.image = _previewTexture;
var previewButton = visualTree.Q<Button>("preview-button");
previewButton.clickable.clicked += BakePreview;
var bakeButton = visualTree.Q<Button>("bake-button");
bakeButton.clickable.clicked += Bake;
rootVisualElement.Add(visualTree);
}
private void OnDestroy()
{
RenderTexture.ReleaseTemporary(_previewTexture);
}
}
}

View File

@@ -1,11 +1,13 @@
fileFormatVersion: 2 fileFormatVersion: 2
guid: c2a5c3542255fad4b803f96cc141e84d guid: 46ee5c2bb652c6942a58aa97f3a8473b
MonoImporter: MonoImporter:
externalObjects: {} externalObjects: {}
serializedVersion: 2 serializedVersion: 2
defaultReferences: defaultReferences:
- m_ViewDataDictionary: {instanceID: 0} - m_ViewDataDictionary: {instanceID: 0}
- IntegratorShader: {fileID: 7200000, guid: 0aa27def3e695d34d9e06b6015d57142, type: 3} - _visualAsset: {fileID: 9197481963319205126, guid: 36e5f9eef212a0547b97e2643cd514de,
type: 3}
- _bakerShader: {fileID: 7200000, guid: 7bf3d5f03d1a012489a8f673afe8a6b3, type: 3}
executionOrder: 0 executionOrder: 0
icon: {instanceID: 0} icon: {instanceID: 0}
userData: userData:

View File

@@ -0,0 +1,44 @@
<engine:UXML xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:engine="UnityEngine.UIElements" xmlns:editor="UnityEditor.UIElements" noNamespaceSchemaLocation="../../../../UIElementsSchema/UIElements.xsd" editor-extension-mode="True">
<engine:VisualElement data-source-type="Misaki.HdrpToon.Editor.SSSLutBakerView, Misaki.HdrpToon.Editor" style="flex-grow: 1; padding-top: 8px; padding-right: 8px; padding-bottom: 8px; padding-left: 8px;">
<engine:Label text="SSS Lut Baker" style="font-size: 18px; padding-top: 0; padding-right: 0; padding-bottom: 0; padding-left: 0; margin-top: 12px; margin-bottom: 8px; margin-left: 4px; margin-right: 6px; -unity-font-style: bold;" />
<engine:Label text="Parameters:" style="-unity-font-style: bold; margin-top: 12px; margin-bottom: 4px; margin-right: 2px; margin-left: 2px;" />
<engine:FloatField label="Scatter Radius" value="1">
<Bindings>
<engine:DataBinding property="value" data-source-path="scatterRadius" binding-mode="TwoWay" />
</Bindings>
</engine:FloatField>
<engine:Slider label="Intensity" value="1" high-value="10" show-input-field="true" page-size="0.1">
<Bindings>
<engine:DataBinding property="value" data-source-path="intensity" binding-mode="TwoWay" />
</Bindings>
</engine:Slider>
<engine:EnumField label="Sample Count" value="Center" type="Misaki.HdrpToon.Editor.SSSLutBakerView+Quality, Misaki.HdrpToon.Editor">
<Bindings>
<engine:DataBinding property="value" binding-mode="TwoWay" data-source-path="sampleCount" />
</Bindings>
</engine:EnumField>
<engine:DropdownField label="Apply Tonemap" choices="Disable,Enable" index="0">
<Bindings>
<engine:DataBinding property="index" data-source-path="applyTonemap" binding-mode="TwoWay" />
</Bindings>
</engine:DropdownField>
<engine:EnumField label="Output Resolution" value="Center" type="Misaki.HdrpToon.Editor.SSSLutBakerView+Quality, Misaki.HdrpToon.Editor">
<Bindings>
<engine:DataBinding property="value" binding-mode="TwoWay" data-source-path="outputResolution" />
</Bindings>
</engine:EnumField>
<engine:SliderInt label="Output Quality" value="75" show-input-field="true" high-value="100" low-value="50">
<Bindings>
<engine:DataBinding property="value" data-source-path="outputQuality" binding-mode="TwoWay" />
</Bindings>
</engine:SliderInt>
<engine:Label text="Preview:" style="-unity-font-style: bold; margin-top: 12px; margin-bottom: 4px; margin-right: 2px; margin-left: 2px;" />
<engine:VisualElement style="flex-grow: 1; padding-top: 8px; padding-right: 8px; padding-bottom: 8px; padding-left: 8px; border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-left-color: rgb(0, 0, 0); border-right-color: rgb(0, 0, 0); border-top-color: rgb(0, 0, 0); border-bottom-color: rgb(0, 0, 0); margin-top: 4px; margin-right: 4px; margin-bottom: 4px; margin-left: 4px;">
<engine:Image name="preview-image" style="flex-grow: 1;" />
</engine:VisualElement>
<engine:VisualElement style="flex-direction: row; margin-top: 4px;">
<engine:Button text="Preview" name="preview-button" style="flex-grow: 1; flex-basis: 0;" />
<engine:Button text="Bake" name="bake-button" style="flex-basis: 0; flex-grow: 1; background-color: rgb(70, 96, 124);" />
</engine:VisualElement>
</engine:VisualElement>
</engine:UXML>

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 36e5f9eef212a0547b97e2643cd514de
ScriptedImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 2
userData:
assetBundleName:
assetBundleVariant:
script: {fileID: 13804, guid: 0000000000000000e000000000000000, type: 0}

View File

@@ -1,119 +0,0 @@
using UnityEditor;
using UnityEngine;
namespace EditorTools
{
public class SubsurfaceLookupTextureIntegratorWindow : EditorWindow
{
[MenuItem("Tools/Subsurface LUT Integrator", false, 1000)]
static void ShowIntegratorWindow()
{
GetWindow(typeof(SubsurfaceLookupTextureIntegratorWindow), false, "Subsurface LUT Integrator");
}
private Color FalloffColor = new Color(1.0f, 0.3f, 0.2f);
private float Radius = 4;
private bool KeepDirectBounce = false;
[SerializeField]
private ComputeShader IntegratorShader;
private RenderTexture IntegratedLUT = null;
private int resolution = 512;
private void OnEnable()
{
//IntegratorShader = AssetDatabase.LoadAssetAtPath<ComputeShader>("Assets/Scripts/Tools/Editor/SSS/SubsurfaceLookupTextureIntegrator.compute");
}
private void OnDestroy()
{
if (IntegratedLUT != null)
{
RenderTexture.ReleaseTemporary(IntegratedLUT);
}
}
void OnGUI()
{
GUILayout.Label("Base Settings", EditorStyles.boldLabel);
EditorGUI.BeginChangeCheck();
FalloffColor = EditorGUILayout.ColorField("Fallof Color", FalloffColor);
Radius = EditorGUILayout.Slider("Radius", Radius, 0, 20);
KeepDirectBounce = EditorGUILayout.Toggle("Keep Direct Bounce", KeepDirectBounce);
resolution = EditorGUILayout.IntField("Resolution", resolution);
if (EditorGUI.EndChangeCheck())
{
Bake();
}
EditorGUILayout.BeginHorizontal();
if (GUILayout.Button("Bake") && IntegratorShader != null)
{
Bake();
}
if (GUILayout.Button("Save") && IntegratedLUT != null)
{
IntegratorShader.SetFloat("_Resoultion", (float)resolution);
RenderTexture rt = RenderTexture.GetTemporary(resolution, resolution, 0, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Linear);
Graphics.Blit(IntegratedLUT, rt);
RenderTexture.active = rt;
Texture2D tex = new Texture2D(resolution, resolution, TextureFormat.ARGB32, false, true);
tex.ReadPixels(new Rect(0, 0, resolution, resolution), 0, 0);
RenderTexture.active = null;
RenderTexture.ReleaseTemporary(rt);
string path = EditorUtility.SaveFilePanel("Export Texture", Application.dataPath, "SSS_Lut", "png");
if (path == null) return;
System.IO.File.WriteAllBytes(path, tex.EncodeToPNG());
AssetDatabase.Refresh();
IntegratorShader.SetFloat("_Resoultion", (float)resolution);
}
EditorGUILayout.EndHorizontal();
EditorGUILayout.Space();
float width = position.width - 100;
float height = position.height - 189;
float sacle = width > height ? height / resolution : width / resolution;
Rect rect = new Rect(50, 150, resolution * sacle, resolution * sacle);
if (IntegratedLUT != null)
{
EditorGUI.DrawPreviewTexture(rect, IntegratedLUT);
}
else
{
EditorGUI.DrawRect(rect, Color.black);
}
}
private void Bake()
{
if (IntegratedLUT != null)
{
RenderTexture.ReleaseTemporary(IntegratedLUT);
}
IntegratedLUT = RenderTexture.GetTemporary(resolution, resolution, 0, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Linear);
IntegratedLUT.enableRandomWrite = true;
if (KeepDirectBounce)
{
IntegratorShader.EnableKeyword("KEEP_DIRECT_BOUNCE");
}
else
{
IntegratorShader.DisableKeyword("KEEP_DIRECT_BOUNCE");
}
IntegratorShader.SetTexture(0, "_IntegratedLUT", IntegratedLUT);
IntegratorShader.SetVector("_FalloffColor", FalloffColor);
IntegratorShader.SetFloat("_Radius", Radius);
IntegratorShader.SetFloat("_Resoultion", (float)resolution);
IntegratorShader.Dispatch(0, resolution / 8, resolution / 8, 1);
}
}
}

View File

@@ -931,11 +931,11 @@ Shader "HDRP/Toon"
// Setup DECALS_OFF so the shader stripper can remove variants // Setup DECALS_OFF so the shader stripper can remove variants
#pragma multi_compile DECALS_OFF DECALS_3RT DECALS_4RT #pragma multi_compile DECALS_OFF DECALS_3RT DECALS_4RT
// Supported shadow modes per light type #define PUNCTUAL_SHADOW_MEDIUM
#pragma multi_compile SHADOW_LOW SHADOW_MEDIUM SHADOW_HIGH #define DIRECTIONAL_SHADOW_MEDIUM
#define AREA_SHADOW_MEDIUM
#define USE_CLUSTERED_LIGHTLIST // There is not FPTL lighting when using transparent #define USE_CLUSTERED_LIGHTLIST // There is not FPTL lighting when using transparent
#define AREA_SHADOW_LOW
#define SHADERPASS SHADERPASS_FORWARD #define SHADERPASS SHADERPASS_FORWARD
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/Material/Material.hlsl" #include "Packages/com.unity.render-pipelines.high-definition/Runtime/Material/Material.hlsl"
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/Lighting.hlsl" #include "Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/Lighting.hlsl"

View File

@@ -172,9 +172,9 @@ namespace Misaki.HdrpToon
var format = _hairBlendingQuality switch var format = _hairBlendingQuality switch
{ {
BufferQuality.Low => GraphicsFormat.R8G8B8A8_SNorm, BufferQuality.Low => GraphicsFormat.A2B10G10R10_UNormPack32,
BufferQuality.High => GraphicsFormat.R8G8B8A8_SRGB, BufferQuality.High => GraphicsFormat.R16G16B16A16_UNorm,
_ => GraphicsFormat.R8G8B8A8_SRGB _ => GraphicsFormat.A2B10G10R10_UNormPack32
}; };
_hairBlendingRTHandle?.Release(); _hairBlendingRTHandle?.Release();
@@ -187,9 +187,6 @@ namespace Misaki.HdrpToon
protected override void Setup(ScriptableRenderContext renderContext, CommandBuffer cmd) protected override void Setup(ScriptableRenderContext renderContext, CommandBuffer cmd)
{ {
_exposureArray = new float[_ADJUSTMENT_CURVE_PRECISION]; _exposureArray = new float[_ADJUSTMENT_CURVE_PRECISION];
ReallocateHairShadowBuffer();
ReallocateHairBlendingBuffer();
} }
private void UpdateSceneEV(UTSRenderer utsRenderer) private void UpdateSceneEV(UTSRenderer utsRenderer)