3665 lines
125 KiB
HLSL
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__
|