Search Home Members Contacts
About Us
Products
Downloads
Community
Support
Pages: [1]
  Print  
Author Topic: Unlimited Polygonal Lights  (Read 2400 times)
Aki
Customers
Community Member
*****
Posts: 84


« on: December 31, 2009, 02:47:32 PM »

For games with camera angles like Neverwinter Nights, RTS games, or even 2D collision games like Star Wars Galaxies or KOTOR, I've created a neat lighting technique that can really improve game scenes.

This is probably just adapting a 2D technique to a 3D environment, but I haven't seen it used before. And in my opinion, it's a hell of a lot better for any outdoor environment scene than any solution I've seen.

The technique renders all the lights from a camera above the scene, then projects it back onto the scene. I've tried to do a technique like this when I didn't know anything about shaders a long time ago, but now that I do, I'm finally able to do it properly.

I find TV3D lighting very frustrating so I hope somebody else uses this technique since it's really awesome. I plan to be using it for my upcoming (mm)ORPG.

Pros:
-Unlimited lights (500 in screenshot scene)
-Fast (way faster than 60 FPS on screenshot - vsync is on)
-Any shape lights
-Very organized

Cons:
-More difficult to implement
-Loss of normal data
-No shadows (stencil shadows as used by TV3D are BAD anyways)
-No Y attenuation (without a depth surface anyways)

Load:
Code:
CameraLight = TVCameraFactory.CreateCamera();
CameraLight.SetViewIsometric(1024.0f, 1025.0f, 1.0f);
SurfaceLight = TVScene.CreateRenderSurface(1024, 1024, false, CONST_TV_RENDERSURFACEFORMAT.TV_TEXTUREFORMAT_DEFAULT);
SurfaceLight.SetNewCamera(CameraLight);
SurfaceLight.SetBackgroundColor(TVMath.Globals.RGBA(0.0f, 0.0f, 0.0f, 1.0f));

Update:
Code:
TV_3DVECTOR Position = TVScene.GetCamera().GetPosition();
CameraLight.SetCamera(Position.x, 1024.0f, Position.z, Position.x, 0, Position.z);
SurfaceLight.StartRender(false);
//Render lights
Scene.Render(CONSTANT.RENDERMODE_LIGHT);
SurfaceLight.EndRender();
TV_3DMATRIX LightMatrix = new TV_3DMATRIX();
TVMath.Math.TVMatrixMultiply(ref LightMatrix, CameraLight.GetViewMatrix(), CameraLight.GetProjectionMatrix());
//Pass params to shaders
foreach (FWorld World in Scene.WorldList)
{
    World.ShaderTerrain.SetEffectParamMatrix("LightMatrix", LightMatrix);
}

Object Shader:
Code:
/////////////////////////
// LightMatrix;
// tex0 Low Layer
// tex1 High Layer
// tex2 Cliff Layer
// tex3 Light Layer

matrix LightMatrix;

texture tex0:TEXTURE0;
sampler2D samp0 = sampler_state
{
    texture = (tex0);
};

texture tex1:TEXTURE1;
sampler2D samp1 = sampler_state
{
    texture = (tex1);
};

matrix ViewProjectionMatrix:ViewProjection;
matrix WorldMatrix:World;
float3 ViewPosition:ViewPosition;
matrix ViewMatrix={0.5,0,0,0.5,0,-0.5,0,0.5,0,0,0.5,0.5,0,0,0,1};

struct IN0
{
     float4 pos : POSITION;
     float2 uv0 : TEXCOORD0;
};

struct OUT0
{
    float4 pos : POSITION;
    float2 uv0 : TEXCOORD0;
    float2 lightproj : TEXCOORD1;
};

OUT0 VS(IN0 IN)
{
    OUT0 OUT;
    float4 Wpos = mul(IN.pos,WorldMatrix);
    OUT.pos = mul(Wpos,ViewProjectionMatrix);
    OUT.uv0 = IN.uv0;
   
    OUT.lightproj = mul(ViewMatrix,mul(Wpos,LightMatrix));
   
    return OUT;
}

float4 PS(OUT0 IN) : COLOR
{
    float4 Texture = tex2D(samp0, IN.uv0);
   
    float4 Light = pow(tex2D(samp1, IN.lightproj) * 3, 2);
    float2 SaturateProj = saturate(IN.lightproj);
    Light *= (IN.lightproj.x == SaturateProj.x && IN.lightproj.y == SaturateProj.y);
   
    float4 RGBA = Texture * Light;
    return RGBA;
}

technique Albedo
{
    pass P0
    {
        VertexShader = compile vs_2_0 VS();
        PixelShader = compile ps_2_0 PS();
    }
}

As for the lights themselves, they're just minimeshes with the following settings:
Code:
MinimeshLightPoint = TVScene.CreateMiniMesh(MinimeshMax);
MinimeshLightPoint.CreateBillboard(1.0f, 1.0f, true);
MinimeshLightPoint.SetTexture(TexturePointLight); //Gradient - bright in center, black at edge or any shape you like - yes, real area lights are possible
MinimeshLightPoint.SetColorMode(true);
MinimeshLightPoint.SetAlphaTest(true, 0, false);
MinimeshLightPoint.SetAlphaToCoverage(true);
MinimeshLightPoint.SetBlendingMode(CONST_TV_BLENDINGMODE.TV_BLEND_ADDALPHA);

Screenshot attached I hope. Unfortunately, I'm too lazy to put together an example program since it's really tangled inside my project right now. I feel guilty keeping this technique to myself, though Sad
« Last Edit: December 31, 2009, 02:49:52 PM by Aki » Logged

Celledor
Customers
Community Member
*****
Posts: 242


WWW
« Reply #1 on: January 04, 2010, 04:27:20 AM »

Looks great, will try it out if I get the time... have any techniques you recomend using with this to get nice shadows?
Logged

Aki
Customers
Community Member
*****
Posts: 84


« Reply #2 on: January 04, 2010, 06:22:52 AM »

I've been using shadow mapping with a directional light for sunlight shadows, which are good enough for me. Having hundreds of fully dynamic tiny lights casting shadows wouldn't really be possible, though.

However, I suppose it would be possible to render depth cubemaps for each light once, then project the cubemap depth texture as a 2D texture onto the light projection texture, but it'd have to be static.

Or, you can do a technique like this one or this one.

If somebody figured that out, it'd be reallllllllllly complicated but completely awesome.

Or, you can render things like walls as black and move them away from light sources, but it wouldn't look right all the time and would be very hacky.

In short, no. I'd say just use this plus shadow mapping for a direcitonal light  Grin
Logged

kTecH
Customers
Community Member
*****
Posts: 132


« Reply #3 on: January 04, 2010, 12:50:47 PM »

I've been using shadow mapping with a directional light for sunlight shadows, which are good enough for me.

Can you PLEASE post your directional light shader?
Logged
Raul
Customers
Community Member
*****
Posts: 550

I like games.


WWW
« Reply #4 on: January 04, 2010, 01:13:02 PM »

Can you PLEASE post your directional light shader?

yeah. I want to have a look to Smiley
Logged

Aki
Customers
Community Member
*****
Posts: 84


« Reply #5 on: January 05, 2010, 11:20:32 AM »

Suuure, it's not too impressive - there's no PSSM or VSM or any of that fancy crap, since I just use it for structure and nature geometry. But it's really easy to implement.

Load:
Code:
CameraShadow = TVCameraFactory.CreateCamera();
CameraShadow.SetViewIsometric(512.0f, 1024.0f, 1.0f);

SurfaceShadow = TVScene.CreateRenderSurface(1024, 1024, true, CONST_TV_RENDERSURFACEFORMAT.TV_TEXTUREFORMAT_HDR_R32F);
SurfaceShadow.SetNewCamera(CameraShadow);
SurfaceShadow.SetBackgroundColor(TVMath.Globals.RGBA(0.0f, 0.0f, 1.0f, 1.0f));

Update:
Code:
TV_4DVECTOR ShadowPosition = new TV_4DVECTOR(Position.x + 256.0f, 768.0f, Position.z + 256.0f, 1024.0f);
CameraShadow.SetCamera(ShadowPosition.x, ShadowPosition.y, ShadowPosition.z, Position.x, 0.0f, Position.z);
TV_3DMATRIX ShadowMatrix = new TV_3DMATRIX();
TVMath.Math.TVMatrixMultiply(ref ShadowMatrix, CameraShadow.GetViewMatrix(), CameraShadow.GetProjectionMatrix());
foreach (FWorld World in Scene.WorldList)
{
                World.ShaderTerrain.SetEffectParamVector("ShadowPosition", ShadowPosition);
                World.ShaderTerrain.SetEffectParamMatrix("ShadowMatrix", ShadowMatrix);
                World.ShaderTerrainDepth.SetEffectParamVector("ShadowPosition", ShadowPosition);
}
//Render using depth shader
SurfaceShadow.StartRender(false);
Scene.Render(CONSTANT.RENDERMODE_DEPTH);
SurfaceShadow.EndRender();

Depth Shader:
Code:
//////////////////////////////////////////////////
//
// Shadow Shader
//
//////////////////////////////////////////////////

/////////////////////////
// ShadowPosition
// tex0 Texture

float4 ShadowPosition;

texture tex0:TEXTURE0;
sampler2D samp0 = sampler_state
{
    texture = (tex0);
};

matrix WorldMatrix:World;
matrix VPMatrix:ViewProjection;

struct IN0
{
    float4 pos : POSITION;
};

struct OUT0
{
    float4 pos : POSITION;
    float depth : TEXCOORD0;
};

OUT0 VS(IN0 IN)
{
    OUT0 OUT;
    float4 Wpos = mul(IN.pos,WorldMatrix);
    OUT.pos = mul(Wpos,VPMatrix);
    OUT.depth = saturate((ShadowPosition.y-Wpos.y)/ShadowPosition.w);
    return OUT;
}

float4 PS(OUT0 IN) : COLOR
{
    float Color = IN.depth;
    return float4(Color,0,0,1);
}

technique Depth
{
    pass P0
    {
        VertexShader = compile vs_2_0 VS();
        PixelShader = compile ps_2_0 PS();
    }
}

Okay, it didn't need the texture struct, but I keep it in there just incase anybody wants to implement alpha transparency. I've got a minimesh depth shader too, if anybody is too lazy to make one.

The REAL shader:
Code:
//////////////////////////////////////////////////
//
// Terrain Shader
//
//////////////////////////////////////////////////

/////////////////////////
// ShadowPosition;
// ShadowMatrix;
// tex0 Low Layer
// tex1 Shadow

float4 ShadowPosition;
matrix ShadowMatrix;

texture tex0:TEXTURE0;
sampler2D samp0 = sampler_state
{
    texture = (tex0);
};

texture tex1:TEXTURE1;
sampler2D samp1 = sampler_state
{
    texture = (tex1);
};

matrix ViewProjectionMatrix:ViewProjection;
matrix WorldMatrix:World;
float3 ViewPosition:ViewPosition;
matrix ViewMatrix={0.5,0,0,0.5,0,-0.5,0,0.5,0,0,0.5,0.5,0,0,0,1}; //Whatever you do, don't change this
float ZDepth = 0.004f; //You might have to change this

struct IN0
{
     float4 pos : POSITION;
     float2 uv0 : TEXCOORD0;
};

struct OUT0
{
    float4 pos : POSITION;
    float4 uv0 : TEXCOORD0;
    float4 shadowproj : TEXCOORD1;
};

OUT0 VS(IN0 IN)
{
    OUT0 OUT;
    float4 Wpos = mul(IN.pos,WorldMatrix);
    OUT.pos = mul(Wpos,ViewProjectionMatrix);
    OUT.uv0 = IN.uv0;
   
    OUT.shadowproj.xy = mul(ViewMatrix,mul(Wpos,ShadowMatrix));
    OUT.shadowproj.z = ShadowPosition.y-Wpos.y;
   
    Distance = float2(0.5f, 0.5f) - OUT.shadowproj.xy;
    OUT.shadowproj.w = 1.0f - saturate(4.0f * dot(Distance, Distance));
   
    return OUT;
}

