wip: Path to Omnissiah

This commit is contained in:
Alexandre Coirier
2026-05-18 23:11:16 +02:00
parent c4ad46990b
commit 0ca3cafe96
36 changed files with 4194 additions and 6130 deletions
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -1,18 +0,0 @@
fileFormatVersion: 2
guid: adf06fb1c82bec94d8daea4d30c135e9
ScriptedImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 2
userData:
assetBundleName:
assetBundleVariant:
script: {fileID: 11500000, guid: 625f186215c104763be7675aa2d941aa, type: 3}
useAsTemplate: 0
exposeTemplateAsShader: 0
template:
name:
category:
description:
icon: {instanceID: 0}
thumbnail: {instanceID: 0}
@@ -67,65 +67,19 @@ float StableStripes(float x, float depth, float width, float smooth)
return smoothstep(w + s, w - s, abs(uv.x - .5) * 2);
}
void EnkiBillal_float
(
float4 Color,
float2 ScreenUV,
float3 PositionWS,
float3 PositionOS,
float3 NormalWS,
float3 NormalOS,
float3 ObjectScale,
float TriplanarBlend,
float StripesDensity,
float StripesWidth,
float StripesSmooth,
int Step,
out float3 Output
)
float WorldStripes()
{
float3 scaledPositionOS = PositionOS * ObjectScale;
float depth = length(PositionWS - _WorldSpaceCameraPos.xyz);
//Light mainLight = GetMainLight(0);
float3 mainLightDir = normalize(float3(1, -1, 1)); //normalize(float3(0, 13, 8) - PositionWS); //float3(0, -1, 0);//normalize(mainLight.direction);
float lightGradient = dot(normalize(NormalWS), normalize(mainLightDir));
lightGradient = smoothstep(-.5, 1, lightGradient);
float ao = GetScreenSpaceAmbientOcclusion(ScreenUV).directAmbientOcclusion;
// Triplanar
//float3 triplanarMask = TriplanarMask(NormalWS, TriplanarBlend);
// Shadow
float shadowMask = lightGradient;//MainLightShadowAtten(PositionWS, NormalWS, .8);
float shadowAtten = Remap(0, 1, .6, 1, shadowMask);
// Grain
float grain = ValueNoise3DLOD(PositionWS, scaledPositionOS, 600, 3.5);
float grainMin = lerp(.4, .8, shadowMask);
float grainAtten = Remap(0, 1, grainMin, 1, grain);
// Dirt
float dirt = FBMNoise3D(scaledPositionOS, 1, 3, 2, .5);
float dirtMin = lerp(.2, .7, shadowMask);
float dirtAtten = Remap(0, 1, dirtMin, 1, dirt);
/*// Stripes
float StripesScale = StripesDensity;
/*float StripesScale = StripesDensity;
//float StripesWidth = .5;
//float StripesSmooth = .05;
// Octahedral face normals (4 faces + 3 world axes)
float3 octaFaceNormals[7] = {
normalize(float3(1, 1, 1)),
normalize(float3(-1, 1, 1)),
normalize(float3(1, -1, 1)),
normalize(float3(-1, -1, 1)),
float3 octaFaceNormals[7] =
{
normalize(float3(1, 1, 1)),
normalize(float3(-1, 1, 1)),
normalize(float3(1, -1, 1)),
normalize(float3(-1, -1, 1)),
float3(1, 0, 0),
float3(0, 1, 0),
float3(0, 0, 1)
@@ -135,16 +89,22 @@ void EnkiBillal_float
float sharpness = Remap(0, 1, 1, 16, smoothstep(0, .9, TriplanarBlend));
float octaMask[7];
float hardMax = -1;
int hardIdx = 0;
int hardIdx = 0;
for (int i = 0; i < 7; i++)
{
float d = abs(dot(NormalWS, octaFaceNormals[i]));
octaMask[i] = pow(saturate(d), sharpness);
if (d > hardMax) { hardMax = d; hardIdx = i; }
if (d > hardMax)
{
hardMax = d;
hardIdx = i;
}
}
float maskSum = 0;
for (int i = 0; i < 7; i++) maskSum += octaMask[i];
for (int i = 0; i < 7; i++) octaMask[i] /= max(maskSum, 0.0001);
for (int i = 0; i < 7; i++)
maskSum += octaMask[i];
for (int i = 0; i < 7; i++)
octaMask[i] /= max(maskSum, 0.0001);
float hardFactor = smoothstep(.9, 1, TriplanarBlend);
for (int i = 0; i < 7; i++)
{
@@ -154,8 +114,8 @@ void EnkiBillal_float
// Patern
float3 stripesPos = PositionWS;
float3 stripesPos0 = stripesPos;// + PerlinColor3D(PositionWS, .63) * .10;
float3 stripesPos1 = stripesPos;// + PerlinColor3D(PositionWS, 5.7) * .02;
float3 stripesPos0 = stripesPos; // + PerlinColor3D(PositionWS, .63) * .10;
float3 stripesPos1 = stripesPos; // + PerlinColor3D(PositionWS, 5.7) * .02;
float width = StripesWidth; // * .5;
float smooth = max(StripesSmooth, 1e-5);
@@ -190,6 +150,169 @@ void EnkiBillal_float
float stripes = max(stripes0, stripes1 * .5);
stripes *= smoothstep(.5, 0, lightGradient) * smoothstep(.97, .93, ao);*/
return 0;
}
float ProjectionMask(
float3 PositionWS,
float3 CamPositionWS,
float3 RectPositionWS,
float3 RectNormalWS,
float3 RectUpWS,
float2 RectSize,
float Oval)
{
// Build the rectangle local frame
float3 N = normalize(RectNormalWS);
float3 U = normalize(RectUpWS);
float3 R = normalize(cross(N, U)); // Right axis
U = normalize(cross(R, N)); // Recompute Up orthogonally in case RectUpWS is not perfectly perpendicular to RectNormalWS
// Ray from camera toward the fragment
float3 rayDir = normalize(PositionWS - CamPositionWS);
// Ray-plane intersection
// Plane equation: dot(P - RectPositionWS, N) = 0
float denom = dot(rayDir, N);
// Ray is parallel to the plane or facing away — no hit
if (abs(denom) < 1e-6)
return 0;
float t = dot(RectPositionWS - CamPositionWS, N) / denom;
// Intersection must be in front of the camera (t > 0)
// and not beyond the fragment (t <= distance from camera to fragment)
float tFrag = dot(PositionWS - CamPositionWS, rayDir);
if (t < 0.0 || t > tFrag + 1e-4)
return 0;
// Compute the hit point on the plane
float3 hitPoint = CamPositionWS + rayDir * t;
// Project hit point into the rectangle local space
float3 localVec = hitPoint - RectPositionWS;
float localU = dot(localVec, R); // horizontal axis
float localV = dot(localVec, U); // vertical axis
float halfW = RectSize.x * 0.5;
float halfH = RectSize.y * 0.5;
// Corner radius: 0 = rectangle, min(halfW, halfH) = oval
float radius = saturate(Oval) * min(halfW, halfH);
// Rounded rectangle SDF
float2 uv = float2(localU, localV);
float2 ext = float2(halfW, halfH);
float2 q = abs(uv) - ext + radius;
float sdf = length(max(q, 0.0)) - radius;
return sdf <= 0.0 ? 1.0 : 0.0;
}
float SampleProjectionMask(float3 PositionWS, float4x4 M)
{
if (M[0].w == 0)
return 0;
return ProjectionMask(
PositionWS,
M[0].xyz, // CamPositionWS
M[1].xyz, // RectPositionWS
M[3].xyz, // RectNormalWS
M[2].xyz, // RectUpWS
float2(M[2].w, M[3].w), // RectSize
M[1].w // Shape
);
}
void EnkiBillal_float
(
float4 Color,
float2 ScreenUV,
float3 PositionWS,
float3 PositionOS,
float3 NormalWS,
float3 NormalOS,
float3 ObjectScale,
float TriplanarBlend,
float StripesDensity,
float StripesWidth,
float StripesSmooth,
int Step,
float MaskID,
float4x4 Mask0,
float4x4 Mask1,
float4x4 Mask2,
out float3 Output,
out float Alpha
)
{
float3 scaledPositionOS = PositionOS * ObjectScale;
float depth = length(PositionWS - _WorldSpaceCameraPos.xyz);
//Light mainLight = GetMainLight(0);
float3 mainLightDir = normalize(float3(1, -1, 1)); //normalize(float3(0, 13, 8) - PositionWS); //float3(0, -1, 0);//normalize(mainLight.direction);
float lightGradient = dot(normalize(NormalWS), normalize(mainLightDir));
lightGradient = smoothstep(-.5, 1, lightGradient);
float ao = GetScreenSpaceAmbientOcclusion(ScreenUV).directAmbientOcclusion;
// Triplanar
//float3 triplanarMask = TriplanarMask(NormalWS, TriplanarBlend);
// Shadow
float shadowMask = lightGradient;//MainLightShadowAtten(PositionWS, NormalWS, .8);
float shadowAtten = Remap(0, 1, .6, 1, shadowMask);
// Grain
float grain = ValueNoise3DLOD(PositionWS, scaledPositionOS, 600, 3.5);
float grainMin = lerp(.4, .8, shadowMask);
float grainAtten = Remap(0, 1, grainMin, 1, grain);
// Dirt
float dirt = FBMNoise3D(scaledPositionOS, 1, 3, 2, .5);
float dirtMin = lerp(.2, .7, shadowMask);
float dirtAtten = Remap(0, 1, dirtMin, 1, dirt);
// Stripes
// float stripes = WorldStripes();
// Mask
if (Mask2[0].w == 1)
{
float mask = SampleProjectionMask(PositionWS, Mask2);
Alpha = (MaskID <= 1) ? 1 - mask : mask;
}
else if (MaskID == 0)
{
Alpha = 1;
}
else
{
float Active = Mask0[0].w + Mask1[0].w;// + Mask2[0].w;
if (Active > 0)
{
float mask = saturate(
SampleProjectionMask(PositionWS, Mask0) +
SampleProjectionMask(PositionWS, Mask1)// +
//SampleProjectionMask(PositionWS, Mask2)
);
Alpha = (MaskID == 1) ? 1 - mask : mask;
}
else
{
Alpha = (MaskID == 1) ? 0 : 1;
}
}
// Test