The shader thread?

I'm messing with shaders a bit right now.

Right now I am looking specifically at adding control for specular to the existing reflect shader... on Deyan's Murcielago the unified wheel/tyre texturing poses some problems.

I have to control reflection strength with an alpha map, so use the old trick of adding a syntax in the reflection shader so if we define reflection = -1, the baseCol.a is used to control reflection strength.

ambientColor=FresnelMix(ambientColor,envColor.rgb,(Kr>0?Kr:-Kr*baseCol.a),fresnel);


The problem now is that I have no spare texture slot for specular/shininess control.

So I have added this little fragment of code (from the bump speca shader)

Ks=baseCol*Ks;

This now allows the colouring of the outside of the tyre in the diffuse (rgb) channels, to do some work.



However, because the tyre is still dark in the diffuse texture (near black as it is a tyre), it doesn't have much effect on it's own.

I need to somehow increase the brightness of the texture so Racer pumps up the specular we see.

So I added a *5 multiplier to the Ks as you can see in the image attached.

shader_01.gif




Now what I don't understand is why the two images look different.

First case:
Ks in car.shd is 8, while Ks = baseCol * Ks * 5 essentially gives us Ks = baseCol * 40

Second case:
Ks in car.shd is 40, while Ks = baseCol * Ks essentially gives us Ks = baseCol * 40


Now, I don't get why they look different. Ks is meant to control the size of the specular too, but in either case they both calculate out to a peak shininess of 40, because the baseCol lookup isn't changing.
The specular settings remain the same.

It appears that multiplying by 5 in the shader means the specular level is pumped up 5x, while the shininess (size of the specular) is retained at 8 in the car.shd...

That is the effect I wanted to achieve, pumping up the actual output of the specular blob, while keeping it soft at a value of 8, but it seems un-intuitive/wrong because the value that really needs bumping up is the specular value, not shininess? (though the specular being multiplied by 5x (2.5 2.5 2.5) looked awful)

Am I missing something obvious here?




Ideally I'd like to control reflection amount, specular AND shininess using one shader here...

Probably using rgb.a for diffuse.reflection strength, and then another 3 channel texture for spec/shine and leaving another slot free for something else (perhaps transparrency?)

Specular/shininess maps add so much to these kinds of materials, so it is a shame that they haven't really been considered in the default shaders very much. I think they should almost be defaults in all materials that err away from being generally reflective (ie, using the envmap)


Bodging in the code I have for the Lambo works quite nicely in this case, but it's obviously not ideal to use the diffuse channel to control specular in this way.



Hmmmm

Dave
 
Thats an 8 bladed aperture lens.

Ideally, I'd only want that effect in replay cameras.

From the driving POV, or 'eye' view, I just want it like in Alex's pictures.


It's a lot down to personal preference and also capability. I've asked that we have a camera 'type' be defineable so we can set things like this (ie, is it a camera, or an eye etc)


In theory, you can modify the glare/bloom pass to represent different patterns of diffusion of the light as it passes into the lens/es... in the train image above, the 8 blades of the aperture cause a pattern like blurring in 8 directions... not sure of the actual physical method, but as in my other post, high end renderers just use obstruction maps to generate these effects from 'raw' glare (what we have now in Alex's pictures, and is probably what is about right enough for a wide open human eye in a realtime game)

Dave

Maybe it is just my eyes, but when I look at a distant car coming to me in real life, I see flares! When the car gets closer, the flares are not so noticeable though...
 
Well, ultimately, I think the car maker should just specify where are the head light sources located, where they point, what are the light porperties etc.
And then Racer rendering engine should just create the proper lens flare/light flare according to the camera used in game...

I will stick with headlight flares, if some of their issues can be sorted out (like proper alignment wrt the camera, rotation perhaps, lighting wrt the tod).
The headlight flare shader I created for rFactor looked really good in game actually :)

But every car is different.

Ruud will never make a car lighting system that robust that it works for everything. Flares totally depend on the viewer too. I don't want flares when I'm driving from the driver view, because I don't see flares irl through my eyes :D

The method shown above is effective and robust, and physically much more close to what really happens, and it's intuitive too. What we should maybe do is push to have a way to leverage that bloom/glare map look like it should for different lenses etc?!

A lens flare is really just a bloom flare, or a bloom blurring for us I guess.

The primary/secondary stuff that is internal lens reflections, well we won't get that without some other fancy trickery. I'm not sure where to even start with that :D

Hehe

Dave
 
Maybe it is just my eyes, but when I look at a distant car coming to me in real life, I see flares! When the car gets closer, the flares are not so noticeable though...

Indeed, but they are not 6 sided, or 8 sided, or 12 sided, or regular shaped.

Chances are when they are at a big distance your eye is fairly wide open, especially if it's night time, so the light entering is possibly entering a 4 bladed aperture, eye lids cutting across top and bottom of your iris?!
As the car gets closer, the eye closes up more as the light is brighter, the aperture goes more slitty, eye lashes break up the shape further more, and the iris closes up more.

I guess it depends what you define is a flare. If we look purely at bloom, or things that are bright in our scene, glaring items, we can just blur them depending on what we look at them through.
I guess the weakness now is that the bloom map is 256x256, it might need to be 512x512 to start to look nice, and then more GPU power to blur it... hmmmm...

The alternative is flare polygons imo (like NFS Shift and games going back forever afaik), with textures specified per car with subtle flaring applied, so it's half way between a lens flare and eye flare and ok for all occasions... ie, Audi R8 with it's LED strips, they need flares, but there is no way we should code in about 40 flares just for the sidelights :D
Textures per car make much more sense if we go down that route, but with a good shader like you are emphasising Some1 :D


Hmmmm, which way to go though hehe... I like either way, but as we have all noted, right now they are just a bit too wrong to be useful. I can see why GTP and Alex like the standard bloom for flares so far :D

Dave
 
In current gen hardware, bloom and flares are done on a small frame buffer to improve performance, which is why we could never get a decent high-res flare with post-processing. Texture flares, as Dave said, can help with the situation but should be handled very careful, depends on the viewer and scene settings.

As the headlight shader, the shiness is to control the emission spreading. It is pretty robust now though, maybe we could include the normal map influence into the calculation. As real life diffusers have complicated shape to improve visibility angle.

Try using a smaller shiness value for better result. i.e. 8~10
 

Attachments

  • SCREEN~3.jpg
    SCREEN~3.jpg
    37.1 KB · Views: 228
Hey that looks really nice GTP!

Nice to see shininess impacts the emission spreading. I guess tweaking that value, and emission strength, will get us the right balance between intensity and falloff. Spot on :D

All done automatically too. That looks very 'right' for a human eye kinda response to the glare from the light.


Can't wait to have a play with these later... I'm guessing they work through the glass lenses fine, or are any special shader entries for glass needed (ie, sort offsets etc?)

Thanks

Dave
 
Was just chatting with Cosmo again about glass shaders.

In any case you always end up having a special clause where you might want the alpha to do transparrency or reflection, and then hard-code the other variable via the shader itself.
Or you might then use more shaders than you need to hard code different parts.

It seems then to make sense that you are better off with just one shader, and a pair of textures, for all glass types, and then you have full control of all glass via that one shader and textures. One shader call, one set of textures.


Does this make sense?


TGA > tex0 > rgb > diffuse rgb
TGA > tex1 > rgb > reflectivity (r), transparrency (g), shininess (b)

That also gets tex1 all in linear for gamma control, which is nice since they are all control maps rather than colour info maps.

shininess on blue isn't essential, since we can just bond shininess to reflectivity on the red channel, but it leaves a redundant channel. I'm not sure if it's faster to just leave blue empty!?

Controls on colours isn't important, just the concept that tex0 can be for colour, then move all the controls to another tga or dds on tex1 on colour channels.


It seems the most efficient and effective way to do glass without having loads of shader types for glass so we can use an rgba texture, and/or making loads of similar but subtly different shader entries in our car.shd file (probably more costly than just having that extra texture for all the glass materials)


Hmmmmm

Dave
 
shininess on blue isn't essential, since we can just bond shininess to reflectivity on the red channel, but it leaves a redundant channel. I'm not sure if it's faster to just leave blue empty!?

I don't think there's a big difference in doing texture lookups in only 2 channels instead of 3. If shininess is implemented as Ksnew = tex.b*Ks, then it saves one multiplication to skip it, which isn't a big deal anyway. Since the channel would be mostly constant it would compress fairly well with RLE tga.

Definitely an easy thing to implement, not sure how easy to author the 3 channels. I could edit the 0.8.31 glass shader quick if you want to try it.

I think the base texture should contain transparency in at least one glass shader for legacy reasons though - better if the glass shader is functional on older content without having to author new textures. On the other hand, the Murcielago for one has the alpha channel reversed on glass - so you need to change it anyway (pretty obvious on default installs, the frame's 100% transparent and doesn't reflect anything, or using my glass shader it gets a div/0 error and returns NaN colours). Hmm.
 
Legacy is important I guess.

It just seems odd to have a whole new texture just holding reflectiveness data :D

A single channel DDS would work, but then I worry about users who may not be able to author DDS format stuff.


I think we need to realise also that in a year, very few people will be using non-CG, so hampering forward production because of past methods seems not so ideal.

Perhaps keep the current glass shader for 'legacy' upgrades, and then have a new shader for a new way of doing glass materials.

Then at least content that isn't upgraded properly with new textures, can use the old style glass shader (one we have now), and new products can move forward.
The only downside is that new products might need a specific texture for the glass (moving transparency back to alpha of the base glass texture) for non-cg users, but really that is a trivial copy/paste for any author, and then save as a new file name that only the non-cg references...



Probably best then to ignore shininess control, since I honestly can't see a need for it. Specular is done already with the Kr (reflect) map...

Perhaps handy to leave blue blank, and then it could be used in future perhaps for rain on windscreen coverage or other special effects that just need a single channel?!


If you can set that up for me Stereo, that would be cool for a few of us doing v0.9 content to try out! We are struggling with glass still.

tex0 rgb = diffuse

tex1 r = reflect
tex1 g = transparrency
tex1 b = empty

tex1 in linear colour space



Sounds good to me :D

Will be interesting to see how nice we can get glass with this since so far we have struggled to get the right balance I feel, making glass a weak point!

Dave
 
Okay, left a few extra things in for testing purposes. Better to test on the full set of options than to guess at what is needed, I think.
Code:
//
// Standard
//

#include "atmosphere.cg"
#include "lighting.cg"
#include "fresnel.cg"
#include "shadowmapping.cg"

// Vertex to pixel shader structure
struct v2p
{
  float2 tc0            : TEXCOORD0;
  float3 Direction      : TEXCOORD1;
  float4 RayleighColor  : TEXCOORD2;
  float4 MieColor       : TEXCOORD3;
  float4 Position       : TEXCOORD4;    // For fragment shader
  float3 normal         : TEXCOORD5;
  float3 I              : TEXCOORD6;
  //float  fresnel        : TEXCOORD6;
  float3 R              : TEXCOORD7;    // Reflection vector
  float  extinction     : COLOR;
};

void main(
  // In
  in v2p IN,

  // Out
  out float4 outColor : COLOR0,
#ifdef CSM_MRT
  out float4 outShadow : COLOR1,
#endif
  
  // Constants
  uniform sampler2D   baseMap : TEXUNIT0,
  uniform sampler2D   reflMap : TEXUNIT1,
  uniform samplerCUBE envMap  : TEXUNIT2,
  uniform float3    lightDirection,
  uniform float3    lightColor,
  uniform float3    lightAmbient,
  uniform float3    eyePosW,
  uniform float     atmosRayleigh,
  uniform float     atmosMie,
  uniform float3    Ke,
  uniform float3    Ka,
  uniform float3    Kd,
  uniform float3    Ks,
  uniform float     Kr,
  uniform float     shininess,
  uniform float     sunny,
  uniform float     exposure,
#ifdef CSM
  // shadow mapping
	uniform sampler2D    shadowArray  : TEXUNIT7,
  uniform float4x4     smTexMatArray[SM_MAX_SPLITS],  
  uniform float smSplits, 
#endif
  uniform float    fresnelBias,
  uniform float    fresnelScale,
  uniform float    fresnelPower
)
{
  float3 skyColor;
  
#ifdef CSM
  float  shadow;
  
  // Output shadowing and normals
  shadow=GetShadowFactor(IN.Position, IN.normal,shadowArray, smTexMatArray, smSplits, lightDirection)*sunny;
  //outShadow.rgb = IN.normal;  
#else
  const float shadow=1;
#endif

  // Get sky gradient color
  skyColor.rgb=GetSkyColor(lightDirection,IN.Direction,IN.RayleighColor,IN.MieColor,atmosRayleigh,atmosMie,lightColor,lightAmbient);

  // Get base texture color
  float4 baseCol=tex2D(baseMap,IN.tc0);
  float3 reflCol=tex2D(reflMap,IN.tc0);
  Kr *= reflCol.r; // second map red = reflectivity
  shininess *= reflCol.b; // second map blue = specular shininess

  // Reflection
  //const float Kr=0.5f;
  float4 envColor=texCUBE(envMap,IN.R);
//envColor*=3.0f;
  
  // Lighting
  float3 ambient,diffuse,specular;
  LightingSun(Ke,Ka,Kd,Ks,shininess,lightDirection,lightColor,lightAmbient,IN.Position,IN.normal,eyePosW,
    ambient,diffuse,specular);
  float3 litColor=baseCol*diffuse+specular;
  float3 shadowColor=baseCol*(ambient+Ke);
  //baseCol.rgb=baseCol*(ambient+Ke)+baseCol*diffuse+(specular*((int)outShadow.a));

  // Add reflection
  float fresnel=Fresnel(fresnelBias,fresnelScale,fresnelPower,normalize(IN.I),normalize(IN.normal));
  shadowColor=FresnelMix(shadowColor,envColor.rgb,Kr,fresnel);
  // Reflection influences opaque-ness?
  //baseCol.a=max(baseCol.a,envColor.g);

#ifdef CSM_MRT
  // Mix sky with texture color based on atmospheric influence
  outColor.rgb=lerp(skyColor,shadowColor,IN.extinction);
  //outShadow.rgb=lerp(skyColor,litColor,IN.extinction);
  outShadow.rgb=litColor*IN.extinction;
//outColor.rgb=fresnel;

  // Blending
  outColor.a=reflCol.g; // second map green = transparency
//outColor.a=1;
  // CSM
  outShadow.a=shadow;
#else
  outColor.rgb=lerp(skyColor,shadowColor+litColor*shadow,IN.extinction);
  outColor.a=reflCol.g;
#endif
}
As written, tex0 rgb = diffuse, tex1 rgb = refl, transp, specular
Shader with 3 layers -> layer0 = tex0, layer1 = tex1, layer2 = texenvmap
layer1 should use linear textures.

I included blue=specular so you can play with it, to ignore that just leave it at 100% blue.




Also a slight variant for comparison purposes.
Code:
//
// Standard
//

#include "atmosphere.cg"
#include "lighting.cg"
#include "fresnel.cg"
#include "shadowmapping.cg"

// Vertex to pixel shader structure
struct v2p
{
  float2 tc0            : TEXCOORD0;
  float3 Direction      : TEXCOORD1;
  float4 RayleighColor  : TEXCOORD2;
  float4 MieColor       : TEXCOORD3;
  float4 Position       : TEXCOORD4;    // For fragment shader
  float3 normal         : TEXCOORD5;
  float3 I              : TEXCOORD6;
  //float  fresnel        : TEXCOORD6;
  float3 R              : TEXCOORD7;    // Reflection vector
  float  extinction     : COLOR;
};

