Board index FlightGear Development Effects and shaders

How to get upwards vector in fragment shader?

An exciting "new" option in FlightGear, that includes reflections, lightmaps, the particle system etc.. A lot is yet to be discovered/implemented!

How to get upwards vector in fragment shader?

Postby Necolatis » Fri Sep 06, 2019 2:51 am

I think I figured out how to get a vector that points up (as in away from ground) in fragment shaders.

It not so simple as Z is only upwards in world space at latitude/longitude (90,0) it seems.
And in model space Z only points upwards if the aircraft is on a horizontal runway with 0 roll/pitch and the model in which the current triangle is in has not been rotated in any way from aircraft origin.

However its a lot of code, so its expensive to run every fragment. There must be a simpler way, have anyone done something similar before?

I noticed there are defined some uniforms called fg_ViewMatrixInverse and fg_ViewMatrix.
I have a hunch I can use those somehow, but I am not sure how they work, does anyone know?

Here is the code:

This needs to be defined:
Code: Select all
#extension GL_ARB_gpu_shader5 : enable


Notice the 2 first methods and how to use them is shamelessly copied from ubershader:
Code: Select all
mat3 rotY(in float angle)
{
    mat3 rotmat = mat3(
                        cos(angle),     0.0,    sin(angle),
                        0.0,            1.0,    0.0,
                        -sin(angle),    0.0,    cos(angle)
    );
    return rotmat;
}

mat3 rotZ(in float angle)
{
    mat3 rotmat = mat3(
                        cos(angle), -sin(angle),    0.0,
                        sin(angle), cos(angle),     0.0,
                        0.0,        0.0,            1.0
    );
    return rotmat;
}

vec3 upInViewSpace(float lat_deg, float lon_deg)  {
    float latRad = radians(90-lat_deg);
    float lonRad = radians(lon_deg);
    mat3 WorldFGInverse = inverse(rotY(latRad) * rotZ(lonRad));
    vec3 up = vec3(0.0, 0.0, 1.0);// up in FG
    up = WorldFGInverse * up;// up in world space
    up = normalize(osg_ViewMatrix * vec4(up, 0.0)).xyz;// up in view space (as in away from ground)
    return up;
}
"Airplane travel is nature's way of making you look like your passport photo."
— Al Gore
User avatar
Necolatis
 
Posts: 2233
Joined: Mon Oct 29, 2012 1:40 am
Location: EKOD
Callsign: Leto
IRC name: Neco
Version: 2020.3.19
OS: Windows 10

Re: How to get upwards vector in fragment shader?

Postby Thorsten » Fri Sep 06, 2019 6:16 am

It not so simple as Z is only upwards in world space at latitude/longitude (90,0) it seems.


It's actually different in different shaders - the basic idea is always that you take an 'up' in a model coordinate system and apply the relevant transformation matrix - there is no simpler way, basically you always end up in essence doing just that, and since the GPU is pretty good in matrix operations because they're done all the time, the performance impact is a non-issue.

What you have is FG world, but the terrain for instance has the local 'up' as (0,0,1) in model coordinates, models generally have whatever was 'z' in the 3d modeling tool, trees and clouds have the same up as the terrain because they're instanced,...
Thorsten
 
Posts: 12490
Joined: Mon Nov 02, 2009 9:33 am

Re: How to get upwards vector in fragment shader?

Postby Necolatis » Fri Sep 06, 2019 7:53 am

True, I didn't think about terrain, terrain objects or clouds.

Was messing around with some different stuff to try and learn a bit more. Trying to make something silly for aircraft which includes stuff that might have been rotated multiple times, where it wont work to have Z up in shaders model coordinate system.

For example the throttle in the Viggen, the aircraft is rotated, then it has a rotated position in the aircraft, and it itself rotates, and the model space in shaders rotates along with all that, so +Z in there is not up in the aircraft and also not up into the sky.

It would be nice to have a matrix that can transform from FG to one of the systems that are usually used in shaders and opposite. I am kinda hoping fg_ViewMatrixInverse and fg_ViewMatrix does that, but I have tried some different things with them, and I got nowhere. I can see them used in sunlight shaders to get the sun direction, I think for Rembrandt, but I have had no luck doing anything with them.

It would also be nice to have matrices that transforms from FG aircraft origin coord system to one of the shaders coord systems and back.
"Airplane travel is nature's way of making you look like your passport photo."
— Al Gore
User avatar
Necolatis
 
Posts: 2233
Joined: Mon Oct 29, 2012 1:40 am
Location: EKOD
Callsign: Leto
IRC name: Neco
Version: 2020.3.19
OS: Windows 10

