Files
2026-10-09 17:25:14 +03:00

228 lines
9.0 KiB
HLSL

//////////////////////////////////////////////////////
// MK Toon Outline Program //
// //
// Created by Michael Kremmel //
// www.michaelkremmel.de //
// Copyright © 2020 All rights reserved. //
//////////////////////////////////////////////////////
#ifndef MK_TOON_OUTLINE_ONLY_BASE
#define MK_TOON_OUTLINE_ONLY_BASE
#include "Data.hlsl"
#include "../Surface.hlsl"
#include "../Composite.hlsl"
#ifndef MK_OUTLINE_CLIP_OFFSET_SCALE
#define MK_OUTLINE_CLIP_OFFSET_SCALE 0.01
#endif
/////////////////////////////////////////////////////////////////////////////////////////////
// VERTEX SHADER
/////////////////////////////////////////////////////////////////////////////////////////////
VertexOutputOutlineOnly OutlineVert(VertexInputOutlineOnly vertexInput)
{
UNITY_SETUP_INSTANCE_ID(vertexInput);
VertexOutputOutlineOnly vertexOutput;
INITIALIZE_STRUCT(VertexOutputOutlineOnly, vertexOutput);
UNITY_TRANSFER_INSTANCE_ID(vertexInput, vertexOutput);
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(vertexOutput);
half outlineSize = _OutlineSize;
//texcoords
#if defined(MK_TCM)
vertexOutput.uv = vertexInput.texcoord0;
#endif
#ifdef MK_OUTLINE_MAP
outlineSize *= tex2Dlod(_OutlineMap, float4(vertexOutput.uv, 0, 0)).r;
#endif
#ifdef MK_OUTLINE_NOISE
outlineSize = lerp(outlineSize, outlineSize * NoiseSimple(normalize(vertexInput.vertex.xyz), vertexInput.normal.xz), _OutlineNoise);
#endif
#ifdef MK_VERTEX_ANIMATION
vertexInput.vertex.xyz = VertexAnimation(PASS_VERTEX_ANIMATION_ARG(_VertexAnimationMap, PASS_VERTEX_ANIMATION_UV(vertexOutput.uv), _VertexAnimationIntensity, _VertexAnimationFrequency.xyz, vertexInput.vertex.xyz, vertexInput.normal));
#endif
//CurvedWorldSupport
//CurvedWorldVertexTransformations
/*
Replace on the Vertex Transformation code the following:
- v.vertex => vertexInput.vertex
- v.normal => vertexInput.normal
- v.tangent => vertexInput.tangent
*/
//
#ifndef MK_LEGACY_SCREEN_SCALING
#if (defined(USING_STEREO_MATRICES) || defined(MK_MULTI_PASS_STEREO_SCALING)) && defined(MK_OUTLINE_HULL_CLIP)
outlineSize *= 0.5;
#endif
#endif
#ifdef UNITY_SINGLE_PASS_STEREO
outlineSize.x *= 0.5;
#endif
#ifdef MK_OUTLINE_FADING
float dist;
#if defined(USING_STEREO_MATRICES)
float3 stereoOffset = (unity_StereoWorldSpaceCameraPos[1] - unity_StereoWorldSpaceCameraPos[0]) * 0.5;
dist = distance(unity_StereoWorldSpaceCameraPos[0] + stereoOffset, mul(MATRIX_M, float4(vertexInput.vertex.xyz, 1.0)).xyz);
#else
dist = distance(CAMERA_POSITION_WORLD , mul(MATRIX_M, float4(vertexInput.vertex.xyz, 1.0)).xyz);
#endif
#if defined(MK_OUTLINE_FADING_EXPONENTIAL)
outlineSize *= smoothstep(_OutlineFadeMin, _OutlineFadeMax, dist);
#elif defined(MK_OUTLINE_FADING_INVERSE_EXPONENTIAL)
float interp = saturate((dist - _OutlineFadeMin) / (_OutlineFadeMax - _OutlineFadeMin));
outlineSize *= (interp + (interp - (interp * interp * (3.0f - 2.0f * interp))));
#else
outlineSize *= saturate((dist - _OutlineFadeMin) / (_OutlineFadeMax - _OutlineFadeMin));
#endif
#endif
vertexInput.normal = MKSafeNormalize(vertexInput.normal);
#if defined(MK_OUTLINE_HULL_ORIGIN)
//float4x4 modelMatrix = MATRIX_M;
//vertexInput.vertex.xyz += MKSafeNormalize(vertexInput.vertex.xyz) * _OutlineSize * OUTLINE_ORIGIN_SCALE;
//float3 positionWorld = mul(modelMatrix, float4(vertexInput.vertex.xyz, 1.0)).xyz;
float3 worldPos = mul(MATRIX_M, float4(vertexInput.vertex.xyz, 1.0)).xyz;
float distHullOrigin = lerp(1, distance(_WorldSpaceCameraPos, worldPos), _OutlineConstantSize);
float3 scaleOrigin = 1 + _OutlineSize * OUTLINE_ORIGIN_SCALE * distHullOrigin;
float3x3 scale = float3x3
(
scaleOrigin.x, 0, 0,
0, scaleOrigin.y, 0,
0, 0, scaleOrigin.z
);
float3 positionWorld = mul(scale, vertexInput.vertex.xyz);
positionWorld = mul(MATRIX_M, float4(positionWorld, 1.0)).xyz;
vertexOutput.positionWorld = positionWorld;
#elif defined(MK_OUTLINE_HULL_OBJECT)
float3 worldPos = mul(MATRIX_M, float4(vertexInput.vertex.xyz, 1.0)).xyz;
vertexOutput.positionWorld = worldPos;
float distHullObject = lerp(1, distance(_WorldSpaceCameraPos, worldPos), _OutlineConstantSize);
#if defined(MK_OUTLINE_DATA_UV7)
vertexInput.vertex.xyz += vertexInput.normalBaked * outlineSize * OUTLINE_OBJECT_SCALE * distHullObject;
#else
vertexInput.vertex.xyz += vertexInput.normal * outlineSize * OUTLINE_OBJECT_SCALE * distHullObject;
#endif
#endif
#if defined(MK_OUTLINE_HULL_ORIGIN)
vertexOutput.svPositionClip = ComputeWorldToClipSpace(positionWorld);
#elif defined(MK_OUTLINE_HULL_CLIP)
//Make it pixel perfect and SCALED on different aspects and resolutions
vertexOutput.svPositionClip = ComputeObjectToClipSpace(vertexInput.vertex.xyz);
#ifndef MK_LEGACY_SCREEN_SCALING
half oScale;
oScale = ScaleToFitOrthograpicSize(vertexOutput.svPositionClip.w);
half scale = ScaleToFitResolution(REFERENCE_ASPECT, REFERENCE_RESOLUTION, _ScreenParams.xy);
#else
half oScale = 1;
half scaledAspect = SafeDivide(REFERENCE_ASPECT.x, SafeDivide(_ScreenParams.x, _ScreenParams.y));
half scaledResolution = SafeDivide(_ScreenParams.x, REFERENCE_RESOLUTION.x);
half scale = scaledAspect * scaledResolution;
#endif
#if defined(MK_OUTLINE_DATA_UV7)
half3 normalBakedClip = ComputeNormalObjectToClipSpace(vertexInput.normalBaked.xyz) * lerp(1, vertexOutput.svPositionClip.w, _OutlineConstantSize);;
vertexOutput.svPositionClip.xy += 2 * oScale * outlineSize * SafeDivide(normalBakedClip.xy, _ScreenParams.xy) * scale;
#else
half3 normalClip = ComputeNormalObjectToClipSpace(vertexInput.normal.xyz) * lerp(1, vertexOutput.svPositionClip.w, _OutlineConstantSize);
vertexOutput.svPositionClip.xy += 2 * oScale * outlineSize * SafeDivide(normalClip.xy, _ScreenParams.xy) * scale;
#endif
vertexOutput.positionWorld = ComputeObjectToWorldSpace(vertexInput.vertex.xyz);
#else
vertexOutput.svPositionClip = ComputeObjectToClipSpace(vertexInput.vertex.xyz);
#endif
#if UNITY_REVERSED_Z
vertexOutput.svPositionClip.z -= _OutlineClipOffset * MK_OUTLINE_CLIP_OFFSET_SCALE;
#else
//reverse for clip depth needed
vertexOutput.svPositionClip.z += (1.0 - UNITY_NEAR_CLIP_VALUE) * (_OutlineClipOffset * MK_OUTLINE_CLIP_OFFSET_SCALE);
#endif
#ifdef MK_VERTEX_COLOR_REQUIRED
vertexOutput.color = vertexInput.color;
#endif
#if defined(MK_PARALLAX)
vertexOutput.viewTangent = ComputeViewTangent(ComputeViewObject(vertexInput.vertex.xyz), vertexInput.normal, vertexInput.tangent.xyz, cross(vertexInput.normal, vertexInput.tangent.xyz) * vertexInput.tangent.w * unity_WorldTransformParams.w);
#endif
#ifdef MK_FOG
vertexOutput.fogFactor = FogFactorVertex(vertexOutput.svPositionClip.z);
#endif
#ifdef MK_BARYCENTRIC_POS_CLIP
vertexOutput.positionClip = vertexOutput.svPositionClip;
#endif
#ifdef MK_POS_NULL_CLIP
vertexOutput.nullClip = ComputeObjectToClipSpace(0);
#endif
#ifdef MK_FLIPBOOK
vertexOutput.flipbookUV.xy = VERTEX_INPUT.texcoord0.zw;
vertexOutput.flipbookUV.z = VERTEX_INPUT.texcoordBlend;
#endif
return vertexOutput;
}
/////////////////////////////////////////////////////////////////////////////////////////////
// FRAGMENT SHADER
/////////////////////////////////////////////////////////////////////////////////////////////
MKFragmentOutput OutlineFrag(VertexOutputOutlineOnly vertexOutput)
{
UNITY_SETUP_INSTANCE_ID(vertexOutput);
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(vertexOutput);
MKFragmentOutput mkFragmentOutput;
INITIALIZE_STRUCT(MKFragmentOutput, mkFragmentOutput);
#ifdef MK_LOD_FADE_CROSSFADE
LODFadeCrossFade(vertexOutput.svPositionClip);
#endif
MKSurfaceData surfaceData = ComputeSurfaceData
(
vertexOutput.svPositionClip,
PASS_POSITION_WORLD_ARG(vertexOutput.positionWorld)
PASS_FOG_FACTOR_WORLD_ARG(vertexOutput.fogFactor)
PASS_BASE_UV_ARG(float4(vertexOutput.uv.xy, 0, 0))
PASS_LIGHTMAP_UV_ARG(0)
PASS_VERTEX_COLOR_ARG(vertexOutput.color)
PASS_NORMAL_WORLD_ARG(1)
PASS_VERTEX_LIGHTING_ARG(0)
PASS_TANGENT_WORLD_ARG(1)
PASS_VIEW_TANGENT_ARG(vertexOutput.viewTangent)
PASS_BITANGENT_WORLD_ARG(1)
PASS_BARYCENTRIC_POSITION_CLIP_ARG(vertexOutput.positionClip)
PASS_NULL_CLIP_ARG(vertexOutput.nullClip)
PASS_FLIPBOOK_UV_ARG(vertexOutput.flipbookUV)
);
Surface surface = InitSurface(surfaceData, PASS_SAMPLER_2D(_AlbedoMap), half4(_OutlineColor.rgb, _AlbedoColor.a), vertexOutput.svPositionClip);
MKPBSData pbsData = ComputePBSData(surface, surfaceData);
Composite(surface, surfaceData, pbsData);
mkFragmentOutput.svTarget0 = surface.final;
#ifdef MK_WRITE_RENDERING_LAYERS
#if UNITY_VERSION >= 60020000
mkFragmentOutput.svTarget1 = EncodeMeshRenderingLayer();
#else //UNITY_VERSION >= 202220
uint renderingLayers = GetMeshRenderingLayer();
mkFragmentOutput.svTarget1 = float4(EncodeMeshRenderingLayer(renderingLayers), 0, 0, 0);
#endif
#endif
return mkFragmentOutput;
}
#endif