diff --git a/Assets/Materials/Pose Icon Toon.mat b/Assets/Materials/Pose Icon Toon.mat new file mode 100644 index 0000000..1fc4e8a --- /dev/null +++ b/Assets/Materials/Pose Icon Toon.mat @@ -0,0 +1,40 @@ +%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: Pose Icon Toon + m_Shader: {fileID: 4800000, guid: 4feab3af8d45cb545a6f4f9b7bdb6f2d, 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: + - _BaseMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Ints: [] + m_Floats: + - _OutlineWidth: 6 + - _ShadeSoftness: 0.05 + - _ShadeThreshold: 0.5 + m_Colors: + - _BaseColor: {r: 1, g: 1, b: 1, a: 1} + - _OutlineColor: {r: 0.09999997, g: 0.079999976, b: 0.19999996, a: 1} + - _ShadowTint: {r: 0.54999995, g: 0.5, b: 0.65, a: 1} + m_BuildTextureStacks: [] + m_AllowLocking: 1 diff --git a/Assets/Materials/Pose Icon Toon.mat.meta b/Assets/Materials/Pose Icon Toon.mat.meta new file mode 100644 index 0000000..f272e2a --- /dev/null +++ b/Assets/Materials/Pose Icon Toon.mat.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 662451554d7a52d4baa06298116a9b6a +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scenes/Pose Icon.unity b/Assets/Scenes/Pose Icon.unity index 0161090..1e30883 100644 --- a/Assets/Scenes/Pose Icon.unity +++ b/Assets/Scenes/Pose Icon.unity @@ -156,7 +156,7 @@ Camera: m_Enabled: 1 serializedVersion: 2 m_ClearFlags: 2 - m_BackGroundColor: {r: 0.40251565, g: 0.10759059, b: 0.32042146, a: 0} + m_BackGroundColor: {r: 1, g: 0, b: 1, a: 0} m_projectionMatrixMode: 1 m_GateFitMode: 2 m_FOVAxisMode: 0 @@ -278,7 +278,7 @@ PrefabInstance: objectReference: {fileID: 0} - target: {fileID: -8679921383154817045, guid: c2044ff1352a6bb4586d6d04b59012b7, type: 3} propertyPath: m_LocalRotation.w - value: 1 + value: 0.9647873 objectReference: {fileID: 0} - target: {fileID: -8679921383154817045, guid: c2044ff1352a6bb4586d6d04b59012b7, type: 3} propertyPath: m_LocalRotation.x @@ -286,7 +286,7 @@ PrefabInstance: objectReference: {fileID: 0} - target: {fileID: -8679921383154817045, guid: c2044ff1352a6bb4586d6d04b59012b7, type: 3} propertyPath: m_LocalRotation.y - value: 0 + value: 0.2630312 objectReference: {fileID: 0} - target: {fileID: -8679921383154817045, guid: c2044ff1352a6bb4586d6d04b59012b7, type: 3} propertyPath: m_LocalRotation.z @@ -827,7 +827,7 @@ PrefabInstance: - target: {fileID: 5804137883901333613, guid: c2044ff1352a6bb4586d6d04b59012b7, type: 3} propertyPath: 'm_Materials.Array.data[0]' value: - objectReference: {fileID: 2100000, guid: 9d915c00589d8b544a529437f76867fd, type: 2} + objectReference: {fileID: 2100000, guid: 662451554d7a52d4baa06298116a9b6a, type: 2} - target: {fileID: 5866666021909216657, guid: c2044ff1352a6bb4586d6d04b59012b7, type: 3} propertyPath: m_Avatar value: @@ -982,26 +982,154 @@ MonoBehaviour: entries: - clip: {fileID: 7400000, guid: 18925b0fe0029224aa6d9f4d9ca9ab72, type: 2} position: {x: 0, y: 0, z: 0} - rotation: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 30.5, z: 0} - clip: {fileID: 7400000, guid: b4b88b2d2f749a94fbcdc7c0447cd73c, type: 2} position: {x: 0, y: 0, z: 0} - rotation: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 30.5, z: 0} - clip: {fileID: 7400000, guid: 8080490af5235b043abfca704be7ff8d, type: 2} - position: {x: 0, y: 0.48, z: 0} - rotation: {x: 30.93, y: -21.5, z: -12.3} + position: {x: 0.06, y: 0.33, z: 0} + rotation: {x: 20.1, y: -153.5, z: 9.9} - clip: {fileID: 7400000, guid: 7686660013aff7f478d9a6fd61196957, type: 2} - position: {x: 0, y: 0, z: 0} - rotation: {x: 0, y: 0, z: 0} + position: {x: 0, y: 0.46, z: 0} + rotation: {x: -11.5, y: 0, z: 0} - clip: {fileID: 7400000, guid: f8de430ad75135743b87456111e7abac, type: 2} - position: {x: 0, y: 0.4, z: 0} - rotation: {x: 26.42, y: -36.62, z: 0} + position: {x: 0, y: 0.5, z: 0} + rotation: {x: 21.2, y: -133.3, z: 11.56} - clip: {fileID: 7400000, guid: 933a7fdefa4f6974b9ed61bd940da6ed, type: 2} - position: {x: 0.08, y: 0.7, z: 0} - rotation: {x: 43.1, y: -24.67, z: 0} + position: {x: 0.09, y: 0.7, z: 0} + rotation: {x: 24.4, y: -144.8, z: 0} currentIndex: 0 +--- !u!1 &1708736866 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1708736868} + - component: {fileID: 1708736867} + - component: {fileID: 1708736869} + m_Layer: 0 + m_Name: Directional Light + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!108 &1708736867 +Light: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1708736866} + m_Enabled: 1 + serializedVersion: 12 + m_Type: 1 + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_Intensity: 1.1 + m_Range: 10 + m_SpotAngle: 30 + m_InnerSpotAngle: 21.80208 + m_CookieSize2D: {x: 0.5, y: 0.5} + m_Shadows: + m_Type: 0 + m_Resolution: -1 + m_CustomResolution: -1 + m_Strength: 1 + m_Bias: 0.05 + m_NormalBias: 0.4 + m_NearPlane: 0.2 + m_CullingMatrixOverride: + e00: 1 + e01: 0 + e02: 0 + e03: 0 + e10: 0 + e11: 1 + e12: 0 + e13: 0 + e20: 0 + e21: 0 + e22: 1 + e23: 0 + e30: 0 + e31: 0 + e32: 0 + e33: 1 + m_UseCullingMatrixOverride: 0 + m_Cookie: {fileID: 0} + m_DrawHalo: 0 + m_Flare: {fileID: 0} + m_RenderMode: 0 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingLayerMask: 1 + m_Lightmapping: 4 + m_LightShadowCasterMode: 0 + m_AreaSize: {x: 1, y: 1} + m_BounceIntensity: 1 + m_ColorTemperature: 6570 + m_UseColorTemperature: 0 + m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0} + m_UseBoundingSphereOverride: 0 + m_UseViewFrustumForShadowCasterCull: 1 + m_ForceVisible: 0 + m_ShadowRadius: 0 + m_ShadowAngle: 0 + m_LightUnit: 1 + m_LuxAtDistance: 1 + m_EnableSpotReflector: 1 +--- !u!4 &1708736868 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1708736866} + serializedVersion: 2 + m_LocalRotation: {x: 0.3339129, y: -0.20338672, z: 0.07402671, w: 0.9174182} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &1708736869 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1708736866} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 474bcb49853aa07438625e644c072ee6, type: 3} + m_Name: + m_EditorClassIdentifier: Unity.RenderPipelines.Universal.Runtime::UnityEngine.Rendering.Universal.UniversalAdditionalLightData + m_UsePipelineSettings: 1 + m_AdditionalLightsShadowResolutionTier: 2 + m_CustomShadowLayers: 0 + m_LightCookieSize: {x: 1, y: 1} + m_LightCookieOffset: {x: 0, y: 0} + m_SoftShadowQuality: 0 + m_RenderingLayersMask: + serializedVersion: 0 + m_Bits: 1 + m_ShadowRenderingLayersMask: + serializedVersion: 0 + m_Bits: 1 + m_Version: 4 + m_LightLayerMask: 1 + m_ShadowLayerMask: 1 + m_RenderingLayers: 1 + m_ShadowRenderingLayers: 1 --- !u!1660057539 &9223372036854775807 SceneRoots: m_ObjectHideFlags: 0 m_Roots: - {fileID: 843504939} - {fileID: 1331925571} + - {fileID: 1708736868} diff --git a/Assets/Shaders/PoseIconToon.shader b/Assets/Shaders/PoseIconToon.shader new file mode 100644 index 0000000..efefe07 --- /dev/null +++ b/Assets/Shaders/PoseIconToon.shader @@ -0,0 +1,141 @@ +// Minimal cel/toon shader with an inverted-hull outline for the Pose Icon stage +// (icon screenshots of the staged Paintman). Deliberately NOT a URP/Lit clone: +// the stage is a controlled studio setup, so main-light cel banding + ambient is +// all the lighting it needs. Outline runs as a second pass (SRPDefaultUnlit, so +// URP renders it without a Render Feature); width is screen-space (pixel-ish) +// and distance-independent for consistent icon thickness. +Shader "Custom/PoseIconToon" +{ + Properties + { + [MainTexture] _BaseMap("Albedo", 2D) = "white" {} + [MainColor] _BaseColor("Color", Color) = (1,1,1,1) + + [Header(Toon Shading)] + _ShadeThreshold("Shade Threshold", Range(0.0, 1.0)) = 0.5 + _ShadeSoftness("Shade Softness", Range(0.001, 0.5)) = 0.05 + _ShadowTint("Shadow Tint", Color) = (0.55, 0.5, 0.65, 1) + + [Header(Outline)] + _OutlineColor("Outline Color", Color) = (0.1, 0.08, 0.2, 1) + _OutlineWidth("Outline Width (px at 1080p)", Range(0.0, 20.0)) = 6.0 + } + + SubShader + { + Tags { "RenderType" = "Opaque" "RenderPipeline" = "UniversalPipeline" "Queue" = "Geometry" } + + HLSLINCLUDE + #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl" + + CBUFFER_START(UnityPerMaterial) + float4 _BaseMap_ST; + half4 _BaseColor; + half _ShadeThreshold; + half _ShadeSoftness; + half4 _ShadowTint; + half4 _OutlineColor; + half _OutlineWidth; + CBUFFER_END + ENDHLSL + + Pass + { + Name "ToonForward" + // UniversalForwardOnly (not UniversalForward): drawn by BOTH the Forward and the + // Deferred renderer (the deferred path only picks up ForwardOnly/SRPDefaultUnlit + // passes for materials without a GBuffer pass - plain UniversalForward is skipped). + Tags { "LightMode" = "UniversalForwardOnly" } + + HLSLPROGRAM + #pragma vertex ToonVertex + #pragma fragment ToonFragment + + #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl" + + TEXTURE2D(_BaseMap); + SAMPLER(sampler_BaseMap); + + struct Attributes + { + float4 positionOS : POSITION; + float3 normalOS : NORMAL; + float2 uv : TEXCOORD0; + }; + + struct Varyings + { + float4 positionCS : SV_POSITION; + float2 uv : TEXCOORD0; + float3 normalWS : TEXCOORD1; + }; + + Varyings ToonVertex(Attributes input) + { + Varyings output; + output.positionCS = TransformObjectToHClip(input.positionOS.xyz); + output.normalWS = TransformObjectToWorldNormal(input.normalOS); + output.uv = TRANSFORM_TEX(input.uv, _BaseMap); + return output; + } + + half4 ToonFragment(Varyings input) : SV_Target + { + half4 albedo = SAMPLE_TEXTURE2D(_BaseMap, sampler_BaseMap, input.uv) * _BaseColor; + + Light mainLight = GetMainLight(); + half ndl = dot(normalize(input.normalWS), mainLight.direction) * 0.5h + 0.5h; + half lit = smoothstep(_ShadeThreshold - _ShadeSoftness, _ShadeThreshold + _ShadeSoftness, ndl); + + half3 litColor = albedo.rgb * mainLight.color; + half3 shadeColor = albedo.rgb * _ShadowTint.rgb; + half3 ambient = albedo.rgb * SampleSH(input.normalWS) * 0.25h; + + return half4(lerp(shadeColor, litColor, lit) + ambient, albedo.a); + } + ENDHLSL + } + + Pass + { + Name "Outline" + Tags { "LightMode" = "SRPDefaultUnlit" } + Cull Front + + HLSLPROGRAM + #pragma vertex OutlineVertex + #pragma fragment OutlineFragment + + struct Attributes + { + float4 positionOS : POSITION; + float3 normalOS : NORMAL; + }; + + struct Varyings + { + float4 positionCS : SV_POSITION; + }; + + Varyings OutlineVertex(Attributes input) + { + Varyings output; + output.positionCS = TransformObjectToHClip(input.positionOS.xyz); + + // Extrude in clip space: constant on-screen width regardless of distance. + float3 normalWS = TransformObjectToWorldNormal(input.normalOS); + float3 normalCS = normalize(mul((float3x3)UNITY_MATRIX_VP, normalWS).xyz); + float2 offset = normalCS.xy * _OutlineWidth * 2.0 / 1080.0 * output.positionCS.w; + offset.x *= _ScreenParams.y / _ScreenParams.x; // keep width uniform on non-square aspect + output.positionCS.xy += offset; + return output; + } + + half4 OutlineFragment(Varyings input) : SV_Target + { + return _OutlineColor; + } + ENDHLSL + } + } +} diff --git a/Assets/Shaders/PoseIconToon.shader.meta b/Assets/Shaders/PoseIconToon.shader.meta new file mode 100644 index 0000000..f984ec8 --- /dev/null +++ b/Assets/Shaders/PoseIconToon.shader.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 4feab3af8d45cb545a6f4f9b7bdb6f2d +ShaderImporter: + externalObjects: {} + defaultTextures: [] + nonModifiableTextures: [] + userData: + assetBundleName: + assetBundleVariant: