Cone Step Mapping (Ogre CG port)

A place to show off your latest screenshots and for people to comment on them. Only start a new thread here if you have some nice images to show off!
User avatar
nullsquared
Old One
Posts: 3245
Joined: Tue Apr 24, 2007 8:23 pm
Location: NY, NY, USA
x 11

Cone Step Mapping (Ogre CG port)

Post by nullsquared »

Paper & demo here: http://www.gamedev.net/community/forums ... _id=372739 (appears to be some patenting issues, don't use this commercially without researching all of that first)

I consider CSM completely superior to relief mapping or parallax occlusion mapping for 2 reasons:
- it's crazy fast
- it's crazy accurate
However, it has its own fallback: you must pre-process all of your height maps to produce cone step maps. Yet, this not all that bad, considering you can extract normals from the cone step map, meaning there's no need for an additional normal map.

Well, here's the quick port of texture-based LOD CSM (variable # of steps) to CG:

.cg

Code: Select all

struct VIn
{
    float4 p     : POSITION;
    float3 t     : TANGENT;
    float3 n     : NORMAL;
    float2 uv    : TEXCOORD0;
};

struct VOut
{
    float4 p     : POSITION;
    float2 uv    : TEXCOORD0;
    float3 tsPos : TEXCOORD1; // texture-space [view-space vertex] position
};

struct PIn
{
    float2 uv    : TEXCOORD0;
    float3 tsPos : TEXCOORD1; // texture-space [view-space vertex] position
};

struct POut
{
    float4 colour: COLOR0;
};

VOut csm_vs(VIn IN,
    uniform float4x4 wvMat,
    uniform float4x4 wvpMat,
    uniform float tile)
{
    VOut OUT;
    OUT.p = mul(wvpMat, IN.p);
    OUT.uv = IN.uv * tile;

    // cross binormal in OBJECT-SPACE!
    // (otherwise you'll get oddities)
    float3 binormal = cross(IN.t, IN.n);

    // transform normal to view space
    float3 normal = mul(wvMat, float4(IN.n, 0)).xyz;
    normal = normalize(normal);

    // transform tangent to view space
    float3 tangent = mul(wvMat, float4(IN.t, 0)).xyz;
    tangent = normalize(tangent);

    // transform binormal to view space
    binormal = mul(wvMat, float4(binormal, 0)).xyz;
    binormal = normalize(binormal);

    // get the TBN matrix for multiplication
    float3x3 tbn = float3x3(tangent, binormal, normal);

    // get the view-space position of the vertex
    float3 vsPos = mul(wvMat, IN.p).xyz;
    // transform it by the TBN matrix
    OUT.tsPos = mul(tbn, vsPos);

    return OUT;
}

//! COURTESY OF THE CONE-STEP-MAPPING DEMO FOUND AT GAMEDEV.NET
//! http://www.gamedev.net/community/forums/topic.asp?topic_id=372739
void intersect_square_cone_exp(sampler2D csmMap, inout float3 dp, float3 ds, float dist_factor)
{
    // the "not Z" component of the direction vector (for a square cone)
    float iz = max(abs(ds.x), abs(ds.y));
    // my starting location (is at z=0)
    // texture lookup
    float4 t;
    // and how high above the surface am I?
    float ht, old_ht;
    float CR = 0.0;

    //	find the starting location and height
    t = tex2D(csmMap,dp.xy);
    while (t.r > dp.z)
    {
        CR = t.g * t.g;

        // right, I need to take one step.
        // I use the current height above the texture,
        // and the information about the cone-ratio
        // to size a single step.  So it is fast and
        // precise!  (like a coneified version of
        // "space leaping", but adapted from voxels)

        // experimental!!!
        // and take the step
        dp += ds * (dist_factor + (t.r - dp.z) * CR) / (iz + CR);

        //	find the new location and height

        // use tex2Dlod and the first mipmap to avoid
        // using slow gradient-based tex2D fetches with ddx/ddy
        t = tex2Dlod(csmMap, float4(dp.xy, 0, 0));
    }

    // back out to where the cone was (remove the w component)
    //*
    ht = (t.r - dp.z);
    dist_factor /= (iz + CR);
    dp -= ds * dist_factor;
    //*/
    // and sample it
    //*
    t = tex2D(csmMap,dp.xy);
    old_ht = t.r - dp.z;
    // linear interpolation
    dp += ds * dist_factor * (1.0 - clamp (ht / (ht - old_ht), 0.0, 1.0));
    //*/


    // and a nice cone step
    //*
    t = tex2D(csmMap, dp.xy);
    dp += ds * (t.r - dp.z) / (iz/(t.g*t.g) + 1.0);
    //*/

    // all done
    return;
}