Re: How to get upwards vector in fragment shader?

Postby Thorsten » Fri Sep 06, 2019 8:08 am

I guess the 'one size fits all' solution would be to put a reference (e.g. a virtual lightsource) right at the zenith. Since GLSL will handle all transformations for that light source automagically, the pointing vector to that light source will always be 'up' in eye space no matter how many animations are in the matrix stack.
Thorsten
 
Posts: 12490
Joined: Mon Nov 02, 2009 9:33 am

Re: How to get upwards vector in fragment shader?

Postby Necolatis » Fri Sep 06, 2019 8:18 am

Ah, yes. :)
"Airplane travel is nature's way of making you look like your passport photo."
— Al Gore
User avatar
Necolatis
 
Posts: 2233
Joined: Mon Oct 29, 2012 1:40 am
Location: EKOD
Callsign: Leto
IRC name: Neco
Version: 2020.3.19
OS: Windows 10

Re: How to get upwards vector in fragment shader?

Postby Necolatis » Fri Sep 06, 2019 7:55 pm

I found out how to optimize the code rather simply. I have tested it over a couple of airport different places on earth.

It gets rid of the matrix inverse function and therefore also the need for #extension GL_ARB_gpu_shader5 : enable

Code: Select all
vec3 upInViewSpace(float lat_deg, float lon_deg) {
    float latRad = radians(90-lat_deg);
    float lonRad = radians(lon_deg);
    //mat3 WorldFGInverse = inverse(rotY(latRad) * rotZ(lonRad)); // expensive
    mat3 WorldFGInverse = rotZ(-lonRad) * rotY(-latRad); // cheaper
    vec3 up = vec3(0.0, 0.0, 1.0);// up in FG
    up = WorldFGInverse * up;// up in world space
    up = normalize(osg_ViewMatrix * vec4(up, 0.0)).xyz;// up in view space (as in away from ground)
    return up;
}


It still needs to the two methods rotY and rotZ, plus lat, lon as uniforms.
A further optimization was to run it in the vertex shader and pass it as a varying.
"Airplane travel is nature's way of making you look like your passport photo."
— Al Gore
User avatar
Necolatis
 
Posts: 2233
Joined: Mon Oct 29, 2012 1:40 am
Location: EKOD
Callsign: Leto
IRC name: Neco
Version: 2020.3.19
OS: Windows 10

Re: How to get upwards vector in fragment shader?

Postby Thorsten » Fri Sep 06, 2019 8:20 pm

A further optimization was to run it in the vertex shader and pass it as a varying.


This might not actually be one, as varying is a rather limited data type (I think you can only have 32 or so) and the varying extrapolation across a triangle is pretty expensive on older architectures (at some point I had the empirical rule that 3 varying = 10% slowdown) - so I would tread carefully.

But the code as such looks pretty good - using FG world space is a neat idea.
Thorsten
 
Posts: 12490
Joined: Mon Nov 02, 2009 9:33 am

Re: How to get upwards vector in fragment shader?

Postby Necolatis » Fri Sep 06, 2019 8:35 pm

:(

So interpolating 3 vectors could be more expensive than processing like 30 x (2 matrix multiplications + bunch of trigonometry). (in the case of 30 fragments)

That sucks. Didn't know it could be that expensive.
How do you test that for an aircraft effect? Do you look in task-manager at GPU utilization? Or remove scenery and look at FPS?
"Airplane travel is nature's way of making you look like your passport photo."
— Al Gore
User avatar
Necolatis
 
Posts: 2233
Joined: Mon Oct 29, 2012 1:40 am
Location: EKOD
Callsign: Leto
IRC name: Neco
Version: 2020.3.19
OS: Windows 10

Re: How to get upwards vector in fragment shader?

Postby Necolatis » Fri Sep 06, 2019 8:41 pm

Nevermind, I just thought about it, and I think typical fuselage triangles are alot smaller than 30 fragments, unless running with very high Anti-aliasing.
"Airplane travel is nature's way of making you look like your passport photo."
— Al Gore
User avatar
Necolatis
 
Posts: 2233
Joined: Mon Oct 29, 2012 1:40 am
Location: EKOD
Callsign: Leto
IRC name: Neco
Version: 2020.3.19
OS: Windows 10

Re: How to get upwards vector in fragment shader?

Postby Thorsten » Fri Sep 06, 2019 8:55 pm

So interpolating 3 vectors could be more expensive than processing like 30 x (2 matrix multiplications + bunch of trigonometry). (in the case of 30 fragments)


I can't give you a reason for why I observed this (if you continue tinkering, you'll come to the conclusion that GPUs are sometimes just weird...) - it should not be the case, but it's a different processing stage, so it might run into different bottlenecks, you know...

