2026-05-06 15:07:56 +02:00

122 lines
3.6 KiB
C#

using UnityEngine;
namespace UMA.Examples
{
[ExecuteInEditMode]
public class BRDFLookupTexture : MonoBehaviour
{
public float intensity = 1.0f;
public float diffuseIntensity = 1.0f;
public Color keyColor = ColorRGB (188, 158, 118);
public Color fillColor = ColorRGB (86, 91, 108);
public Color backColor = ColorRGB (44, 54, 57);
public float wrapAround = 0.0f;
public float metalic = 0.0f;
public float specularIntensity = 1.0f;
public float specularShininess = 0.078125f;
public float translucency = 0.0f; // skin
public Color translucentColor = ColorRGB (255, 82, 82);
public int lookupTextureWidth = 128;
public int lookupTextureHeight = 128;
public bool fastPreview = true;
public Texture2D lookupTexture;
void Awake () {
if (!lookupTexture)
Bake ();
}
static Color ColorRGB (int r, int g, int b) {
return new Color ((float)r / 255.0f, (float)g / 255.0f, (float)b / 255.0f, 0.0f);
}
void CheckConsistency () {
intensity = Mathf.Max (0.0f, intensity);
wrapAround = Mathf.Clamp (wrapAround, -1.0f, 1.0f);
metalic = Mathf.Clamp (metalic, 0.0f, 12.0f);
diffuseIntensity = Mathf.Max (0.0f, diffuseIntensity);
specularIntensity = Mathf.Max (0.0f, specularIntensity);
specularShininess = Mathf.Clamp (specularShininess, 0.01f, 1.0f);
translucency = Mathf.Clamp01 (translucency);
}
Color PixelFunc (float ndotl, float ndoth)
{
// pseudo metalic falloff
ndotl *= Mathf.Pow (ndoth, metalic);
float modDiffuseIntensity = (1f + metalic * 0.25f) * Mathf.Max (0f, diffuseIntensity - (1f-ndoth) * metalic);
// diffuse tri-light
float t0 = Mathf.Clamp01 (Mathf.InverseLerp (-wrapAround, 1f, ndotl * 2f - 1f));
float t1 = Mathf.Clamp01 (Mathf.InverseLerp (-1f, Mathf.Max(-0.99f,-wrapAround), ndotl * 2f - 1f));
Color diffuse = modDiffuseIntensity * Color.Lerp (backColor, Color.Lerp (fillColor, keyColor, t0), t1);
diffuse += backColor * (1f - modDiffuseIntensity) * Mathf.Clamp01 (diffuseIntensity);
// Blinn-Phong specular (with energy conservation)
float n = specularShininess * 128f;
float energyConservationTerm = ((n + 2f)*(n + 4f)) / (8f * Mathf.PI * (Mathf.Pow (2f, -n/2f) + n)); // by ryg
//float energyConservationTerm = (n + 8f) / (8f * Mathf.PI); // from Real-Time Rendering
float specular = specularIntensity * energyConservationTerm * Mathf.Pow (ndoth, n);
// pseudo translucency (view dependent)
float a = ndotl + 0.1f;
float t = 0.5f * translucency * Mathf.Clamp01 (1f-a*ndoth) * Mathf.Clamp01 (1f-ndotl);
Color c = diffuse * intensity + translucentColor * t + new Color(0f,0f,0f, specular);
return c * intensity;
}
void TextureFunc (Texture2D tex)
{
for (int y = 0; y < tex.height; ++y)
for (int x = 0; x < tex.width; ++x)
{
float w = tex.width;
float h = tex.height;
float vx = x / w;
float vy = y / h;
float NdotL = vx;
float NdotH = vy;
Color c = PixelFunc (NdotL, NdotH);
tex.SetPixel(x, y, c);
}
}
void GenerateLookupTexture (int width, int height) {
Texture2D tex;
if (lookupTexture && lookupTexture.width == width && lookupTexture.height == height)
tex = lookupTexture;
else
tex = new Texture2D(width, height, TextureFormat.ARGB32, false);
CheckConsistency ();
TextureFunc (tex);
tex.Apply();
tex.wrapMode = TextureWrapMode.Clamp;
if (lookupTexture != tex)
DestroyImmediate (lookupTexture);
lookupTexture = tex;
}
public void Preview () {
GenerateLookupTexture (32, 64);
}
public void Bake () {
GenerateLookupTexture (lookupTextureWidth, lookupTextureHeight);
}
}
}