void main(
  // In
  in v2p IN,

  // Out
  out float4 outColor : COLOR0,
#ifdef CSM_MRT
  out float4 outShadow : COLOR1,
#endif
  
  // Constants
  uniform sampler2D   baseMap : TEXUNIT0,
  uniform sampler2D   reflMap : TEXUNIT1,
  uniform samplerCUBE envMap  : TEXUNIT2,
  uniform float3    lightDirection,
  uniform float3    lightColor,
  uniform float3    lightAmbient,
  uniform float3    eyePosW,
  uniform float     atmosRayleigh,
  uniform float     atmosMie,
  uniform float3    Ke,
  uniform float3    Ka,
  uniform float3    Kd,
  uniform float3    Ks,
  uniform float     Kr,
  uniform float     shininess,
  uniform float     sunny,
  uniform float     exposure,
#ifdef CSM
  // shadow mapping
	uniform sampler2D    shadowArray  : TEXUNIT7,
  uniform float4x4     smTexMatArray[SM_MAX_SPLITS],  
  uniform float smSplits, 
#endif
  uniform float    fresnelBias,
  uniform float    fresnelScale,
  uniform float    fresnelPower
)
{
  float3 skyColor;
  
#ifdef CSM
  float  shadow;
  
  // Output shadowing and normals
  shadow=GetShadowFactor(IN.Position, IN.normal,shadowArray, smTexMatArray, smSplits, lightDirection)*sunny;
  //outShadow.rgb = IN.normal;  
#else
  const float shadow=1;
#endif

  // Get sky gradient color
  skyColor.rgb=GetSkyColor(lightDirection,IN.Direction,IN.RayleighColor,IN.MieColor,atmosRayleigh,atmosMie,lightColor,lightAmbient);

  // Get base texture color
  float4 baseCol=tex2D(baseMap,IN.tc0);
  float3 reflCol=tex2D(reflMap,IN.tc0);
  Kr *= reflCol.r; // second map red = reflectivity
  shininess *= reflCol.b; // second map blue = specular shininess

  // Reflection
  //const float Kr=0.5f;
  float4 envColor=texCUBE(envMap,IN.R);
//envColor*=3.0f;
  
  // Lighting
  float3 ambient,diffuse,specular;
  LightingSun(Ke,Ka,Kd,Ks,shininess,lightDirection,lightColor,lightAmbient,IN.Position,IN.normal,eyePosW,
    ambient,diffuse,specular);
  float3 litColor=baseCol*diffuse+specular;
  float3 shadowColor=baseCol*(ambient+Ke);
  //baseCol.rgb=baseCol*(ambient+Ke)+baseCol*diffuse+(specular*((int)outShadow.a));

  // Add reflection
  float fresnel=Fresnel(fresnelBias,fresnelScale,fresnelPower,normalize(IN.I),normalize(IN.normal));
  shadowColor=FresnelMix(shadowColor,envColor.rgb/(0.001+baseCol.a),Kr,fresnel);
  // Reflection influences opaque-ness?
  //baseCol.a=max(baseCol.a,envColor.g);

#ifdef CSM_MRT
  // Mix sky with texture color based on atmospheric influence
  outColor.rgb=lerp(skyColor,shadowColor,IN.extinction);
  //outShadow.rgb=lerp(skyColor,litColor,IN.extinction);
  outShadow.rgb=litColor*IN.extinction;
//outColor.rgb=fresnel;

  // Blending
  outColor.a=reflCol.g; // second map green = transparency
//outColor.a=1;
  // CSM
  outShadow.a=shadow;
#else
  outColor.rgb=lerp(skyColor,shadowColor+litColor*shadow,IN.extinction);
  outColor.a=reflCol.g;
#endif
}
tex0 rgb = diffuse
tex0 a = reflection correction fudge factor
tex1 r = reflectivity
tex1 g = transparency
tex1 b = specularity