POut csm_ps(PIn IN,
    uniform float4 texSize,
    uniform float depth, // depth scale of the surface
    uniform sampler2D diffuseMap : TEXUNIT0,
    uniform sampler2D csmMap : TEXUNIT1)
{
    POut OUT;

    float a = -depth / IN.tsPos.z;
    float3 s = float3((IN.tsPos * a).xy, 1);
    // texture-delta-based LOD
    float df = 0.05 * sqrt(length(fwidth(IN.uv)));

    float3 uv = float3(IN.uv, 0);
    intersect_square_cone_exp(csmMap, uv, s, df);

    // expand normal from normal map in local polygon space
    // blue = df/dx
    // alpha = df/dy

    // not used in this little port
    // (you'd use this for NdotL with the tangent-space light direction)

//    float4 normal = tex2D(csmMap, uv.xy);
//    normal = float4((normal.ba - 0.5) * (-depth * texSize.xy), 1.0, 0.0);
//    normal.xyz = normalize(normal.xyz);

    float4 diffuse = tex2D(diffuseMap, uv.xy);

    OUT.colour = diffuse;

    return OUT;
}
.material

Code: Select all

vertex_program csm_vs cg
{
    source csm.cg
    profiles vs_1_1 arbvp1
    entry_point csm_vs
    default_params
    {
        param_named_auto wvpMat worldviewproj_matrix
        param_named_auto wvMat worldview_matrix
        param_named tile float 1
    }
}

fragment_program csm_ps cg
{
    source csm.cg
    profiles ps_3_0 arbfp1
    entry_point csm_ps
    default_params
    {
        param_named_auto texSize texture_size 0
        param_named depth float 0.15
    }
}

material csm_template
{
    technique
    {
        pass
        {
            vertex_program_ref csm_vs
            {
            }

            fragment_program_ref csm_ps
            {
            }

            texture_unit diffuse_map
            {
                texture rockwall_d.bmp
            }

            texture_unit csm_map
            {
                texture rockwall_csm.png
            }
        }
    }
}
Images to test with until you get the cone step map processor:
ImageImage

There's no lighting done since I use this for deferred shading, adding lighting is up to you (just transform the light position same was as the vertex position, subtract, and dot against the commented-out normals).

(once again, there's patent issues, I'm just kind of assuming porting it like this is not against the patents :lol: )

Oh, and this is another little piece of code that I can't run in OpenGL. Technically, it should Just work with fp40, but my machine is a little fubar right now, so I can't make it work myself.

Screenshots (1 quad with cone-step mapping):
Image
Image
Image
Image
(I used a small alpha_rejection hack above to reject tiling, very cool-looking for terrains and what-not)

And, I almost forgot: the tool to generate cone step maps from height maps is found with the demo at the link I posted to gamedev.
Last edited by nullsquared on Sun Jul 13, 2008 5:47 pm, edited 4 times in total.
Caphalor
Greenskin
Posts: 116
Joined: Tue Feb 06, 2007 8:54 pm
Location: Berlin, Germany
x 25

Post by Caphalor »

You are very fast. :D
Looks awesome, even without lightening!
User avatar
nullsquared
Old One
Posts: 3245
Joined: Tue Apr 24, 2007 8:23 pm
Location: NY, NY, USA
x 11

Post by nullsquared »

Caphalor wrote:You are very fast. :D
All I did was port some GLSL code to CG :) (and guess what most of the 1-letter variables meant :lol:) Sorry about cluttering your thread up with CSM/RSM stuff, though.
User avatar
PolyVox
OGRE Contributor
OGRE Contributor
Posts: 1316
Joined: Tue Nov 21, 2006 11:28 am
Location: Groningen, The Netherlands
x 18
Contact:

Post by PolyVox »

Dude, slow down. You're making the rest of us look bad :P

Seriously though, very impressive. Is this the relaxed variant of CSM? And how long does it take to generate the cone maps?
User avatar
nullsquared
Old One
Posts: 3245
Joined: Tue Apr 24, 2007 8:23 pm
Location: NY, NY, USA
x 11

Post by nullsquared »

PolyVox wrote:Is this the relaxed variant of CSM?
Nope. It's just the original cone step mapping from one of the geniuses over at gamedev.net. Well, it's the texture-based LOD variant with a variable number of steps. There's also 3-step and 10-step variants that I didn't port, as well as a distance-based LOD variant that I didn't port, either. But the base code is pretty much the same, you can just "plug-n-play".
And how long does it take to generate the cone maps?
Using his tool, it takes maybe 1-2 seconds to generate one 512x512 cone step map. Apparently, you can batch stuff very easily with his tool, and it outputs in DDS/TGA/PNG all at once. So just produce height maps (no normal maps needed) for all of your stuff and then batch-convert to cone step maps.

