# problems with conestep mapping

## Recommended Posts

well ive been trying to implementent something like conestepmapping... dunno if its the same thing but as far as ive read its pretty similar... it works great on non steep viewing angles.. but with steep viewing angles it gets all messed up... i also have some problem of "holes" in certain objects... first i calculate the highest horizon for every point in 4 directions and save it to a texture...

void CSTEPMAP::CalculateHorizonSlope(vec2 dir)
{
for (int  z = 0; z < size; z++)
{
for (int x = 0; x < size; x++)
{
step[(x+z*size)*4+0] = max(GetHorizonSlope(vec2(x,z), dir), step[(x+z*size)*4+0]);

}
}
}

float CSTEPMAP::GetHorizonSlope(vec2 pos, vec2 dir)
{
dir = normalize(dir);
vec2 rpos = pos;

float maxSlope = 0;
for (rpos = pos+dir; rpos < size && rpos > 0; rpos+=dir)
{
float slope = 0;
slope = float(GetHeight(rpos)-GetHeight(pos))/(length(pos-rpos)*1.0/size);

if (slope > maxSlope)
maxSlope = slope;

}
return sqrt(maxSlope);

}

float GetHeight(int x, int z)
{
x = clamp(x,1,size-1);
z = clamp(z,1,size-1);
return HeightMap.GetAlpha(x,z)/255.0f;
}

float GetHeight(vec2 pos)
{
int x = clamp(int(pos.x),1,size-1);
int z = clamp(int(pos.y),1,size-1);
return HeightMap.GetAlpha(x,z)/255.0f;
}

float Interpolate(float a, float b, float x)
{
float f  = ( 1.0f - (float)cos ( x * PI ) ) * 0.5f;

return ( a * ( 1.0f - f ) + b * f );
}

float GetInterpolatedHeight(vec2 pos)
{
int x = pos.x;
int z = pos.y;

int ix1 = (int) x;
float fx1 = x - ix1;

int iz1 = (int) z;
float fz1 = z - iz1;

float v1 = GetHeight(ix1, iz1);
float v2 = GetHeight(ix1+1, iz1);
float v3 = GetHeight(ix1, iz1+1);
float v4 = GetHeight(ix1+1, iz1+1);

float v12 = Interpolate(v1,v2,fx1);//(1.0f-fx1)*v1 + fx1*v2;
float v34 = Interpolate(v2,v3,fx1);//(1.0f-fx1)*v2 + fx1*v3;

float v1234 = Interpolate(v12,v34,fz1);//(1.0f-fz1)*v12 + fz1*v34;

return v1234;

}


and then in the fragment shader i skip raytracing the volume given by the horizons... i trace until the "skip step" reaches a certain value...
vec2 parallax(vec3 V, vec2 TexCoord)
{
float acc = 4.0/256.0; // accuracy

vec2 dt = -V.xy * 0.08 / (V.z);
vec2 CurTexCoord = TexCoord;

float curheight = 0.0; // heightmap height
float rheight = 1.0; // rayheight

float offset;
float slope; // horizonslope
float dy; // ray height above heightmap

for(int i = 0; offset > acc; i++)
{
CurTexCoord = TexCoord+(1.0-rheight)*dt;
curheight = texture2D(NormalMap, CurTexCoord).a;
slope = pow(texture2D(StepMap, CurTexCoord).r,2.0);
dy = rheight-curheight;
offset = (slope*dy)/(slope+V.z/length(V.xy)); // skip distance

rheight -= offset;
}

return CurTexCoord;

}

mat3 GetTBN()
{
vec3 Normal = vec3(0.0, 1.0, 0.0);
vec3 Tangent = cross(Normal,vec3(0.0,0.0,1.0));
vec3 Binormal = cross(Normal,vec3(-1.0,0.0,0.0));
return mat3((Tangent), (Binormal), (Normal));
}

void main()
{
vec2 TexCoord = gl_TexCoord[0].st;

mat3 TBN = GetTBN();

vec3 nViewVec = normalize(ViewVec)*TBN;

vec2 NewTexCoord = parallax(nViewVec, TexCoord);

vec4 Color = texture2D(TextureMap, NewTexCoord).rgba;

gl_FragColor = Color;
}



##### Share on other sites
lonesock    807
would you mind posting a picture of your results?

##### Share on other sites
i wouldnt mind

as far as ive got with finding the fault... dy which is the rays height over the heightmap is negative at several places... but this means that the ray has alrdy intersected the heightmap.. which shouldnt be possible with the defined hrozion volumes (cones)