reflection correction fudge factor -> somewhere between 1.0 (no correction) and tex1 g (transparency). My calculations using blendfunc=blend suggested using transparency, but I'm keeping it separate so you can play with it.
Note: don't make it 0.0 (0 black) or it'll cause NaN brightness, and if it's less than tex1 g, it's not physically correct since the reflections would be brighter than the incoming light.
If it turns out this fudge factor is always gonna be the same as tex1 g, or always 1.0, for best looking glass, it can just be written out. But I liked what it added to glass in the garage map.



Specular and reflectivity are multiplied onto the original coefficients.
So in the material, set those to the max value you want on the map - probably reflect=1.0, shininess=80, or something like that. Then just treat the channel as a percent - so for 8 shininess, 10% blue.

EDIT: minor bug, fixed. Recopy shaders.
 
Wow, cool, thanks Stereo!

I think the fudge was handy when we didn't have the correct power to control all variables.

With the correct controls we should probably be able to get glass right enough to not feel the need to fudge things now. I always struggled before as balancing the maps was tough to get the desired look, but now it should be straight forward which values to use in different maps.

Probably also needs it's own set of fresnel values as glass type materials. The defaults might be ideal for paints, but not sure on glassy types. Hmmmm...

Will test tomorrow!

Dave
 
Just fooling with the Murcielago's front windscreen.

Same texture in both cases, using the 2 shaders from the previous post in order. (1 = top, 2 = bottom)

Windscreen texture is mapped with a gradient both ways:
top-bottom: opacity (about 70% top, 0% bottom). The glass itself is gray, which is showing through. Interior of course is black. Could have a better example subject for this of course.
left-right: reflectivity (100% left, 0% right)

In the bottom screenshot, the fudge factor is equal to the layer's transparency. So basically it reflects as if it were 100% opaque in almost all cases (if it's 0%, or completely transparent, it gets clipped, avoidable by just never having transparent=0)

The black windowframe is white, or 255,255,255 in the second texture, so completely reflective and opaque.

murcglasscompare.jpg


My feeling is that #2 gives the creator more intuitive editing, because reflectivity (left-right gradient) doesn't depend on the transparency (top-bottom).

Code:
shader_glass~vf_reflect_window
{
  ;sort_offset=1
  reflect=1.0
  layer0
  {
    map=glasstest.tga
    blendfunc=blend
    ;blendfunc=one src_alpha
  }
  layer1
  {
    map=glasstest_r2.tga
    mode=linear
  }
  layer2
  {
    map=$trackenvmap
  }
}
As an example I've included the Lamborghini's glass, converted to expected format. glasstest.tga is just the regular glass.tga, but with the alpha channel flipped on the windows.
 

Attachments

  • glasstest_r2.zip
    25.5 KB · Views: 133
Hehe, you have confused me there :D

"My feeling is that #2 gives the creator more intuitive editing, because reflectivity (left-right gradient) doesn't depend on the transparency (top-bottom)."



That isn't the case with the first shader though is it?

Transparrency only effects the diffuse colouring?

Reflectivity is just the intensity of the overlay of the envmap layer isn't it?

Or that is how it should be!?



Imagine this as rough glass, so no glossy reflection.

diffuse colour (rgb), and then transparrency on (alpha), is all you really need for control.

The reflective element is then basically an effect on top, added when the glass surface is smoothed.


I'm just confused why you say reflectivity doesn't depend on transparrency, when it doesn't, or shouldn't, to start with anyway.

Reflect power should be only defined by the reflect map, and fresnel. The transparrency is independent to the reflection.




Thinking more, basically, what I mean is, the shader in the first case, should give the result of the second case, without the fudge map.

It looks like the transparency information is impacting the reflection intensity, which as said, shouldn't happen. I'm fairly certain the fresnel coeffs when set for glass, will deal with the loss through transparrency in itself!?
Best to just have reflection ONLY controlled via the map and fresnel imo. In that case the fudge map shouldn't be needed.

Hmmm

Dave
 