How do you test that for an aircraft effect?


Used to be pretty obvious on old GPUs - you had 30 fps before a change, then you added the change and observed 27 fps, you added more and found yourself at 20 fps.

With the GeForce 1080, it's generally less obvious now as it tends to take a lot of crap without breaking a sweat.

So having a number of different computers and different drivers (I have two with NVIDIA and one nouveau testbed) helps getting the overall picture.
Thorsten
 
Posts: 12490
Joined: Mon Nov 02, 2009 9:33 am

Re: How to get upwards vector in fragment shader?

Postby icecode » Sat Sep 07, 2019 11:31 am

I noticed there are defined some uniforms called fg_ViewMatrixInverse and fg_ViewMatrix.


These are used by Rembrandt only and contain the same matrices as osg_ViewMatrix. As with the light uniforms, they are used in fullscreen passes to access the scene transformation matrices.

I think I figured out how to get a vector that points up (as in away from ground) in fragment shaders.


Wouldn't something like
Code: Select all
vec4 up_view_space = normalize(gl_ModelViewMatrix * vec4(0.0, 0.0, 1.0, 0.0));

work?
icecode
 
Posts: 709
Joined: Thu Aug 12, 2010 1:17 pm
Location: Spain
Version: next
OS: Fedora

Re: How to get upwards vector in fragment shader?

Postby Necolatis » Sat Sep 07, 2019 8:47 pm

Thanks for that info.

Icecode GL wrote in Sat Sep 07, 2019 11:31 am:Wouldn't something like
Code: Select all
vec4 up_view_space = normalize(gl_ModelViewMatrix * vec4(0.0, 0.0, 1.0, 0.0));

work?


No, +Z in model space wont be pointing up in the sky except by coincidence.
All the rotations that has been applied to the object where the triangle currently being shaded will make +Z point somewhere else.
In world it also don't point up, unless you are at the northpole.
And yes, just to be sure I tested it.
"Airplane travel is nature's way of making you look like your passport photo."
— Al Gore
User avatar
Necolatis
 
Posts: 2233
Joined: Mon Oct 29, 2012 1:40 am
Location: EKOD
Callsign: Leto
IRC name: Neco
Version: 2020.3.19
OS: Windows 10

Re: How to get upwards vector in fragment shader?

Postby icecode » Sun Sep 08, 2019 12:40 am

All the rotations that has been applied to the object where the triangle currently being shaded will make +Z point somewhere else.


What about using osg_ViewMatrix and osg_ProjectionMatrix instead? These do not contain the model matrix so they don't depend on local transformations.
icecode
 
Posts: 709
Joined: Thu Aug 12, 2010 1:17 pm
Location: Spain
Version: next
OS: Fedora

Re: How to get upwards vector in fragment shader?

Postby Necolatis » Sun Sep 08, 2019 12:52 am

osg_ViewMatrix works, but only at latitude 90, longitude 0 (northpole).

Flightgears world coordinate system is setup so +Z point up in the sky at that location, and as you move away from that location +Z will not point up towards the sky.

osg_ProjectionMatrix I don't really know how works. So no clue. Isn't that to transform into coordinate system for the frustum? Does +Z point skyward in that?
"Airplane travel is nature's way of making you look like your passport photo."
— Al Gore
User avatar
Necolatis
 
Posts: 2233
Joined: Mon Oct 29, 2012 1:40 am
Location: EKOD
Callsign: Leto
IRC name: Neco
Version: 2020.3.19
OS: Windows 10

Re: How to get upwards vector in fragment shader?

Postby icecode » Sun Sep 08, 2019 2:51 pm

Yeah, you are right. I had to deal with a similar issue when experimenting with the voxel clouds. I ended up just taking advantage of the coordinate system itself: Since the FG world space position is the cartesian position on a sphere (Earth), normalizing any vector in world space (you might need to multiply by gl_ModelViewMatrix and then by osg_ViewMatrixInverse to avoid doing the model and view transforms at the same time) will yield its up direction in world space. To obtain it in view space just multiply it by osg_ViewMatrix.
icecode
 
Posts: 709
Joined: Thu Aug 12, 2010 1:17 pm
Location: Spain
Version: next
OS: Fedora


Return to Effects and shaders

Who is online

Users browsing this forum: No registered users and 1 guest