Board index FlightGear Development Effects and shaders

Effects, animations and conditions

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

Effects, animations and conditions

Postby Thorsten » Fri Mar 04, 2016 6:34 am

Since the question emerges once in a while, some context on this:

Say you have a livery system, one of them is very glossy, the other is not - and you want to change the effect to go with the livery to use a different specular map. Or say you have a rotate animation but want to execute this only when the plane is on the ground. The 'obvious' thing to do is to use a <condition> tag like

Code: Select all
 <animation>
  <object-name>Object</object-name>
  <type>rotate</type>
  <property>my_rotation_property</property>
  <condition>
    <equals>
     <property>my_test</property>
     <value>1</value>
   </equals>
 </condition>
 (...)


Sadly, this doesn't work. Neither does a condition in the effect declaration. Why?

The reason is the way effects and animations are processed internally and how a condition is processed internally. For instance, the rotation you specify in the animation is translated into a 4x4 rotation matrix M_rot which, along with all other positioning, scaling and rotating matrices, becomes a uniform mat4 data type which is part of the state set for the object and accessible by the shader.

However, what is actually delivered is the whole stack of matrices

M = M1 * M2 * ... * M_rot * ... * M_n-1 * M_n

- the point being, you can't simply take it out. If you want to take it out, you have to re-compute the whole matrix and basically re-assign the state set - something which involves plenty of data transfer from the CPU to the GPU and which isn't particularly fast. Which is why FGs effect implementation refuses to do these things.

The fast way is to simply leave the matrix in, but to make it a unit matrix so that multiplying it with anything doesn't change the outcome.

In contrast, what a <condition> tag is internally is usually equivalent to an if-statement. Which is to say, the branch does not get computed if the condition is not met. Applied to a transformation matrix, it means the matrix stays at its last value when the condition is no longer met, it's not set to unity.

Declaring two animations such that always one of them is true doesn't solve the problem, because then we create two matrices M_rot1 and M_rot2, if the condition is true M_rot1 has the correct value and M_rot2 the last value it had, if the condition is not true M_rot1 freezes and M_rot2 updates correctly, so the outcome is undefined.

The solution is to make sure the matrix becomes a unit matrix if the animation is not to be used, and the way to accomplish that is to make sure my_rotation_property in the above example is set to 0 if the condition is not met. Which is to say, the condition needs to act on the parameter of the animation, not on the animation itself.

For effects in general, the problem is related - the effect can't comceptually know what you mean with a condition tag. Effects internally have a cascade of conditions called predicates to select based on GPU ability and user settings just what combinations of shaders to run (which will ultimately end in either a safe fallback or nothing rendered at all). If you graft an external condition, it's not clear what the meaning of this should be - render nothing? Render a fallback? Render no reflection? You might end up asking the renderer to assign no effect to a surface (because no condition is met), in which case there's undefined behavior (the renderer always expects an effect to go with a surface - even when you don't assign one, FG assigns a default).

To the degree that this is possible, in order to make an effect conditional you need to make its parameters conditional, aka pass color values, reflectance values etc. as properties to the effect and change the values of these properties conditional on what you want to see. This fails for overlay textures (the base texture layer is runtime selectable using the livery system, but normal/lightmaps are not).

The only solution here is to make duplicate xml declaration for the surface in question (they can reference the same ac file I think), assign different effects in each of these xmls, and then use a select animation to show which of the surfaces you need (that it pretty much how it would have to work internally if conditions would work for this purpose).

So, to sum up, the problem is that the <condition> tag is far too simple to deal with the internals that need to be set. Dependent on situation, it would have to stop computing or change a matrix to a unit matrix or re-load a surface or yet other things to accomplish what you have in mind, but it's not implemented that way. So to get good interaction with the rendering system, you need to structure your scheme along the lines rendering works.
Thorsten
 
Posts: 11748
Joined: Mon Nov 02, 2009 8:33 am

Return to Effects and shaders

Who is online

Users browsing this forum: No registered users and 1 guest