PS, just had a bit of a read on the old "Transparency blending" thread where you went through this a lot Stereo :D

I wonder if this is any use!?

http://processing.org/reference/blend_.html

I wonder if a LIGHTEST blending would be good for glass?


I'm a bit of a shader noob, but I'm struggling with the fudge you are using Stereo :D

Ideally, if the shader is set up right, I think it should just 'work' with intuitive control maps...

I think the issue may be in fresnel which is set up for glossy paints by default maybe, or the blending method?!

Hmmmm

Dave
 
I'm just thinking about how the various types of light in/out need to behave in reality.

On a flat sheet, for each point you basically start with a sphere of input, and a sphere of output.

If a material's perfectly reflective and opaque, you just do a mirror transform to the input vectors across the normal of the surface. All incoming light is reflected, so diffuse/ambient are zero. Just a matter of making sure inputs equal outputs.
If you make the material reflecting according to fresnel, then it picks up light from both sides, adds them to create output. Technically this would include car paint, as the gloss coat is the source of fresnel reflection, but the 'behind' light is diffuse/ambient/specular off the paint itself.
reflectionfresn.png

This is just the general form for something completely transparent.
(note: transparency/opacity are complementary variables - opacity = 1 - transparency. For the sake of consistency, all variables related to the amount of light that can pass through glass will be used as if var=1.0 is completely solid, var=0.0. is completely transparent. Just to keep my head straight.)
When dealing with the different light sources independently, they can just be added up -
out = diffuse * transparency + reflection * fresnel + behind * (1-fresnel) * (1 - transparency)
(Kr is missing from here. Not exactly sure how it comes into play)
where 'behind' is whatever light comes directly from behind the glass.
The difficult part is that in blending, we only have 8 values to work with directly:
front rgba
behind rgba
The shader never sees the rear object directly, so it can't add it in directly. Instead there's blendfunc, which in the case of blendfunc=blend is:
out= f.rgb * f.a + b.rgb * (1 - f.a).

What the shader does see, and can work with, to produce front.rgba, is everything other than 'behind'.
So mathematically, behind just needs to be separated from the equation in such a way that it can be reintroduced using a blendfunc.
Comparing the two equations, (1 - f.a) = (1 - fresnel) * (1 - transparency)
So to solve for f.a, just swap things around.
f.a = 1 - (1 - fresnel) * (1 - transparency)
Or, rearranging a bit,
f.a = fresnel + transparency - fresnel*transparency

Now, what remains is f.rgb, we have
out = diffuse * transparency + reflection * fresnel
But - and it's an important but - this is later multiplied by f.a (when doing the blending).
If we want to use blendfunc=blend, this needs to be compensated for - within the shader - by having
f.rgb = (diffuse * transparency + reflection * fresnel) / f.a
That way, when we do blendfunc = blend, we get
out = f.rgb*f.a + b.rgb*(1-f.a)
out = diffuse * transparency + reflection * fresnel + b.rgb * (1 - fresnel) * (1 - transparency)
Just what would be expected.

So yes, it's an issue of blending method.
Looking through racer.nl docs for blendfuncs, it seems a more appropriate one would be
blendfunc=one one_minus_src_alpha
Instead of out=f.rgb*f.a + b.rgb*(1-f.a), this reduces it to out=f.rgb + b.rgb*(1-f.a)
If this is the case, then it's simplified:
f.rgb = diffuse * transparency + reflection * fresnel
f.a = fresnel + transparency - fresnel*transparency

The trouble with doing this is that it has cascading effects on other things - mixing sky colour in, and the Kr component.

Anyway, the 'fudge' is just taking care of this problem in the easiest manner - in practice it would probably be done as
Code:
  shadowColor=FresnelMix(shadowColor,envColor.rgb/(0.001+reflCol.g),Kr,fresnel);