float4 PS(OUT0 IN) : COLOR
{
    float4 Diffuse = tex2D(samp1, IN.uv0)

    float Depth = 4.0f;
    //I forget what this technique is called, but it helps smooth out the edges of the shadows
    Depth -= IN.shadowproj.z/ShadowPosition.w>tex2D(samp4, IN.shadowproj.xy+float2(0.00025f,0.00025f)).r+ZDepth;
    Depth -= IN.shadowproj.z/ShadowPosition.w>tex2D(samp4, IN.shadowproj.xy+float2(-0.00025f,-0.00025f)).r+ZDepth;
    Depth -= IN.shadowproj.z/ShadowPosition.w>tex2D(samp4, IN.shadowproj.xy+float2(-0.00025f,0.00025f)).r+ZDepth;
    Depth -= IN.shadowproj.z/ShadowPosition.w>tex2D(samp4, IN.shadowproj.xy+float2(0.00025f,-0.00025f)).r+ZDepth;
   
    Depth /= 4;
    Depth = lerp(1.0f, Depth, IN.shadowproj.w);
   
    float4 Shadow = float4(0.5, 0.4, 0.3, 1.0) * Depth;
   
    float4 RGBA = Diffuse * (Shadow + float4(0.4f, 0.4f, 0.4f, 1.0f));
    return RGBA;
}

technique Albedo
{
    pass P0
    {
        VertexShader = compile vs_2_0 VS();
        PixelShader = compile ps_2_0 PS();
    }
}

It's disorganized because I haven't finished everything yet! It shouldn't be too hard to figure out, though. The two float4s in the shader that aren't using a neat variable name are just directional and ambient light, which should be parametrized. So should some other things, but to me, it's not worth the effort of de-organizing everything. Oh, and this one has a neat fade at the edges instead of the clipping like the old light shader used.

My original shader has these two combined, so I've really just made it more difficult for you to use both  (they should work alone, I haven't tried) Roll Eyes
Logged

DarekRuman
Customers
Community Member
*****
Posts: 184

game developer


WWW
« Reply #6 on: January 09, 2010, 05:07:57 PM »

Many Thanks!

Based on your light shader I managed to implement projected shadow in my road reflection shader Smiley

It's hard to see but projected shadow is there ! Smiley


http://img402.imageshack.us/img402/5690/fiatshadow.jpg
Logged

www.reddotgames.pl
tv6.3 tv6.5 developer
games made in TV : Paintball Extreme, Reindeer Adventure, Mole : Great Adventure, Foxy Fox, Włatcy móch : Śnieżna Rozwałka, Włatcy Móch : Magiczni Wojownicy, Ski:), Lowrider Extreme
Aki
Customers
Community Member
*****
Posts: 84


« Reply #7 on: January 09, 2010, 08:14:08 PM »

That's brilliant! I didn't even think of using it for shadows. And it looks nice too Smiley
Logged

Zaknafein
Customers
Community Member
*****
Posts: 2940


WWW
« Reply #8 on: January 10, 2010, 03:20:36 PM »

That looks ridiculously awesome DarekRuman! You stuff gets better and more polished all the time. Smiley
Logged

DarekRuman
Customers
Community Member
*****
Posts: 184

game developer


WWW
« Reply #9 on: January 11, 2010, 12:36:39 PM »

That looks ridiculously awesome DarekRuman! You stuff gets better and more polished all the time. Smiley

Thanks! Smiley

You can take a look on video here : http://www.truevision3d.com/forums/showcase/my_racing_game-t19839.0.html;msg135965#msg135965

Logged

www.reddotgames.pl
tv6.3 tv6.5 developer
games made in TV : Paintball Extreme, Reindeer Adventure, Mole : Great Adventure, Foxy Fox, Włatcy móch : Śnieżna Rozwałka, Włatcy Móch : Magiczni Wojownicy, Ski:), Lowrider Extreme
rootsage
Customers
Community Member
*****
Posts: 444

Gamer Enthusiast


WWW
« Reply #10 on: January 14, 2010, 06:49:02 PM »


Very nice, man! I am loving it...
Logged

while( !( succeed = try_again()) );
------
10 print "Is this recursive?"
20 goto 10
Pages: [1]
  Print  
 
Jump to:  

Powered by SMF 1.1.3 | SMF © 2006-2007, Simple Machines LLC
Seo4Smf v0.2 © Webmaster's Talks