Try it yourself, just download his demo and you'll get the height-map converter, too.
User avatar
vilgeits
Goblin
Posts: 298
Joined: Tue Aug 02, 2005 10:41 pm

Post by vilgeits »

nullsquared wrote:
PolyVox wrote:Is this the relaxed variant of CSM?
Nope. It's just the original cone step mapping from one of the geniuses over at gamedev.net. Well, it's the texture-based LOD variant with a variable number of steps. There's also 3-step and 10-step variants that I didn't port, as well as a distance-based LOD variant that I didn't port, either. But the base code is pretty much the same, you can just "plug-n-play".
And how long does it take to generate the cone maps?
Using his tool, it takes maybe 1-2 seconds to generate one 512x512 cone step map. Apparently, you can batch stuff very easily with his tool, and it outputs in DDS/TGA/PNG all at once. So just produce height maps (no normal maps needed) for all of your stuff and then batch-convert to cone step maps.

Try it yourself, just download his demo and you'll get the height-map converter, too.
Where we can get the distance based one?
User avatar
nullsquared
Old One
Posts: 3245
Joined: Tue Apr 24, 2007 8:23 pm
Location: NY, NY, USA
x 11

Post by nullsquared »

vilgeits wrote: Where we can get the distance based one?
Download his demo and look at the shaders. It's simply a different way of calculating the LOD factors ;). I didn't port that one since it used to lock up my machine randomly, and the texture-based one ray better (prettier + faster) on my machine anyways.

Oh, and big miss: I didn't port the self-shadowing variants. Like I said, I did not do any lighting, so self-shadowing didn't make sense.
User avatar
vilgeits
Goblin
Posts: 298
Joined: Tue Aug 02, 2005 10:41 pm

Post by vilgeits »

nullsquared wrote:
vilgeits wrote: Where we can get the distance based one?
Download his demo and look at the shaders. It's simply a different way of calculating the LOD factors ;). I didn't port that one since it used to lock up my machine randomly, and the texture-based one ray better (prettier + faster) on my machine anyways.

Oh, and big miss: I didn't port the self-shadowing variants. Like I said, I did not do any lighting, so self-shadowing didn't make sense.
Looks really great but it has some problems at certain distances (wrong lines etc) this errors are not angle dependant since I rotate the cam and the fails are in the same portion of the mesh.
User avatar
nullsquared
Old One
Posts: 3245
Joined: Tue Apr 24, 2007 8:23 pm
Location: NY, NY, USA
x 11

Post by nullsquared »

vilgeits wrote:Looks really great but it has some problems at certain distances (wrong lines etc) this errors are not angle dependant since I rotate the cam and the fails are in the same portion of the mesh.
It's not like I invented the technique, I simply ported it to Ogre ;). Though I am indeed curious, where does it look wrong?
Last edited by nullsquared on Tue Jul 08, 2008 1:23 am, edited 1 time in total.
User avatar
vilgeits
Goblin
Posts: 298
Joined: Tue Aug 02, 2005 10:41 pm

Post by vilgeits »

nullsquared wrote:
vilgeits wrote:Looks really great but it has some problems at certain distances (wrong lines etc) this errors are not angle dependant since I rotate the cam and the fails are in the same portion of the mesh.
It's not like I ported the technique, I simply ported it to Ogre ;). Though I am indeed curious, where does it look wrong?
Sorry :oops: but i dont understand if you are looking for solve that error, or you are just curios about where it happens to me.
User avatar
nullsquared
Old One
Posts: 3245
Joined: Tue Apr 24, 2007 8:23 pm
Location: NY, NY, USA
x 11

Post by nullsquared »

vilgeits wrote:
nullsquared wrote:
vilgeits wrote:Looks really great but it has some problems at certain distances (wrong lines etc) this errors are not angle dependant since I rotate the cam and the fails are in the same portion of the mesh.
It's not like I ported the technique, I simply ported it to Ogre ;). Though I am indeed curious, where does it look wrong?
Sorry :oops: but i dont understand if you are looking for solve that error, or you are just curios about where it happens to me.
Wait, that didn't make sense :lol:. I meant to say "it's not like I invented the technique," not ported :D. Anyways, I'm honestly lost in all of the math here (kind of glad it all Just Works ;)), I'm just curious where you get that error, since I didn't notice it myself.
User avatar
vilgeits
Goblin
Posts: 298
Joined: Tue Aug 02, 2005 10:41 pm

