Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
0c3b37a
debug: Add collider shader.
freezy Apr 25, 2026
6bba06e
Add more diffusion profiles.
freezy Apr 25, 2026
73ea757
Cleanup
freezy Apr 25, 2026
bd81656
Add runtime conversion code.
freezy Apr 25, 2026
53fed69
import: First migration toward a coherent GLB-based format.
freezy Apr 25, 2026
21f1428
packaging: Pack sidecar textures into single BLOB for faster loading.
freezy Apr 25, 2026
f8f0d0c
packaging: Add some diagnostics.
freezy Apr 25, 2026
f0c4e82
packaging: Optimize HDRP normal repack with GPU swizzle path
freezy Apr 25, 2026
33b7f2f
packaging: Disables MIPS for linear textures.
freezy Apr 25, 2026
a4265b6
packaging: Read various missing material and light props to the .vpe …
freezy May 10, 2026
64c6ecf
shadergraphs: Rename props to semantic names for Rubber and Metal sha…
freezy May 13, 2026
3a6c691
packaging: Update property ref names during export.
freezy May 13, 2026
9a9ddc7
packaging: Add screenshot generator.
freezy May 16, 2026
45cd8a6
packaging: More screenshot tweaks.
freezy May 16, 2026
f1496e1
packaging: Fix lighting when screenshotting.
freezy May 17, 2026
407b1b7
packaging: Clean up screenshot code.
freezy May 17, 2026
679e5bd
packaging: Cook textures into GPU-ready payloads during export.
freezy Jun 12, 2026
50654fc
packaging: Ship source textures, cook GPU payloads at runtime.
freezy Jun 12, 2026
5521144
material: Drop V1 suffix and split HDRP-specific lit hints.
freezy Jun 12, 2026
b14bc91
packaging: Downconvert 16-bit PNGs to 8-bit before packing.
freezy Jun 13, 2026
5be972b
packaging: Downconvert 16-bit PNGs via libvips off the main thread.
freezy Jun 13, 2026
64dcc98
packaging: Defer texture blob loading off the main thread.
freezy Jun 13, 2026
bf9db28
graphics: Apply VpeGraphicsSettings to HDRP at runtime.
freezy Jun 14, 2026
352395e
material: Add HDRP Fabric Silk profile and broaden lit hint coverage.
freezy Jun 15, 2026
bdc1463
material: Fall back to template shader when HDRP/Lit lookup is null
freezy Jun 15, 2026
ff0d5b0
packaging: Upgrade to Unity 6000.5 and HDRP 17.5.0.
freezy Jun 26, 2026
5125668
ci: Sign UPM package before publishing to registry.
freezy Jun 26, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 22 additions & 5 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,38 @@ jobs:
publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Publish
- uses: actions/checkout@v5
- name: Install Unity Package Manager CLI
run: |
curl -fsSL https://cdn.packages.unity.com/upm-cli/install.sh | bash
echo "$HOME/.upm/bin" >> "$GITHUB_PATH"
"$HOME/.upm/bin/upm" --version
- name: Pack and sign
run: |
test -n "${UNITY_ORGANIZATION_ID}"
mkdir -p "$RUNNER_TEMP/signed-package"
upm pack . \
--organization-id "${UNITY_ORGANIZATION_ID}" \
--destination "$RUNNER_TEMP/signed-package"
env:
UPM_SERVICE_ACCOUNT_KEY_ID: ${{ secrets.UPM_SERVICE_ACCOUNT_KEY_ID }}
UPM_SERVICE_ACCOUNT_KEY_SECRET: ${{ secrets.UPM_SERVICE_ACCOUNT_KEY_SECRET }}
UNITY_ORGANIZATION_ID: ${{ secrets.UNITY_ORGANIZATION_ID }}
- name: Publish signed package
run: |
echo "//registry.visualpinball.org/:_authToken=${NPM_TOKEN}" > ~/.npmrc
npm publish
package_tgz="$(find "$RUNNER_TEMP/signed-package" -maxdepth 1 -name '*.tgz' -print -quit)"
test -n "$package_tgz"
npm publish "$package_tgz" --registry=https://registry.visualpinball.org/
env:
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}

