Organized folder structure;
Added new SSS Lut Baker; Removed old SubsurfaceLookupTextureIntegrator;
This commit is contained in:
103
Editor/SSS/SSSLutBaker.compute
Normal file
103
Editor/SSS/SSSLutBaker.compute
Normal 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);
|
||||
}
|
||||
7
Editor/SSS/SSSLutBaker.compute.meta
Normal file
7
Editor/SSS/SSSLutBaker.compute.meta
Normal file
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7bf3d5f03d1a012489a8f673afe8a6b3
|
||||
ComputeShaderImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
170
Editor/SSS/SSSLutBakerView.cs
Normal file
170
Editor/SSS/SSSLutBakerView.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,13 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c2a5c3542255fad4b803f96cc141e84d
|
||||
guid: 46ee5c2bb652c6942a58aa97f3a8473b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences:
|
||||
- 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
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
44
Editor/SSS/SSSLutBakerView.uxml
Normal file
44
Editor/SSS/SSSLutBakerView.uxml
Normal 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>
|
||||
10
Editor/SSS/SSSLutBakerView.uxml.meta
Normal file
10
Editor/SSS/SSSLutBakerView.uxml.meta
Normal file
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 36e5f9eef212a0547b97e2643cd514de
|
||||
ScriptedImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
script: {fileID: 13804, guid: 0000000000000000e000000000000000, type: 0}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user