##### Share on other sites
lonesock    807
The image definitely suggests you are overshooting the cones (as you suspected). The code for the (cone) slope generation looks correct. In the main portion of your shader, however, I got slightly different results. (note, in the preview function at least this forum code seems to be swallowing my plus signs, hence the "{plus}" instead of a "+") Here's your code:

offset = (slope*dy)/(slope {plus} V.z/length(V.xy)); // skip distance

and mine would have been something like:

offset = (slope*dy)/(length(V.xy) - V.z*slope); // skip distance

we do some different things to prepare the initial vector, though, so the transformation may just not be obvious to me. One other note: I don't know the behavior of your shader compiler, but you may want to initialize offset to:

float offset = acc {plus} 1.0;

##### Share on other sites
ive rewritten the code using some of the code from ur shaders... and it works fine with the cone-ratiomap that u sent with the demo...

but when i try to use my preprocessing code it doesnt seem to work properly...

what do u do differently in the preprocessing? (GetHorizonSlope)

id like to get this working so i can try using ellips and directed cones... and also double cones

##### Share on other sites
lonesock    807
I believe the source for the pre-processor is included in the demo, if not I'll post it. From memory, though, there are 2 things:

1) I invert the height values in the texture: i.e. red = 255 - red, or whatever
2) I do a pass at the end of the computation (i.e. once all the cone values have been computed) for the following reason: during the linear interpolation that happens on the GPU during the sampling of the texture, sometimes the sampled value will have a cone that is too wide. So I do 1 pass over all the data and for each texel I find the narrowest cone-ratio of all the original pixels surrounding it, then keep that value.

here is the source:
// All of the 3D rendering API's will do    // interpolation of the cone_ratios. This    // can be *BAD*    cout << "  <Safety>";    unsigned char *safeCR = new unsigned char [width * height];    // for each pixel, find the lowest nearby ConeRatio value    for (int y = 0; y < height; ++y)        for (int x = 0; x < width; ++x)        {            int main_idx = y*ScanWidth + chans*x;            unsigned char LowestCR = Data[main_idx + OFF_CONERATIO];            unsigned char TheHeight = Data[main_idx + OFF_HEIGHT];            for (int dy = -1; dy < 2; ++dy)                for (int dx = -1; dx < 2; ++dx)                {                    int idx = xy2index (x+dx, y+dy, width, height, chans);                    {                        // this is a valid comparison point                        if ((Data[idx + OFF_HEIGHT] <= TheHeight) &&                                (Data[idx + OFF_CONERATIO] < LowestCR))                        {                            // this is the lowest CR of interest so far                            LowestCR = Data[idx + OFF_CONERATIO];                        }                    }                }            // OK, I have the replacement CR value, just hold on to it for a while            safeCR[x+y*width] = LowestCR;        }    // now I've done all the computing, update my walues    for (int y = 0; y < height; ++y)        for (int x = 0; x < width; ++x)        {            Data [y*ScanWidth + chans*x + OFF_CONERATIO] = safeCR[x+y*width];        }    delete [] safeCR;

##### Share on other sites

i dont quite understand what you mean... and i havent been able to figure out your code yet...

but i calculate the coneratio by finding the horizon in four direction and then save the sqrt(sqrt( of the horizon with the highest slope... what do u do differently?

EDIT:: and im plannig to solve the problem u described by sampling more direction when calcualting the conestepmap... since cthe clac is done one time it might as well be as accurate as possible

EDIT2:: ok now i see what u mean.. u store the heightmap inverted in the the texture... now im getting descenet results... works fine with the stepmap u supplied but it doesnt work well when i use my own preproccessing... it overshoots the cones still...

void CSTEPMAP::CalculateHorizonSlope(vec2 dir)	for (int  z = 0; z < size; z++)	{		for (int x = 0; x < size; x++)		{			step[(x+z*size)*4+0] = GetHeight(x,z);			step[(x+z*size)*4+1] = max(GetHorizonSlope(vec2(x,z), dir), step[(x+z*size)*4+1]);;		}	}}float CSTEPMAP::GetHorizonSlope(vec2 pos, vec2 dir){	dir = normalize(dir);	vec2 rpos = pos;	float maxSlope = 0;	for (rpos = pos+dir; rpos < size && rpos > 0; rpos+=dir)	{		float slope = 0;		slope = fabs(GetHeight(rpos)-GetHeight(pos))/(length(pos-rpos)*1.0/size);		if (slope > maxSlope)			maxSlope = slope;					}	return (sqrt(maxSlope));		}		float GetHeight(vec2 pos)		{			int x = clamp(int(pos.x),1,size-1);			int z = clamp(int(pos.y),1,size-1);			return HeightMap.GetAlpha(x,z)/255.0f;		}

[Edited by - Dragon_Strike on March 20, 2007 5:09:46 PM]