dispatch:
runs-on: ubuntu-latest
needs: [ publish ]
steps:
- uses: peter-evans/repository-dispatch@v1
- uses: peter-evans/repository-dispatch@v4
with:
token: ${{ secrets.GH_PAT }}
event-type: publish-complete
client-payload: '{"artifacts_run_id": "${{ github.run_id }}"}'

291 changes: 291 additions & 0 deletions Assets/Art/Graphs/ColliderShader.shader
Original file line number Diff line number Diff line change
@@ -0,0 +1,291 @@
Shader "Pinball/HDRP/ColliderShader"
{
Properties
{
[HDR]_Color ("Color", Color) = (0.1, 1.0, 0.25, 1.0)
_FaceOpacity ("Face Opacity", Range(0, 1)) = 0.15
_WireThickness ("Wire Thickness", Range(0.5, 8.0)) = 1.5
[Toggle] _DrawOnTop ("Draw On Top", Float) = 0
}

SubShader
{
Tags
{
"RenderPipeline" = "HDRenderPipeline"
"Queue" = "Transparent+100"
"RenderType" = "Transparent"
}

Pass
{
Name "ForwardOnly"
Tags { "LightMode" = "ForwardOnly" }

Blend SrcAlpha OneMinusSrcAlpha
ZWrite Off
ZTest Always
Cull Off

HLSLPROGRAM
#pragma target 4.5
#pragma only_renderers d3d11 playstation xboxone xboxseries vulkan switch switch2
#pragma vertex Vert
#pragma geometry Geom
#pragma fragment Frag
#pragma editor_sync_compilation

#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl"
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/ShaderLibrary/ShaderVariables.hlsl"

CBUFFER_START(UnityPerMaterial)
float4 _Color;
float _FaceOpacity;
float _WireThickness;
float _DrawOnTop;
CBUFFER_END

struct Attributes
{
float3 positionOS : POSITION;
};

struct VaryingsToGeom
{
float4 positionCS : SV_POSITION;
};

struct Varyings
{
float4 positionCS : SV_POSITION;
float3 barycentric : TEXCOORD0;
};

float2 SafeNormalize2(float2 v)
{
float len2 = dot(v, v);
if (len2 <= 1e-10)
{
return float2(1.0, 0.0);
}
return v * rsqrt(len2);
}

VaryingsToGeom Vert(Attributes input)
{
VaryingsToGeom output;
output.positionCS = TransformObjectToHClip(input.positionOS);
return output;
}

[maxvertexcount(3)]
void Geom(triangle VaryingsToGeom input[3], inout TriangleStream<Varyings> stream)
{
float4 p0 = input[0].positionCS;
float4 p1 = input[1].positionCS;
float4 p2 = input[2].positionCS;

float w0 = (abs(p0.w) > 1e-6) ? p0.w : 1e-6;
float w1 = (abs(p1.w) > 1e-6) ? p1.w : 1e-6;
float w2 = (abs(p2.w) > 1e-6) ? p2.w : 1e-6;

float2 n0 = p0.xy / w0;
float2 n1 = p1.xy / w1;
float2 n2 = p2.xy / w2;

float2 e0 = n1 - n0;
float2 e1 = n2 - n0;
float area2 = abs(e0.x * e1.y - e0.y * e1.x);
float minArea2 = 8.0 / max(_ScreenSize.x * _ScreenSize.y, 1.0);

if (area2 <= minArea2)
{
float pixelToNdc = 2.0 / max(_ScreenSize.x, _ScreenSize.y);
float inflate = pixelToNdc * max(_WireThickness, 1.0) * 1.5;

float d01 = dot(n1 - n0, n1 - n0);
float d12 = dot(n2 - n1, n2 - n1);
float d20 = dot(n0 - n2, n0 - n2);
float maxLen2 = max(d01, max(d12, d20));

float2 new0 = n0;
float2 new1 = n1;
float2 new2 = n2;

if (maxLen2 <= 1e-12)
{
float2 center = (n0 + n1 + n2) / 3.0;
new0 = center + float2( inflate, 0.0);
new1 = center + float2(-inflate, 0.0);
new2 = center + float2(0.0, inflate);
}
else if (d01 >= d12 && d01 >= d20)
{
float2 axis = SafeNormalize2(n1 - n0);
float2 perp = float2(-axis.y, axis.x);
float2 mid = (n0 + n1) * 0.5;
new2 = mid + perp * inflate;
}
else if (d12 >= d20)
{
float2 axis = SafeNormalize2(n2 - n1);
float2 perp = float2(-axis.y, axis.x);
float2 mid = (n1 + n2) * 0.5;
new0 = mid + perp * inflate;
}
else
{
float2 axis = SafeNormalize2(n0 - n2);
float2 perp = float2(-axis.y, axis.x);
float2 mid = (n2 + n0) * 0.5;
new1 = mid + perp * inflate;
}

n0 = new0;
n1 = new1;
n2 = new2;

p0.xy = n0 * w0;
p1.xy = n1 * w1;
p2.xy = n2 * w2;
}

Varyings output = (Varyings)0;

output.positionCS = p0;
output.barycentric = float3(1.0, 0.0, 0.0);
stream.Append(output);

output.positionCS = p1;
output.barycentric = float3(0.0, 1.0, 0.0);
stream.Append(output);

output.positionCS = p2;
output.barycentric = float3(0.0, 0.0, 1.0);
stream.Append(output);
}

bool IsOccluded(float fragDeviceDepth, float sceneDeviceDepth)
{
// Compare linearized eye depth so this works consistently for
// perspective + orthographic cameras and reversed-Z setups.
float fragEyeDepth = LinearEyeDepth(fragDeviceDepth, _ZBufferParams);
float sceneEyeDepth = LinearEyeDepth(sceneDeviceDepth, _ZBufferParams);
return fragEyeDepth > (sceneEyeDepth + 1e-4);
}

float4 Frag(Varyings input) : SV_Target
{
if (_DrawOnTop < 0.5)
{
uint2 pixelCoords = (uint2)(input.positionCS.xy * _RTHandleScale.xy);
pixelCoords = clamp(pixelCoords, uint2(0, 0), (uint2)_ScreenSize.xy - 1);

// Compare device-depth values from the same space.
float fragDeviceDepth = input.positionCS.z / max(input.positionCS.w, 1e-6);
float sceneDeviceDepth = LoadCameraDepth(pixelCoords);

if (IsOccluded(fragDeviceDepth, sceneDeviceDepth))
{
clip(-1);
}
}

float minBarycentric = min(input.barycentric.x, min(input.barycentric.y, input.barycentric.z));
float pixelWidth = max(fwidth(minBarycentric), 1e-5);
float wireMask = 1.0 - smoothstep(0.0, pixelWidth * _WireThickness, minBarycentric);

float faceAlpha = saturate(_Color.a * _FaceOpacity);
float wireAlpha = saturate(_Color.a);
float alpha = lerp(faceAlpha, wireAlpha, wireMask);

return float4(_Color.rgb, alpha);
}
ENDHLSL
}
}

// Fallback for platforms without geometry shaders.
SubShader
{
Tags
{
"RenderPipeline" = "HDRenderPipeline"
"Queue" = "Transparent+100"
"RenderType" = "Transparent"
}

Pass
{
Name "ForwardOnlyFallback"
Tags { "LightMode" = "ForwardOnly" }

Blend SrcAlpha OneMinusSrcAlpha
ZWrite Off
ZTest Always
Cull Off

HLSLPROGRAM
#pragma target 4.5
#pragma only_renderers d3d11 playstation xboxone xboxseries vulkan switch switch2
#pragma vertex VertFallback
#pragma fragment FragFallback
#pragma editor_sync_compilation

#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl"
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/ShaderLibrary/ShaderVariables.hlsl"

CBUFFER_START(UnityPerMaterial)
float4 _Color;
float _FaceOpacity;
float _DrawOnTop;
CBUFFER_END

struct Attributes
{
float3 positionOS : POSITION;
};

struct Varyings
{
float4 positionCS : SV_POSITION;
};

Varyings VertFallback(Attributes input)
{
Varyings output;
output.positionCS = TransformObjectToHClip(input.positionOS);
return output;
}

bool IsOccluded(float fragDeviceDepth, float sceneDeviceDepth)
{
// Compare linearized eye depth so this works consistently for
// perspective + orthographic cameras and reversed-Z setups.
float fragEyeDepth = LinearEyeDepth(fragDeviceDepth, _ZBufferParams);
float sceneEyeDepth = LinearEyeDepth(sceneDeviceDepth, _ZBufferParams);
return fragEyeDepth > (sceneEyeDepth + 1e-4);
}

float4 FragFallback(Varyings input) : SV_Target
{
if (_DrawOnTop < 0.5)
{
uint2 pixelCoords = (uint2)(input.positionCS.xy * _RTHandleScale.xy);
pixelCoords = clamp(pixelCoords, uint2(0, 0), (uint2)_ScreenSize.xy - 1);

float fragDeviceDepth = input.positionCS.z / max(input.positionCS.w, 1e-6);
float sceneDeviceDepth = LoadCameraDepth(pixelCoords);

if (IsOccluded(fragDeviceDepth, sceneDeviceDepth))
{
clip(-1);
}
}

return float4(_Color.rgb, saturate(_Color.a * _FaceOpacity));
}
ENDHLSL
}
}
}
9 changes: 9 additions & 0 deletions Assets/Art/Graphs/ColliderShader.shader.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,7 @@ Material:
- _DoubleSidedGIMode: 0
- _DoubleSidedNormalMode: 1
- _DstBlend: 0
- _DstBlend2: 0
- _EmissiveColorMode: 1
- _EmissiveExposureWeight: 1
- _EmissiveIntensity: 1
Expand Down Expand Up @@ -237,6 +238,7 @@ Material:
- _PPDMinSamples: 5
- _PPDPrimitiveLength: 1
- _PPDPrimitiveWidth: 1
- _PerPixelSorting: 0
- _RayTracing: 1
- _ReceivesSSR: 1
- _ReceivesSSRTransparent: 0
Expand Down Expand Up @@ -310,3 +312,4 @@ Material:
- _UVMappingMask: {r: 1, g: 0, b: 0, a: 0}
- _UVMappingMaskEmissive: {r: 1, g: 0, b: 0, a: 0}
m_BuildTextureStacks: []
m_AllowLocking: 1
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,7 @@ Material:
- _DoubleSidedGIMode: 0
- _DoubleSidedNormalMode: 1
- _DstBlend: 0
- _DstBlend2: 0
- _EmissiveColorMode: 1
- _EmissiveExposureWeight: 1
- _EmissiveIntensity: 1
Expand Down Expand Up @@ -237,6 +238,7 @@ Material:
- _PPDMinSamples: 5
- _PPDPrimitiveLength: 1
- _PPDPrimitiveWidth: 1
- _PerPixelSorting: 0
- _RayTracing: 1
- _ReceivesSSR: 1
- _ReceivesSSRTransparent: 0
Expand Down Expand Up @@ -302,3 +304,4 @@ Material:
- _UVMappingMask: {r: 1, g: 0, b: 0, a: 0}
- _UVMappingMaskEmissive: {r: 1, g: 0, b: 0, a: 0}
m_BuildTextureStacks: []
m_AllowLocking: 1
Loading