i dont know if i understand what you are trying to achieve …
- sampling the grid with interpolation ?
- extracting slope pitch and yaw angles ?
- extracting the general slope-ness to threshold wallride ?
your plane is XZ (would be easier to read the following if i’d be XY).
sampling the point could be something like (pseudocode) …
float interpolatedHeightAtPoint( vec2 point_to_sample )
{
vec2 sample = point_to_sample / cellsize
vec2 integerpart = floor(sample); // integer
vec2 fractionalpart = fract(sample); // float 0..1
float a = get_height_at_cell( integerpart.x , integerpart.y ); // 4 vertices in the height-map
float b = get_height_at_cell( integerpart.x+1, integerpart.y );
float c = get_height_at_cell( integerpart.x , integerpart.y+1 );
float d = get_height_at_cell( integerpart.x+1, integerpart.y+1 );
return mix( mix( a, b, fractionalpart.x), mix( c, d, fractionalpart.x), fractionalpart.y);
}
basicly something like value/latice-noise.
extracting the angle could become a bit nasty. you could just grab the 4 edges of the cell you’re sampling the point in, and use pythagoras to get the angles … but only if your cell is a quad. usualy you end up with two triangles.
to get the slope-ness we could “dot” the normal at sampling point with “up”. we can do it analytical (fast) or with the central difference (easy) or maybe with a normal.
central difference would be something like (pseudo code) … the bigger eps is the smoother the normal should become … :
vec2 point; // some point in worldspace
float eps = 0.01; // magic number, should it match the cellsize ?
vec3 normal = vec3( interpolatedHeightAtPoint( vec2(point.x - eps, point.y) ) - interpolatedHeightAtPoint( vec2(point.x + eps, point.y ) ),
interpolatedHeightAtPoint( vec2(point.x, point.y - eps) ) - interpolatedHeightAtPoint( vec2(point.x, point.y + eps) ), 2.0 * eps );
normal = normalize(normal);
we could caluculate the normal the same way we would calculate any triangle-normal (pseudocode) … should create a flat normal too … :
// assuming we have the four corner vertices of the cell we sample in ..
vec3 vertex_a;
vec3 vertex_b;
vec3 vertex_c;
vec3 vertex_d;
// assuming A B C are forming one triangle of the two possible.
// maybe we need to swizzle around and calc C B A if winding is CW.
// i dont know what to do with the 2nd triangle in the quad. maybe calculate it too and sum both ?
vec3 normal = cross(vertex_a.x - vertex_b.x, vertex_a.y - vertex_b.y, vertex_a.z - vertex_b.z, vertex_a.x - vertex_c.x, vertex_a.y - vertex_c.y, vertex_a.z - vertex_c.z);
normal = normalize(normal);
we could calculate the normal analytical (pseudocode) … should create a flat normal too …
float deriv(vec2 value)
{
return 1.0 - abs(value * 2.0 - 1.0); // a triangle.
// return abs(value * 2.0 - 1.0); // or is this correct ?
}
float interpolatedHeightAndNormalAtPoint( vec2 point_to_sample, out vec3 normal_output )
{
// just like the other method ..
vec2 sample = point_to_sample / cellsize
vec2 integerpart = floor(sample); // integer
vec2 fractionalpart = fract(sample); // float 0..1
float a = get_height_at_cell( integerpart.x , integerpart.y ); // 4 vertices in the height-map
float b = get_height_at_cell( integerpart.x+1, integerpart.y );
float c = get_height_at_cell( integerpart.x , integerpart.y+1 );
float d = get_height_at_cell( integerpart.x+1, integerpart.y+1 );
// and the normal ..
vec2 dv = deriv(fractionalpart);
normal.x = dv.x * mix( b-a, d-c, fractionalpart.y);
normal.y = dv.y * mix( c-a, d-b, fractionalpart.x);
normal.z = 1.0; // not sure about this (z pointing up)
normal = normalize(normal); // maybe not required
return mix( mix( a, b, fractionalpart.x), mix( c, d, fractionalpart.x), fractionalpart.y);
}
now with the normal you can do something like …
float slope = dot(normal, vec3( 0.0, 0.0, 1.0 )); // Z pointing up, not Y in this example.
if( slope == 1.0 ) { /* driving on super flat surface */ }
if( slope == 0.0 ) { /* driving on a perfectly aligned wall */ }
if( slope == -1.0 ) { /* driving on the ceiling */ }
//
i have no idea if that code is correct, i did not test it. it’s just glsl-like-pseudocode. 