I'm trying to find the right blendfunc to make transparent windows work properly.
When I use blendfunc=blend, it makes this "negative" effect, depending on the brightness of the front texture - eg. where the clouds are reflecting, the seat appears blue, while it's red without the cloud reflection. The driver's hair/face also invert brightness.
Along the top edge of the window, the texture is 100% opaque - shouldn't be getting any of the object behind it. But the same "blue" from the seat is visible there too in the reflection.
Here's one on a brighter day showing the same thing. The reflection is more blue but it's a similar effect.
I'm not sure why the colour of the closer layer would be affected like this.
Part of the problem, of course, is that the reflect_window_v/f.cg is not up to date with the new fresnel functions. Using the normal reflect_v.cg doesn't work for windows because it doesn't adjust transparency at all. I ended up fixing these first.
dyn_standard_reflect_window_v.cg
This substitutes the Fresnel function used by other shaders for the old version, which was the same thing done manually. I think the old values were also 0, 1, 2, which I changed to 0.15 0.85 3.0 because that seems closer to glass.
dyn_standard_reflect_window_f.cg
I changed the functions a little more here, to get it working right. I also ended up writing in a new function in fresnel.cg to calculate the alpha transparency at the same time as the rest:
fresnel.cg
Without multiplying by Kr and fresnel, envCol.g was overpowering the transparency of the glass. Really, doing this could have stayed in _reflect_window_f.cg. But it's easier to find the function here.
After these changes, it looks quite a bit nicer, and it became more clear to me what blending function I want.
The problem is that the reflection off of glass is only visible where it's brighter than the backing. So what I really need is something more like a maximum -
blendfunc = max(refl_color, dst.rgb)
Where refl_color = glass.a * glass.rgb + (1 - glass.a) * dst.rgb, ie. the normal blend, and dst is the background it's being overlaid onto.
Or, maybe
reflection_strength = min(0, (refl - dst))
blend = reflection_strength*refl + (1 - reflection_strength)*dst
This represents the opacity of the reflection increasing with the difference between the reflection and its backing. If the backing was entirely dark then it should reflect more completely.
When I use blendfunc=blend, it makes this "negative" effect, depending on the brightness of the front texture - eg. where the clouds are reflecting, the seat appears blue, while it's red without the cloud reflection. The driver's hair/face also invert brightness.
Along the top edge of the window, the texture is 100% opaque - shouldn't be getting any of the object behind it. But the same "blue" from the seat is visible there too in the reflection.
Here's one on a brighter day showing the same thing. The reflection is more blue but it's a similar effect.
I'm not sure why the colour of the closer layer would be affected like this.
Part of the problem, of course, is that the reflect_window_v/f.cg is not up to date with the new fresnel functions. Using the normal reflect_v.cg doesn't work for windows because it doesn't adjust transparency at all. I ended up fixing these first.
dyn_standard_reflect_window_v.cg
Code:
#include \\\\\\"fresnel.cg\\\\\\"
[...]
// Fresnel
const float fresnelBias=0.15; //0.2;
const float fresnelScale=0.85; //0.9
const float fresnelPower=3.0; //4.0;
I=normalize(I);
OUT.fresnel=Fresnel(fresnelBias,fresnelScale,fresnelPower,I,N);
dyn_standard_reflect_window_f.cg
Code:
#include \\\\\\"fresnel.cg\\\\\\"
[...]
{
float3 skyColor;
// 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);
// 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);
baseCol.rgb=baseCol*(ambient+Ke)+baseCol*diffuse*lightColor+specular;
// HDR toning of sky
//skyColor.rgb=1.0-exp(-exposure*skyColor.rgb);
// Add reflection
//baseCol=lerp(baseCol,envColor,Kr);
//baseCol.rgb+=envColor.rgb*Kr*IN.fresnel;
//baseCol.rgb=FresnelMix(baseCol.rgb,envColor.rgb,Kr,IN.fresnel);
baseCol.rgba=FresnelGlassMix(baseCol.rgba,envColor.rgb,Kr,IN.fresnel);
//baseCol.rgb+=envColor.rgb; //*Kr*IN.fresnel;
// Reflection influences opaque-ness
//baseCol.a=1; //max(baseCol.a,envColor.g);
//baseCol.a=max(baseCol.a,envColor.g);
//baseCol.rgb+=envColor.rgb; //*Kr*IN.fresnel;
//baseCol=envColor;
// Mix sky with texture color based on atmospheric influence
outColor.rgb=lerp(skyColor,baseCol,IN.extinction);
//outColor.rgb=IN.fresnel;
//outColor.rgb=baseCol;
//outColor.rgb=Kr;
// Blending
outColor.a=baseCol.a;
//outColor.a=1;
}
fresnel.cg
Code:
float4 FresnelGlassMix(float4 diffCol,float3 envCol, float Kr, float fresnel)
// mix with alpha
{
float4 retCol = diffCol;
retCol.rgb = (diffCol.rgb+envCol*Kr*fresnel)*diffCol.a + (1-diffCol.a)*envCol;
// retCol.rgb += envCol*Kr*fresnel;
retCol.a = max(diffCol.a, envCol.g*Kr*fresnel);
return retCol;
}
After these changes, it looks quite a bit nicer, and it became more clear to me what blending function I want.
The problem is that the reflection off of glass is only visible where it's brighter than the backing. So what I really need is something more like a maximum -
blendfunc = max(refl_color, dst.rgb)
Where refl_color = glass.a * glass.rgb + (1 - glass.a) * dst.rgb, ie. the normal blend, and dst is the background it's being overlaid onto.
Or, maybe
reflection_strength = min(0, (refl - dst))
blend = reflection_strength*refl + (1 - reflection_strength)*dst
This represents the opacity of the reflection increasing with the difference between the reflection and its backing. If the backing was entirely dark then it should reflect more completely.