(this is the only line difference between #1 and #2 - except call this #3, one where transparency is automatically used for the fudge) This is simplified even from what I calculated above, where the actual fudge should be division by (fresnel + transp. - fresnel*transp), but the shader's also missing diffuse*transparency, so. A few changes to make.


This is all working with a simplified version of the variables in the shader unfortunately. skyColor (for fog) and Kr (for less reflective surfaces) are both intimately involved in final rgba outputs. Specular light off a reflective surface is another issue - though with glass it's not so bad.

So I have a question: In the diagram above, how does Kr come in?
easy answer: out = diffuse * transparency + reflection * fresnel * Kr + behind * (1-fresnel) * (1 - transparency)
That is, Kr just affects reflective strength directly.
But... where is the other non-reflected light going? Is it all diffuse (implicit in the diffuse colour)? Some passes through (in which case the transmitted light needs to be affected by Kr)?

Working through this properly would entail changes in the cg shader and material, maybe I'll try it tonight when I have a bit more free time.
 
This is the problem, reflection and diffuse are physically the same, but we have split them out for our realtime use.

I'd ignore specular for now for main glass on windscreen etc.

Hmmm.


I'm still not sure what the fudge is doing. I'm not familiar with shaders being set up in pure maths terms, I usually set up trees via a shader UI in say Maxwell, Mental Ray, 3ds Max etc... hmmm...

Maybe the fresnel stuff is automatically considering the non-reflected light and other factors.

Cosmo was looking at fresnel values, as was I, and glass seems better at around 0.04 bias, and maybe almost 1 for scale, with power being maybe 3 or 4?!

I'm really not sure where to go with it mathematically, I just think that all we should need is to define rgb in diffuse, trans, and reflect, and fresnels for glass, and it just look like glass :D

If the 'fudge' has some basis in reality, and can be stuffed in the shader without an artist seeing it or having to edit the map channel for it, and it's intuitive, then I think that is cool :D

Not had chance to play with this yet, but will tonight!

Dave
 
Maybe the fresnel stuff is automatically considering the non-reflected light and other factors.

Cosmo was looking at fresnel values, as was I, and glass seems better at around 0.04 bias, and maybe almost 1 for scale, with power being maybe 3 or 4?!

The main thing I'm thinking right now is, Kr should be 1.0 unless the glass is dusty (scattered to diffuse) or frosted (same). If it's a smooth surface, all the reflected light will follow the fresnel curve exactly, which does go to 1.0. I need to look up a better word for mirror-reflection vs. diffuse/specular reflection, too. In reality it's all reflecting, there's just some scattering.

The 'fudge' is a compensation for using one blendfunc, since we really want two types of blending - plain blend for diffuse/ambient, then additive or lightest for reflections.


Random aside - GIMP won't let me edit channels as greyscale, period. So it's a pain to produce these. Should really write or find a plugin to combine 3 greyscale layers into rgb.
 
Ah ok, I think I get it now.

Because we have different components for reflection over transparency with light coming through from behind, and reflection with an opaque base, we need two different mixes.

By using the 'fudge', we use the map which is controlling opacity, to tell the shader when to use the appropriate mixing style for reflection blending?


Yes, reflection is almost always near 1 for glass. The problem is, sometimes we want to decal glass, so that might be dead flies, or dust, or dirty, so removing reflection and reducing transparency is nice.
We might also want to add small stickers to the glass, or whatever else. I guess you could always add those as separate materials over the top, but it seems wasteful if we can do it all at once with one texture/shader.



As per the GIMP issue, that is a tough one. Can you not just edit in redscale, bluescale, and greenscale, as it were?

Or better yet, keep each map as a greyscale, then copy/paste to the appropriate channel in the TGA for final use?


I've never properly used GIMP, might grab a copy to see, because I agree it's important that this method is also easy for artists to use no matter what their tool set :)

Dave
 

Latest News

What's needed for simracing in 2024?

  • More games, period

  • Better graphics/visuals

  • Advanced physics and handling

  • More cars and tracks

  • AI improvements

  • AI engineering

  • Cross-platform play

  • New game Modes

  • Other, post your idea


Results are only viewable after voting.
Back
Top