1 registered members (BrainSailor),
869
guests, and 5
spiders. |
Key:
Admin,
Global Mod,
Mod
|
|
|
Re: Dynamic light bleeding
[Re: Stansmedia]
#442974
07/07/14 08:15
07/07/14 08:15
|
Joined: Mar 2011
Posts: 3,150 Budapest
sivan
Expert
|
Expert
Joined: Mar 2011
Posts: 3,150
Budapest
|
okay, too long thread for a simple thing. use this or shut up forever (I mean, ask if something unclear, except WED related stuff because I don't use it) without advertising my little free editor, but there you can find a lovely shader set supporting what you need. for example a simple normal mapping shader without lod (the other one does not apply normal mapping for far lods): - max 8 dynamic point lights. - optional per pixel lighting. - specular lighting for Sun. (but you can modify it to work with a directional light) - optional support for specular map put in normal map alpha channel. - uses material ambient/diffuse/specular/emissive/albedo/power, entity rgb/ambient. - alphatesting. - shadowmapping (requires outer file from MapBuilder package), but fine with pssm too. - it works fast for many entities in the level (but its lodded version might be faster). - shader model 3.0 with fog support. - fake sky lighting (a secondary distance fog). - height fog (requires outer dependency). Notes: as you can see in the vertex shader, the binormal calculation is a bit tricky, it differs from all the ones I found in 3dgs or other shader related sources, but only it works fine for map entities or models created from WED blocks, for any Sun angle. other calculations including the one in shader tutorials provide bad lighting (differs on sunny and shadowed sides). just comment out shadowmapping related lines to get it work. add a line where variables are: float scsm_brightness = 1.0; (I use 1.6 to get brighter, more dynamic light range) there are some lines commented out how to use BumpStrength (it should be read from an entity skill or a global varialble which is not implemented) set object material ambient to 50-50-50, and material diffuse to 225-225-225, emissive to 0,0,0 and specular (0..255) and power (0..10) to any you wish. set Sun to a high value (rgb over 200, sun light over 80). tested with dynamic light entities: lightrange 50, ambient 50, BRIGHT, rgb 255,0,0 (for colour correctness, but any works). sc_obj_modelN_nolodMB.fx
bool AUTORELOAD;
//bool REQUIRE_NORMAL;
////////////////////////////////////////////////////////////////////////////////////////////////
// defines
#define PER_PIXEL_LIGHTS
//#define SPECULAR_MAP
////////////////////////////////////////////////////////////////////////////////////////////////
// matrices, vectors, variables passed by the engine
float4x4 matWorldViewProj;
float4x4 matWorld;
float3x3 matTangent; // needed for normalmapping
float4 vecFog;
float4 vecFogColor;
float4 vecViewPos;
float4 vecViewDir;
float4 vecSunColor;
float4 vecSunPos;
float3 vecSunDir;
float4 vecLight;
float4 vecColor;
float4 vecAmbient;
float4 vecDiffuse;
float4 vecSpecular;
float4 vecEmissive;
float fPower;
////////////////////////////////////////////////////////////////////////////////////////////////
// skins/textures
texture entSkin1; // Colormap
// Color map sampler
sampler colorSampler = sampler_state
{
Texture = <entSkin1>;
MinFilter = Linear;
MagFilter = Linear;
MipFilter = Linear;
};
texture entSkin2; // Normalmap
// Normal map sampler
sampler NormalSampler = sampler_state
{
Texture = <entSkin2>;
MinFilter = Linear;
MagFilter = Linear;
MipFilter = Linear;
};
////////////////////////////////////////////////////////////////////////////////////////////////
// includes
#include "sc_defines_MB.fx"
#include "sc_pointlight_MB.fx"
#include "sc_shadowmapping_MB.fx" // scsm shadowmapping - variables, shadow samplers, vertex shader functions, pixel shader function
#ifdef HEIGHT_FOG
#include "sc_heightfog_MB.fx" // blend distance fog with height fog
#endif
//////////////////////////////////////////////////////////////////////////////////////////////////
// structs
struct outVS
{
float4 Color : COLOR0;
float4 Pos : POSITION;
float2 Tex : TEXCOORD0;
float3 ViewDir : TEXCOORD1;
float3 WorldNormal : TEXCOORD2;
// float3 SunDir : TEXCOORD3;
#ifdef SKY_LIGHT
float SkyLight : TEXCOORD3;
#endif
#ifdef PER_PIXEL_LIGHTS
float3 WorldPos : TEXCOORD4;
#endif
float3 Tangent : TEXCOORD5;
float3 Binormal : TEXCOORD6;
float4 Shadow : TEXCOORD7;
float Fog : FOG;
};
struct inPS
{
float4 Color : COLOR0;
float2 Tex : TEXCOORD0;
float3 ViewDir : TEXCOORD1;
float3 WorldNormal : TEXCOORD2;
// float3 SunDir : TEXCOORD3;
#ifdef SKY_LIGHT
float SkyLight : TEXCOORD3;
#endif
#ifdef PER_PIXEL_LIGHTS
float3 WorldPos : TEXCOORD4;
#endif
float3 Tangent : TEXCOORD5;
float3 Binormal : TEXCOORD6;
float4 Shadow : TEXCOORD7;
float Fog : FOG;
};
//////////////////////////////////////////////////////////////////////////////////////////////////
// vertex shader
outVS ModelNVS
(
float4 InPos : POSITION,
float3 InNormal : NORMAL,
float2 InTex : TEXCOORD0,
float3 InTangent : TEXCOORD2 // was float4 but that is bad with flat separated surfaces
)
{
outVS Out;
// InPos.w = 1.0f; // to get proper matrix multiplication?
//----------------------------------------------------------------
Out.Tex = InTex;
//---------------------------------------------------------------
float4 PosWorld = mul(InPos, matWorld); // needed for a couple of calculations... float4 for shadowmapping!
//----------------------------------------------------------------
Out.Pos = mul(InPos, matWorldViewProj);
//----------------------------------------------------------------
{}
#ifdef PER_PIXEL_LIGHTS
Out.WorldPos = PosWorld.xyz;
#endif
//----------------------------------------------------------------
Out.ViewDir = normalize(vecViewPos.xyz - PosWorld.xyz);
//----------------------------------------------------------------
Out.Tangent = normalize( mul(InTangent.xyz, (float3x3)matWorld) ); // tangent (*bumpstrength)
Out.Binormal = -abs(normalize( mul(cross(InTangent.xyz,InNormal), (float3x3)matWorld) )); // binormal, without cross() * InTangent.w !!! (*bumpstrength)
// - abs(binormal) is needed because of float3 tangent, and to have similarly correct vertical shading on all sides!
Out.WorldNormal = normalize( mul(InNormal, (float3x3)matWorld) ); // normal
//----------------------------------------------------------------
#ifndef HEIGHT_FOG
Out.Fog = vecFogColor.w // fog is applied
* saturate( (distance(PosWorld, vecViewPos) - vecFog.x) * (vecFog.z) ); // saturate needed when fadeout distance is closer than clipping distance
#else
Out.Fog = VS_heightfog(PosWorld.xyz);
#endif
//----------------------------------------------------------------
#ifdef SKY_LIGHT
Out.SkyLight = saturate( (distance(PosWorld, vecViewPos) - map_skylight_start_var) / (map_skylight_end_var - map_skylight_start_var) );
#endif
//----------------------------------------------------------------
Out.Shadow = VS_shadowmapping(PosWorld);
//----------------------------------------------------------------
// lighting
// final color
Out.Color = (vecAmbient * vecLight) + (vecEmissive * vecColor); // ambient + emissive
{}
#ifndef PER_PIXEL_LIGHTS
float4 Lights = 0;
for (int i=1; i<iLights; i++) // add (max 7) dynamic lights (except Sun)
Lights += PointLightDiffuse(PosWorld, Out.WorldNormal, i-1);
Lights *= 2.0f * vecDiffuse;
Out.Color += Lights;
#endif
//-----------------------------------------------------------------
return Out;
}
//////////////////////////////////////////////////////////////////////////////////////////////////
// pixel shader
float4 ModelNPS(inPS In): COLOR
{
//----------------------------------------------------------
// shadowmapping
float Shadow = clamp( PS_shadowmapping(In.Shadow, scsm_esm_obj_var), 1-scsm_run_var, 1);
//----------------------------------------------------------
// normalize input vectors
// float BumpStrength = 2.0f;
In.ViewDir = normalize(In.ViewDir);
// In.Tangent = normalize(In.Tangent) * BumpStrength;
// In.Binormal = normalize(In.Binormal) * BumpStrength;
// In.WorldNormal = normalize(In.WorldNormal);
//----------------------------------------------------------
// normal mapping
{}
#ifndef SPECULAR_MAP
float3 NormalMap = 2 * tex2D(NormalSampler, In.Tex).rgb - 1; // Read the normal from the normal map and convert from [0..1] to [-1..1] range
NormalMap = normalize(In.Tangent * NormalMap.r + In.Binormal * NormalMap.g + In.WorldNormal * NormalMap.b); // transform to world space
#else
float4 BumpSpec = tex2D(NormalSampler, In.Tex);
float SpecularMap = BumpSpec.a;
float3 NormalMap = 2 * BumpSpec.rgb - 1;
NormalMap = normalize(In.Tangent * NormalMap.r + In.Binormal * NormalMap.g + In.WorldNormal * NormalMap.b);
#endif
//----------------------------------------------------------
// Sun lighting
float LightIntensity = saturate(dot(NormalMap, -vecSunDir));
// diffuse
float4 Diffuse = scsm_brightness * 5.0 * vecDiffuse * LightIntensity * vecSunColor * vecLight;
// specular
float4 Specular = 0;
if (LightIntensity * Shadow > 0.50f) // a bit higher limtit looks fine and more exact, than in flat shading (no speculars under shadows)
{
float3 Halfway = saturate(dot(normalize(In.ViewDir - vecSunDir), NormalMap));
Specular = vecSpecular * pow( dot(NormalMap, Halfway), fPower) * vecSunColor * vecLight;
{}
#ifdef SPECULAR_MAP
// specular mapping
Specular = Specular * SpecularMap;
#endif
}
// specular - another calculation
// float3 Reflect = normalize(2 * LightIntensity * In.WorldNormal - vecSunDir); // R
// float4 Specular = vecSpecular * pow(saturate(dot(Reflect, In.ViewDir)), fPower) * vecSunColor * vecLight; // R.V^n
//----------------------------------------------------------
// texture - keep its alpha afterwards
float4 Color = tex2D(colorSampler, In.Tex);
//----------------------------------------------------------
// dynamic lights
{}
#ifdef PER_PIXEL_LIGHTS
float4 Lights = 0;
for (int i=1; i<iLights; i++) // add max 8 dynamic lights, ignore the last which is the Sun
Lights += PointLightDiffuse(In.WorldPos, NormalMap, i-1);
Lights *= 2.0f * vecDiffuse;
#ifdef DEBUG_TILE
Color.rgb *= DebugTerrain(In.WorldPos, In.WorldNormal);
#endif
//----------------------------------------------------------
// add lighting to color
Color.rgb *= (Diffuse + Specular + Lights + In.Color); // with per pixel dynamic lights, InColor contains only entity ambient fAmbient
#else
Color.rgb *= (Diffuse + Specular + In.Color); // with per vertex dynamic lights
#endif
//----------------------------------------------------------
// add shadows
Color.rgb *= Shadow; // dynamic shadows, added to lightintensity
//----------------------------------------------------------
// add fog
Color.rgb = lerp(Color.rgb, vecFogColor, In.Fog); // sm 3.0 fog support
//----------------------------------------------------------
// add sky light
{}
#ifdef SKY_LIGHT
Color.rgb = lerp(Color.rgb, map_skylight_color_var, In.SkyLight);
#endif
//----------------------------------------------------------
return Color;
}
////////////////////////////////////////////////////////////////////////////////////////////////
technique model
{
pass p0
{
// cullmode = none;
ZWriteEnable = True;
AlphaTestEnable = True;
AlphaBlendEnable = False;
VertexShader = compile vs_3_0 ModelNVS();
PixelShader = compile ps_3_0 ModelNPS();
}
}
//////////////////////////////////////////
technique fallback
{
pass
{
// cullmode = none;
ZWriteEnable = True;
AlphaTestEnable = True;
AlphaBlendEnable = False;
}
}
sc_pointlight_MB.fx
///////////////////////////////////////////////////////////////////////////////////////////
// varialbles
float4 vecLightPos[8];
float4 vecLightColor[8];
//float4 vecLightDir[8]; // normalized vector, only for directional lights, otherwise vecLightDir.w == 0
int iLights;
///////////////////////////////////////////////////////////////////////////////////////////
// original approach (no vecDiffuse and diffuse light weighting applied inside the functions)
// diffuse - original version
float4 PointLightDiffuse(float3 WorldPos, float3 WorldNormal, int i)
{
float3 LightDir = vecLightPos[i].xyz - WorldPos;
float LightIntensity = saturate(dot(WorldNormal, normalize(LightDir)));
float4 Color = vecLightColor[i] * LightIntensity;
float LightFactor = 0.f;
// if ((LightIntensity >= 0.f) && (vecLightPos[i].w > 0.f)) // vecLightPos.w (range) check can be neglected because of iLights?
// if (LightIntensity >= 0.f) // alway because of saturate
{
float LightAttenuation = length(LightDir) / vecLightPos[i].w;
if (LightAttenuation < 1.f)
{
LightFactor = 1.f - LightAttenuation;
}
}
return Color * LightFactor;
}
///////////////////////////////////////////////////////////////////////////////////////////
Last edited by sivan; 07/07/14 08:23.
|
|
|
Re: Dynamic light bleeding
[Re: sivan]
#443047
07/08/14 13:22
07/08/14 13:22
|
Joined: Jul 2007
Posts: 619 Turkey, Izmir
Emre
User
|
User
Joined: Jul 2007
Posts: 619
Turkey, Izmir
|
Ahahahahah okay, too long thread for a simple thing. use this or shut up forever This one is good too @Stansmedia there are a lot of good shader in Aum75 (Slin's shaders) maybe you should look at them. here's one (per pixel light)
//Variables
float4x4 matWorld;
float4x4 matWorldViewProj;
float4 vecViewDir;
float4 vecViewPos;
float4 vecFog;
float4 vecTime;
float4 vecColor;
float4 vecLight;
float4 vecLightPos[8];
float4 vecLightColor[8];
//Textures
texture entSkin1;
//Sampler
sampler colorMap = sampler_state
{
Texture = (entSkin1);
AddressU = Wrap;
AddressV = Wrap;
MagFilter = Linear;
MinFilter = Linear;
MipFilter = Linear;
};
//Structs
struct VS_TO_PS // Output to the pixelshader
{
float4 Pos : POSITION;
float Fog : FOG;
float2 Tex0 : TEXCOORD0;
float3 WPos : TEXCOORD1;
float3 Norm : TEXCOORD2;
};
//Vertexshader
VS_TO_PS VS_v0( float4 inPos : POSITION,
float3 inNormal : NORMAL,
float2 inTex0 : TEXCOORD0 )
{
VS_TO_PS Out;
//Do transformations
Out.Pos = mul(inPos,matWorldViewProj);
//Pass the Texcoords
Out.Tex0 = inTex0;
//Vertexposition in worldspace
Out.WPos = mul(inPos,matWorld);
//Vertexnormal
Out.Norm = normalize(mul(inNormal,matWorld));
//Fog
Out.Fog = 1 - (distance(Out.WPos,vecViewPos)-vecFog.x) * vecFog.z;
return Out;
}
//Pixelshader
float4 PS_p0( VS_TO_PS In ) : COLOR
{
float3 LightDir;
float3 Diffuse = vecLight+0.5;
float attenuation = 0;
for(int i = 0; i < 5; i++)
{
LightDir = vecLightPos[i]-In.WPos;
attenuation = saturate(1.0f - length(LightDir/vecLightPos[i].w));
Diffuse += saturate(dot(normalize(LightDir),In.Norm))*vecLightColor[i]*attenuation;
}
float4 Color = tex2D(colorMap,In.Tex0);
Color.rgb *= Diffuse;
return Color;
}
//////////////////////////////////////////////////////////////////
technique Lighting
{
pass one
{
AlphaTestEnable = True;
zWriteEnable = true;
VertexShader = compile vs_1_1 VS_v0();
PixelShader = compile ps_2_0 PS_p0();
}
}
technique fallback { pass one { } }
|
|
|
|