Add 3D pixel-art render style (pixelation + depth/normal outlines)
Full-screen URP post effect on the active PC renderer that pixelates the scene to a fixed low-res grid and draws depth + normal edge-detection outlines, with color posterization and tone controls, for a stylized "3D pixel art" look. Runs via Unity's built-in Full Screen Pass feature (no custom C#); reads camera depth/normals so it applies to DOTS entities and GameObjects identically. - PixelOutline.shader/.mat: pixel-snap fill + gamma-space posterize + brightness/contrast/saturation + depth/normal outlines. Normal threshold tuned high so outlines don't flood small characters. - PC_Renderer.asset: FullScreenPassRendererFeature (Depth|Normal, after post-processing). - PostFX_Daylight.asset: tonemapping ACES -> Neutral (poppier color). - Game.unity: brighter base atmosphere (ambient + fog pushed back) and a stronger directional key light so the fill reads under the effect. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,45 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!21 &2100000
|
||||
Material:
|
||||
serializedVersion: 8
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: PixelOutline
|
||||
m_Shader: {fileID: 4800000, guid: ab66a5a8f176cac469b6ade5a4286ef0, type: 3}
|
||||
m_Parent: {fileID: 0}
|
||||
m_ModifiedSerializedProperties: 0
|
||||
m_ValidKeywords: []
|
||||
m_InvalidKeywords: []
|
||||
m_LightmapFlags: 4
|
||||
m_EnableInstancingVariants: 0
|
||||
m_DoubleSidedGI: 0
|
||||
m_CustomRenderQueue: -1
|
||||
stringTagMap: {}
|
||||
disabledShaderPasses: []
|
||||
m_LockedProperties:
|
||||
m_SavedProperties:
|
||||
serializedVersion: 3
|
||||
m_TexEnvs: []
|
||||
m_Ints: []
|
||||
m_Floats:
|
||||
- _Brightness: 1.1
|
||||
- _ColorLevels: 12
|
||||
- _Contrast: 1.05
|
||||
- _DepthEdgesEnabled: 1
|
||||
- _DepthThreshold: 0.08
|
||||
- _EdgeStrength: 1
|
||||
- _NormalEdgesEnabled: 1
|
||||
- _NormalThreshold: 1
|
||||
- _OutlineThickness: 1
|
||||
- _PixelHeight: 200
|
||||
- _PixelateEnabled: 1
|
||||
- _PosterizeEnabled: 1
|
||||
- _Saturation: 1.35
|
||||
m_Colors:
|
||||
- _OutlineColorInner: {r: 0, g: 0, b: 0, a: 1}
|
||||
- _OutlineColorOuter: {r: 0, g: 0, b: 0, a: 1}
|
||||
m_BuildTextureStacks: []
|
||||
m_AllowLocking: 1
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 13d75b55291d02c4db05da1243629fa6
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 2100000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,130 @@
|
||||
Shader "Hidden/ProjectM/PixelOutline"
|
||||
{
|
||||
Properties
|
||||
{
|
||||
_PixelHeight ("Pixel Grid Height", Float) = 200
|
||||
[ToggleUI] _PosterizeEnabled ("Posterize (banded color)", Float) = 1
|
||||
_ColorLevels ("Posterize Levels / channel", Range(2,64)) = 12
|
||||
_Brightness ("Brightness", Range(0.5,2)) = 1.1
|
||||
_Contrast ("Contrast", Range(0.5,2)) = 1.05
|
||||
_Saturation ("Saturation", Range(0,2)) = 1.35
|
||||
_DepthThreshold ("Depth Threshold (relative)", Range(0,1)) = 0.08
|
||||
_NormalThreshold ("Normal Threshold", Range(0,4)) = 1.0
|
||||
_OutlineThickness ("Outline Thickness (texels)", Range(0.25,4)) = 1
|
||||
_EdgeStrength ("Edge Strength", Range(0,1)) = 1
|
||||
[HDR] _OutlineColorOuter ("Outline Color - Depth/Silhouette", Color) = (0,0,0,1)
|
||||
[HDR] _OutlineColorInner ("Outline Color - Normal/Detail", Color) = (0,0,0,1)
|
||||
[ToggleUI] _PixelateEnabled ("Pixelate", Float) = 1
|
||||
[ToggleUI] _DepthEdgesEnabled ("Depth Edges", Float) = 1
|
||||
[ToggleUI] _NormalEdgesEnabled ("Normal Edges", Float) = 1
|
||||
}
|
||||
|
||||
SubShader
|
||||
{
|
||||
Tags { "RenderType" = "Opaque" "RenderPipeline" = "UniversalPipeline" }
|
||||
ZWrite Off ZTest Always Cull Off
|
||||
|
||||
Pass
|
||||
{
|
||||
Name "PixelOutline"
|
||||
|
||||
HLSLPROGRAM
|
||||
#pragma vertex Vert
|
||||
#pragma fragment Frag
|
||||
#pragma target 3.5
|
||||
|
||||
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
|
||||
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DeclareDepthTexture.hlsl"
|
||||
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DeclareNormalsTexture.hlsl"
|
||||
#include "Packages/com.unity.render-pipelines.core/Runtime/Utilities/Blit.hlsl"
|
||||
|
||||
CBUFFER_START(UnityPerMaterial)
|
||||
float _PixelHeight;
|
||||
float _PosterizeEnabled;
|
||||
float _ColorLevels;
|
||||
float _Brightness;
|
||||
float _Contrast;
|
||||
float _Saturation;
|
||||
float _DepthThreshold;
|
||||
float _NormalThreshold;
|
||||
float _OutlineThickness;
|
||||
float _EdgeStrength;
|
||||
float4 _OutlineColorOuter;
|
||||
float4 _OutlineColorInner;
|
||||
float _PixelateEnabled;
|
||||
float _DepthEdgesEnabled;
|
||||
float _NormalEdgesEnabled;
|
||||
CBUFFER_END
|
||||
|
||||
float2 SnapUV(float2 uv, float2 res)
|
||||
{
|
||||
return (floor(uv * res) + 0.5) / res;
|
||||
}
|
||||
|
||||
half4 Frag(Varyings input) : SV_Target
|
||||
{
|
||||
float2 uv = input.texcoord;
|
||||
|
||||
// Fixed, square-pixel low-res grid derived from a target grid height.
|
||||
float aspect = _ScreenParams.x / max(_ScreenParams.y, 1.0);
|
||||
float2 res = float2(max(_PixelHeight * aspect, 1.0), max(_PixelHeight, 1.0));
|
||||
|
||||
bool doPixelate = _PixelateEnabled > 0.5;
|
||||
float2 sampleUV = doPixelate ? SnapUV(uv, res) : uv;
|
||||
float2 texel = 1.0 / res;
|
||||
float2 off = texel * _OutlineThickness;
|
||||
|
||||
// Chunky fill: point-sampled scene color at the snapped grid cell.
|
||||
float3 col = SAMPLE_TEXTURE2D_X(_BlitTexture, sampler_PointClamp, sampleUV).rgb;
|
||||
col = max(col, 0.0);
|
||||
|
||||
// ---- Tone shaping so flat pixel blocks read clearly ----
|
||||
col *= _Brightness;
|
||||
col = (col - 0.5) * _Contrast + 0.5;
|
||||
float luma = dot(col, float3(0.2126, 0.7152, 0.0722));
|
||||
col = lerp(luma.xxx, col, _Saturation);
|
||||
col = saturate(col);
|
||||
|
||||
// ---- Posterize in perceptual (gamma) space so dark detail survives ----
|
||||
if (_PosterizeEnabled > 0.5)
|
||||
{
|
||||
float levels = max(_ColorLevels, 2.0);
|
||||
float3 g = pow(col, 1.0 / 2.2);
|
||||
g = floor(g * levels + 0.5) / levels;
|
||||
col = pow(saturate(g), 2.2);
|
||||
}
|
||||
|
||||
// ---- Depth edges (outer silhouettes) ----
|
||||
float d0 = LinearEyeDepth(SampleSceneDepth(sampleUV), _ZBufferParams);
|
||||
float dL = LinearEyeDepth(SampleSceneDepth(sampleUV - float2(off.x, 0)), _ZBufferParams);
|
||||
float dR = LinearEyeDepth(SampleSceneDepth(sampleUV + float2(off.x, 0)), _ZBufferParams);
|
||||
float dD = LinearEyeDepth(SampleSceneDepth(sampleUV - float2(0, off.y)), _ZBufferParams);
|
||||
float dU = LinearEyeDepth(SampleSceneDepth(sampleUV + float2(0, off.y)), _ZBufferParams);
|
||||
float depthDiff = abs(d0 - dL) + abs(d0 - dR) + abs(d0 - dU) + abs(d0 - dD);
|
||||
float depthEdge = step(_DepthThreshold, depthDiff / max(d0, 1e-3)) * _DepthEdgesEnabled;
|
||||
|
||||
// ---- Normal edges (inner detail creases) ----
|
||||
float3 n0 = SampleSceneNormals(sampleUV);
|
||||
float3 nL = SampleSceneNormals(sampleUV - float2(off.x, 0));
|
||||
float3 nR = SampleSceneNormals(sampleUV + float2(off.x, 0));
|
||||
float3 nD = SampleSceneNormals(sampleUV - float2(0, off.y));
|
||||
float3 nU = SampleSceneNormals(sampleUV + float2(0, off.y));
|
||||
float ne = (1.0 - saturate(dot(n0, nL))) + (1.0 - saturate(dot(n0, nR)))
|
||||
+ (1.0 - saturate(dot(n0, nU))) + (1.0 - saturate(dot(n0, nD)));
|
||||
float normalEdge = step(_NormalThreshold, ne) * _NormalEdgesEnabled;
|
||||
|
||||
// Mask inner lines out of silhouette edges to avoid double outlines.
|
||||
float normalEdgeMasked = normalEdge * (1.0 - depthEdge);
|
||||
|
||||
float edge = saturate(depthEdge + normalEdgeMasked) * _EdgeStrength;
|
||||
float3 lineCol = lerp(_OutlineColorInner.rgb, _OutlineColorOuter.rgb, depthEdge);
|
||||
float3 outCol = lerp(col, lineCol, edge);
|
||||
|
||||
return half4(outCol, 1.0);
|
||||
}
|
||||
ENDHLSL
|
||||
}
|
||||
}
|
||||
|
||||
Fallback Off
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ab66a5a8f176cac469b6ade5a4286ef0
|
||||
ShaderImporter:
|
||||
externalObjects: {}
|
||||
defaultTextures: []
|
||||
nonModifiableTextures: []
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user