Finding the z coordinate of the position in the Fragment Shader

Hello all,



How can I find the z coordinate of the pixel currently being rendered in the Fragment Shader?



Currently I am using TerrainLighting.jme3d as reference. The only thing changed is that when the .frag calculates the diffuse color in line 566 I use [java]vec4 diffuseColor = vect4 (position.z, 0, 0, 1);[/java]



This is calculated in .vert the following way: (this is default, didn’t touch it)

[java]void main(){

vec4 pos = vec4(inPosition, 1.0);

gl_Position = g_WorldViewProjectionMatrix * pos;[/java]



I get this:

ERROR: 0:571: error(#143) Undeclared identifier gl_Position
ERROR: 0:571: error(#216) Vector field selection out of range 'z'
ERROR: 0:571: error(#202) No matching overloaded function found vect4
WARNING: 0:571: warning(#402) Implicit truncation of vector from size 1 to size 4.


I don't understand this since doc this doc says
gl_Position is the standard GLSL variable holding projection space position. It must be filled in the vertex shader

Hm, well, as first, there is nothing like vect4(); you probably mean vec4();

As next, show the declaration of position in the .frag

What space do you need it in? If you want to get the Z in clip space, use gl_FragCoord.z

@zzuegg thanks for the catch.



@Momoko_Fan no not the clip space, what I need is the height of the points in the world (example: how high is this mountain? 1 Km)



When I got here this morning it was working without errors, I don’t understand. Oh well…

Wont the height be the pre-transform y co-ordinate…?



Well, you will want to apply the world transformation but not apply the screen transformation…then look at the resulting y.

@kotoko said:
no not the clip space, what I need is the height of the points in the world (example: how high is this mountain? 1 Km)

Well...then you need the Y not the Z component, also you have to compute them in world space.
You have to include the WolrdMatrix global uniform and declare it as g_WorldMatrix.
then you go
[java]
...
varrying float height;
...
main(){
...
height = (g_WorldMatrix * vec4(inPosition, 1.0)).y;
...
[/java]
you'll have the height of the vertex in world space

You are both right about the y coordinate, that is what I’m looking for.



So what I understand is that the value that I give here:

[java]TerrainQuad terrain = new TerrainQuad(TERRAIN_NAME, PATCH_SIZE, MAP_SIZE + 1, heightmap.getHeightMap());[/java]

Is used as is (since I’m not scaling) and corresponds directly to the coordinates in object space (the inPosition variable).



Did I miss something?



Thank you for your help! :slight_smile:

You should just explain what you want to do. If you wanna follow the terrain with a character just do a rayCast downwards…

I’m using jMonkey to do a bathymery visualization tool so I need to color the terrain according to the height on the heightmap.



I’m modifying the shader to read the y of the position and build the color accordingly.

You should maybe calculate the color inside the Vertex shader, not inside the Fragment shader.



Vertexes know their positions precisely.

I didn’t find much difference between vertex and fragment in terms of results but the calculations are probably done less times.



I feel like I’m missing some concept because I can’t understand why I have such abrupt changes in color.

Could you give your input?

What I’m using is TerrainLight.jme3d with this bit of code inside:



[java]float interpolate (float z, float lowerBound, float maxRGB){

float scaled = z - lowerBound;

float interval = 63.75;

return (scaledmaxRGB)/interval;

}



void main(){

//Transformation of the object space coordinate to projection space

//coordinates.

//- gl_Position is the standard GLSL variable holding projection space

//position. It must be filled in the vertex shader

//- To convert position we multiply the worldViewProjectionMatrix by

//by the position vector.

//The multiplication must be done in this order.

position = g_WorldMatrix * vec4(inPosition, 0.0);

vec4 pos = vec4(inPosition, 1.0);

gl_Position = g_WorldViewProjectionMatrix * pos;

//________________________________________________________________________

vec4 diffuseColor;

float i;

float alpha = 1;

float interval = maxHeight/4;

int maxRGB_1 = 1;

int maxHeight = 255;

if(position.y < interval){ // blue to cyan

i = interpolate (position.y, 0, maxRGB_1);

diffuseColor = vec4(0, i, maxHeight, alpha);

}

else if(position.y < interval
2){ // cyan to yellow

i = interpolate (position.y, interval1, maxRGB_1);

diffuseColor = vec4(i, maxHeight, 1-i, alpha);

}

else if(position.y < interval
3){ // yellow to red

i = interpolate (position.y, interval2, maxRGB_1);

diffuseColor = vec4(maxHeight, 1-i, 0, alpha);

}

else{ // red to dark red

i = interpolate (position.y, interval
3, 0.5);

diffuseColor = vec4(1-i, 0, 0, alpha);

}

gl_FrontColor = diffuseColor;

//________________________________________________________________________[/java]



In the Fragment Shader I just have:

[java]//vec4 diffuseColor = calculateDiffuseBlend(texCoord);

vec4 diffuseColor = gl_Color;[/java]



The annoying result is this:





The heightmap

Colors components in glsl are not int from 0 to 255 but floats from 0 to 1

vec4(1.0,1.0,1.0,1.0) is solid white

vec4(0.0,0.0,0.0,1.0) is solid black

@nehon

I take that into account.

The 255 is the max height from the gray scale height map. The name of the variable was misleading but now I changed the name.



Or were you talking about something else?

It might help to see the latest code. The code pasted above has a few problems… like using maxHeight before it’s set, etc…



Also, just as an aside, your shader will flat out fail on some platforms because your floating point literals don’t have decimal places. Lots of cases of 0 instead of 0.0, etc.

1 Like

the name is not the problem it’s the value it holds

[java]

int maxHeight = 255;

diffuseColor = vec4(0, i, maxHeight, alpha);

[/java]

this is wrong. the value is out of range and you are feeding a constructor that takes floats with an int.

It does not fail on your card, because I guess the drivers are permissive enough, but that will fail on numerous other cards/system.

Same for the maxRGB_1 that you pass to your interpolate method



maxHeight should be float and equal to 1.0



since we are in best practice and things that will fail on other cards :

  • Always write float values with a “.0” : 1 for a float value is invalid, it should be “1.0”. Same for 0. That could be the reason of your issue since integer math might kick in at some point leading to the “break” in the color on your terrain.
  • Branching in a shader is usually a bad idea, you have to avoid it if possible.



    Edit : ninjaed by Paul
1 Like

OMG :o



I cannot thank you enough!



With the floating point literals fixed and the maximum value for the colors fixed this is what I get:

Photobucket



Maybe I can share this shader.

It’s not that hard but maybe someone without shader experience might need it.

3 Likes

Looking good :slight_smile:

Nice! :wink:

Thanks! 8)

Without your help this would have been totally impossible!



I share the whole thing in project, ready to try out here

1 Like