Post by vilgeits »

My little little aportation :oops:

Fixed 10 steps mode:

Code: Select all

void intersect_square_cone_10step (sampler2D csmMap, inout vec3 dp, in vec3 ds)
{
   // the "not Z" component of the direction vector (for a square cone)
   float iz = max(abs(ds.x),abs(ds.y));
   // SOR
   float w = 1.2;
   // my starting location (is at z=0)
   // texture lookup
   float4 t;

   //	find the initial location and height
   t=tex2D(csmMap,dp.xy);
   // right, I need to take one step.
   // I use the current height above the texture,
   // and the information about the cone-ratio
   // to size a single step.  So it is fast and 
   // precise!  (like a coneified version of
   // "space leaping", but adapted from voxels)
   dp += ds * w * (t.r - dp.z) / (iz/(t.g*t.g) + 1.0);
   
   // and repeat a few (4) times 
   t=tex2D(csmMap,dp.xy);
   dp += ds * w * (t.r - dp.z) / (iz/(t.g*t.g) + 1.0);
   t=tex2D(csmMap,dp.xy);
   dp += ds * w * (t.r - dp.z) / (iz/(t.g*t.g) + 1.0);
   t=tex2D(csmMap,dp.xy);
   dp += ds * w * (t.r - dp.z) / (iz/(t.g*t.g) + 1.0);
   t=tex2D(csmMap,dp.xy);
   dp += ds * w * (t.r - dp.z) / (iz/(t.g*t.g) + 1.0);
   
   // and another 5 times 
   t=tex2D(csmMap,dp.xy);
   dp += ds * w * (t.r - dp.z) / (iz/(t.g*t.g) + 1.0);
   t=tex2D(csmMap,dp.xy);
   dp += ds * w * (t.r - dp.z) / (iz/(t.g*t.g) + 1.0);
   t=tex2D(csmMap,dp.xy);
   dp += ds * w * (t.r - dp.z) / (iz/(t.g*t.g) + 1.0);
   t=tex2D(csmMap,dp.xy);
   dp += ds * w * (t.r - dp.z) / (iz/(t.g*t.g) + 1.0);
   t=tex2D(csmMap,dp.xy);
   dp += ds * w * (t.r - dp.z) / (iz/(t.g*t.g) + 1.0);
      
   // all done
   return;
}
you also must replace

Code: Select all

    intersect_square_cone_exp(csmMap, uv, s, df);
with:

Code: Select all

	intersect_square_cone_10step(csmMap, uv, s);
User avatar
nullsquared
Old One
Posts: 3245
Joined: Tue Apr 24, 2007 8:23 pm
Location: NY, NY, USA
x 11

Post by nullsquared »

Good job on porting the 10 step version, some people might find it useful :D. Just be careful with the depth scale used on the 10 step version, anything too deep or irregular (like spikes) and you'll get artifacting.
User avatar
vilgeits
Goblin
Posts: 298
Joined: Tue Aug 02, 2005 10:41 pm

Post by vilgeits »

nullsquared wrote:Good job on porting the 10 step version, some people might find it useful :D. Just be careful with the depth scale used on the 10 step version, anything too deep or irregular (like spikes) and you'll get artifacting.
I have more artifacts using the textured based one. :S it occurs at certains positions as i said before, this afternoon i'll post some screenshots.
User avatar
nullsquared
Old One
Posts: 3245
Joined: Tue Apr 24, 2007 8:23 pm
Location: NY, NY, USA
x 11

Post by nullsquared »

vilgeits wrote:
nullsquared wrote:Good job on porting the 10 step version, some people might find it useful :D. Just be careful with the depth scale used on the 10 step version, anything too deep or irregular (like spikes) and you'll get artifacting.
I have more artifacts using the textured based one. :S it occurs at certains positions as i said before, this afternoon i'll post some screenshots.
Oh. That sounds odd, since the texture-based one is where CSM completely excels for me. I might end up porting the distance-based one as well, just to see if it changes anything for some people (for me, it only tends to lock up :lol:)
User avatar
vilgeits
Goblin
Posts: 298
Joined: Tue Aug 02, 2005 10:41 pm

Post by vilgeits »

Probably my "artifacts" are caused by a wellknown problem with CSM fixed in Relaxed Cone Step Mapping (RCSM) that you can't find in GPU Gems 3.

Nvidia has released freely the chapter 18... the RCSM one :D http://developer.download.nvidia.com/bo ... 3_ch18.pdf
User avatar
nullsquared
Old One
Posts: 3245
Joined: Tue Apr 24, 2007 8:23 pm
Location: NY, NY, USA
x 11

