Files
GTASource/game/shader_source/common.fxh
T
expvintl 419f2e4752 init
2025-02-23 17:40:52 +08:00

3665 lines
125 KiB
HLSL

//
//
//
//
#ifndef __GTA_COMMON_FXH
#define __GTA_COMMON_FXH
#if __MAX
#define SKINNING_COUNT 32
#endif
#if RSG_PC
#ifdef SCALEFORM_SHADER
#define SCALEFORM_TEXTURE 1
#else
#define SCALEFORM_TEXTURE 0
#endif
#endif
#ifndef DIFFUSE_TEXTURE
#define DIFFUSE_TEXTURE 1 // this was the default, so for paths that do not #define it, we'll just force it on
#endif
#define DISABLE_RAGE_LIGHTING
#ifndef __RAGE_COMMON_FXH
#include "../../rage/base/src/shaderlib/rage_common.fxh"
#endif
#include "../../rage/base/src/grcore/config_switches.h"
#include "Util/macros.fxh"
#include "Peds/ped_common_values.h"
#include "../vfx/vfx_shared.h"
#include "../scene/EntityId_shared.h"
#include "Util/BatchInstancing.fxh"
#if RSG_PC || RSG_ORBIS || RSG_DURANGO
#if __LOW_QUALITY
#define AUTOGENERATED_MIPMAPS 1
#define HQLINEAR LINEAR
#define SHQLINEAR LINEAR
#define MIPLINEAR POINT
#define MAGLINEAR LINEAR
#define MINANISOTROPIC LINEAR
#define ANISOTROPIC_LEVEL(x)
#else
#define AUTOGENERATED_MIPMAPS 1
#define HQLINEAR ANISOTROPIC
#define SHQLINEAR ANISOTROPIC
#define MIPLINEAR LINEAR
#if RSG_PC // PC sets anisotropic level in settings for all anisotropic shaders. Low Quality won't have this either to avoid sampler construction errors
#define ANISOTROPIC_LEVEL(x)
#else
#define ANISOTROPIC_LEVEL(x) MaxAnisotropy = x;
#endif
#if RSG_ORBIS
#define MAGLINEAR ANISOTROPIC
#else
#define MAGLINEAR LINEAR
#endif
#define MINANISOTROPIC ANISOTROPIC
#endif // __LOW_QUALITY
#else
#define HQLINEAR LINEAR
#define SHQLINEAR LINEAR
#define MIPLINEAR LINEAR
#define MAGLINEAR LINEAR
#define MINANISOTROPIC ANISOTROPIC
#define ANISOTROPIC_LEVEL(x) MaxAnisotropy = x;
#endif
#if RSG_PC && CASCADE_SHADOW_TEXARRAY
#undef PIXELSHADER
#define PIXELSHADER ps_4_1
#endif
#define USE_FULLSCREEN_PUDDLE_PASS 1
// SLOPE is used for procedurally texturing terrain for puddles
#define USE_SLOPE 1
// =============================================================================================== //
// DEFINES
// =============================================================================================== //
// BS#29944 .. switching off unused techniques removes over 1.15MB on ps3
/*
// ================================================================================================
techniques which we want to control:
lightweight0_draw
lightweight0_drawskinned
lightweight4_draw
lightweight4_drawskinned
draw
drawskinned
deferred_draw
deferred_drawskinned
deferredalphaclip_draw
deferredalphaclip_drawskinned
deferredsubsamplealpha_draw
deferredsubsamplealpha_drawskinned
deferredsubsamplewritealpha_draw
deferredsubsamplewritealpha_drawskinned
waterreflection_draw
waterreflection_drawskinned
waterreflectionalphaclip_draw
wdcascade_draw
wdcascade_drawskinned
wdcascadeedge_draw
wdcascadeedge_drawskinned
shadtexture_wdcascade_draw
shadtexture_wdcascade_drawskinned
shadtexture_wdcascadeedge_draw
shadtexture_wdcascadeedge_drawskinned
ld_draw
ld_drawskinned
ldpoint_draw (deprecated?)
ldpoint_drawskinned (deprecated?)
ldedgepoint_draw
ldedgepoint_drawskinned
shadtexture_ld_draw
shadtexture_ld_drawskinned
shadtexture_ldpoint_draw (deprecated?)
shadtexture_ldpoint_drawskinned (deprecated?)
shadtexture_ldedgepoint_draw
shadtexture_ldedgepoint_drawskinned
notes:
lightweight0 ................. is used for alpha shaders and mirror reflection (0 lights), and water reflection
lightweight4 ................. is used for alpha shaders and mirror reflection (1-4 lights)
draw ......................... is used for alpha shaders and mirror reflection (5-8 lights)
deferred ..................... is used for deferred and decals
deferredalphaclip ............ is used for cutout
deferredsubsamplealpha ....... is used for SSA
deferredsubsamplewritealpha .. is used for SSA
waterreflection .............. is used for water reflection
waterreflectionalphaclip ......is used for water reflection with alpha cutout
wdcascade .................... is used for directional (cascade) shadows
ldpoint ...................... is used for local (cubemap) shadows
| paraboloid reflection | mirror reflection | water reflection |
----------------------+-----------------------+-------------------+------------------+-
megashader | yes | yes | yes |
terrain | yes | yes* | yes |
trees | no | yes* | yes |
peds | no | yes | yes |
vehicles | no | yes | yes |
glass_breakable | no | yes | no |
distance_map | no | no | no |
blend_2lyr | yes | no | no |
rope | no | no | no |
| | | |
draw "exterior" stuff | yes | no | yes |
draw "interior" stuff | yes | yes | no |
----------------------+-----------------------+-------------------+------------------+-
(* required for special mirrors which see the exterior)
// ================================================================================================
*/
#define WATER_REFLECTION_CLIP_IN_PIXEL_SHADER (1 && __PS3) // keep in sync with both common.fxh and water_common.fxh
// consider rename: 'DEFERRED_TECHNIQUES && CUTOUT_OR_SSA_TECHNIQUES' -> DEFERRED_CUTOUT_TECHNIQUES
// consider rename: 'DEFERRED_TECHNIQUES && NON_CUTOUT_DEFERRED_TECHNIQUES' -> DEFERRED_NON_CUTOUT_TECHNIQUES
// consider rename: SHADER_USES_ONLY_BUCKETS_1_AND_3 -> SHADER_USES_ONLY_ALPHA_AND_CUTOUT_BUCKETS
#define CAN_BE_MEGASHADER_SKINNED (1) // TODO -- determine which megashaders actually need skinning, this can only be done by analysing drawables in-game
#define CAN_BE_VEHICLEMOD (1) // TODO -- for now, let's assume all vehicle shaders can be vehiclemods, later we can remove some of these unskinned techniques on 360
#if defined(DECAL_SHADER) // if decal shaders inherit from non-decal shaders, we don't want to inherit their alpha/cutout properties
#ifdef CAN_BE_ALPHA_SHADER
#undef CAN_BE_ALPHA_SHADER
#endif
#ifdef CAN_BE_CUTOUT_SHADER
#undef CAN_BE_CUTOUT_SHADER
#endif
#if defined(ALPHA_SHADER)
#error "ALPHA_SHADER and DECAL_SHADER used together!"
#endif // defined(ALPHA_SHADER)
#if defined(CUTOUT_SHADER)
#error "CUTOUT_SHADER and DECAL_SHADER used together!"
#endif // defined(CUTOUT_SHADER)
#define USE_ALPHACLIP_FADE
#endif // defined(DECAL_SHADER)
#if defined(ALPHA_SHADER) && defined(CUTOUT_SHADER)
#error "ALPHA_SHADER and CUTOUT_SHADER used together!"
#endif
#if defined(ALPHA_SHADER) && defined(CAN_BE_CUTOUT_SHADER)
#error "ALPHA_SHADER and CAN_BE_CUTOUT_SHADER used together!"
#endif
#if defined(CUTOUT_SHADER) && defined(CAN_BE_ALPHA_SHADER)
#error "CUTOUT_SHADER and CAN_BE_ALPHA_SHADER used together!"
#endif
#if defined (USE_ALPHA_SHADOWS)
#define ALPHA_SHADOWS ( __SHADERMODEL >= 40 )
#endif
#if defined(MIRROR_FX) || defined(MIRROR_DECAL_FX)
#define MIRROR_SHADER
#endif // defined(MIRROR_FX) || defined(MIRROR_DECAL_FX)
#if defined(DECAL_SHADER) && !defined(PROJTEX_SHADER) // projtex is a special decal which requires forward techniques
#define STATIC_DECAL_SHADER
#endif // defined(DECAL_SHADER) && !defined(PROJTEX_SHADER)
#if !defined(NO_SKINNING) && !defined(MIRROR_SHADER) && !defined(GRASS_SHADER) && !INSTANCED && !BATCH_INSTANCING
#define DRAWSKINNED_TECHNIQUES (!__PS3 || defined(USE_VEHICLE_INSTANCED_WHEEL_SHADER)) // ps3 uses EDGE, which does the skinning internally; , vehicle_tire always requires both skinned and non-skinned techniques (on both platforms)
#else
#define DRAWSKINNED_TECHNIQUES (0)
#endif
#define NONSKINNED_PED_TECHNIQUES (!DRAWSKINNED_TECHNIQUES || defined(CAN_BE_UNSKINNED_PED_PROP_SHADER)) // all peds are skinned (unless we're using edge)
#define NONSKINNED_VEHICLE_TECHNIQUES (!DRAWSKINNED_TECHNIQUES || (!__PS3 && CAN_BE_VEHICLEMOD) || defined(USE_VEHICLE_INSTANCED_WHEEL_SHADER)) // all vehicles are skinned (unless we're using EDGE, or it's a wheel), , vehicle_tire requires both skinned and non-skinned techniques
#define CUTOUT_OR_SSA_TECHNIQUES (defined(CUTOUT_SHADER) || defined(CAN_BE_CUTOUT_SHADER) || (defined(USE_ALPHACLIP_FADE) && __SHADERMODEL >= 40)) // Use alphaclip for stipple-fading on PC
#define NON_CUTOUT_DEFERRED_TECHNIQUES (!defined(ALPHA_SHADER) && !defined(CUTOUT_SHADER) && !defined(SHADER_USES_ONLY_ALPHA_AND_CUTOUT_BUCKETS))
#if !defined(UNLIT_TECHNIQUES)
#if __PS3
#define UNLIT_TECHNIQUES (defined(VEHICLE_PAINT_1_SHADER)) // don't need unlit techniques, we use shadow techniques for rain collision heightmap
#else
#define UNLIT_TECHNIQUES_FOR_SHADER (defined(__GTA_MEGASHADER_FXH__) || defined(__GTA_TERRAIN_CB_COMMON_FXH__) || defined(VEHICLE_PAINT_SHADER) || defined(VEHICLE_GLASS_SHADER))
#define UNLIT_TECHNIQUES_FOR_TECHNIQUE ((!defined(DECAL_SHADER) && (NON_CUTOUT_DEFERRED_TECHNIQUES || defined(FORCE_RAIN_COLLISION_TECHNIQUE))) || defined(USE_UNLIT_TECHNIQUES))
#define UNLIT_TECHNIQUES (UNLIT_TECHNIQUES_FOR_SHADER && UNLIT_TECHNIQUES_FOR_TECHNIQUE)
#endif
#endif // !defined(UNLIT_TECHNIQUES)
#define FORWARD_TECHNIQUES ((!defined(STATIC_DECAL_SHADER) && !defined(GRASS_SHADER)) || __WIN32PC || RSG_ORBIS)
#define FORWARD_BLEND2LYR_TECHNIQUES (0 && FORWARD_TECHNIQUES) // don't need this (neither for mirror nor water reflection)
#define FORWARD_TERRAIN_TECHNIQUES (1 && FORWARD_TECHNIQUES) // need this to draw terrain in mirrors which can see the exterior
#define FORWARD_TREE_TECHNIQUES (1 && FORWARD_TECHNIQUES) // need this to draw trees in mirrors which can see the exterior
#define FORWARD_VEHICLE_NORMAL_MAPS (defined(ALPHA_SHADER))
#define FORWARD_VEHICLE_DIRT_LAYER (defined(ALPHA_SHADER))
#define FORWARD_PED_NORMAL_MAPS (1)
#define FORWARD_PED_WRINKLE_MAPS (1)
#define CUBEMAP_REFLECTION_TECHNIQUES (!defined(DECAL_SHADER) && !defined(WEAPON_SHADER) && !defined(MIRROR_SHADER) && !defined(USE_CLOTH) && !defined(CUTOUT_SHADER))
#define PUDDLE_TECHNIQUES (!USE_FULLSCREEN_PUDDLE_PASS && !defined(DECAL_SHADER) && !defined(WEAPON_SHADER) && !defined(MIRROR_SHADER) && !defined(USE_CLOTH) && !defined(CUTOUT_SHADER) && !defined(ALPHA_SHADER) && !defined(USE_EMISSIVE) && !defined(SHADER_USES_ONLY_ALPHA_AND_CUTOUT_BUCKETS))
#define TERRAIN_SHADER_WORLD_EYE_POS (__MAX)
#if defined(ALPHA_SHADER)
#if !__LOW_QUALITY
#define USE_FOGRAY_FORWARDPASS
#endif // !__LOW_QUALITY
#define DEFERRED_TECHNIQUES (0)
#define SHADOW_CASTING_TECHNIQUES_OK ((__PS3 && defined(FORCE_RAIN_COLLISION_TECHNIQUE)) || ALPHA_SHADOWS)
#define DIRECTIONAL_LIGHT_FWD_0_LIGHTS (!defined(MIRROR_SHADER)) // alpha shaders need shadows
#define DIRECTIONAL_LIGHT_FWD_4_OR_8_LIGHTS (!defined(MIRROR_SHADER) || defined(USE_UI_TECHNIQUES)) // alpha shaders need shadows
#else
#define DEFERRED_TECHNIQUES (1)
#define SHADOW_CASTING_TECHNIQUES_OK (!defined(DECAL_SHADER) && (__PS3 || defined(CAN_BE_CUTOUT_SHADER) || defined(CUTOUT_SHADER) || defined(USE_CLOTH) || defined(__GTA_VEHICLE_COMMON_FXH__) || defined(__GTA_PED_COMMON_FXH__) || defined(__TREES_COMMON_FXH__) || defined(PRAGMA_CONSTANT_ROPE))) // TODO -- since we use customshadows peds which contain cloth, we can't assume just because it's not PED_CLOTH means we don't need shadow techniques
#define DIRECTIONAL_LIGHT_FOR_NON_ALPHA (defined(__GTA_MEGASHADER_FXH__) || __WIN32PC || RSG_ORBIS) // megashader needs directional light in non-alpha shaders, not sure why pc needs this ..
#define DIRECTIONAL_LIGHT_FWD_0_LIGHTS (defined(CAN_BE_ALPHA_SHADER) || DIRECTIONAL_LIGHT_FOR_NON_ALPHA || defined(USE_UI_TECHNIQUES)) // don't need this (unless we might be an alpha shader), since mirrors don't have shadows yet
#define DIRECTIONAL_LIGHT_FWD_4_OR_8_LIGHTS (defined(CAN_BE_ALPHA_SHADER) || DIRECTIONAL_LIGHT_FOR_NON_ALPHA || defined(USE_UI_TECHNIQUES)) // don't need this (unless we might be an alpha shader), since mirrors don't have shadows yet
#endif
#define WATER_REFLECTION_TECHNIQUES (1 && FORWARD_TECHNIQUES)
#define HIGHQUALITY_FORWARD_TECHNIQUES_ENABLED (1 && FORWARD_TECHNIQUES) // TODO -- replace with "FORWARD_TECHNIQUES" once this system is on
#if defined(USE_UI_TECHNIQUES)
#define UI_TECHNIQUES (1)
#else
#define UI_TECHNIQUES (0)
#endif
#if defined(USE_HIGHQUALITY_FORWARD_TECHNIQUES)
#define HIGHQUALITY_FORWARD_TECHNIQUES (1)
#else
#define HIGHQUALITY_FORWARD_TECHNIQUES (0)
#endif
// can't use these defines directly in code since they have "defined(..)" in them
#if DIRECTIONAL_LIGHT_FWD_0_LIGHTS
#define USE_DIRECTIONAL_LIGHT_FWD_0_LIGHTS (1)
#else
#define USE_DIRECTIONAL_LIGHT_FWD_0_LIGHTS (0)
#endif
#if DIRECTIONAL_LIGHT_FWD_4_OR_8_LIGHTS
#define USE_DIRECTIONAL_LIGHT_FWD_4_OR_8_LIGHTS (1)
#else
#define USE_DIRECTIONAL_LIGHT_FWD_4_OR_8_LIGHTS (0)
#endif
#if DRAWSKINNED_TECHNIQUES
#define DRAWSKINNED_TECHNIQUES_ONLY(x) x
#else
#define DRAWSKINNED_TECHNIQUES_ONLY(x)
#endif
#define NORMALIZE_VS(x) x // i don't think we need to normalise vectors in the vertex shader, right?
#if __WIN32PC || RSG_ORBIS
#define ABS_PC(x) abs(x)
#else
#define ABS_PC(x) x
#endif
//On DX11 specifiying a static const constant puts it into the immediate constant buffer which allows it to be defined in the shader.
#if __SHADERMODEL >= 40 && !RSG_ORBIS
#define IMMEDIATECONSTANT static const
#else
#define IMMEDIATECONSTANT const
#endif
#if (__SHADERMODEL<40)
#define OutFloatColor float4
#define CastOutFloatColor(res) ((res).xxxx)
#else
#define OutFloatColor float
#define CastOutFloatColor(res) (res)
#endif
// ================================================================================================
#define PARTICLE_SHADOWS_SUPPORT (RSG_PC || RSG_DURANGO || RSG_ORBIS)
// Copied from rage_drawbucket.fxh because I couldn't get relative paths to work when common.fxh
// is included for rage and jimmy shaders
#ifndef RAGE_DRAWBUCKET
#if __FXL
#define RAGE_DRAWBUCKET(n) property int __rage_drawbucket = n;
#define RAGE_DRAWBUCKETMASK(n) property int __rage_drawbucketmask = n;
#define RAGE_NAMED_DRAWBUCKET(c) property string drawBucketNamed = c;
#else
#define RAGE_DRAWBUCKET(n)
#define RAGE_DRAWBUCKETMASK(n)
#define RAGE_NAMED_DRAWBUCKET(c)
#endif
#endif
#if (defined USE_SSTAA) && (__SHADERMODEL >=40) && (!__LOW_QUALITY)
#define SSTAA (1)
#define GBUFFER_COVERAGE (1)
#define PS_GBUFFER_COVERAGE ps_5_0
#define ENABLE_TRANSPARENCYAA (gTransparencyAASamples > 0)
#define SSTA_TECHNIQUE(x) SHADER_MODEL_50_OVERRIDE(x)
#else // USE_SSTAA
#define SSTAA (0)
#define GBUFFER_COVERAGE (0)
#define PS_GBUFFER_COVERAGE PIXELSHADER
#define ENABLE_TRANSPARENCYAA (0)
#define SSTA_TECHNIQUE(x) x
#endif // USE_SSTAA
// ----------------------------------------------------------------------------------------------- //
// set it to 1 to compile shaders for 3dsMax's rageviewer (it supports only basic lighting setup)
// (Andrzej was too lazy to setup separate build config for this type of shaders):
#define __WIN32PC_MAX_RAGEVIEWER (0 && __WIN32PC)
// ----------------------------------------------------------------------------------------------- //
#define USE_ANISOTROPIC
// ----------------------------------------------------------------------------------------------- //
#if __MAX
// ----------------------------------------------------------------------------------------------- //
// 3dsMax: "Perspective View" limitations:
#undef __SHADERMODEL
#define __SHADERMODEL 30 //20
#define PIXELSHADER ps_3_0
#define VERTEXSHADER vs_3_0
#undef COLORIZE
#undef USE_ANIMATED_UVS
#define NOINTERPOLATION
// renderstate required for Max shaders:
#define MAX_TOOL_TECHNIQUE_RS CullMode=CW; ShadeMode=Gouraud;
#define MAX_TOOL_TECHNIQUE_RS_CULLNONE CullMode=None; ShadeMode=Gouraud;
// convert Max texcoords into Rage texcoords:
float2 Max2RageTexCoord2(float2 maxTexCoord0)
{
return float2(maxTexCoord0.x, 1.0f-maxTexCoord0.y);
}
float4 Max2RageTexCoord4(float4 maxTexCoord0)
{
return float4(maxTexCoord0.x, 1.0f-maxTexCoord0.y, maxTexCoord0.z, 1.0f-maxTexCoord0.w);
}
// ----------------------------------------------------------------------------------------------- //
#else
// ----------------------------------------------------------------------------------------------- //
float2 Max2RageTexCoord2(float2 maxTexCoord0)
{
return maxTexCoord0;
}
float4 Max2RageTexCoord4(float4 maxTexCoord0)
{
return maxTexCoord0;
}
// ----------------------------------------------------------------------------------------------- //
#endif //__MAX...
// ----------------------------------------------------------------------------------------------- //
#define SKINNING_USE_34 1
// ----------------------------------------------------------------------------------------------- //
#define USE_EDGE __PS3
// ----------------------------------------------------------------------------------------------- //
// also @see rage_atmoscatt_clouds.fx::ps_DpGTAMain
#define PS3_FAKE_ARGB8888_REFLECTION_SCALE (gToneMapScalers.y)
#define PS3_FAKE_ARGB8888_REFLECTION_INV_SCALE (gToneMapScalers.x)
// hack to BS#1552107 - mirror tone map scalar constant is getting corrupted when health pack is visible, but it's always 1 on ps3 anyway
#if __PS3 && defined(MIRROR_FX)
#define PS3_HDR_ARGB8888_SCALE 1
#define PS3_HDR_ARGB8888_INV_SCALE 1
#else
#define PS3_HDR_ARGB8888_SCALE (gHdrScalars.y)
#define PS3_HDR_ARGB8888_INV_SCALE (gHdrScalars.x)
#endif
// ----------------------------------------------------------------------------------------------- //
#define SET_COLOR_WRITE_ENABLE(E0, E1, E2, E3) \
ColorWriteEnable=E0;\
ColorWriteEnable1=E1;\
ColorWriteEnable2=E2;\
ColorWriteEnable3=E3;
#if __MAX
#define NONE 0
#define RED 1
#define GREEN 2
#define BLUE 4
#define ALPHA 8
#endif //__MAX
#if USE_INVERTED_PROJECTION_ONLY
#define FixedupLESS GREATER
#define FixedupLESSEQUAL GREATEREQUAL
#define FixedupGREATER LESS
#define FixedupGREATEREQUAL LESSEQUAL
#else
#define FixedupLESS LESS
#define FixedupLESSEQUAL LESSEQUAL
#define FixedupGREATER GREATER
#define FixedupGREATEREQUAL GREATEREQUAL
#endif
// Common setup for deferredsubsamplewritealpha technique
#define DEFERRED_SUBSAMPLEWRITEALPHA_RENDERSTATES() \
ColorWriteEnable = ALPHA; \
ColorWriteEnable1 = 0; \
ColorWriteEnable2 = 0; \
ColorWriteEnable3 = 0; \
zFunc = FixedupLESS; \
ZWriteEnable = false; \
StencilEnable = false; \
AlphaBlendEnable = false;
#define DEFERRED_SUBSAMPLEWRITEALPHA_RENDERSTATES_TRANSPARENT() \
ColorWriteEnable = ALPHA; \
ColorWriteEnable1 = 0; \
ColorWriteEnable2 = 0; \
ColorWriteEnable3 = 0; \
zFunc = FixedupLESS; \
ZWriteEnable = false; \
StencilEnable = false; \
AlphaBlendEnable = true; \
SEPARATEALPHABLENDENABLE = true; \
BLENDOP = ADD; \
SRCBLEND = ONE; \
DESTBLEND = ZERO; \
BLENDOPALPHA = ADD; \
SRCBLENDALPHA = ONE; \
DESTBLENDALPHA = INVSRCALPHA;
// useful macro to keep certain (usually stripped) vars visible:
#if __WIN32PC || RSG_ORBIS
#define WIN32PC_DONTSTRIP int nostrip=1; // dont strip
#else
#define WIN32PC_DONTSTRIP
#endif
#define USE_UBYTE4 (__PSP2 || __PSSL)
// ----------------------------------------------------------------------------------------------- //
#if USE_UBYTE4
// ----------------------------------------------------------------------------------------------- //
#define index4 int4
// ----------------------------------------------------------------------------------------------- //
#else
// ----------------------------------------------------------------------------------------------- //
#define index4 float4
// ----------------------------------------------------------------------------------------------- //
#endif
// ----------------------------------------------------------------------------------------------- //
// reverts step(b,a) ((a>=b)?1:0) params order to more intuitive form:
#define GtaStep(a, b) step((b), (a))
// ----------------------------------------------------------------------------------------------- //
// materialID stuff (values taken from shaders/ShaderLib.h):
// materialID: bits 0-2:
#define DEFERRED_MATERIAL_DEFAULT 0
#define DEFERRED_MATERIAL_PED 1
#define DEFERRED_MATERIAL_VEHICLE 2
#define DEFERRED_MATERIAL_TREE 3
#define DEFERRED_MATERIAL_TERRAIN 4
// BANK_ONLY
#define DEFERRED_MATERIAL_SELECTED 5 // Selected in picker
#define DEFERRED_MATERIAL_WATER_DEBUG 6 // Water mask
#define DEFERRED_MATERIAL_CLEAR 7
#define DEFERRED_MATERIAL_TYPE_MASK (0x7)
// materialID: bits 3-7:
#define DEFERRED_MATERIAL_INTERIOR 8 // anything can be OR'd with interior material
#define DEFERRED_MATERIAL_SPECIALBIT 16 // general purpose bit for marking pre-pass areas
#define DEFERRED_MATERIAL_SPAREOR1 32
#define DEFERRED_MATERIAL_SPAREOR2 64
#define DEFERRED_MATERIAL_SPAREMASK 96 // DEFERRED_MATERIAL_SPAREOR1 | DEFERRED_MATERIAL_SPAREOR2
#define DEFERRED_MATERIAL_MOTIONBLUR 128 // anything can be OR'd with motion blur flag
// ----------------------------------------------------------------------------------------------- //
#define DEFERRED_MATERIAL_INTERIOR_TERRAIN 12
// ----------------------------------------------------------------------------------------------- //
#define SetGlobalDeferredMaterial(matID) StencilRef=matID; \
StencilEnable=true; \
StencilPass=REPLACE; \
ZFunc=FixedupLESS
// ----------------------------------------------------------------------------------------------- //
#ifdef USE_UMOVEMENTS
#define UMOVEMENTS (1)
#ifdef USE_UMOVEMENTS_INV_BLUE
#define UMOVEMENTS_INV_BLUE (1)
#else
#define UMOVEMENTS_INV_BLUE (0)
#endif
#else
#define UMOVEMENTS (0)
#endif
#ifdef USE_UMOVEMENTS_TEX
#ifdef USE_UMOVEMENTS
#error "USE_UMOVEMENTS and USE_UMOVEMENTS_TEX defined at the same time!"
#endif
#define UMOVEMENTS_TEX (1)
#ifdef USE_UMOVEMENTS_INV_BLUE
#define UMOVEMENTS_INV_BLUE (1)
#else
#define UMOVEMENTS_INV_BLUE (0)
#endif
#else
#define UMOVEMENTS_TEX (0)
#endif
// ----------------------------------------------------------------------------------------------- //
#define dpNearClip (1.0f)
#define dpFarClip (1000.0f)
// ----------------------------------------------------------------------------------------------- //
#define LumFactors float3(0.2125f, 0.7154f, 0.0721f)
// ----------------------------------------------------------------------------------------------- //
#define RAGE_MOTIONBLUR (0)
#define RAGE_VELOCITYBUFFER (RAGE_MOTIONBLUR && __PS3)
#define RAGE_MOTIONBLUR_MRT 1
#define RAGE_ENCODEOPAQUECOLOR (0 && __PS3)
// ----------------------------------------------------------------------------------------------- //
#define RAGE_PREVWORLDVIEWPROJ (RAGE_MOTIONBLUR)
// ----------------------------------------------------------------------------------------------- //
#if RAGE_PREVWORLDVIEWPROJ
#define RAGE_PREVWORLDVIEWPROJ_ONLY(x) x
#else
#define RAGE_PREVWORLDVIEWPROJ_ONLY(x)
#endif // RAGE_PREVWORLDVIEWPROJ
// ----------------------------------------------------------------------------------------------- //
#define RAGE_PREVWORLDVIEWPROJ_REGISTER 214
// ----------------------------------------------------------------------------------------------- //
// cubemap sampling is disabled for now. paraboloid sampling is used instead
#define REFLECTION_CUBEMAP_SAMPLING (0)
// ----------------------------------------------------------------------------------------------- //
// small epsilon value to avoid Nan
#define EPSILON 0.0001f
// =============================================================================================== //
// SAMPLERS
// =============================================================================================== //
// note: diffuseSampler must be always first sampler in any shader (hardcoded Tools/MaxViewport requirement)
#ifdef USE_DIFFUSE_SAMPLER
#include "../../rage/base/src/shaderlib/rage_diffuse_sampler.fxh"
#endif
// Re-enable this if want to use cubemap sampling ... water effect doesn't use cubemap sampling
#if REFLECTION_CUBEMAP_SAMPLING
BeginSharedSampler(sampler, ReflectionTex, ReflectionSampler, ReflectionTex, s1)
ContinueSharedSampler(sampler, ReflectionTex, ReflectionSampler, ReflectionTex, s1)
AddressU = CLAMP;
AddressV = CLAMP;
AddressW = CLAMP;
MINFILTER = LINEAR;
MAGFILTER = LINEAR;
MIPFILTER = LINEAR;
EndSampler;
BeginSharedSampler(samplerCUBE, ReflectionCubeTex, ReflectionCubeSampler, ReflectionCubeTex, s14)
ContinueSharedSampler(samplerCUBE, ReflectionCubeTex, ReflectionCubeSampler, ReflectionCubeTex, s14)
AddressU = WRAP;
AddressV = WRAP;
MIPFILTER = LINEAR;
MINFILTER = LINEAR;
MAGFILTER = LINEAR;
EndSharedSampler;
#else
BeginSharedSampler(sampler, ReflectionTex, ReflectionSampler, ReflectionTex, s1)
ContinueSharedSampler(sampler, ReflectionTex, ReflectionSampler, ReflectionTex, s1)
AddressU = CLAMP;
AddressV = CLAMP;
AddressW = CLAMP;
MINFILTER = HQLINEAR;
MAGFILTER = LINEAR;
MIPFILTER = LINEAR;
EndSampler;
#endif // REFLECTIONS_SAMPLE_CUBEMAP
#if defined(USE_FOGRAY_FORWARDPASS) && !__LOW_QUALITY
BeginSharedSampler(sampler, FogRayTex, FogRaySampler, FogRayTex, s11)
ContinueSharedSampler(sampler, FogRayTex, FogRaySampler, FogRayTex, s11)
AddressU = CLAMP;
AddressV = CLAMP;
AddressW = CLAMP;
MINFILTER = LINEAR;
MAGFILTER = LINEAR;
MIPFILTER = LINEAR;
EndSampler;
#endif
#pragma sampler 2
// =============================================================================================== //
// Samplers
// =============================================================================================== //
// Globals
/// DiffuseSampler s0 common.fxh
/// ReflectionSampler s1 common.fxh
/// unused s2
/// gCSMShadowTextureVSSamp s3 cascadeshadows_receiving.fxh
/// unused s4
/// unused s5
/// unused s6
/// unused s7
/// unused s8
/// unused s9
/// unused s10
/// unused s11
/// SfxWindSampler3D s12 trees_windfuncs.fxh
/// FogRayTex s13 common.fxh
/// StereoParmsTexture s13 rage_samplers.fxh
/// gCSMDitherTextureSamp s14 cascadeshadows_receiving.fxh (not used)
/// gCSMShadowTextureSamp s15 cascadeshadows_receiving.fxh
/// GBUF Pass
/// pedTattooTargetSampler s14 ped_common.fxh
/// pedBloodTargetSampler s15 ped_common.fxh
// Deferred Pass
/// gShadowZSamplerCache s14 localshadowglobals.fxh
/// gShadowZCMSampleCache s15 localshadowglobals.fxh
/// gLocalDitherTexture s1 localshadowglobals.fxh
// Lighting pass
/// ...
// Forward pass
/// ...
// Water pass
/// HeightSampler s0 water_common.fxh
/// ReflectionSampler s1 common.fxh
/// unused s2
/// unused s3
/// unused s4
/// unused s5
/// unused s6
/// unused s7
/// unused s8
/// WetSampler s9 water_common.fxh
/// BumpSampler s10 water_common.fxh
/// RefractionDepthSampler s11 water_common.fxh
/// RefractionSampler s12 water_common.fxh
/// NoiseSampler s13 water_common.fxh
/// DepthSampler s14 water_common.fxh
/// gCSMDitherTextureSamp s14 cascadeshadows_receiving.fxh (not used)
/// LightingSampler s15 water_common.fxh
/// gCSMShadowTextureSamp s15 cascadeshadows_receiving.fxh
// FX Pass
/// ...
/// HUD Pass
/// pedTattooTargetSampler s14 ped_common.fxh
// =============================================================================================== //
// GLOBAL CONSTANT BUFFERS
// =============================================================================================== //
// b0 rage_clipplanes(rage_common.fxh)
// b1 rage_matrices(rage_common.fxh)
// b2 misc_globals(common.fxh)
// b3 lighting_globals(common.fxh), grassglobals(grass.fx)
// b4 rage_bonemtx(rage_common.fxh), matWheelBuffer(vehicle_damage.fxh), cable_locals(cable,fx)
// b5 more_stuff(common.fxh), postfx_cbuffer (postfx.fx), rage_CamMtxBuffer
// b6 csmshader(cascadeshadows_receiving.fxh), warpshadow(localshadowglobals.fxh), rage_ShadowSphereBuffer
// b7 vehicle_globals(vehicle_damage.fxh), rage_SoftParticleBuffer, wave_globals, rage_ShadowConstBuffer1
// b8 vehicle_tyredeformation(vehicle_damage.fxh), (DEBUG) playercolenabled_buffer (trees_common.fxh) (DEBUG)
// b9 glass_breakable_locals
// b10 terrain_globals (terrain_cb_tessellation_funcs.fxh)
// b11 pedcloth (ped_common.fxh) (__WIN32PC) tri_uMovment_and_branch_bend_shared (trees_windfuncs.fxh)
// Locals get allocated registers from 13 backwards so try to avoid filling this up too much.
// =============================================================================================== //
// CONSTANT REGISTERS
// =============================================================================================== //
/// gAllGlobals[64] REGISTER( c0); // rage_common.fxh
// Transforms
/// gWorld REGISTER( c0); // rage_common.fxh
/// gWorld REGISTER( c1); // rage_common.fxh
/// gWorld REGISTER( c2); // rage_common.fxh
/// gWorld REGISTER( c3); // rage_common.fxh
/// gWorldView REGISTER( c4); // rage_common.fxh
/// gWorldView REGISTER( c5); // rage_common.fxh
/// gWorldView REGISTER( c6); // rage_common.fxh
/// gWorldView REGISTER( c7); // rage_common.fxh
/// gWorldViewProj REGISTER( c8); // rage_common.fxh
/// gWorldViewProj REGISTER( c9); // rage_common.fxh
/// gWorldViewProj REGISTER( c10); // rage_common.fxh
/// gWorldViewProj REGISTER( c11); // rage_common.fxh
/// gViewInverse REGISTER( c12); // rage_common.fxh
/// gViewInverse REGISTER( c13); // rage_common.fxh
/// gViewInverse REGISTER( c14); // rage_common.fxh
/// gViewInverse REGISTER( c15); // rage_common.fxh
CBSHARED BeginConstantBufferPagedDX10(misc_globals, b2)
// Misc
#if RSG_PC || __SHADERMODEL >= 40 || __MAX
shared float4 globalFade : globalFade;
//#if __SHADERMODEL >= 40
//// x = WheelTessellation, y = tree tesselation, z = Tree PN triangle control point K.
//shared float4 gTessellationGlobal1 : gTessellationGlobal1;
//#endif
//global scaler for the POM / displacement
shared float globalHeightScale : globalHeightScale = 1.0f;
#if RSG_PC && (__SHADERMODEL >= 40)
shared float globalShaderQuality: GlobalShaderQuality < int nostrip=1;> = 2.0; // CSettingsManager::GetInstance().GetSettings().m_graphics.m_ShaderQuality: 0-3 (low,med,high,ultra)
shared float globalReuseMe00001 : GlobalReuseMe00001 < int nostrip=1; > = 0.0f;
shared float globalReuseMe00002 : GlobalReuseMe00002 < int nostrip=1; > = 0.0f;
#endif // RSG_PC && __SHADERMODEL >= 40...
#endif
#if __SHADERMODEL >= 40 && !__LOW_QUALITY && (!SHADER_FINAL || RSG_PC)
shared float4 POMFlags : POMFlags;
#define POMDisable (POMFlags.x == 1.0f)
#else
#define POMDisable (false)
#endif
#if __SHADERMODEL >= 40 && !SHADER_FINAL && !__LOW_QUALITY
#define POMEdgeVisualiser (POMFlags.y == 1.0f)
#define POMDistanceBasedStep (POMFlags.z == 1.0f)
#define POMDistanceDebug (POMFlags.w == 1.0f)
shared float4 POMValues : POMValues;
#define POMMinSteps (POMValues.z)
#define POMMaxSteps (POMValues.w)
#define POMDistanceStart (POMValues.x);
#define POMDistanceEnd (POMValues.y);
shared float4 POMValues2 : POMValues2;
#define POMForwardFadeOffset (POMValues2.x)
#define POMReduceSamples (POMValues2.y == 1.0f)
#define POMVDotNBlendFactor (0.25f)
#else
#define POMEdgeVisualiser (false)
#define POMDistanceBasedStep (true)
#define POMDistanceDebug (false)
#define POMMinSteps (3)
#define POMMaxSteps (27)
#define POMDistanceStart (0.0)
#define POMDistanceEnd (20.0)
#define POMForwardFadeOffset (8.0f)
#define POMVDotNBlendFactor (0.25f)
#endif
#if !SHADER_FINAL
shared float4 TerrainTintBlendValues : TerrainTinBlendValues;
#define TerrainTintNear (TerrainTintBlendValues.x)
#define TerrainTintFar (TerrainTintBlendValues.y)
#else
#define TerrainTintNear (70.0f)
#define TerrainTintFar (90.0f)
#endif
#include "../../rage/base/src/shaderlib/rage_pntriangles_globalvars.fxh"
shared float4 globalScalars : globalScalars REGISTER( c16) = float4(1.0f, 1.0f, 1.0f, 1.0f);
#if __MAX
#define globalAlpha 1.0f
#define gArtificialAmbientScale 1.0f
#define gNaturalAmbientScale 1.0f
#define gEmissiveScale 1.0f
#else
#define globalAlpha float(globalScalars.x)
#define gArtificialAmbientScale float(globalScalars.y)
#define gNaturalAmbientScale float(globalScalars.z)
#define gEmissiveScale float(globalScalars.w)
#endif
shared float4 globalScalars2 : globalScalars2 REGISTER( c17) = float4(1.0f, 0.0f, 0.0f, 1.0f);
#define gUmGlobalTimer float(globalScalars2.x)
#if __MAX
#define gDayNightEffects 1.0f
#define gDayNightEffectsVertexScale 1.0f
#else
#define gDayNightEffects float(globalScalars2.y)
#define gDayNightEffectsVertexScale (1.0f - step(float(globalScalars2.y), 0.0f))
#endif
#define gInInterior float(globalScalars2.z)
#define gPedRimLightingScale float(globalScalars2.w)
// also used for Thermal/SeeThrough
#define gFadeStartDistance float(globalScalars2.x)
#define gFadeEndDistance float(globalScalars2.y)
#define gMaxThickness float(globalScalars2.z)
shared float4 globalScalars3 : globalScalars3 REGISTER( c18) = float4(16.0f, 1.0f/16.0f, 0.0f, 0.0f);
#if __MAX
#define gToneMapScalers float2(1.0f, 1.0f)
#define gHdrScalars float2(1.0f, 1.0f)
#else
#define gToneMapScalers float2(globalScalars3.xy)
#define gHdrScalars float2(globalScalars3.zw)
#endif
shared float4 globalScreenSize REGISTER( c19) = float4(1.0f, 1.0f, 1.0f, 1.0f);
#define gScreenSize float4(globalScreenSize.x, globalScreenSize.y, 0.0f, 0.0f) // this less so, specialise
#define gooScreenSize float4(globalScreenSize.z, globalScreenSize.w, 0.0f, 0.0f) // this is required by alot of stuff
// ----------------------------------------------------------------------------------------------- //
#define SCR_BUFFER_WIDTH (gScreenSize.x)
#define SCR_BUFFER_HEIGHT (gScreenSize.y)
#if __SHADERMODEL >= 40
shared uint4 gTargetAAParams : gTargetAAParams < int nostrip = 1; > = 0;
#define gMSAANumSamples (gTargetAAParams.x)
# if ENABLE_EQAA
# define gMSAANumFragments (gTargetAAParams.y)
# define gMSAAFmaskEnabled (gTargetAAParams.z)
# define gMSAAFmaskShift (gTargetAAParams.z)
# define gMSAAFmaskShiftExt (gTargetAAParams.w)
# define translateAASample(fmask,sampleId) ((fmask)>>((sampleId)*gMSAAFmaskShift)) & ((1<<gMSAAFmaskShift)-1)
# define translateAASampleExt(fmask,sampleId) ((fmask)>>((sampleId)*gMSAAFmaskShiftExt)) & ((1<<gMSAAFmaskShiftExt)-1)
# endif // ENABLE_EQAA
//shared float2 gMSAALocations[16] : gMSAALocations < int nostrip = 1; >;
#endif //__SHADERMODEL >= 40
shared float4 colorize : Colorize REGISTER( c20) = float4(1.0f, 1.0f, 1.0f, 1.0f);
#if PARTICLE_SHADOWS_SUPPORT || (__SHADERMODEL >= 40)
shared float4 gGlobalParticleShadowBias : gGlobalParticleShadowBias;
#define gGlobalPtfxShadowSlopeBias gGlobalParticleShadowBias.x
#define gGlobalPtfxShadowDepthBiasRange gGlobalParticleShadowBias.y
#define gGlobalPtfxShadowDepthBiasRangeFalloff gGlobalParticleShadowBias.z
#define gGlobalPtfxShadowDepthBiasRangeDivision gGlobalParticleShadowBias.w //(1.0/range+falloff)
#else
#define gGlobalPtfxShadowSlopeBias (0)
#define gGlobalPtfxShadowDepthBiasRange (0)
#define gGlobalPtfxShadowDepthBiasRangeFalloff (0)
#define gGlobalPtfxShadowDepthBiasRangeDivision (1.0f)
#endif
#if PTFX_APPLY_DOF_TO_PARTICLES
shared float gGlobalParticleDofAlphaScale : gGlobalParticleDofAlphaScale;
#endif //PTFX_APPLY_DOF_TO_PARTICLES
#if (__SHADERMODEL >= 40)
shared float gGlobalFogIntensity : gGlobalFogIntensity;
shared float4 gPlayerLFootPos : gPlayerLFootPos < int nostrip=1; > = float4(0,0,0,0);
shared float4 gPlayerRFootPos : gPlayerRFootPos < int nostrip=1; > = float4(0,0,0,0);
#else
#define gGlobalFogIntensity (1.0)
#endif
#ifdef NVSTEREO
// used for nv stereo detection
shared float4 gStereoParams : gStereoParams;
#define gMinimapRendering gStereoParams.x
#define gStereorizeHud gStereoParams.y
#define gStereoPuddle gStereoParams.z
#define gStereorizeReticule gStereoParams.w
#define gStereoPhone gStereoParams.z
shared float4 gStereoParams1 : gStereoParams1 = float4(1,1,1,1);
#define gWWheelDepthScale gStereoParams1.x;
#endif
EndConstantBufferDX10(misc_globals)
CBSHARED BeginConstantBufferPagedDX10(lighting_globals, b3)
// Lighting VS
shared float4 gDirectionalLight REGISTER( c21); // x,y,z, intensity multiplier.
shared float4 gDirectionalColour REGISTER( c22); // r,g,b, intensity
// Because we suck
#if __SHADERMODEL >= 40
SHARED int gNumForwardLights = 8;
shared float4 gLightPositionAndInvDistSqr[8];
shared float4 gLightDirectionAndFalloffExponent[8];
shared float4 gLightColourAndCapsuleExtent[8];
shared float gLightConeScale[8];
shared float gLightConeOffset[8];
#else // WIN32 3.0
shared float4 gLight0PosX REGISTER( c23);
shared float4 gLight0PosY REGISTER( c24);
shared float4 gLight0PosZ REGISTER( c25);
shared float4 gLight0DirX REGISTER( c26);
shared float4 gLight0DirY REGISTER( c27);
shared float4 gLight0DirZ REGISTER( c28);
shared float4 gLight0InvDistSqr REGISTER( c29);
shared float4 gLight0ConeScale REGISTER( c30);
shared float4 gLight0ConeOffset REGISTER( c31);
shared float4 gLight0ColR REGISTER( c32);
shared float4 gLight0ColG REGISTER( c33);
shared float4 gLight0ColB REGISTER( c34);
shared float4 gLight0FalloffExponent REGISTER( c35) = float4(0.0f, 0.0f, 0.0f, 0.0f);
shared float4 gLight0CapsuleExtent REGISTER( c36) = float4(0.0f, 0.0f, 0.0f, 0.0f);
#endif
shared float4 gLightNaturalAmbient0 REGISTER( c37) < string UIWidget = "Natural Ambient 0"; string Space = "material"; > = { 0.0f, 0.0f, 0.0f, 1.0f };
shared float4 gLightNaturalAmbient1 REGISTER( c38) < string UIWidget = "Natural Ambient 1"; string Space = "material"; > = { 0.0f, 0.0f, 0.0f, 1.0f };
shared float4 gLightArtificialIntAmbient0 REGISTER( c39) < string UIWidget = "Artificial Interior Ambient 0"; string Space = "material"; > = {0.0f, 0.0f, 0.0f, 1.0f};
shared float4 gLightArtificialIntAmbient1 REGISTER( c40) < string UIWidget = "Artificial Interior Ambient 1"; string Space = "material"; > = {0.0f, 0.0f, 0.0f, 1.0f};
shared float4 gLightArtificialExtAmbient0 REGISTER( c41) < string UIWidget = "Artificial Exterior Ambient 0"; string Space = "material"; > = {0.0f, 0.0f, 0.0f, 1.0f};
shared float4 gLightArtificialExtAmbient1 REGISTER( c42) < string UIWidget = "Artificial Exterior Ambient 1"; string Space = "material"; > = {0.0f, 0.0f, 0.0f, 1.0f}; // move to VS
#define ambientDownWrap float(gLightNaturalAmbient0.w)
#define ooOnePlusAmbientDownWrap float(gLightNaturalAmbient1.w)
#define naturalAmbientPush float(gLightArtificialIntAmbient0.w)
#define directionalAmbientDirection float3(gLightArtificialIntAmbient1.w, gLightArtificialExtAmbient0.w, gLightArtificialExtAmbient1.w)
shared float4 gDirectionalAmbientColour REGISTER( c43) = float4(0.0, 0.0, 0.0, 0.0);
#define gBakeAdjust float(gDirectionalAmbientColour.w)
// Fog
shared float4 globalFogParams[5] REGISTER( c44); // x, y, z, facing backwards flag
/// REGISTER( c45); // x, y, z, w
/// REGISTER( c46); // x, y, z, free
/// REGISTER( c47); // x, y, z, free
/// REGISTER( c48); // x, y, z, free
shared float4 globalFogColor REGISTER( c49) = float4(1.0f, 1.0f, 1.0f, 1.0f);
shared float4 globalFogColorE REGISTER( c50) = float4(1.0f, 1.0f, 1.0f, 1.0f);
shared float4 globalFogColorN REGISTER( c51) = float4(1.0f, 1.0f, 1.0f, 1.0f);
shared float4 globalFogColorMoon REGISTER( c52) = float4(1.0f, 1.0f, 1.0f, 1.0f);
// ----------------------------------------------------------------------------------------------- //
shared float4 gReflectionTweaks REGISTER( c53) = float4(1.0f, 1.0f, 1.0f, 1.0f);
#define gReflectionTweaksCameraDir (gReflectionTweaks.xyz)
#define gReflectionTweakEmissive (gReflectionTweaks.w)
#define gReflectionTweakDirectional (gDirectionalLight.w)
// ----------------------------------------------------------------------------------------------- //
/// gCSMShaderVars_shared REGISTER( c51);
/// gCSMShaderVars_shared REGISTER( c51);
/// gCSMShaderVars_shared REGISTER( c52);
/// gCSMShaderVars_shared REGISTER( c53);
/// gCSMShaderVars_shared REGISTER( c54);
/// gCSMShaderVars_shared REGISTER( c55);
/// gCSMShaderVars_shared REGISTER( c56);
/// gCSMShaderVars_shared REGISTER( c57);
/// gCSMShaderVars_shared REGISTER( c58);
/// gCSMShaderVars_shared REGISTER( c59);
/// gCSMShaderVars_shared REGISTER( c60);
/// gCSMShaderVars_shared REGISTER( c61);
#if LINEAR_PIECEWISE_FOG
shared float4 linearPiecewiseFogParams[LINEAR_PIECEWISE_FOG_NUM_SHADER_VARIABLES] REGISTER( c54);
#endif // LINEAR_PIECEWISE_FOG
// NOTE: If this changes please change rage_fastmipmap.fx so it doesn't nuke our globals
EndConstantBufferDX10(lighting_globals)
#define globalFogColorSun globalFogColor.rgb
#define globalFogColorAtmophere globalFogColorE.rgb
#define globalFogColorGround globalFogColorN.rgb
#define globalFogColorHaze float3( globalFogColor.a, globalFogColorE.a, globalFogColorN.a)
#define globalFogColorMoon globalFogColorMoon.rgb
#define globalFogNearDist globalFogParams[0].x
#define globalFogFarClip globalFogParams[0].y
#define globalFogNearDepth globalFogParams[0].z // depth of the blit in screen space.
#define globalDoubleSidedRendering globalFogParams[0].w
#define globalFogHazeDensity globalFogParams[1].x // Exponential far fog (haze) density factor (prenegated)
#define globalFogHazeAlpha globalFogParams[1].y // alpha for far fog (haze)
#define globalHorizonTintScale globalFogParams[1].z // home much we blend from the ground fog color to the east/west haze color
#define globalGroundFogDensityAtViewer globalFogParams[1].w // precacluated constant in code to save a exp() in the pixel shader (premultiplied by -globalGroundFogDensity)
#define globalFogHazeStart globalFogParams[2].x // haze start distance
#define globalGroundFogAlpha globalFogParams[2].y // alpha for near fog (ground fog)
#define globalGroundFogHeightFalloff globalFogParams[2].z // near (ground) fog height fall off factor
#define globalFogHazeAtFarClip globalFogParams[2].w // precalculated fog at far clip scale
#define globalFogSunSpriteDirection globalFogParams[3].xyz // Use sun sprite direction instead of global light direction.
#define globalFogSunLightingCalcPower globalFogParams[3].w
#define globalFogMoonSpriteDirection globalFogParams[4].xyz // We also now apply a moon glow!
#define globalFogMoonLightingCalcPower globalFogParams[4].w
#define gInvColorExpBias (1.0f)
/// gBoneMtx[48] REGISTER2(vs, c64); // rage_common.fxh, 32 on PC
// Now override skinning matrices as ps only
//Overloaded shader register for Entity Selection
CBSHARED BeginConstantBufferPagedDX10(more_stuff, b5)
shared float4 gEntitySelectColor[ENTITYSELECT_NO_OF_PLANES] : EntitySelectColor REGISTER2(ps, c64) = { float4(1.0f, 1.0f, 1.0f, 1.0f), float4(1.0f, 1.0f, 1.0f, 1.0f)};
#if __SHADERMODEL < 40
// Lighting PS
shared float4 gLight1PosX REGISTER2(ps, c64);
shared float4 gLight1PosY REGISTER2(ps, c65);
shared float4 gLight1PosZ REGISTER2(ps, c66);
shared float4 gLight1DirX REGISTER2(ps, c67);
shared float4 gLight1DirY REGISTER2(ps, c68);
shared float4 gLight1DirZ REGISTER2(ps, c69);
shared float4 gLight1InvDistSqr REGISTER2(ps, c70);
shared float4 gLight1ConeScale REGISTER2(ps, c71);
shared float4 gLight1ConeOffset REGISTER2(ps, c72);
shared float4 gLight1ColR REGISTER2(ps, c73);
shared float4 gLight1ColG REGISTER2(ps, c74);
shared float4 gLight1ColB REGISTER2(ps, c75);
shared float4 gLight1FalloffExponent REGISTER2(ps, c76) = float4(0.0f, 0.0f, 0.0f, 0.0f);
shared float4 gLight1CapsuleExtent REGISTER2(ps, c77) = float4(0.0f, 0.0f, 0.0f, 0.0f);
#endif
/// Unused REGISTER2(ps, c78);
shared float4 gAmbientOcclusionEffect : globalAOEffectScale REGISTER2(ps, c79) = float4(1.0f, 1.0f, 1.0f, 1.0f); // Global, Ped, Veh, SSAO
shared float4 gDynamicBakesAndWetness REGISTER2(ps, c80);
#define gDynamicBakeStart (gDynamicBakesAndWetness.x)
#define gDynamicBakeRange (gDynamicBakesAndWetness.y)
#define gWetnessBlend (gDynamicBakesAndWetness.z)
// Alpha Ref
#if 1
// AlphaRefs constants:
shared float4 gAlphaRefVec0 : alphaRefVec0 REGISTER2(ps, c81) = float4(0.0f, 0.0f, 0.0f, 0.0f);
shared float4 gAlphaRefVec1 : alphaRefVec1 REGISTER2(ps, c82) = float4(0.0f, 0.0f, 0.0f, 0.0f);
#define global_alphaRef (gAlphaRefVec0.x)
// #define ped_alphaRef (gAlphaRefVec0.y)
// #define ped_longhair_alphaRef (gAlphaRefVec0.z)
#define ped_alphaRef (128.f/255.0f)
#define ped_longhair_alphaRef (128.f/255.0f)
//#define foliage_alphaRef (gAlphaRefVec0.w)
//#define foliageImposter_alphaRef (gAlphaRefVec1.x)
//#define billboard_alphaRef (gAlphaRefVec1.y)
//#define shadowBillboard_alphaRef (gAlphaRefVec1.z)
#define grass_alphaRef (gAlphaRefVec1.w)
//#define global_alphaRef (90.0f/255.0f)
//#define ped_alphaRef (1.0f/255.0f)
//#define ped_longhair_alphaRef (128.0f/255.0f)
//#define foliage_alphaRef (90.0f/255.0f)
//#define foliageImposter_alphaRef (88.0f/255.0f)
//#define billboard_alphaRef (148.0f/255.0f)
//#define shadowBillboard_alphaRef (88.0f/255.0f)
//#define grass_alphaRef (32.0f/255.0f)
#define vehicle_alphaRef (1.0f/255.0f)
#else
#define grass_alphaRef (32.0f/255.0f)
//#define foliage_alphaRef (90.0f/255.0f)
#define ped_alphaRef (90.0f/255.0f)
#define ped_longhair_alphaRef (90.0f/255.0f)
#define vehicle_alphaRef (90.0f/255.0f)
#define global_alphaRef (90.0f/255.0f)
#endif
//No alpha test on DX11.
#if __SHADERMODEL >= 40
shared float gAlphaTestRef : alphaTestRef REGISTER2(ps, c83) = 0.0f;
#endif
#if __SHADERMODEL >= 40
shared bool gTreesUseDiscard : gTreesUseDiscard REGISTER2(ps, c84) = true;
shared float gReflectionMipCount : gReflectionMipCount REGISTER2(ps, c85) = 4.0f;
shared float gTransparencyAASamples : gTransparencyAASamples REGISTER2(ps, c86) = true;
shared bool gUseFogRay : gUseFogRay REGISTER2(ps, c87) = true;
#else
#define gUseFogRay (false)
#endif
EndConstantBufferDX10(more_stuff)
// Reserve register slots that are used as globals in ped shaders
#ifndef IS_PED_SHADER
#if __XENON || __PS3 // No need to reserve slots for platforms that use constant buffers
float4 RESERVE_VS_CONST_c253 REGISTER2(vs, c253) <int nostrip=1;>; // Reserve slot for: matWetClothesData
float4 RESERVE_VS_CONST_c254 REGISTER2(vs, c254) <int nostrip=1;>; // Reserve slot for: umPedGlobalOverrideParams
float4 RESERVE_VS_CONST_c255 REGISTER2(vs, c255) <int nostrip=1;>; // Reserve slot for: envEffFatSweatScale
#endif // __XENON || __PS3
#endif // IS_PED_SHADER
/// See rage_softparticles.fxh REGISTER( c128);
/// See rage_softparticles.fxh REGISTER2(ps, c129);
/// Skining matrices REGISTER2(vs, ...);
/// Skining matrices REGISTER2(vs, c208); // till 160 on pc
// ----------------------------------------------------------------------------------------------- //
#ifdef USE_PALETTE_TINT
#define PALETTE_TINT (1 && !__MAX)
#define PALETTE_TINT_MAX (__MAX)
#else
#define PALETTE_TINT (0)
#define PALETTE_TINT_MAX (0)
#endif
#define PALETTE_TINT_EDGE (PALETTE_TINT && __PS3)
#define PALETTE_TINT_WATER_REFLECTION (PALETTE_TINT && 0)
#define PALETTE_TINT_WATER_REFLECTION_EDGE (PALETTE_TINT_WATER_REFLECTION && __PS3)
// ----------------------------------------------------------------------------------------------- //
#if defined(USE_WRINKLE_MAP) && defined(USE_NORMAL_MAP)
#define WRINKLE_MAP (1)
#else
#define WRINKLE_MAP (0)
#endif
// ----------------------------------------------------------------------------------------------- //
// WIN32PC: it doesn't matter at runtime, but helps dx9's fxc not to fail
#if __WIN32PC || RSG_ORBIS
#if defined(PRAGMA_CONSTANT_ROPE)
#pragma constant 185
#elif defined(PRAGMA_CONSTANT_TREE)
#pragma constant 156
#else
#pragma constant 160
#endif
#else
#if defined(PRAGMA_CONSTANT_ROPE)
#pragma constant 241
#elif defined(PRAGMA_CONSTANT_TREE)
#pragma constant 212
#else
#pragma constant 216
#endif
#endif
BeginConstantBufferDX10( common_locals )
#ifdef USE_ANIMATED_UVS
// uvAnimation variables (changed by runtime code):
float3 globalAnimUV0 = float3(1, 0, 0);
float3 globalAnimUV1 = float3(0, 1, 0);
#endif //USE_ANIMATED_UVS
#if UMOVEMENTS || UMOVEMENTS_TEX
// micro-movement params: [globalScaleH | globalScaleV | globalArgFreqH | globalArgFreqV ]
float4 umGlobalParams : umGlobalParams0
<
string UIWidget = "slider";
string UIName = "Global umParams: ScaleH/ScaleV/FreqH/FreqV";
float UIMin = 0.0;
float UIMax = 15.0;
float UIStep = 0.001;
> = float4(0.025f, 0.025f, 1.000f, 1.000f);
float4 umGlobalOverrideParams : umGlobalOverrideParams0 = float4(1.0f, 1.0f, 1.0f, 1.0f);
#endif //UMOVEMENTS || UMOVEMENTS_TEX...
// ----------------------------------------------------------------------------------------------- //
#if PALETTE_TINT || PALETTE_TINT_MAX
float2 tintPaletteSelector : TintPaletteSelector
<
string UIName = "Tint Palette Selector";
float UIMin = 0.0;
float UIMax = 7.0;
float UIStep = 1.0;
int nostrip=1; // dont strip
> = float2(0.0f, 0.0f); // x=paletteSelector, y=heightOfLine (360 only)
#endif //PALETTE_TINT || PALETTE_TINT_MAX
#if WRINKLE_MAP
float4 wrinkleMaskStrengths0 : WrinkleMaskStrengths0
<
string UIWidget = "slider";
int nostrip=1;
float UIMin = 0.0;
float UIMax = 2.0;
float UIStep = .01;
string UIName = "wrinkle str0";
> = { 0.0, 0.0, 0.0, 0.0};
// ----------------------------------------------------------------------------------------------- //
float4 wrinkleMaskStrengths1 : WrinkleMaskStrengths1
<
string UIWidget = "slider";
int nostrip=1;
float UIMin = 0.0;
float UIMax = 2.0;
float UIStep = .01;
string UIName = "wrinkle str1";
> = { 0.0, 0.0, 0.0, 0.0};
// ----------------------------------------------------------------------------------------------- //
float4 wrinkleMaskStrengths2 : WrinkleMaskStrengths2
<
string UIWidget = "slider";
int nostrip=1;
float UIMin = 0.0;
float UIMax = 2.0;
float UIStep = .01;
string UIName = "wrinkle str2";
> = { 0.0, 0.0, 0.0, 0.0};
// ----------------------------------------------------------------------------------------------- //
float4 wrinkleMaskStrengths3 : WrinkleMaskStrengths3
<
string UIWidget = "slider";
int nostrip=1;
float UIMin = 0.0;
float UIMax = 2.0;
float UIStep = .01;
string UIName = "wrinkle str3";
> = { 0.0, 0.0, 0.0, 0.0};
#endif //WRINKLE_MAP
EndConstantBufferDX10( common_locals )
// =============================================================================================== //
// FUNCTIONS
// =============================================================================================== //
half2 CalculateBakeAdjust(half3 surfaceToEye, half2 currentBakes)
{
#if !defined(VFX_DECAL) && !defined(DECAL_DIRT) && !defined(PROJTEX_SHADER) && !__MAX && !GLASS_LIGHTING
half distSqr = dot(surfaceToEye, surfaceToEye);
half blend = saturate(distSqr / (500.0f * 500.0f));
return saturate(currentBakes * lerp(1.0f, gBakeAdjust, saturate(float2(blend, 1.0 - blend) - gInInterior.xx)));
#else
return saturate(currentBakes);
#endif
}
half ArtificialBakeAdjustMult()
{
return saturate(gBakeAdjust + gInInterior);
}
// ----------------------------------------------------------------------------------------------- //
float __powapprox(float a, float b) { return a / ((1 - b) * a + b); }
float2 __powapprox(float2 a, float2 b) { return a / ((1 - b) * a + b); }
float3 __powapprox(float3 a, float3 b) { return a / ((1 - b) * a + b); }
float4 __powapprox(float4 a, float4 b) { return a / ((1 - b) * a + b); }
float __powapproxinv(float a, float b) { return a * b / ((b - 1) * a + 1); }
float2 __powapproxinv(float2 a, float2 b) { return a * b / ((b - 1) * a + 1); }
float3 __powapproxinv(float3 a, float3 b) { return a * b / ((b - 1) * a + 1); }
float4 __powapproxinv(float4 a, float4 b) { return a * b / ((b - 1) * a + 1); }
float __sinapprox_REFERENCE(float x) // accurate to within 0.056 - may be slower in shaders, but should be much faster on CPU
{
const float t = x/(2.0*PI);
const float a = 1 - 2*frac(t);
const float b = 1 - abs(a);
const float y = 4*a*b;
return y;
}
void __sincosapprox_REFERENCE(float x, out float s, out float c)
{
const float2 t = x.xx/(2.0*PI) + float2(0, 0.25);
const float2 a = 1 - 2*frac(t);
const float2 b = 1 - abs(a);
const float2 y = 4*a*b;
s = y.x;
c = y.y;
}
// ----------------------------------------------------------------------------------------------- //
half3 sRGBtoLinear(half3 sRGB)
{
half3 linearColor;
//linearColor = (sRGB <= 0.04045) ? sRGB / 12.92f : pow((sRGB + 0.055) / (1.0 + 0.055), 2.4);
linearColor.r = (sRGB.r <= 0.04045) ? sRGB.r / 12.92f : pow((sRGB.r + 0.055) / (1.0 + 0.055), 2.4);
linearColor.g = (sRGB.g <= 0.04045) ? sRGB.g / 12.92f : pow((sRGB.g + 0.055) / (1.0 + 0.055), 2.4);
linearColor.b = (sRGB.b <= 0.04045) ? sRGB.b / 12.92f : pow((sRGB.b + 0.055) / (1.0 + 0.055), 2.4);
return linearColor;
}
half3 linearToSRGB(half3 linearColor)
{
half3 srgb;
//srgb = (linearColor <= 0.0031308) ? linearColor * 12.92f : (1.0 + 0.055) * pow(linearColor, 1.0/2.4) - 0.055;
srgb.r = (linearColor.r <= 0.0031308) ? linearColor.r * 12.92f : (1.0 + 0.055) * pow(linearColor.r, 1.0/2.4) - 0.055;
srgb.g = (linearColor.g <= 0.0031308) ? linearColor.g * 12.92f : (1.0 + 0.055) * pow(linearColor.g, 1.0/2.4) - 0.055;
srgb.b = (linearColor.b <= 0.0031308) ? linearColor.b * 12.92f : (1.0 + 0.055) * pow(linearColor.b, 1.0/2.4) - 0.055;
return srgb;
}
half3 sRGBtoLinearCheap(half3 sRGB)
{
half3 linearColor;
linearColor = sRGB * sRGB;//pow(sRGB, 2.0f);
return linearColor;
}
half3 linearToSRGBCheap(half3 linearColor)
{
half3 srgb;
srgb = sqrt(linearColor);//pow(linearColor, 0.5f);
return srgb;
}
// ----------------------------------------------------------------------------------------------- //
#if __PS3
//
// PS3 specifics for storing pixels in G16R16f surface:
// for reading: texture format is Y16X16_FLOAT
// for writing: surface format is A8B8G8R8:
//
half4 PackG16R16f(float2 _val)
{
half2 val = half2(_val.xy);
float temp = pack_2half(val.xy);
half4 ret = unpack_4ubyte(temp);
return(ret.xyzw);
}
#else
half4 PackG16R16f(float2 val)
{
return half4(val.xyxy);
}
#endif
// ----------------------------------------------------------------------------------------------- //
half3 PackColor_3h(float3 color)
{
#if (__PS3 || __XENON || RSG_ORBIS) // TODO - Move PC to same color range
return color.rgb * PS3_FAKE_ARGB8888_REFLECTION_INV_SCALE;
#else // (1 == __PS3)
return color;
#endif // (1 == __PS3)
}
// ----------------------------------------------------------------------------------------------- //
half4 PackColor(half4 color)
{
half3 outColor = PackColor_3h(color.rgb);
return half4(outColor.rgb, color.a);
}
// ----------------------------------------------------------------------------------------------- //
half3 UnpackColor_3h(half3 color)
{
#if (__PS3 || __XENON || RSG_ORBIS) // TODO - Move PC to same color range
return color.rgb * PS3_FAKE_ARGB8888_REFLECTION_SCALE;
#else // (1 == __PS3)
return color;
#endif // (1 == __PS3)
}
// ----------------------------------------------------------------------------------------------- //
half4 UnpackColor(half4 color)
{
half3 outColor = UnpackColor_3h(color.rgb);
return half4(outColor.rgb, color.a);
}
// ----------------------------------------------------------------------------------------------- //
half3 PackHdr_3h(half3 color)
{
return color.rgb * PS3_HDR_ARGB8888_INV_SCALE;
}
// ----------------------------------------------------------------------------------------------- //
half4 PackHdr(half4 color)
{
half3 outColor = PackHdr_3h(color.rgb);
return half4(outColor.rgb, color.a);
}
// ----------------------------------------------------------------------------------------------- //
half3 UnpackHdr_3h(half3 color)
{
return color.rgb * PS3_HDR_ARGB8888_SCALE;
}
// ----------------------------------------------------------------------------------------------- //
half4 UnpackHdr(half4 color)
{
half3 outColor = UnpackHdr_3h(color.rgb);
return half4(outColor.rgb, color.a);
}
// ----------------------------------------------------------------------------------------------- //
#if __SHADERMODEL >= 40
uint GetNumCoverageSamples()
{
#if ENABLE_EQAA
return gMSAANumFragments;
#else
return gMSAANumSamples;
#endif
}
uint ConvertAlphaToCoverage(float alpha)
{
//Using table from ShaderLib.cpp.
const uint ms_aaMaskLut[32] = {
0x0, 0x0, // 0x0000, 0x0000,
0x0, 0x0, 0x1, // 0x000E, 0x000E, 0x000E,
0x1, 0x1, 0x1, // 0xE00E, 0xE00E, 0xE00E,
0x1, 0x1, 0x1, // 0x000F, 0x000F, 0x000F,
0x1, 0x1, 0x9, // 0xE00F, 0xE00F, 0xE00F,
0x9, 0x9, 0x9, // 0xF00F, 0xF00F, 0xF00F,
0x9, 0x9, 0xb, // 0xF0EF, 0xF0EF, 0xF0EF,
0xb, 0xb, 0xe, // 0xFEEF, 0xFEEF, 0xFEEF,
0xd, 0xd, 0xd, // 0xFF0F, 0xFF0F, 0xFF0F,
0xd, 0xd, 0xd, // 0xFFEF, 0xFFEF, 0xFFEF,
0xf, 0xf, 0xf // 0xFFFF, 0xFFFF, 0xFFFF
};
uint numSamples = GetNumCoverageSamples();
uint coverage = ms_aaMaskLut[(int)(saturate(alpha) * 31.99999f)];
switch(numSamples)
{
case 2: return coverage >> 2;
case 4: return coverage;
case 8: return coverage * 0x11;
case 16: return coverage * 0x1111;
default: return 0xffff; //Disable coverage?
}
}
#endif
bool IsMSAAEnabled()
{
#if __SHADERMODEL >= 40
return GetNumCoverageSamples() > 1;
#else
return false;
#endif
}
bool IsCoverageEnabled()
{
#if __SHADERMODEL >= 41
return IsMSAAEnabled();
#else
return false;
#endif
}
// ----------------------------------------------------------------------------------------------- //
#define PackReflection_3h PackColor_3h
#define UnpackReflection_3h UnpackColor_3h
#define PackReflection PackColor
#define UnpackReflection UnpackColor
half4 UnpackColorLinearise(half4 color)
{
#if __PS3 || RSG_ORBIS // TODO - Move PC to same color range - !__XENON // __PS3
half3 outColor = (color.rgb * color.rgb) * PS3_FAKE_ARGB8888_REFLECTION_SCALE;
#else
half3 outColor = (color.rgb * color.rgb);
#endif
return half4(outColor.rgb, color.a);
}
// ----------------------------------------------------------------------------------------------- //
#if __XENON
// Standard 7e3 conversion. bPreShifted indicates if the vEncodedPixel is already pre-shifted
// by 3 bits (false indicates that we'll need to shift it ourselves).
float4 Decode7e3 ( float4 vEncodedPixel, bool bPreShifted )
{
// Shift left 3 bits. This allows us to have the exponent and mantissa on opposite
// sides of the decimal point for extraction. This can shift can be done for free by
// setting the sampler state as Format.ExpAdjust = 3. If we don't set the sampler state
// then we will need to shift manually here.
if ( !bPreShifted ) // Compile time branch... unless you're doing something wrong.
{
// Color was not pre-shifted 3 bits by the sampler so we need to do it here
vEncodedPixel.rgb *= 8.0f;
}
else
{
// Since the channels were pre-shifted by ths sampler, we need to shift alpha back (alpha is not encoded)
vEncodedPixel.a /= 8.0f;
}
// Extract the exponent and mantissa that are now on opposite sides of the decimal point.
float3 e = floor( vEncodedPixel.rgb );
float3 m = frac( vEncodedPixel.rgb );
// Perform the 7e3 conversion. Note that this varies on the value of e for each channel:
// if e != 0.0f then the correct conversion is (1+m)/8*pow(2,e).
// else it is m*pow( 2, ).
// Note that 2^0 = 1 so we can reduce this more.
// Removing the /8 and putting it inside the pow() does not save instructions
float3 vDecodedColor = (e == 0.0f) ? 2*m/8 : (1+m)/8 * pow(2,e);
float4 vDecodedPixel = float4( vDecodedColor, vEncodedPixel.a );
return vDecodedPixel;
}
// Color only decode
float3 Decode7e3 ( float3 vEncodedPixel, bool bPreShifted )
{
// Dead code removal should strip the alpha scaling in the float4 version of the function
float3 vDecodedPixel = Decode7e3( float4(vEncodedPixel,1), bPreShifted ).rgb;
return vDecodedPixel;
}
// ----------------------------------------------------------------------------------------------- //
// 4 tap bilinear filter for 7e3 float packed in 10bit int texture
float4 BilinearSample7e3 ( sampler2D sSampler, float2 vUV, bool bPreShifted )
{
float4 vSampleA, vSampleB, vSampleC, vSampleD, vWeights;
asm
{
tfetch2D vSampleA.rgba, vUV, sSampler, MinFilter=point, MagFilter=point, OffsetX=-0.5, OffsetY=-0.5
tfetch2D vSampleB.rgba, vUV, sSampler, MinFilter=point, MagFilter=point, OffsetX= 0.5, OffsetY=-0.5
tfetch2D vSampleC.rgba, vUV, sSampler, MinFilter=point, MagFilter=point, OffsetX=-0.5, OffsetY= 0.5
tfetch2D vSampleD.rgba, vUV, sSampler, MinFilter=point, MagFilter=point, OffsetX= 0.5, OffsetY= 0.5
getWeights2D vWeights, vUV, sSampler, MagFilter=linear, MinFilter=linear
};
vWeights = float4( (1-vWeights.x)*(1-vWeights.y), vWeights.x*(1-vWeights.y), (1-vWeights.x)*vWeights.y, vWeights.x*vWeights.y );
vSampleA = Decode7e3( vSampleA, bPreShifted );
vSampleB = Decode7e3( vSampleB, bPreShifted );
vSampleC = Decode7e3( vSampleC, bPreShifted );
vSampleD = Decode7e3( vSampleD, bPreShifted );
float4 vFilteredTexel = vSampleA*vWeights.xxxx + vSampleB*vWeights.yyyy + vSampleC*vWeights.zzzz + vSampleD*vWeights.wwww;
return vFilteredTexel;
}
// ----------------------------------------------------------------------------------------------- //
// 2 tap linear filter for 7e3 float packed in 10bit int texture
float4 LinearSample7e3Offset(sampler2D sSampler, float2 vUV, bool bPreShifted, float2 offset)
{
float4 vSampleA, vSampleB, vSampleC, vSampleD, vWeights;
float4 offsets = offset.xyxy + float2(-0.5, 0.5).xxyy;
float offsetX1 = offsets.x;
float offsetY1 = offsets.y;
float offsetX2 = offsets.z;
float offsetY2 = offsets.w;
asm
{
tfetch2D vSampleA.rgba, vUV, sSampler, MinFilter=point, MagFilter=point, OffsetX = offsetX1, OffsetY = offsetY1
tfetch2D vSampleB.rgba, vUV, sSampler, MinFilter=point, MagFilter=point, OffsetX = offsetX2, OffsetY = offsetY2
getWeights2D vWeights, vUV, sSampler, MagFilter=linear, MinFilter=linear
};
float2 vLinearWeights = float2( (1-vWeights.x)*(1-vWeights.y), vWeights.x*vWeights.y );
vLinearWeights.xy += (1.f.xx-(vLinearWeights.xx + vLinearWeights.yy))*0.5.xx;
vSampleA = Decode7e3( vSampleA, bPreShifted );
vSampleB = Decode7e3( vSampleB, bPreShifted );
float4 vFilteredTexel = vSampleA*vLinearWeights.xxxx + vSampleB*vLinearWeights.yyyy;
return vFilteredTexel;
}
float4 LinearSample7e3(sampler2D sSampler, float2 vUV, bool bPreShifted)
{
float4 vSample;
asm
{
tfetch2D vSample.rgba, vUV, sSampler, MinFilter=point, MagFilter=point
};
vSample = Decode7e3( vSample, bPreShifted );
return vSample;
}
float4 PointSample7e3Offset( sampler2D sSampler, float2 vUV, bool bPreShifted, float2 offset)
{
float4 vSample;
float offsetX = offset.x;
float offsetY = offset.y;
asm
{
tfetch2D vSample.rgba, vUV, sSampler, MinFilter=point, MagFilter=point, OffsetX = offsetX, OffsetY = offsetY
};
vSample = Decode7e3( vSample, bPreShifted );
return vSample;
}
// ----------------------------------------------------------------------------------------------- //
// 1 tap point filter for 7e3 float packed in 10bit int texture
float4 PointSample7e3( sampler2D sSampler, float2 vUV, bool bPreShifted)
{
return PointSample7e3Offset(sSampler, vUV, bPreShifted, 0);
}
#endif // __XENON
// ----------------------------------------------------------------------------------------------- //
float IsInInterior(float materialID)
{
#if __PS3
#if 1
// NOTE: on the PS3 this function is only valid before the scene lighting pass (since we may add stencil bits other than motion blur)
// but since it's only currently used there. I'll leave this version in place
float matID=materialID*255.0f;
float motionBlurMask = GtaStep(matID,127.9f);
matID-=128.0f*motionBlurMask;
return GtaStep(matID,7.9f);
#else
return GtaStep(fmod(materialID, 16.0f/255), 7.9f/255); // on the ps3 we need to mask off the spare bits, etc
#endif
#elif __XENON
float matID = materialID*255.0f;
matID-=128.0f*(matID>=128.0f); //deal with motion blur mask
return (matID>=7.9f);
#elif __SHADERMODEL >= 40
uint matID = (uint)(materialID * 255.0); //(1/255) in IEEE float32 is rounded up, so we don't need to round here
return GtaStep(matID & DEFERRED_MATERIAL_INTERIOR, 7.9f);
#else
float matID=materialID * 255.0f;
matID-=128.0f*GtaStep(matID,128.0f);
return GtaStep(matID,8.0f);
#endif
}
// ----------------------------------------------------------------------------------------------- //
float IsWettable(float materialID)
{
#if __PS3
return GtaStep((0.1f/255.0f), materialID);
#elif __XENON
return (materialID <= (0.1f/255.0f));
#else
return (materialID <= (0.1f/255.0f)) ? 1.0f : 0.0f;
#endif
}
// ----------------------------------------------------------------------------------------------- //
#ifdef USE_ANIMATED_UVS
// ----------------------------------------------------------------------------------------------- //
// helper function for animated UVs:
float2 AnimateUVs(float2 uv)
{
float2 OUT;
OUT.x = dot(globalAnimUV0, float3(uv.xy, 1.0f));
OUT.y = dot(globalAnimUV1, float3(uv.xy, 1.0f));
return(OUT);
}
// ----------------------------------------------------------------------------------------------- //
#else // USE_ANIMATED_UVS...
// ----------------------------------------------------------------------------------------------- //
#define AnimateUVs(uv) uv
// ----------------------------------------------------------------------------------------------- //
#endif // !USE_ANIMATED_UVS...
// ----------------------------------------------------------------------------------------------- //
// ----------------------------------------------------------------------------------------------- //
#if UMOVEMENTS || UMOVEMENTS_TEX
// ----------------------------------------------------------------------------------------------- //
#define umGlobalScaleH (umGlobalParams.x) // (0.025f)micro-movement: globalScaleHorizontal
#define umGlobalScaleV (umGlobalParams.y) // (0.025f)micro-movement: globalScaleVertical
#define umGlobalArgFreqH (umGlobalParams.z) // (1.000f) micro-movement: globalArgFreqHorizontal
#define umGlobalArgFreqV (umGlobalParams.w) // (1.000f) micro-movement: globalArgFreqVertical
// um override params:
#define umOverrideScaleH (umGlobalOverrideParams.x) // override scaleH
#define umOverrideScaleV (umGlobalOverrideParams.y) // override scaleV
#define umOverrideArgFreqH (umGlobalOverrideParams.z) // override ArgFreqH
#define umOverrideArgFreqV (umGlobalOverrideParams.w) // override ArgFreqV
// ----------------------------------------------------------------------------------------------- //
float3 VS_ApplyMicromovements(float3 vertpos, float3 IN_Color0)
{
float3 newVertpos;
// local micro-movements of plants:
float umScaleH = IN_Color0.r * umGlobalScaleH * umOverrideScaleH; // horizontal movement scale (red0: 255=max, 0=min)
#if UMOVEMENTS_INV_BLUE
float umScaleV = IN_Color0.b * umGlobalScaleV * umOverrideScaleV; // vertical movement scale (blue0: 0=min, 255=max)
#else
float umScaleV = (1.0f-IN_Color0.b)* umGlobalScaleV * umOverrideScaleV; // vertical movement scale (blue0: 0=max, 255=min)
#endif
float umArgPhase= IN_Color0.g * TWO_PI; // phase shift (green0: phase 0-1 )
float3 uMovementArg = float3(gUmGlobalTimer, gUmGlobalTimer, gUmGlobalTimer);
float3 uMovementArgPhase = float3(umArgPhase, umArgPhase, umArgPhase);
float3 uMovementScaleXYZ = float3(umScaleH, umScaleH, umScaleV);
uMovementArg *= float3(umGlobalArgFreqH, umGlobalArgFreqH, umGlobalArgFreqV) * float3(umOverrideArgFreqH, umOverrideArgFreqH, umOverrideArgFreqV);
uMovementArg += uMovementArgPhase;
float3 uMovementAdd = sin(uMovementArg);
uMovementAdd *= uMovementScaleXYZ;
// add final micro-movement:
newVertpos = vertpos.xyz + uMovementAdd;
return newVertpos.xyz;
}
// ----------------------------------------------------------------------------------------------- //
#endif //UMOVEMENTS || UMOVEMENTS_TEX...
// ----------------------------------------------------------------------------------------------- //
// ----------------------------------------------------------------------------------------------- //
#if PALETTE_TINT || PALETTE_TINT_MAX
// ----------------------------------------------------------------------------------------------- //
BeginSampler(sampler2D,tintPaletteTex,TintPaletteSampler,TintPaletteTex)
int nostrip=1; // dont strip
string UIName="Tint Palette";
string TCPTemplateRelative="maps_other/TintPalette";
string TextureType="Palette";
ContinueSampler(sampler2D,tintPaletteTex,TintPaletteSampler,TintPaletteTex)
AddressU = CLAMP;
AddressV = CLAMP;
AddressW = CLAMP;
MIPFILTER = POINT;
MINFILTER = POINT;
MAGFILTER = POINT;
EndSampler;
// ----------------------------------------------------------------------------------------------- //
// inColor0: R = ambScale, G=emissiveScale, B=TintIndex
float4 UnpackTintPalette(float4 inColor0)
{
float4 OUT = float4(1,1,1,1);
#if PALETTE_TINT_EDGE
OUT = inColor0; // EDGE decompresses colors directly into streams
#elif __XENON
// sample tint palette directly from 64x4H palette:
const float tintPalLineHeight = tintPaletteSelector.y;
float tintIdx = inColor0.b*4.0f; // expand to <0; 4>
tintIdx = min(tintIdx, 3.999f);
float tintX = frac(tintIdx);
float tintY = floor(tintIdx)*tintPalLineHeight;
float4 tint = tex2Dlod(TintPaletteSampler, float4(tintX, tintY+tintPaletteSelector.x, 0.0f, 0.0f));
OUT = tint.rgba; //bgra;
#elif __SHADERMODEL >= 40
// sample tint palette directly
#if __LOW_QUALITY
// Working around weird DX10 cards issue with sampling. Shifting towards the real pixel center, assuming 512 width.
// The real with can be smaller (say, 256), and the shift still fixes it. See B#2137217.
float tintIdx = (inColor0.b * 511.0 + 0.5) / 512.0;
#else
float tintIdx = inColor0.b;
#endif
float4 tint = tex2Dlod(TintPaletteSampler, float4(tintIdx, tintPaletteSelector.x, 0.0f, 0.0f));
OUT = tint.rgba; //bgra;
#else
OUT = float4(1,1,1,1);
#endif
return(OUT);
}
// ----------------------------------------------------------------------------------------------- //
#endif //PALETTE_TINT...
// ----------------------------------------------------------------------------------------------- //
float2 convertToNormalizedScreenPos(float2 vpos, float4 screenSize)
{
float2 screenPos;
#if __PS3
screenPos.xy = (vpos.xy) * (screenSize.zw);
#elif __SHADERMODEL >= 40
screenPos.xy = vpos.xy * screenSize.zw;
#else
screenPos.xy = (vpos.xy + 0.51f) * screenSize.zw;
#endif
return screenPos;
}
// ----------------------------------------------------------------------------------------------- //
// NOTE: When using for screen position if vertex was in world space have to divide by w component before usage
// for full-screen quads this is not an issue as the z and w components are 1.0.
// - screenSize is assumed to be (w,h,1/w,1/h)
float4 convertToVpos(float4 p, float4 screenSize)
{
// Assume we need to add the half pixel offset on XENON
// Source: http://diaryofagraphicsprogrammer.blogspot.com/2008/09/calculating-screen-space-texture.html
#if __PS3 || __SHADERMODEL >= 40
return float4(0.5 * (float2(p.x + p.w, p.w - p.y)), p.zw);
#else
return float4(0.5 * (float2(p.x + p.w, p.w - p.y) + p.w * screenSize.zw), p.zw);
#endif
}
// ----------------------------------------------------------------------------------------------- //
float getLinearDepthOrtho(float sampleDepth, float2 projParams)
{
return projParams.x + projParams.y*sampleDepth;
}
float4 getLinearDepthOrtho4(float4 samples, float2 projParams)
{
return projParams.xxxx + projParams.yyyy*samples;
}
float getSampleDepthOrtho(float linearDepth, float2 projParams)
{
return (linearDepth - projParams.x)/projParams.y;
}
float getLinearGBufferDepthOrtho(float sampleDepth, float2 projParams)
{
return projParams.x + projParams.y - projParams.y * sampleDepth;
}
float4 getLinearGBufferDepthOrtho4(float4 samples, float2 projParams)
{
return projParams.xxxx + projParams.yyyy - projParams.yyyy * samples;
}
float getSampleGbufferDepthOrtho(float linearDepth, float2 projParams)
{
return 1.0f - (linearDepth - projParams.x)/projParams.y;
}
// don't enable this by default - it will slow down the rest of the shaders
// but it can be enabled locally for testing
#define AUTO_DETECT_ORTHO (0 && !defined(SHADER_FINAL))
// ----------------------------------------------------------------------------------------------- //
float getLinearDepth(float depthSample, float2 projParams)
{
#if AUTO_DETECT_ORTHO
if (projParams.y > 0)
return getLinearDepthOrtho(depthSample, projParams);
#endif
/*#if __XENON
// float Q = f/(f-n);
// float P = 1.0f/(-n*Q);
// float QPmP = Q*P-P;
float P = projParams.x;
float QPmP = projParams.y;
float ood = -(depthSample * P + QPmP);
#else
// float Q = f/(f-n);
// float P = 1.0f/(-n*Q);
// float QP = Q*P;
float P = projParams.x;
float QP = projParams.y;
float ood = depthSample * P - QP;
#endif
return (1.0f / ood);*/
// This is an optimized version of the above code shaving off one instructions of most shaders that use it
// Q = f/(f-n);
// For __XENON:
// projParams.x = n * Q
// projParams.y = Q - 1
// Other platforms:
// projParams.x = -n * Q
// projParams.y = -Q
return projParams.x / (depthSample + projParams.y);
}
float getLinearGBufferDepth(float depthSample, float2 projParams)
{
#if AUTO_DETECT_ORTHO
if (projParams.y > 0)
return getLinearDepthOrtho(depthSample, projParams);
#endif
#if SUPPORT_INVERTED_PROJECTION
#if RSG_ORBIS //orbis ignores order of operations from parenthesis/declarations, add a dummy operation to force precedence (TEMPORARY)
float OnePlusNegQ = min(1 + projParams.y, 0);
#else
float OnePlusNegQ = 1 + projParams.y;
#endif
return projParams.x / (OnePlusNegQ - depthSample);
#else // SUPPORT_INVERTED_PROJECTION
return projParams.x / (depthSample + projParams.y);
#endif // SUPPORT_INVERTED_PROJECTION
}
float4 getLinearGBufferDepth4(float4 depthSamples, float2 projParams)
{
#if AUTO_DETECT_ORTHO
if (projParams.y > 0)
return getLinearDepthOrtho(depthSample, projParams);
#endif
#if SUPPORT_INVERTED_PROJECTION
#if RSG_ORBIS //orbis ignores order of operations from parenthesis/declarations, add a dummy operation to force precedence (TEMPORARY)
float OnePlusNegQ = min(1 + projParams.y, 0);
#else
float OnePlusNegQ = 1 + projParams.y;
#endif
return projParams.xxxx / (OnePlusNegQ.xxxx - depthSamples);
#else // SUPPORT_INVERTED_PROJECTION
return projParams.xxxx / (depthSamples + projParams.yyyy);
#endif // SUPPORT_INVERTED_PROJECTION
}
float getLinearGBufferDepth4(float depthSample, float2 projParams, bool orthographic)
{
if (orthographic)
return getLinearGBufferDepthOrtho4(depthSample, projParams);
else
return getLinearGBufferDepth4(depthSample, projParams);
}
float getLinearGBufferDepth(float depthSample, float2 projParams, bool orthographic)
{
if (orthographic)
return getLinearGBufferDepthOrtho(depthSample, projParams);
else
return getLinearGBufferDepth(depthSample, projParams);
}
float4 getLinearDepth4(float4 depthSamples, float2 projParams)
{
#if AUTO_DETECT_ORTHO
if (projParams.y > 0)
return getLinearDepthOrtho4(depthSamples, projParams);
#endif
return projParams.xxxx / (depthSamples + projParams.yyyy);
}
// inverse of getLinearDepth
float getSampleDepth(float linearDepth, float2 projParams)
{
#if AUTO_DETECT_ORTHO
if (projParams.y > 0)
return getSampleDepthOrtho(linearDepth, projParams);
#endif
return (projParams.x / linearDepth) - projParams.y;
}
float getLinearDepth(float depthSample, float2 projParams, bool orthographic)
{
if (orthographic)
return getLinearDepthOrtho(depthSample, projParams);
else
return getLinearDepth(depthSample, projParams);
}
float4 getLinearDepth4(float4 depthSamples, float2 projParams, bool orthographic)
{
if (orthographic)
return getLinearDepthOrtho4(depthSamples, projParams);
else
return getLinearDepth4(depthSamples, projParams);
}
#if MULTISAMPLE_TECHNIQUES
float getStencilValueScreenMS(TEXTURE_STENCIL_TYPE stencilTexture, int3 coords, int sampleIndex)
{
#if SHADER_STENCIL_ACCESS_AS_UINT2
float stencilSample = (float)stencilTexture.Load(coords,sampleIndex).g;
#else
float stencilSample = (float)stencilTexture.Load(coords,sampleIndex).r;
#endif
return (stencilSample / 255.0f);
}
#elif __SHADERMODEL >= 40
float getStencilValueScreen( TEXTURE_STENCIL_TYPE stencilTexture, float2 screenPos )
{
int3 iScreen = int3(screenPos.xy, 0);
#if SHADER_STENCIL_ACCESS_AS_UINT2
float stencilSample = (float)stencilTexture.Load( iScreen ).g;
#else
float stencilSample = (float)stencilTexture.Load( iScreen ).r;
#endif
return (stencilSample / 255.0f);
}
#endif //MULTISAMPLE_TECHNIQUES
float fixupDepth(float zed)
{
float red = zed;
#if SUPPORT_INVERTED_VIEWPORT
red = 1.0f - zed;
#endif // SUPPORT_INVERTED_VIEWPORT
return red;
}
float4 fixupDepth(float4 zed)
{
float4 red = zed;
#if SUPPORT_INVERTED_VIEWPORT
red = 1.0f.xxxx - zed;
#endif // SUPPORT_INVERTED_VIEWPORT
return red;
}
float negateDepth(float zed)
{
float red = zed;
#if SUPPORT_INVERTED_VIEWPORT
red = -zed;
#endif // SUPPORT_INVERTED_VIEWPORT
return red;
}
float4 rageTexDepth2D(sampler2D depthMap, float2 texCoords)
{
return fixupDepth(tex2D(depthMap, texCoords).r).xxxx;
}
float fixupGBufferDepth(float zed)
{
float red = zed;
#if SUPPORT_INVERTED_PROJECTION
red = 1.0f - zed;
#endif // SUPPORT_INVERTED_PROJECTION
return red;
}
float4 fixupGBufferDepth(float4 zed)
{
float4 red = zed;
#if SUPPORT_INVERTED_PROJECTION
red = 1.0f.xxxx - zed;
#endif // SUPPORT_INVERTED_PROJECTION
return red;
}
float negateGBufferDepth(float zed)
{
float red = zed;
#if SUPPORT_INVERTED_PROJECTION
red = -zed;
#endif // SUPPORT_INVERTED_PROJECTION
return red;
}
float4 GBufferTexDepth2D(sampler2D depthMap, float2 texCoords)
{
return fixupGBufferDepth(tex2D(depthMap, texCoords).r).xxxx;
}
// Help macros to be used in MSAA-supported techniques for PC - as that supports multiple shader model versions
#if RSG_PC && MULTISAMPLE_TECHNIQUES && __SHADERMODEL>=40
#define _MSAA_NAME(name) name##_sm41
#define MSAA_PIXEL_SHADER ps_4_1
#else
#define _MSAA_NAME(name) name
#define MSAA_PIXEL_SHADER PIXELSHADER
#endif
#define MSAA_NAME(name) _MSAA_NAME(name)
// ----------------------------------------------------------------------------------------------- //
half3 filmicTweakedTonemap(float3 x, half4 filmicParams0, half4 filmicParams1)
{
#define C_mul_B filmicParams1.x
#define D_mul_E filmicParams1.y
#define D_mul_F filmicParams1.z
#define E_div_F filmicParams1.w
half A = filmicParams0.x;
half B = filmicParams0.y;
return ((x*(A*x+C_mul_B)+D_mul_E)/(x*(A*x+B)+D_mul_F))-E_div_F;
}
// ----------------------------------------------------------------------------------------------- //
half3 filmicToneMap(float3 sampleColor, half4 filmicParams0, half4 filmicParams1, half exposure)
{
const half ooFilmicToneMappedWhitePoint = filmicParams0.z;
const half3 linearColour = max(0.0f, sampleColor * exposure);
const half3 toneMappedColour = filmicTweakedTonemap(linearColour, filmicParams0, filmicParams1) * ooFilmicToneMappedWhitePoint;
return saturate(toneMappedColour);
}
// ----------------------------------------------------------------------------------------------- //
// Computes the binormal given the normal & tangent (accounts for mirroring UV's)
float3 rageComputeBinormal( float3 normal, float3 tangent, float sign )
{
float3 OUT;
OUT = cross(tangent, normal);
OUT *= sign;
return OUT;
}
// ----------------------------------------------------------------------------------------------- //
// "Decompresses" normal from dxt5 format (0G0R/0Y0X) into standard format (RGB/XYZ):
float3 DecompressNormalDXT5(float4 normalDXT5)
{
float3 OUT;
#if __XENON || __PS3
OUT.xy = normalDXT5.xy; // cleverly remaps dxt5 normal maps
#else
OUT.xy = normalDXT5.xy; // TODO -- support DXT5 normal maps on pc, but we'll have to handle this in the texture pipeline
// OUT.xy = lerp(normalDXT5.wy, normalDXT5.xy, ((normalDXT5.x)>(1.0f-normalDXT5.w))?1:0);
#endif
#ifdef DECAL_USE_NORMAL_MAP_ALPHA
OUT.z = normalDXT5.w; //normal map alpha stored here
#else
OUT.z = 1.0f;
#endif
#if __MAX
OUT.y = 1.0f - OUT.y;
#endif // __MAX
return OUT;
}
// ----------------------------------------------------------------------------------------------- //
// helper function to sample normal maps in dxt5 format:
float3 tex2D_NormalMap(sampler2D sampler0, float2 texcoord0)
{
float4 nrm_dxt5 = h4tex2D(sampler0, texcoord0.xy);
return( DecompressNormalDXT5(nrm_dxt5) );
}
// ----------------------------------------------------------------------------------------------- //
// sampler for normal+height map in dxt5 format (R=Height, G=NormalY, B=0, A=NormalX):
float4 tex2D_NormalHeightMap(sampler2D sampler0, float2 texcoord0)
{
float4 OUT;
#if 1 // standard mapping for VFX guys for tests, etc.
// (will be switched to swizzled format when they are ready)
float4 nrm_dxt5 = tex2D(sampler0, texcoord0.xy);
// R=Nx, G=Ny, B=NormalAlpha, A=Height:
OUT.xyw = nrm_dxt5.xyw; // Nx, Ny, Height
#ifdef DECAL_USE_NORMAL_MAP_ALPHA
OUT.z = nrm_dxt5.z; // normal map alpha stored here
#else
OUT.z = 1.0f;
#endif
#else
// NOTE - i changed DecompressNormalDXT5 to expect pre-swizzled normal maps for both xenon and PS3
// this needs to be taken into account when calling DecompressNormalDXT5 from here
float4 nrm_dxt5 = tex2D(sampler0, texcoord0.xy);
OUT.w = nrm_dxt5.r; // height is kept in Red channel
nrm_dxt5.r = 0.0f;
OUT.xyz = DecompressNormalDXT5(nrm_dxt5);
#endif
return(OUT);
}
// ----------------------------------------------------------------------------------------------- //
// NOTE:
// IN_packedNormalXY should be range-compressed [0..1]
// IN_tangentX is 'tangent'
// IN_tangentY is 'binormal'
// IN_tangentZ is 'normal'
half3 CalculateWorldNormal(half2 IN_packedNormalXY, half IN_bumpiness, half3 IN_tangentX, half3 IN_tangentY, half3 IN_tangentZ)
{
half3 n = half3(IN_packedNormalXY*2 - 1, 0); // [-1..1]
n.z = sqrt(ABS_PC(1 - dot(n.xy, n.xy)));
n.xy *= max(0.001f, IN_bumpiness);
return normalize
(
n.x*IN_tangentX +
n.y*IN_tangentY +
n.z*IN_tangentZ
);
}
half3 CalculateWorldNormal(half2 IN_packedNormalXY, half3 IN_tangentX, half3 IN_tangentY, half3 IN_tangentZ) // without bumpiness, doesn't require normalization
{
half3 n = half3(IN_packedNormalXY*2 - 1, 0); // [-1..1]
n.z = sqrt(ABS_PC(1 - dot(n.xy, n.xy)));
return
(
n.x*IN_tangentX +
n.y*IN_tangentY +
n.z*IN_tangentZ
);
}
// ----------------------------------------------------------------------------------------------- //
// http://blog.selfshadow.com/publications/blending-in-detail/
float3 ReorientedNormalBlend(float3 baseNormal, float3 detailNormal, float alpha)
{
float3 t = baseNormal * float3(2.f, 2.f, 2.f) + float3(-1.f, -1.f, 0.f);
float3 u = detailNormal * float3(-2.f, -2.f, 2.f) + float3(1.f, 1.f, -1.f);
u = alpha * u + (1.f - alpha) * float3(0.f, 0.f, 1.f);
float3 r = normalize(t * dot(t, u) / t.z - u);
return r * 0.5f + 0.5f;
}
// ------------------------------------------------------------------------------------------------
float TraceHeight(sampler2D heightMapSampler, float2 texCoords, float2 direction, float2 bias, int maxNumberOfSteps)
{
if(maxNumberOfSteps == 0 || POMDisable)
{
return 0.0f;
}
float heightStep = 1.0f / float(maxNumberOfSteps);
float2 offsetPerStep = direction * heightStep;
float currentBound = 1.0f;
float previousBound = currentBound;
float2 texCoordOffset = bias;
float2 ddx0 = ddx(texCoords.xy);
float2 ddy0 = ddy(texCoords.xy);
float currentHeight = tex2Dgrad(heightMapSampler, texCoords.xy, ddx0, ddy0).r + 1e-6f;
float previousHeight = currentHeight;
for(int s = 0; s < maxNumberOfSteps; ++s)
{
if(currentHeight < currentBound)
{
previousBound = currentBound;
previousHeight = currentHeight;
currentBound -= heightStep;
texCoordOffset += offsetPerStep;
currentHeight = tex2Dgrad(heightMapSampler, texCoords + texCoordOffset, ddx0, ddy0).r;
}
else
{
s = maxNumberOfSteps;
}
}
//Interpolate between the two points to find a more precise height
float currentDelta = currentBound - currentHeight;
float previousDelta = previousBound - previousHeight;
float denominator = previousDelta - currentDelta;
float finalHeight = currentHeight;
if(denominator > 0)
{
finalHeight = ((currentBound * previousDelta) - (previousBound * currentDelta)) / denominator;
}
return clamp(finalHeight, 0.0, 1.0f);
}
float4 TraceSelfShadow(float2 texCoords, sampler2D heightMapSampler, float3 lightDir, float edgeWeight, float heightScale)
{
float2 inXY = (lightDir.xy * heightScale * edgeWeight) / lightDir.z; // we use the global z to limit the shadow offset
//Compute the blurry shadows (note that this computation takes into account self-occlusion for shadow computation)
float sh0 = tex2D(heightMapSampler, texCoords).r;
float shA = (tex2D(heightMapSampler, texCoords + inXY * 0.88).r - sh0 - 0.88 ) * 1;
float sh9 = (tex2D(heightMapSampler, texCoords + inXY * 0.77).r - sh0 - 0.77 ) * 2;
float sh8 = (tex2D(heightMapSampler, texCoords + inXY * 0.66).r - sh0 - 0.66 ) * 4;
float sh7 = (tex2D(heightMapSampler, texCoords + inXY * 0.55).r - sh0 - 0.55 ) * 6;
float sh6 = (tex2D(heightMapSampler, texCoords + inXY * 0.44).r - sh0 - 0.44 ) * 8;
float sh5 = (tex2D(heightMapSampler, texCoords + inXY * 0.33).r - sh0 - 0.33 ) * 10;
float sh4 = (tex2D(heightMapSampler, texCoords + inXY * 0.22).r - sh0 - 0.22 ) * 12;
//Compute the actual shadow strength
float finalHeight = max(max(max(max(max(max(shA, sh9), sh8), sh7), sh6), sh5), sh4);
return saturate(finalHeight);
}
// ----------------------------------------------------------------------------------------------- //
// Transform a world pos to paraboloid projection
float4 DualParaboloidPosTransform(float3 localPos, float4x4 worldMtx)
{
float3 pos = ApplyCompositeWorldTransform(float4(localPos, 1.0f), INSTANCING_ONLY_ARG(worldMtx) gWorldView).xyz;
float len = length(pos);
pos.xy /= pos.z + len;
pos.z = (len - 1.0f)/4499.0f;
return float4(pos, 1.0f);
}
float4 DualParaboloidPosTransform(float3 localPos)
{
return DualParaboloidPosTransform(localPos, gWorld);
}
// ----------------------------------------------------------------------------------------------- //
float2 fresnelSlick2(float2 F0, float2 angle)
{
// Approx version of: return ( 1.0f - rollOff ) + ( rollOff ) * ragePow( 1.0 - angle, 5 );
float2 num = (1.0f - angle);
float2 pow5 = num * num * num * num * num;
return (1.0f - F0) + F0 * pow5;
}
// ----------------------------------------------------------------------------------------------- //
float fresnelSlick(float F0, float angle)
{
// Approx version of: return ( 1.0f - rollOff ) + ( rollOff ) * ragePow( 1.0 - VdotN, 5 );
float num = (1.0 - angle);
float pow5 = num * num * num * num * num;
return (1.0f - F0) + F0 * pow5;
}
// ----------------------------------------------------------------------------------------------- //
float3 naturalAmbient(float downMult)
{
return (gLightNaturalAmbient0.rgb * downMult) + gLightNaturalAmbient1.rgb;
}
// ----------------------------------------------------------------------------------------------- //
float3 artificialInteriorAmbient(float downMult)
{
return (gLightArtificialIntAmbient0.rgb * downMult) + gLightArtificialIntAmbient1.rgb;
}
// ----------------------------------------------------------------------------------------------- //
float3 artificialExteriorAmbient(float downMult)
{
return (gLightArtificialExtAmbient0.rgb * downMult) + gLightArtificialExtAmbient1.rgb;
}
// ----------------------------------------------------------------------------------------------- //
half2 DualParaboloidTexCoord_2h(half3 reflection, half scale)
{
half2 fbCoord = half2(0.25f,0.5f) - (half2(0.25f,0.5f)*reflection.xy) / (scale*(1.0f+abs(reflection.z)));
fbCoord.x = (reflection.z > 0.0f) ? 1.0f-fbCoord.x : fbCoord.x;
return fbCoord;
}
// ----------------------------------------------------------------------------------------------- //
float2 DualParaboloidTexCoord(float3 reflection, float scale)
{
float4 fbCoord = float4(0.75f,0.5f,0.25f,0.5f) - (float4(-0.25f,0.5f,0.25f,0.5f)*reflection.xyxy) / (scale*(1.0f+abs(reflection.zzzz)));
return (reflection.z > 0.0f) ? fbCoord.xy : fbCoord.zw;
}
// ----------------------------------------------------------------------------------------------- //
// Compute the appropriate MIP level for a given Blinn-Phong specular exponent (assuming Normalized
// Blinn-Phong BRDF).
// See "Plausible Blinn-Phong Reflection of Standard Cube MIP-Maps" for derivation
// http://graphics.cs.williams.edu/papers/EnvMipReport20 13/paper.pdf
//
// fMapWidth = Cube Map face width @ MIP 0
float CalculateCubeMapMIP ( float fGlossyExponent, float fMapWidth )
{
float fExponent = fGlossyExponent;
float fMIPLevel = log2(fMapWidth * sqrt(3)) - (0.5 * log2(fExponent + 1));
return fMIPLevel;
}
// ----------------------------------------------------------------------------------------------- //
float CalculateDualParabMapMIP (float fSpecularExponent, float fNumMips)
{
// We used to have 5 mips, now we compensate to keep surfaces looking the same
float refMip = (1.0 - saturate(fSpecularExponent / 1500.0f));
float offset = fNumMips - 5.0;
// Two parts (0 to max - 5) and (max - 5 to max)
float mipLevel = (refMip * fNumMips < offset) ?
(refMip * fNumMips) - 5.0 :
offset + (refMip * refMip) * 5.0;
return mipLevel;
}
// ----------------------------------------------------------------------------------------------- //
float3 calcReflection(sampler2D parabTex, float3 eyeWorldDir, float3 worldNormal, float specularExponent)
{
float maxRefMip = 4.0;
#if __SHADERMODEL >= 40
maxRefMip = gReflectionMipCount;
#endif
#if REFLECTION_CUBEMAP_SAMPLING
float3 onNorm = worldNormal * min(0.0, dot(eyeWorldDir, worldNormal));
float3 reflectionVector = eyeWorldDir - onNorm * 2.0;
float refMip = CalculateDualParabMapMIP(specularExponent, maxRefMip);
float2 UVs = DualParaboloidTexCoord(reflectionVector, 1.0f);
float3 parabMap = tex2Dlod(parabTex, float4(UVs, 0.0, refMip * maxRefMip)).rgb;
float3 cubeMap = texCUBElod(ReflectionCubeSampler, float4(-reflectionVector, refMip * 9.0)).rgb;
return UnpackReflection_3h(lerp(parabMap, cubeMap, 1.0f));
#else
// This version does the same thing as the above code - it just uses the reflection math instead of the function call
// With this math the isolate for 4 forward lights is no longer needed on shaders that use this function
float3 reflectionVector = reflect(eyeWorldDir, worldNormal);
float mipLevel = CalculateDualParabMapMIP(specularExponent, maxRefMip);
float2 UVs = DualParaboloidTexCoord(reflectionVector, 1.0f);
return UnpackReflection_3h(tex2Dlod(parabTex, float4(UVs, 0.0, mipLevel)).rgb);
#endif
}
float3 calcReflectionFlatClamped(sampler2D parabTex, float3 eyeWorldDir, float3 worldNormal, float specularExponent)
{
float maxRefMip = 4.0;
#if __SHADERMODEL >= 40
maxRefMip = gReflectionMipCount;
#endif
//#if REFLECTION_CUBEMAP_SAMPLING
// //float3 onNorm = worldNormal * min(0.0, dot(eyeWorldDir, worldNormal));
// float3 reflectionVector = reflect(eyeWorldDir,worldNormal);//eyeWorldDir - onNorm * 2.0;
// float selfReflect=1.;
// if (reflectionVector.z < 0.0)
// {
// reflectionVector.z = -eyeWorldDir.z;
// //selfReflect=0.0f;
// }
//
// float mipLevel = CalculateDualParabMapMIP(specularExponent, maxRefMip);
//
// //return UnpackColor_3h(ReflectionCubeTex.Sample(ReflectionCubeSampler,-reflectionVector).rgb) * selfReflect;
// return UnpackReflection_3h(ReflectionCubeTex.SampleLevel(ReflectionCubeSampler,-reflectionVector, mipLevel).rgb) * selfReflect;
//#else
float3 onNorm = worldNormal * min(0.0, dot(eyeWorldDir, worldNormal));
float3 reflectionVector = eyeWorldDir - onNorm * 2.0;
float selfReflect=1.;
if (reflectionVector.z < 0.0)
{
reflectionVector.z = -eyeWorldDir.z;
//selfReflect=0.0f;
}
float mipLevel = CalculateDualParabMapMIP(specularExponent, maxRefMip);
// return reflection value * saturate(reflectionVector.z*16.);
float2 UVs = DualParaboloidTexCoord(reflectionVector, 1.0f);
return UnpackReflection_3h(tex2Dlod(parabTex, float4(UVs, 0.0, mipLevel)).rgb) * selfReflect;
//#endif
}
// ----------------------------------------------------------------------------------------------- //
float3 calcReflectionDiffuse(sampler2D parabTex, float3 eyeWorldDir, float3 worldNormal, float specularExponent)
{
float maxRefMip = 4.0;
#if __SHADERMODEL >= 40
maxRefMip = gReflectionMipCount;
#endif
//#if REFLECTION_CUBEMAP_SAMPLING
// const float3 reflectionVector = worldNormal;
//
// float refMip =1.;
//
// //return UnpackColor_3h(ReflectionCubeTex.Sample(ReflectionCubeSampler, -reflectionVector).rgb)*0.5;
// return UnpackColor_3h(ReflectionCubeTex.SampleLevel(ReflectionCubeSampler, -reflectionVector, refMip * maxRefMip).rgb)*0.5;
//#else
const float3 reflectionVector = worldNormal;
float refMip =1.;
float2 UVs = DualParaboloidTexCoord(reflectionVector, 1.0f);
return UnpackColor_3h(tex2Dlod(parabTex, float4(UVs, 0.0, refMip * maxRefMip)).rgb)*0.5;
//#endif
}
// ----------------------------------------------------------------------------------------------- //
float3 calcAmbient(
float nz,
float naturalAmbientScale,
float artificialAmbientScale,
float inInterior)
{
const float downMult = max(0.0, ( nz + gLightNaturalAmbient0.w) * gLightArtificialIntAmbient0.w);
return((naturalAmbient(downMult) * naturalAmbientScale) +
(artificialInteriorAmbient(downMult) * artificialAmbientScale) * inInterior +
(artificialExteriorAmbient(downMult) * artificialAmbientScale) * (1.0 - inInterior));
}
// ----------------------------------------------------------------------------------------------- //
half4 ProcessDiffuseColor(half4 diffuseColor)
{
return half4(diffuseColor.rgb * diffuseColor.rgb, diffuseColor.a);
}
// ----------------------------------------------------------------------------------------------- //
half3 ProcessDiffuseColor(half3 diffuseColor)
{
return diffuseColor * diffuseColor;
}
// ----------------------------------------------------------------------------------------------- //
float fselect(float x, float y, float a, float b)
{
float k = step(y, x);
return (a - b)*k + b;
}
float2 fselect(float x, float y, float2 a, float2 b)
{
float k = step(y, x);
return (a - b)*k + b;
//return (1.0f - k)*b + k*a;
}
// (x >= y) : a ? b.
#define fselect_ge(x, y, a, b) fselect(x, y, a, b)
// (x < y) : a ? b => !(x >= y) : a ? b => (x >= y) : b ? a.
#define fselect_lt(x, y, a, b) fselect(x, y, b, a)
// (x <= y) : a ? b => (y >= x) : a ? b.
#define fselect_le(x, y, a, b) fselect(y, x, a, b)
// (x > y) : a ? b => !(x <= y) : a ? b => !(y >= x) : a ? b => (y >= x) ? b : a
#define fselect_gt(x, y, a, b) fselect(y, x, b, a)
// ----------------------------------------------------------------------------------------------- //
#if LINEAR_PIECEWISE_FOG
#define lpf_NumPieces linearPiecewiseFogParams[0].x
#define lpf_DensityAtViewer linearPiecewiseFogParams[0].y
#define lpf_CameraHeight linearPiecewiseFogParams[0].z
struct lpf_PieceDesc
{
float h1;
float h2;
float A;
float B;
};
#define LINEAR_PIECEWISE_FOG_USE_FSELECT 1
#if LINEAR_PIECEWISE_FOG_USE_FSELECT
float PerformLineIntegralOverPiece( float rayStart, float rayEnd, float rayDelta, float invRayDelta, lpf_PieceDesc pieceDesc )
{
float resultMultiplier;
// Disard result if the ray doesn`t intersect our piece.
resultMultiplier = fselect_gt(rayStart, pieceDesc.h2, 0.0f, 1.0f);
resultMultiplier = fselect_lt(rayEnd, pieceDesc.h1, 0.0f, resultMultiplier);
// Clip to piece.
float lamda1 = (pieceDesc.h1 - rayStart)*invRayDelta;
float lamda2 = (pieceDesc.h2 - rayStart)*invRayDelta;
lamda1 = fselect_lt(lamda1, 0.0f, 0.0f, lamda1);
lamda2 = fselect_gt(lamda2, 1.0f, 1.0f, lamda2);
// Compute the line integral over the range [lamda1, lamda2].
float integral = 0.5f*(lamda2*lamda2 - lamda1*lamda1)*pieceDesc.A*rayDelta + (lamda2 - lamda1)*(pieceDesc.A*rayStart + pieceDesc.B);
return integral*resultMultiplier;
}
float ComputeLinearPiecewiseVolumetricFog( float3 cameraToWorldPos, out float dist )
{
const float threshold = 0.001;
float rayEnd;
float rayStart;
float camPos = lpf_CameraHeight; //gViewInverse[3].z;
// Always go along the ray in the +ve direction.
float2 v = fselect_gt(cameraToWorldPos.z, 0.0f, float2(camPos, camPos + cameraToWorldPos.z), float2(camPos + cameraToWorldPos.z, camPos));
rayStart = v.x;
rayEnd = v.y;
float rayDelta = rayEnd - rayStart;
// Detect if ray is horizontal.
float2 w = fselect_lt(rayDelta, threshold, float2(100.0f, 1.0f), float2(0.0f, 0.0f));
float treatAsHorizontalRay = w.y;
rayDelta += w.x; // Add on something if ray is horizontal to avoid a divide by zero.
float invRayDelta = 1.0f/rayDelta;
float fogValue = 0.0f;
int numPieces = (int)lpf_NumPieces;
// Perform the line integral over each piece.
[loop]
for(int i=0; i<numPieces; i++)
{
lpf_PieceDesc pieceDesc;
pieceDesc.h1 = linearPiecewiseFogParams[i + 1].x;
pieceDesc.h2 = linearPiecewiseFogParams[i + 1].y;
pieceDesc.A = linearPiecewiseFogParams[i + 1].z;
pieceDesc.B = linearPiecewiseFogParams[i + 1].w;
fogValue += PerformLineIntegralOverPiece(rayStart, rayEnd, rayDelta, invRayDelta, pieceDesc);
}
float fullDist = length( cameraToWorldPos );
dist = max(0, fullDist - globalFogNearDist); // dist is adjusted by the delayed fog start distance
// Chose horizontal ray value.
float fogInt = (lpf_DensityAtViewer - fogValue)*treatAsHorizontalRay + fogValue;
// Finalize the line integrals and apply "standard exponential absorption".
return 1.0f - exp(-dist*fogInt);
}
#else // LINEAR_PIECEWISE_FOG_USE_FSELECT
float PerformLineIntegralOverPiece( float rayStart, float rayEnd, float rayDelta, float invRayDelta, lpf_PieceDesc pieceDesc )
{
float resultMultiplier = 1.0f;
// Disard result if the ray doesn`t intersect our piece.
if(rayStart > pieceDesc.h2)
{
resultMultiplier = 0.0f;
}
if(rayEnd < pieceDesc.h1)
{
resultMultiplier = 0.0f;
}
// Clip to piece.
float lamda1 = (pieceDesc.h1 - rayStart)*invRayDelta;
float lamda2 = (pieceDesc.h2 - rayStart)*invRayDelta;
if(lamda1 < 0.0f)
{
lamda1 = 0.0f;
}
if(lamda2 > 1.0f)
{
lamda2 = 1.0f;
}
// Compute the line integral over the range [lamda1, lamda2].
float integral = 0.5f*(lamda2*lamda2 - lamda1*lamda1)*pieceDesc.A*rayDelta + (lamda2 - lamda1)*(pieceDesc.A*rayStart + pieceDesc.B);
return integral*resultMultiplier;
}
float ComputeLinearPiecewiseVolumetricFog( float3 cameraToWorldPos, out float dist )
{
const float threshold = 0.001;
float rayEnd;
float rayStart;
float camPos = lpf_CameraHeight; //gViewInverse[3].z;
// Always go along the ray in the +ve direction.
if(cameraToWorldPos.z > 0.0f)
{
rayStart = camPos;
rayEnd = camPos + cameraToWorldPos.z;
}
else
{
rayStart = camPos + cameraToWorldPos.z;
rayEnd = camPos;
}
float rayDelta = rayEnd - rayStart;
float treatAsHorizontalRay = 0.0f;
if(rayDelta < threshold)
{
rayDelta += 100.0f; // The results of the ray line integrals will be ignored, this is to prevent a divide by zero.
treatAsHorizontalRay = 1.0f;
}
float invRayDelta = 1.0f/rayDelta;
float fogValue = 0.0f;
int numPieces = (int)lpf_NumPieces;
// Perform the line integral over each piece.
[loop]
for(int i=0; i<numPieces; i++)
{
lpf_PieceDesc pieceDesc;
pieceDesc.h1 = linearPiecewiseFogParams[i + 1].x;
pieceDesc.h2 = linearPiecewiseFogParams[i + 1].y;
pieceDesc.A = linearPiecewiseFogParams[i + 1].z;
pieceDesc.B = linearPiecewiseFogParams[i + 1].w;
fogValue += PerformLineIntegralOverPiece_fselect(rayStart, rayEnd, rayDelta, invRayDelta, pieceDesc);
}
float fullDist = length( cameraToWorldPos );
dist = max(0, fullDist - globalFogNearDist); // dist is adjusted by the delayed fog start distance
// Chose horizontal ray value.
float fogInt = (lpf_DensityAtViewer - fogValue)*treatAsHorizontalRay + fogValue;
// Finalize the line integrals and apply "standard exponential absorption".
return 1.0f - exp(-dist*fogInt);
}
#endif // LINEAR_PIECEWISE_FOG_USE_FSELECT
#endif // LINEAR_PIECEWISE_FOG
// ----------------------------------------------------------------------------------------------- //
// based on Crytek SIGGraph 2006 paper
float ComputeGlobalVolumetricFogValue_Crytek( float3 cameraToWorldPos, out float dist )
{
const float threshold = 0.01;
float fullDist = length( cameraToWorldPos );
dist = max(0, fullDist - globalFogNearDist); // dist is adjusted by the delayed fog start distance
float deltaZ = cameraToWorldPos.z * (dist/fullDist); // adjust height by shortened ray
float t = (globalGroundFogHeightFalloff * deltaZ);
float fogInt = (abs(deltaZ) > threshold) ? (1.0 - exp( -t) ) / t : 1.0;
// NOTE: globalGroundFogDensityAtViewer is premultiplied by -globalGroundFogDensity now to save a couple cycles
float val = min(1.0f, globalGroundFogDensityAtViewer * dist * fogInt);
float res = 1.0 - saturate(exp(val));
return res;
}
float ComputeGlobalVolumetricFogValue( float3 cameraToWorldPos, out float dist )
{
#if LINEAR_PIECEWISE_FOG
if(linearPiecewiseFogParams[0].w > 0.0f)
{
return ComputeLinearPiecewiseVolumetricFog( cameraToWorldPos, dist );
}
else
{
return ComputeGlobalVolumetricFogValue_Crytek( cameraToWorldPos, dist );
}
#else // LINEAR_PIECEWISE_FOG
return ComputeGlobalVolumetricFogValue_Crytek( cameraToWorldPos, dist );
#endif // LINEAR_PIECEWISE_FOG
}
// ----------------------------------------------------------------------------------------------- //
// calc the fog color and blend weight from and eye to point ray
float4 __CalcFogData( float3 eyeRayToPoint, float hazeScale)
{
// NOTE: the order of the calculations affects the shader performance (sadly),
// so if you reorder them to make them easier to "read",
// please check the compiled shader output for both the ps3 and 360...
// Calculate the height based volumetric fog.
float dist = 0.0f;
float groundFogAmount = ComputeGlobalVolumetricFogValue(eyeRayToPoint, dist)*globalGroundFogAlpha;
// calculate the mix of sun/moon and non sun/moon atmosphere colors
float moonAmount = pow( saturate(dot(normalize(eyeRayToPoint), globalFogMoonSpriteDirection.xyz)), globalFogMoonLightingCalcPower);
float sunAmount = pow( saturate(dot(normalize(eyeRayToPoint), globalFogSunSpriteDirection.xyz)), globalFogSunLightingCalcPower);
// Calculate the amount of blending between ground fog and haze, so they don't double up
// we also remove haze from the sky and clouds (via enableHaze), and respect haze alpha
float horizonHazeBlend = hazeScale*globalFogHazeAlpha*(1-groundFogAmount);
// Calculate amount of haze. It is needed since the far mountains would have not haze on them if the hight falloff is tuned high to simulate ground fog.
float horizonHazeAmount = horizonHazeBlend * (1-exp(globalFogHazeDensity* max(0,dist-globalFogHazeStart)));
// compute the total amount of fog/haze blended with the original color.
float finalFogBlend = saturate(horizonHazeAmount + groundFogAmount);
// Calculate the amount of horizon tint color we mix into the fog (increases with distance)
float atmosphereBlend = 1.0 - exp(-globalHorizonTintScale*dist);
// blend fog, haze, atmosphere, and sun/moon tinting
float3 atmosphereAndMoonColor = lerp(globalFogColorAtmophere, globalFogColorMoon, moonAmount);
float3 atmosphereColor = lerp(atmosphereAndMoonColor, globalFogColorSun, sunAmount);
float3 groundFogAtmoColor = lerp(globalFogColorGround, atmosphereColor, atmosphereBlend);
float3 groundFogHazeAtmoColor = lerp(groundFogAtmoColor, globalFogColorHaze , horizonHazeBlend);
//float3 groundFogHazeAtmoColor = globalFogColorHaze + (1.0 - horizonHazeBlend) * (globalFogColorGroundMinusHaze + atmosphereBlend * (globalFogColorAtmophereMinusGround + sunAmount * globalFogColorSunMinusAtmophere ) );
return float4( groundFogHazeAtmoColor, finalFogBlend);
}
#if defined(USE_FOGRAY_FORWARDPASS) && !__LOW_QUALITY
float GetFogRayIntensity(float2 texcoord)
{
if (gGlobalFogIntensity > 0.0f)
{
float rayIntensity = tex2D(FogRaySampler, texcoord);
return saturate(lerp(1.0f,rayIntensity,gGlobalFogIntensity));
}
else
return 1.0f;
}
#endif
float4 CalcFogData( float3 eyeRayToPoint)
{
return __CalcFogData( eyeRayToPoint, 1.0f);
}
float4 CalcFogDataNoHaze( float3 eyeRayToPoint)
{
return __CalcFogData( eyeRayToPoint, 0.0f);
}
// ----------------------------------------------------------------------------------------------- //
half4 calcDepthFxE(float3 eyeRayToPoint)
{
return __CalcFogData( eyeRayToPoint, 1.0f);
}
half4 calcDepthFxERay(float3 eyeRayToPoint, float rayIntensity)
{
float4 r = __CalcFogData( eyeRayToPoint, 1.0f);
// change fog color instead of alpha blend
r.xyz *= rayIntensity;
return r;
}
half4 calcDepthFxE(float4 colour, float3 eyeRayToPoint)
{
half4 fogData = __CalcFogData( eyeRayToPoint, 1.0f);
colour.rgb = lerp(colour.rgb, fogData.rgb, fogData.a);
return colour;
}
half4 calcDepthFxE(float4 colour, float3 eyeRayToPoint, float2 texcoord)
{
half4 fogData = __CalcFogData( eyeRayToPoint, 1.0f);
#if defined(USE_FOGRAY_FORWARDPASS) && !__LOW_QUALITY
fogData.rgb *= GetFogRayIntensity(texcoord);
#endif
colour.rgb = lerp(colour.rgb, fogData.rgb, fogData.a);
return colour;
}
half4 calcDepthFxE(float4 colour, float3 eyeRayToPoint, float shadowAmount)
{
half4 fogData = __CalcFogData( eyeRayToPoint, 1.0f);
fogData.rgb *= shadowAmount;
colour.rgb = lerp(colour.rgb, fogData.rgb, fogData.a);
return colour;
}
// ----------------------------------------------------------------------------------------------- //
//
// same as calcDepthFxE, but takes a world position of the pixel to be fogged.
//
float4 calcDepthFx(float4 colour, float3 worldPos)
{
float3 eyeRayToPoint = worldPos - gViewInverse[3].xyz;
return calcDepthFxE(colour, eyeRayToPoint);
}
float4 calcDepthFx(float4 colour, float3 worldPos, float2 texcoord)
{
float3 eyeRayToPoint = worldPos - gViewInverse[3].xyz;
return calcDepthFxE(colour, eyeRayToPoint, texcoord);
}
float4 calcDepthFx(float4 colour, float3 worldPos, float shadowAmount)
{
float3 eyeRayToPoint = worldPos - gViewInverse[3].xyz;
return calcDepthFxE(colour, eyeRayToPoint, shadowAmount);
}
// ----------------------------------------------------------------------------------------------- //
float4 calcDepthFxBasic(float4 colour, float3 worldPos)
{
return calcDepthFx(colour, worldPos);
}
float4 calcDepthFxBasic(float4 colour, float3 worldPos, float2 texcoord)
{
return calcDepthFx(colour, worldPos, texcoord);
}
float4 calcDepthFxBasic(float4 colour, float3 worldPos, float shadowAmount)
{
return calcDepthFx(colour, worldPos, shadowAmount);
}
// ----------------------------------------------------------------------------------------------- //
#if defined(DECAL_SHADER)
RAGE_DRAWBUCKET(2);
#endif
#if defined(ALPHA_SHADER)
RAGE_DRAWBUCKET(1);
#endif
// ----------------------------------------------------------------------------------------------- //
#if (defined(USE_ALPHA_CLIP) || defined(USE_EMISSIVE)) && !__MAX
property int ExposeAlphaMap = 1;
#endif
// ----------------------------------------------------------------------------------------------- //
#if __PS3
float4 northTexDepthStencil2D(sampler2D depthMap, float2 texCoords)
{
float4 depthSample = tex2D(depthMap, texCoords);
float4 depthStencil;
depthStencil.xyz= rageDepthUnpack(depthSample.xyzw).xxx; // depth
depthStencil.w = depthSample.w; // stencil
return(depthStencil);
}
#endif // __PS3
#if __XENON
float4 tex2DOffsetDecode7e3(sampler2D ss, float2 uv, float2 offset, bool bPreShifted)
{
// This is done in assembly to emphasize POINT SAMPLING.
// If you do not point sample, you will be averaging floating data
// as an integer and errors will be introduced. You do not have to do this
// if you set your sampler states correctly, but this is just a safety.
// You can choose to filter as integer but it will not be accurate.
float4 result;
float offsetX = offset.x;
float offsetY = offset.y;
asm
{
tfetch2D result.rgba, uv.xy, ss, MinFilter=point, MagFilter=point, OffsetX=offsetX, OffsetY=offsetY
};
// Now that we have the color, we just need to perform standard 7e3 conversion.
result = Decode7e3( result, bPreShifted );
return result;
}
#endif // __XENON
// ----------------------------------------------------------------------------------------------- //
// Used for ps3 msaa : based on normalized texcoord, gives you the matching msaa sampling texcoord for sample a and b
float2 GetTexCoordSampleA(float2 texXY)
{
float2 tex;
float denormX = texXY.x * SCR_BUFFER_WIDTH * 2.0f;
float roundedX = 2.0f * round((denormX + 1.0f)/2.0f);
tex.x = (roundedX - 1.5f)/(SCR_BUFFER_WIDTH * 2.0f);
tex.y = texXY.y;
return tex;
}
// ----------------------------------------------------------------------------------------------- //
float2 GetTexCoordSampleB(float2 texXY)
{
float2 texCoord = GetTexCoordSampleA(texXY);
return texCoord + float2( 1.0f / (2.0f*SCR_BUFFER_WIDTH),0.0f);
}
//Shared code for water refraction blending
float2 GetWaterDepthBlend(float waterDepth, float waterOpacity, float waterHeightToDepth)
{
return exp(float2(-20, -60*waterHeightToDepth) * waterOpacity * waterDepth * 2.71828183);
}
// ----------------------------------------------------------------------------------------------- //
#if WRINKLE_MAP
// ----------------------------------------------------------------------------------------------- //
#pragma sampler 3
BeginSampler(sampler2D,wrinkleMaskTexture_0,WrinkleMaskSampler_0,WrinkleMaskTexture_0)
string UIName="Wrinkle Mask 0";
// string UIHint="MASK_MAP";
// int nostrip=1; // dont strip
string TCPTemplate="Diffuse";
string TextureType="WrinkleMask";
ContinueSampler(sampler2D,wrinkleMaskTexture_0,WrinkleMaskSampler_0,WrinkleMaskTexture_0)
AddressU = WRAP;
AddressV = WRAP;
AddressW = WRAP;
MIPFILTER = MIPLINEAR;
MINFILTER = HQLINEAR;
MAGFILTER = MAGLINEAR;
EndSampler;
// ----------------------------------------------------------------------------------------------- //
BeginSampler(sampler2D,wrinkleMaskTexture_1,WrinkleMaskSampler_1,WrinkleMaskTexture_1)
string UIName="Wrinkle Mask 1";
// string UIHint="MASK_MAP";
// int nostrip=1; // dont strip
string TCPTemplate="Diffuse";
string TextureType="WrinkleMask";
ContinueSampler(sampler2D,wrinkleMaskTexture_1,WrinkleMaskSampler_1,WrinkleMaskTexture_1)
AddressU = WRAP;
AddressV = WRAP;
AddressW = WRAP;
MIPFILTER = MIPLINEAR;
MINFILTER = HQLINEAR;
MAGFILTER = MAGLINEAR;
EndSampler;
// ----------------------------------------------------------------------------------------------- //
BeginSampler(sampler2D,wrinkleMaskTexture_2,WrinkleMaskSampler_2,WrinkleMaskTexture_2)
string UIName="Wrinkle Mask 2";
// string UIHint="MASK_MAP";
// int nostrip=1; // dont strip
string TCPTemplate="Diffuse";
string TextureType="WrinkleMask";
ContinueSampler(sampler2D,wrinkleMaskTexture_2,WrinkleMaskSampler_2,WrinkleMaskTexture_2)
AddressU = WRAP;
AddressV = WRAP;
AddressW = WRAP;
MIPFILTER = MIPLINEAR;
MINFILTER = HQLINEAR;
MAGFILTER = MAGLINEAR;
EndSampler;
// ----------------------------------------------------------------------------------------------- //
BeginSampler(sampler2D,wrinkleMaskTexture_3,WrinkleMaskSampler_3,WrinkleMaskTexture_3)
string UIName="Wrinkle Mask 3";
// string UIHint="MASK_MAP";
// int nostrip=1; // dont strip
string TextureType="WrinkleMask";
ContinueSampler(sampler2D,wrinkleMaskTexture_3,WrinkleMaskSampler_3,WrinkleMaskTexture_3)
AddressU = WRAP;
AddressV = WRAP;
AddressW = WRAP;
MIPFILTER = MIPLINEAR;
MINFILTER = HQLINEAR;
MAGFILTER = MAGLINEAR;
EndSampler;
// ----------------------------------------------------------------------------------------------- //
BeginSampler(sampler2D,wrinkleTexture_A,WrinkleSampler_A,WrinkleTexture_A)
string UIName="Wrinkle A";
string UIHint="NORMAL_MAP";
string TCPTemplate="NormalMap";
string TextureType="WrinkleMap";
ContinueSampler(sampler2D,wrinkleTexture_A,WrinkleSampler_A,WrinkleTexture_A)
AddressU = WRAP;
AddressV = WRAP;
AddressW = WRAP;
MIPFILTER = MIPLINEAR;
MINFILTER = HQLINEAR;
MAGFILTER = MAGLINEAR;
EndSampler;
// ----------------------------------------------------------------------------------------------- //
BeginSampler(sampler2D,wrinkleTexture_B,WrinkleSampler_B,WrinkleTexture_B)
string UIName="Wrinkle B";
string UIHint="NORMAL_MAP";
string TCPTemplate="NormalMap";
string TextureType="WrinkleMap";
ContinueSampler(sampler2D,wrinkleTexture_B,WrinkleSampler_B,WrinkleTexture_B)
AddressU = WRAP;
AddressV = WRAP;
AddressW = WRAP;
MIPFILTER = MIPLINEAR;
MINFILTER = HQLINEAR;
MAGFILTER = MAGLINEAR;
EndSampler;
#endif //WRINKLE_MAP...
// ----------------------------------------------------------------------------------------------- //
#if defined(WRINKLE_MAP) || defined(PED_WRINKLE)
half3 PS_GetWrinkledNormal(
sampler2D IN_bumpSampler,
sampler2D IN_wrinkleNormalSampler_A,
sampler2D IN_wrinkleNormalSampler_B,
sampler2D IN_wrinkleMaskSampler_0,
sampler2D IN_wrinkleMaskSampler_1,
sampler2D IN_wrinkleMaskSampler_2,
sampler2D IN_wrinkleMaskSampler_3,
half4 IN_wrinkleMask_0,
half4 IN_wrinkleMask_1,
half4 IN_wrinkleMask_2,
half4 IN_wrinkleMask_3,
float2 IN_texCoord,
half IN_bumpiness,
half3 IN_worldNormal,
half3 IN_worldTangent,
half3 IN_worldBinormal
)
{
const half wrinkleStrength_A =
dot(IN_wrinkleMask_0, h4tex2D(IN_wrinkleMaskSampler_0, IN_texCoord.xy))+
dot(IN_wrinkleMask_1, h4tex2D(IN_wrinkleMaskSampler_1, IN_texCoord.xy));
const half wrinkleStrength_B =
dot(IN_wrinkleMask_2, h4tex2D(IN_wrinkleMaskSampler_2, IN_texCoord.xy))+
dot(IN_wrinkleMask_3, h4tex2D(IN_wrinkleMaskSampler_3, IN_texCoord.xy));
half2 packedNormal = tex2D_NormalMap(IN_bumpSampler, IN_texCoord.xy).xy;
packedNormal = lerp(packedNormal, tex2D_NormalMap(IN_wrinkleNormalSampler_A, IN_texCoord.xy).xy, wrinkleStrength_A);
packedNormal = lerp(packedNormal, tex2D_NormalMap(IN_wrinkleNormalSampler_B, IN_texCoord.xy).xy, wrinkleStrength_B);
return CalculateWorldNormal(packedNormal, IN_bumpiness, IN_worldTangent, IN_worldBinormal, IN_worldNormal);
}
half3 PS_GetWrinkledNormalCS(
sampler2D IN_bumpSampler,
sampler2D IN_wrinkleNormalSampler_A,
sampler2D IN_wrinkleNormalSampler_B,
sampler2D IN_wrinkleMaskSampler_0,
sampler2D IN_wrinkleMaskSampler_1,
sampler2D IN_wrinkleMaskSampler_2,
sampler2D IN_wrinkleMaskSampler_3,
sampler2D IN_wrinkleMaskSampler_4,
sampler2D IN_wrinkleMaskSampler_5,
half4 IN_wrinkleMask_0,
half4 IN_wrinkleMask_1,
half4 IN_wrinkleMask_2,
half4 IN_wrinkleMask_3,
half4 IN_wrinkleMask_4,
half4 IN_wrinkleMask_5,
float2 IN_texCoord,
half IN_bumpiness,
half3 IN_worldNormal,
half3 IN_worldTangent,
half3 IN_worldBinormal
)
{
const half wrinkleStrength_A =
dot(IN_wrinkleMask_0, h4tex2D(IN_wrinkleMaskSampler_0, IN_texCoord.xy))+
dot(IN_wrinkleMask_1, h4tex2D(IN_wrinkleMaskSampler_1, IN_texCoord.xy))+
dot(IN_wrinkleMask_2, h4tex2D(IN_wrinkleMaskSampler_2, IN_texCoord.xy));
const half wrinkleStrength_B =
dot(IN_wrinkleMask_3, h4tex2D(IN_wrinkleMaskSampler_3, IN_texCoord.xy))+
dot(IN_wrinkleMask_4, h4tex2D(IN_wrinkleMaskSampler_4, IN_texCoord.xy))+
dot(IN_wrinkleMask_5, h4tex2D(IN_wrinkleMaskSampler_5, IN_texCoord.xy));
half2 packedNormal = tex2D_NormalMap(IN_bumpSampler, IN_texCoord.xy).xy;
packedNormal = lerp(packedNormal, tex2D_NormalMap(IN_wrinkleNormalSampler_A, IN_texCoord.xy).xy, wrinkleStrength_A);
packedNormal = lerp(packedNormal, tex2D_NormalMap(IN_wrinkleNormalSampler_B, IN_texCoord.xy).xy, wrinkleStrength_B);
return CalculateWorldNormal(packedNormal, IN_bumpiness, IN_worldTangent, IN_worldBinormal, IN_worldNormal);
}
#endif // (WRINKLE_MAP) || (PED_WRINKLE)...
bool SSAIsOpaquePixelFrac( float2 vPos ){
return frac(dot(vPos.xy,.5f))<.5f;
}
bool SSAIsOpaquePixel( float2 vPos ){
return SSAIsOpaquePixelFrac(vPos);
}
void rageDiscard( bool killPix )
{
#if __XENON
if(killPix) clip(-1);
#else
if(killPix) discard;
#endif
}
#if __SHADERMODEL >= 40
void FadeDiscardOptional( float2 vPos, float4 fadeParams, bool extraFlag )
{
uint2 iPos = uint2(vPos) % uint2(2,2);
float fadeVal = fadeParams[iPos.x + 2*iPos.y];
rageDiscard( extraFlag && fadeVal < 1 );
}
void FadeDiscard( float2 vPos, float4 fadeParams)
{
FadeDiscardOptional( vPos, fadeParams, true );
}
#else
void FadeDiscardOptional( float2 vPos, float4 fadeParams, bool extraFlag )
{
}
void FadeDiscard( float2 vPos, float4 fadeParams)
{
}
#endif // __SHADERMODEL >= 40
// ----------------------------------------------------------------------------------------------- //
#if __MAX
// ----------------------------------------------------------------------------------------------- //
int texcoord0 : Texcoord
<
int Texcoord = 0;
int MapChannel = 1;
bool ColorChannel = true;
>;
// ----------------------------------------------------------------------------------------------- //
int texcoord1 : Texcoord
<
int Texcoord = 1;
int MapChannel = 2;
bool ColorChannel = true;
>;
// ----------------------------------------------------------------------------------------------- //
int texcoord2 : Texcoord
<
int Texcoord = 2;
int MapChannel = 3;
bool ColorChannel = true;
>;
// ----------------------------------------------------------------------------------------------- //
int texcoord3 : Texcoord
<
int Texcoord = 3;
int MapChannel = 4;
bool ColorChannel = true;
>;
// ----------------------------------------------------------------------------------------------- //
int texcoord4 : Texcoord
<
int Texcoord = 4;
int MapChannel = 5;
bool ColorChannel = true;
>;
// ----------------------------------------------------------------------------------------------- //
int texcoord5 : Texcoord // diffuse
<
int Texcoord = 5;
#if PALETTE_TINT_MAX
int MapChannel = 13; // vertex tint channel
#else
int MapChannel = 0;
#endif
bool ColorChannel = true;
>;
// ----------------------------------------------------------------------------------------------- //
int texcoord6 : Texcoord // diffuseAlpha
<
int Texcoord = 6;
int MapChannel = -2;
bool ColorChannel = true;
>;
// ----------------------------------------------------------------------------------------------- //
int texcoord7 : Texcoord // specular
<
int Texcoord = 7;
int MapChannel = 9;
bool ColorChannel = true;
>;
// ----------------------------------------------------------------------------------------------- //
int useAlphaFromDiffuse
<
string UIName = "Use Alpha From Diffuse Texture";
> = false;
// ----------------------------------------------------------------------------------------------- //
// MAX's light color:
float4 maxLightDirectionColor : LIGHTCOLOR
<
string UIName = "Light Color";
int LightRef = 0;
string UIWidget = "None";
> = {1.0f, 1.0f, 1.0f, 1.0f};
// ----------------------------------------------------------------------------------------------- //
// MAX's light direction:
float3 maxLightDirection : Direction
<
string UIName = "Light Direction";
int LightRef = 0;
string UIWidget = "None";
string Object = "TargetLight";
> = {1.0f, 1.0f, 1.0f};
// ----------------------------------------------------------------------------------------------- //
// MAX's light Position:
float4 maxLightPosition : Position
<
string UIName = "Light Position";
int LightRef = 0;
string UIWidget = "None";
string Object = "Pointlight";
//string Space = "World";
> = {0.0f, 0.0f, 0.0f, 0.0f};
// ----------------------------------------------------------------------------------------------- //
// MAX's lighting switch:
int maxLightingToggle
<
string UIName = "Lighting Toggle";
> = false;
// ----------------------------------------------------------------------------------------------- //
// MAX's lighting switch:
int maxAmbLightingToggle
<
string UIName = "Amb Lighting Toggle";
> = false;
// ----------------------------------------------------------------------------------------------- //
float3 maxLightAmbientDownColor = float3(137.0 / 255.0f, 166.0f / 255.0f, 255.0f / 255.0f);
// ----------------------------------------------------------------------------------------------- //
float3 maxLightAmbientUpColor = float3(255.0 / 255.0f, 215.0f / 255.0f, 117.0f / 255.0f);
// ----------------------------------------------------------------------------------------------- //
struct maxVertexInput
{
float3 pos : POSITION;
float2 texCoord0 : TEXCOORD0;
float2 texCoord1 : TEXCOORD1;
float2 texCoord2 : TEXCOORD2;
float2 texCoord3 : TEXCOORD3;
float2 texCoord4 : TEXCOORD4;
float4 diffuse : TEXCOORD5;
float diffuseAlpha : TEXCOORD6;
float4 specular : TEXCOORD7;
float3 normal : NORMAL;
float3 tangent : TANGENT;
float3 binormal : BINORMAL;
};
// ----------------------------------------------------------------------------------------------- //
#endif // __MAX
// ----------------------------------------------------------------------------------------------- //
#if USE_SLOPE
float CalcSlope( float v) { return saturate(v*128.f -127.f);}
#endif
#if __PSSL
bool any1(float x)
{
return x != 0;
}
bool any2(float2 xy)
{
return xy.x != 0 || xy.y != 0;
}
bool any3(float3 xyz)
{
return xyz.x != 0 || xyz.y != 0 || xyz.z != 0;
}
bool any4(float4 xyzw)
{
return xyzw.x != 0 || xyzw.y != 0 || xyzw.z != 0 || xyzw.w != 0;
}
#else
#define any1(x) any(x)
#define any2(x) any(x)
#define any3(x) any(x)
#define any4(x) any(x)
#endif
#if __XENON
#define COMPILE_PIXELSHADER_NULL() PixelShader = NULL;
#elif RSG_PC || RSG_DURANGO || RSG_ORBIS
#define COMPILE_PIXELSHADER_NULL()
#else // platforms
float4 PS_NULL() : COLOR { return 1; }
#define COMPILE_PIXELSHADER_NULL() PixelShader = compile PIXELSHADER PS_NULL() CGC_FLAGS(CGC_DEFAULTFLAGS);
#endif // platforms
// ----------------------------------------------------------------------------------------------- //
// Fast quad routines
float2 QuadTransform(float2 FixedVertex, float4 Transform)
{
return FixedVertex*Transform.xy + Transform.zw;
}
// Helpers for sm50 overrides.
#if __SHADERMODEL == 40
#define SHADER_MODEL_40_ONLY(x) x
#define SHADER_MODEL_50_OVERRIDE_TECHNIQUES(x, y) x y
#define SHADER_MODEL_50_OVERRIDE(x) x##_sm50
#elif __SHADERMODEL == 50
#define SHADER_MODEL_40_ONLY(x)
#define SHADER_MODEL_50_OVERRIDE_TECHNIQUES(x, y) y
#define SHADER_MODEL_50_OVERRIDE(x) x
#else
#define SHADER_MODEL_40_ONLY(x)
#define SHADER_MODEL_50_OVERRIDE_TECHNIQUES(x, y)
#define SHADER_MODEL_50_OVERRIDE(x)
#endif
// ----------------------------------------------------------------------------------------------- //
// PN triangle routines
#if defined(PN_TRIANGLE_TESSELLATION) && RAGE_SUPPORT_TESSELLATION_TECHNIQUES
#define USE_PN_TRIANGLES 1
#define RAGE_USE_PN_TRIANGLES 1
#define PN_TRIANGLES_ONLY(x) x
#if !defined(PN_TRIANGLES_USE_WORLD_SPACE)
#define PN_TRIANGLES_USE_WORLD_SPACE 0
#endif
#if !defined(PN_TRIANGLES_USE_DEPTH_LENGTH)
#define PN_TRIANGLES_USE_DEPTH_LENGTH 0
#endif
#else
#define USE_PN_TRIANGLES 0
#define PN_TRIANGLES_ONLY(x)
// Other code (cable.fx for example) uses PN triangles independently of tessellation techniques.
#if !defined(RAGE_USE_PN_TRIANGLES)
#define RAGE_USE_PN_TRIANGLES 0
#endif
#endif
#include "../../rage/base/src/shaderlib/rage_pntriangles.fxh"
// The PS3 sce-cgc will not allow functions with an output semantic to be called
// by other functions. This prevents wrapping of the default shaders for debug
// purposes. All other compilers seem to allow it with no issue. As a
// workaround, instead always return a struct with the output semantic specified
// on the member.
//
// The sce-cgc error message is
// error C5122: semantics not allowed on functions other than the entry function
//
struct OutHalf4Color
{
half4 col0 : COLOR;
};
struct OutFloat4Color
{
float4 col0 : COLOR;
};
struct OutHalf4Target0
{
half4 col0 : SV_Target0;
};
OutHalf4Color CastOutHalf4Color(half4 col0)
{
OutHalf4Color OUT;
OUT.col0 = col0;
return OUT;
}
OutFloat4Color CastOutFloat4Color(float4 col0)
{
OutFloat4Color OUT;
OUT.col0 = col0;
return OUT;
}
OutHalf4Target0 CastOutHalf4Target0(half4 col0)
{
OutHalf4Target0 OUT;
OUT.col0 = col0;
return OUT;
}
//Pixel shader output structure used by dof techniques (particles/alpha/decals)
#if PTFX_APPLY_DOF_TO_PARTICLES || APPLY_DOF_TO_ALPHA_DECALS
#define DOF_ALPHA_LIMIT (0.3)
struct DofOutputStruct
{
half depth : SV_Target1;
half alpha : SV_Target2;
};
#endif //PTFX_APPLY_DOF_TO_PARTICLES || APPLY_DOF_TO_ALPHA_DECALS
#if APPLY_DOF_TO_ALPHA_DECALS
struct OutHalf4Color_DOF
{
half4 col0 : COLOR;
DofOutputStruct dof;
};
#endif //APPLY_DOF_TO_ALPHA_DECALS
#endif // __GTA_COMMON_FXH__