////////////////////////////////////////////////////// // MK Toon Forward Program // // // // Created by Michael Kremmel // // www.michaelkremmel.de // // Copyright © 2020 All rights reserved. // ////////////////////////////////////////////////////// #ifndef MK_TOON_FORWARD #define MK_TOON_FORWARD #include "../Forward/Data.hlsl" #include "../Surface.hlsl" #include "../Lighting.hlsl" #include "../Composite.hlsl" ///////////////////////////////////////////////////////////////////////////////////////////// // VERTEX SHADER ///////////////////////////////////////////////////////////////////////////////////////////// void ForwardVert (VertexInputForward VERTEX_INPUT, out VertexOutputLight vertexOutputLight, out VertexOutputForward vertexOutput) { UNITY_SETUP_INSTANCE_ID(VERTEX_INPUT); INITIALIZE_STRUCT(VertexOutputForward, vertexOutput); INITIALIZE_STRUCT(VertexOutputLight, vertexOutputLight); UNITY_TRANSFER_INSTANCE_ID(VERTEX_INPUT, vertexOutput); UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(vertexOutput); #ifdef MK_VERTEX_ANIMATION VERTEX_INPUT.vertex.xyz = VertexAnimation(PASS_VERTEX_ANIMATION_ARG(_VertexAnimationMap, PASS_VERTEX_ANIMATION_UV(VERTEX_INPUT.texcoord0.xy), _VertexAnimationIntensity, _VertexAnimationFrequency.xyz, VERTEX_INPUT.vertex.xyz, VERTEX_INPUT.normal)); #endif //CurvedWorldSupport //CurvedWorldVertexTransformations /* Replace on the Vertex Transformation code the following: - v.vertex => VERTEX_INPUT.vertex - v.normal => VERTEX_INPUT.normal - v.tangent => VERTEX_INPUT.tangent */ // //Clip Pos #ifdef MK_POS_WORLD vertexOutput.positionWorld.xyz = ComputeObjectToWorldSpace(VERTEX_INPUT.vertex.xyz); #else vertexOutput.positionWorld.xyz = 0; #endif vertexOutputLight.SV_CLIP_POS = ComputeObjectToClipSpace(VERTEX_INPUT.vertex.xyz); //vertex positions #ifdef MK_NORMAL vertexOutput.normalWorld.xyz = ComputeNormalWorld(VERTEX_INPUT.normal); #endif #ifdef MK_LIT #if defined(MK_TBN) vertexOutput.tangentWorld.xyz = ComputeTangentWorld(VERTEX_INPUT.tangent.xyz); vertexOutput.bitangentWorld.xyz = ComputeBitangentWorld(vertexOutput.normalWorld.xyz, vertexOutput.tangentWorld.xyz, VERTEX_INPUT.tangent.w * unity_WorldTransformParams.w); #endif #endif //texcoords #if defined(MK_TCM) || defined(MK_TCD) //XY always RAW Coords vertexOutput.uv = VERTEX_INPUT.texcoord0.xyxy; #if defined(MK_SECONDARY_UV_SET) vertexOutput.uv.zw = _DetailUVSet > 0.5 ? VERTEX_INPUT.texcoord7.xy : VERTEX_INPUT.texcoord0.xy; #endif #endif #ifdef MK_PARALLAX half3 viewTangent = ComputeViewTangent(ComputeViewWorld(vertexOutput.positionWorld.xyz), vertexOutput.normalWorld.xyz, vertexOutput.tangentWorld.xyz, vertexOutput.bitangentWorld.xyz); vertexOutput.normalWorld.w = viewTangent.x; vertexOutput.tangentWorld.w = viewTangent.y; vertexOutput.bitangentWorld.w = viewTangent.z; #endif #ifdef MK_VERTEX_COLOR_REQUIRED vertexOutput.color = VERTEX_INPUT.color; #endif #ifdef MK_LIT #ifdef MK_FORWARD_BASE_PASS #ifdef MK_VERTEX_LIGHTING // Approximated illumination from non-important point lights vertexOutputLight.vertexLighting = ComputeVertexLighting(vertexOutput.positionWorld.xyz, vertexOutput.normalWorld.xyz); #endif #ifdef MK_LIGHTMAP_UV vertexOutputLight.lightmapUV = 0; #if defined(MK_URP) || defined(MK_LWRP) #if UNITY_VERSION >= 60000009 OUTPUT_LIGHTMAP_UV(VERTEX_INPUT.staticLightmapUV.xy, unity_LightmapST, vertexOutputLight.lightmapUV.xy); OUTPUT_SH4(vertexOutput.positionWorld.xyz, vertexOutput.normalWorld.xyz, GetWorldSpaceNormalizeViewDir(vertexOutput.positionWorld.xyz), vertexOutputLight.lightmapUV, vertexOutput.probeOcclusion); #ifdef DYNAMICLIGHTMAP_ON vertexOutputLight.lightmapUV.zw = ComputeDynamicLightmapUV(VERTEX_INPUT.dynamicLightmapUV.xy); #endif #elif UNITY_VERSION >= 60000000 OUTPUT_LIGHTMAP_UV(VERTEX_INPUT.staticLightmapUV.xy, unity_LightmapST, vertexOutputLight.lightmapUV.xy); OUTPUT_SH4(vertexOutput.positionWorld.xyz, vertexOutput.normalWorld.xyz, GetWorldSpaceNormalizeViewDir(vertexOutput.positionWorld.xyz), vertexOutputLight.lightmapUV); #ifdef DYNAMICLIGHTMAP_ON vertexOutputLight.lightmapUV.zw = ComputeDynamicLightmapUV(VERTEX_INPUT.dynamicLightmapUV.xy); #endif #else #if defined(LIGHTMAP_ON) vertexOutputLight.lightmapUV.xy = ComputeStaticLightmapUV(VERTEX_INPUT.staticLightmapUV.xy); #else vertexOutputLight.lightmapUV.rgb = ComputeSHVertex(vertexOutput.positionWorld.xyz, vertexOutput.normalWorld.xyz, ComputeViewWorld(vertexOutput.positionWorld.xyz)); #endif #ifdef DYNAMICLIGHTMAP_ON vertexOutputLight.lightmapUV.zw = ComputeDynamicLightmapUV(VERTEX_INPUT.dynamicLightmapUV.xy); #endif #endif #else //lightmaps and ambient //Static lightmaps #if defined(LIGHTMAP_ON) vertexOutputLight.lightmapUV.xy = ComputeStaticLightmapUV(VERTEX_INPUT.staticLightmapUV.xy); //If no lightmaps used, do vertex lit if enabled #elif defined(UNITY_SHOULD_SAMPLE_SH) vertexOutputLight.lightmapUV.rgb = ComputeSHVertex(vertexOutput.positionWorld.xyz, vertexOutput.normalWorld.xyz, ComputeViewWorld(vertexOutput.positionWorld.xyz)); #endif #ifdef DYNAMICLIGHTMAP_ON vertexOutputLight.lightmapUV.zw = ComputeDynamicLightmapUV(VERTEX_INPUT.dynamicLightmapUV.xy); #endif #endif #endif #endif //transform lighting coords TRANSFORM_WORLD_TO_SHADOW_COORDS(vertexOutput, VERTEX_INPUT, vertexOutputLight) #endif #ifdef MK_BARYCENTRIC_POS_CLIP vertexOutput.positionClip = vertexOutputLight.SV_CLIP_POS; #endif #ifdef MK_POS_NULL_CLIP vertexOutput.nullClip = ComputeObjectToClipSpace(0); #endif //vertex fog #ifdef MK_FOG vertexOutput.positionWorld.w = FogFactorVertex(vertexOutputLight.SV_CLIP_POS.z); #endif #ifdef MK_FLIPBOOK vertexOutput.flipbookUV.xy = VERTEX_INPUT.texcoord0.zw; vertexOutput.flipbookUV.z = VERTEX_INPUT.texcoordBlend; #endif } ///////////////////////////////////////////////////////////////////////////////////////////// // FRAGMENT SHADER ///////////////////////////////////////////////////////////////////////////////////////////// MKFragmentOutput ForwardFrag(in VertexOutputLight vertexOutputLight, in VertexOutputForward vertexOutput MK_DECLARE_V_FACE) { 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(vertexOutputLight.SV_CLIP_POS); #endif MKSurfaceData surfaceData = ComputeSurfaceData ( vertexOutputLight.SV_CLIP_POS, PASS_POSITION_WORLD_ARG(vertexOutput.positionWorld.xyz) PASS_FOG_FACTOR_WORLD_ARG(vertexOutput.positionWorld.w) PASS_BASE_UV_ARG(vertexOutput.uv) PASS_LIGHTMAP_UV_ARG(vertexOutputLight.lightmapUV) PASS_VERTEX_COLOR_ARG(vertexOutput.color) PASS_NORMAL_WORLD_ARG(vertexOutput.normalWorld.xyz) PASS_VERTEX_LIGHTING_ARG(vertexOutputLight.vertexLighting) PASS_TANGENT_WORLD_ARG(vertexOutput.tangentWorld.xyz) PASS_VIEW_TANGENT_ARG(half3(vertexOutput.normalWorld.w, vertexOutput.tangentWorld.w, vertexOutput.bitangentWorld.w)) PASS_BITANGENT_WORLD_ARG(vertexOutput.bitangentWorld.xyz) PASS_BARYCENTRIC_POSITION_CLIP_ARG(vertexOutput.positionClip) PASS_NULL_CLIP_ARG(vertexOutput.nullClip) PASS_FLIPBOOK_UV_ARG(vertexOutput.flipbookUV) PASS_PROBE_OCCLUSION_ARG(vertexOutput.probeOcclusion) #ifdef MK_VFACE , vFace #endif ); Surface surface = InitSurface(surfaceData, PASS_SAMPLER_2D(_AlbedoMap), _AlbedoColor, vertexOutputLight.SV_CLIP_POS); MKPBSData pbsData = ComputePBSData(surface, surfaceData); #ifdef MK_LIT //Init per mainLight MKLight mainLight = ComputeMainLight(surfaceData, vertexOutputLight); //Init mainLight data MKLightData lightData = ComputeLightData(mainLight, surfaceData); //Do per pass light LightingIndirect(surface, surfaceData, pbsData, mainLight, lightData); #if defined(MK_URP) || defined(MK_LWRP) #if UNITY_VERSION >= 202220 uint meshRenderingLayers = GetMeshRenderingLayer(); #ifdef _LIGHT_LAYERS if (IsMatchingLightLayer(mainLight.layerMask, meshRenderingLayers)) #endif { LightingDirect(surface, surfaceData, pbsData, mainLight, lightData, surface.direct); } #if defined(_ADDITIONAL_LIGHTS) half4 gD = surface.goochDark; surface.goochDark = 0; uint additionalLightCount = GetAdditionalLightsCount(); half4 additionalDirect = 0; MKLight additionalLight; MKLightData additionalLightData; #if USE_FORWARD_PLUS || USE_CLUSTER_LIGHT_LOOP MKInputDataWrapper inputData; INITIALIZE_STRUCT(MKInputDataWrapper, inputData); inputData.normalizedScreenSpaceUV = surfaceData.screenUV.xy; inputData.positionWS = surfaceData.positionWorld; [loop] for (uint lightIndex = 0; lightIndex < min(URP_FP_DIRECTIONAL_LIGHTS_COUNT, MAX_VISIBLE_LIGHTS); lightIndex++) { #if UNITY_VERSION >= 60010000 CLUSTER_LIGHT_LOOP_SUBTRACTIVE_LIGHT_CHECK #else FORWARD_PLUS_SUBTRACTIVE_LIGHT_CHECK #endif additionalLight = ComputeAdditionalLight(lightIndex, surfaceData, vertexOutputLight); additionalLightData = ComputeLightData(additionalLight, surfaceData); #ifdef _LIGHT_LAYERS if (IsMatchingLightLayer(additionalLight.layerMask, meshRenderingLayers)) #endif { LightingDirectAdditional(surface, surfaceData, pbsData, additionalLight, additionalLightData, additionalDirect); surface.direct += additionalDirect; } } #endif LIGHT_LOOP_BEGIN(additionalLightCount) additionalLight = ComputeAdditionalLight(lightIndex, surfaceData, vertexOutputLight); additionalLightData = ComputeLightData(additionalLight, surfaceData); #ifdef _LIGHT_LAYERS if (IsMatchingLightLayer(additionalLight.layerMask, meshRenderingLayers)) #endif { LightingDirectAdditional(surface, surfaceData, pbsData, additionalLight, additionalLightData, additionalDirect); surface.direct += additionalDirect; } LIGHT_LOOP_END surface.goochDark = gD; #endif #elif UNITY_VERSION >= 202120 uint meshRenderingLayers = GetMeshRenderingLightLayer(); if (IsMatchingLightLayer(mainLight.layerMask, meshRenderingLayers)) { LightingDirect(surface, surfaceData, pbsData, mainLight, lightData, surface.direct); } #ifdef _ADDITIONAL_LIGHTS half4 gD = surface.goochDark; surface.goochDark = 0; uint additionalLightCount = GetAdditionalLightsCount(); half4 additionalDirect = 0; MKLight additionalLight; MKLightData additionalLightData; #if USE_CLUSTERED_LIGHTING MKInputDataWrapper inputData; INITIALIZE_STRUCT(MKInputDataWrapper, inputData); inputData.normalizedScreenSpaceUV = surfaceData.screenUV.xy; inputData.positionWS = surfaceData.positionWorld; for (uint lightIndex = 0; lightIndex < min(_AdditionalLightsDirectionalCount, MAX_VISIBLE_LIGHTS); ++lightIndex) { additionalLight = ComputeAdditionalLight(lightIndex, surfaceData, vertexOutputLight); additionalLightData = ComputeLightData(additionalLight, surfaceData); if (IsMatchingLightLayer(additionalLight.layerMask, meshRenderingLayers)) { LightingDirectAdditional(surface, surfaceData, pbsData, additionalLight, additionalLightData, additionalDirect); surface.direct += additionalDirect; } } #endif LIGHT_LOOP_BEGIN(additionalLightCount) additionalLight = ComputeAdditionalLight(lightIndex, surfaceData, vertexOutputLight); additionalLightData = ComputeLightData(additionalLight, surfaceData); if (IsMatchingLightLayer(additionalLight.layerMask, meshRenderingLayers)) { LightingDirectAdditional(surface, surfaceData, pbsData, additionalLight, additionalLightData, additionalDirect); surface.direct += additionalDirect; } LIGHT_LOOP_END surface.goochDark = gD; #endif #else LightingDirect(surface, surfaceData, pbsData, mainLight, lightData, surface.direct); #ifdef _ADDITIONAL_LIGHTS half4 gD = surface.goochDark; surface.goochDark = 0; uint additionalLightCount = GetAdditionalLightsCount(); half4 additionalDirect = 0; for (uint lightIndex = 0u; lightIndex < additionalLightCount; ++lightIndex) { MKLight additionalLight = ComputeAdditionalLight(lightIndex, surfaceData, vertexOutputLight); MKLightData additionalLightData = ComputeLightData(additionalLight, surfaceData); LightingDirectAdditional(surface, surfaceData, pbsData, additionalLight, additionalLightData, additionalDirect); surface.direct += additionalDirect; } surface.goochDark = gD; #endif #endif #else LightingDirect(surface, surfaceData, pbsData, mainLight, lightData, surface.direct); #endif #endif //Finalize the output 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