Post by nullsquared »

vilgeits wrote:Probably my "artifacts" are caused by a wellknown problem with CSM fixed in Relaxed Cone Step Mapping (RCSM) that you can't find in GPU Gems 3.

Nvidia has released freely the chapter 18... the RCSM one :D http://developer.download.nvidia.com/bo ... 3_ch18.pdf
Wait, you're saying the texture-based LOD version of variable-step cone step mapping gives you results like that? Must be a hardware issue on your side, it's 100% exact here. Yes, the fixed-step (3-step or 10-step) versions artifact, but that's to be expected.
User avatar
sinbad
OGRE Retired Team Member
OGRE Retired Team Member
Posts: 19269
Joined: Sun Oct 06, 2002 11:19 pm
Location: Guernsey, Channel Islands
x 66
Contact:

Post by sinbad »

Great work as usual nullsquared. Man, I'm glad you're not old enough to work full-time yet, we'd be out of a job :)

Can I suggest putting some of these great techniques in the wiki? Just to preserve them from the inevitable burial they'll get after a while in the forum.
User avatar
vilgeits
Goblin
Posts: 298
Joined: Tue Aug 02, 2005 10:41 pm

Post by vilgeits »

Point1 - my problems are shown when the polygon normal is not pointintg at pure Y (horizontal polygon)

Point2 - I've finished a conversion of the next gen version: Relaxed Cone Step Mapping :)
User avatar
nullsquared
Old One
Posts: 3245
Joined: Tue Apr 24, 2007 8:23 pm
Location: NY, NY, USA
x 11

Post by nullsquared »

vilgeits wrote:Point1 - my problems are shown when the polygon normal is not pointintg at pure Y (horizontal polygon)
Good point, I only tested it on a XZ plane and on the Ogre head - I should probably test it on some more planes.
Point2 - I've finished a conversion of the next gen version: Relaxed Cone Step Mapping :)
Sounds great :D. CSM is already crazy fast, I can't wait to test out RCSM :shock:
sinbad wrote:Great work as usual nullsquared. Man, I'm glad you're not old enough to work full-time yet, we'd be out of a job :)
:)
Can I suggest putting some of these great techniques in the wiki? Just to preserve them from the inevitable burial they'll get after a while in the forum.
Sounds good, I'll slap stuff onto the various shaders page.
User avatar
vilgeits
Goblin
Posts: 298
Joined: Tue Aug 02, 2005 10:41 pm

Post by vilgeits »

nullsquared wrote:
Point2 - I've finished a conversion of the next gen version: Relaxed Cone Step Mapping :)
Sounds great :D. CSM is already crazy fast, I can't wait to test out RCSM :shock:
Bit slower much more precise. :D
User avatar
nullsquared
Old One
Posts: 3245
Joined: Tue Apr 24, 2007 8:23 pm
Location: NY, NY, USA
x 11

Post by nullsquared »

vilgeits wrote:Bit slower much more precise. :D
Wait, I thought relaxed cone step mapping used bigger steps to increase the overall speed? I don't see how it can get any more accurate than variable-step CSM - the CSM example used in the GPU Gems 3 chapter used a fixed-step (thus the ugly results). Either way, I still want to play with it :twisted:
User avatar
vilgeits
Goblin
Posts: 298
Joined: Tue Aug 02, 2005 10:41 pm

Post by vilgeits »

I really think this is a problem with tangents or normals :(

Image
User avatar
nullsquared
Old One
Posts: 3245
Joined: Tue Apr 24, 2007 8:23 pm
Location: NY, NY, USA
x 11

Post by nullsquared »

You're right, there DOES seem to be some kind of weird orientational bug! Lets see if I can find it, I absolutely HATE obscure bugs xD...

EDIT: Hold up. I can't reproduce the bug on anything other than the "cube.mesh" in the models directly. Differently orientated planes work, "knot.mesh" works, rotating models work, everything I tried other than "cube.mesh". It must be a UV/normals/tangents error.
User avatar
Kojack
OGRE Moderator
OGRE Moderator
Posts: 7157
Joined: Sun Jan 25, 2004 7:35 am
Location: Brisbane, Australia
x 534

Post by Kojack »

Hmm, I just ran cube.mesh through the xml convertor and examined the xml output.
Strange.
First, there's 25 vertices, one of which isn't used (it's in the middle).
Second, Every vertex has a normal of either <0,0,1.5708> or <0,0,-1.5708>.
That's not normalised, and all normals face along the z or -z axis.
Post Reply