I made a shader for LCD/LED displays.
Replace the JA37 folder references in the effect file to if you want to test as I haven't applied it to any aircraft yet. Notice some folder references are buried halfway down the effect file.
Features and missing features
- It tries to recreate the color distortion and inversion of brightness of old LCDs when viewed from an angle (sorta works like a negative). At very big angles it can be set to go dark. So no more peeking from co-pilots seat to pilots displays if the displays are old LCDs.
- It attempts to play nice with ALS filters.
- Should work for both Canvas displays or static texture displays.
- You will probably need to tune material values in your AC file. The lightning like ambient / diffuse / specular is added, not modulated in any way with the display output. Only emission is modulated with the actual texture colors.
I used: MATERIAL "screen" rgb 0.0 0.0 0.0 amb 0.000 0.000 0.000 emis 0.000 0.000 0.000 spec 0.5 0.5 0.5 shi 96 trans 0.000
- It probably only supports geometry loaded from AC files due to not taking vertex color into account.
- To turn up the brightness, just make a normal material animation and turn up the emission.
- No Rembrandt support yet.
- Doesn't work with display textures or materials that has transparency.
- No moonlight lightning yet.
- No secondary ALS lights yet.
Some feedback would be nice, both for how you think it works, and for the code itself. Or if there is bugs or something it does not play well with.
Its a work in progress, but if it ends up being usable, then next plan is to make CRT display shader.
Notice that I don't own an old LCD display so I could not investigate how it works, but luckily a friend gave me advice on how the colors distort.
Some pics, please note that this display as its mostly one tone of medium grey don't show the brightness inversion very good, but it does show the color distortion:
lcd.eff
- Code: Select all
<!--
License: GPL v2
Author: Nikolai V. Chr.
-->
<PropertyList>
<name>Aircraft/JA37/Models/Effects/displays/lcd</name>
<parameters>
<inner-angle type="float">35</inner-angle><!-- 0-90, use 90 for LED or plasma display-->
<outer-angle type="float">60</outer-angle><!-- 0-90, but greater than inner -->
<black-angle type="float">80</black-angle><!-- 0-90, but greater than outer -->
<texture n="0">
<type>white</type>
</texture>
<vertex-program-two-side type="bool">false</vertex-program-two-side>
<material>
<color-mode-uniform>1</color-mode-uniform>
</material>
<material-id>0</material-id>
<use-als><use>/sim/rendering/shaders/skydome</use></use-als>
<rendering-hint>opaque</rendering-hint>
<transparent>false</transparent>
<render-bin>
<bin-number>1</bin-number>
<bin-name>RenderBin</bin-name>
</render-bin>
<shade-model>smooth</shade-model>
<use_filtering><use>/sim/rendering/als-filters/use-filtering</use></use_filtering>
<gamma><use>/sim/rendering/als-filters/gamma</use></gamma>
<brightness><use>/sim/rendering/als-filters/brightness</use></brightness>
<delta_T><use>/environment/surface/delta-T-structure</use></delta_T>
<fact_grey><use>/sim/rendering/als-filters/grey-factor</use></fact_grey>
<fact_black><use>/sim/rendering/als-filters/black-factor</use></fact_black>
<use_night_vision><use>/sim/rendering/als-filters/use-night-vision</use></use_night_vision>
<use_IR_vision><use>/sim/rendering/als-filters/use-IR-vision</use></use_IR_vision>
<display_xsize><use>/sim/startup/xsize</use></display_xsize>
<display_ysize><use>/sim/startup/ysize</use></display_ysize>
</parameters>
<technique n="5">
<predicate>
<and>
<property>/sim/rendering/shaders/quality-level</property>
<property>/sim/rendering/shaders/model</property>
<or>
<less-equal>
<value type="float">2.0</value>
<glversion/>
</less-equal>
<and>
<extension-supported>GL_ARB_shader_objects</extension-supported>
<extension-supported>GL_ARB_shading_language_100</extension-supported>
<extension-supported>GL_ARB_vertex_shader</extension-supported>
<extension-supported>GL_ARB_fragment_shader</extension-supported>
</and>
</or>
</and>
</predicate>
<pass>
<lighting>true</lighting>
<material>
<active>
<use>material/active</use>
</active>
<ambient>
<use>material/ambient</use>
</ambient>
<diffuse>
<use>material/diffuse</use>
</diffuse>
<specular>
<use>material/specular</use>
</specular>
<emissive>
<use>material/emissive</use>
</emissive>
<shininess>
<use>material/shininess</use>
</shininess>
<color-mode>
<use>material/color-mode</use>
</color-mode>
</material>
<blend>
<active>
<use>blend/active</use>
</active>
<source>
<use>blend/source</use>
</source>
<destination>
<use>blend/destination</use>
</destination>
</blend>
<shade-model>
<use>shade-model</use>
</shade-model>
<cull-face>
<use>cull-face</use>
</cull-face>
<rendering-hint>
<use>rendering-hint</use>
</rendering-hint>
<blend>
<use>transparent</use>
</blend>
<alpha-test>
<use>transparent</use>
</alpha-test>
<render-bin>
<bin-number>
<use>render-bin/bin-number</use>
</bin-number>
<bin-name>
<use>render-bin/bin-name</use>
</bin-name>
</render-bin>
<!-- Albedo texture unit-->
<texture-unit>
<unit>0</unit>
<image>
<use>texture[0]/image</use>
</image>
<type>
<use>texture[0]/type</use>
</type>
<filter>
<use>texture[0]/filter</use>
</filter>
<wrap-s>
<use>texture[0]/wrap-s</use>
</wrap-s>
<wrap-t>
<use>texture[0]/wrap-t</use>
</wrap-t>
<internal-format>
<use>texture[0]/internal-format</use>
</internal-format>
</texture-unit>
<vertex-program-two-side>
<use>vertex-program-two-side</use>
</vertex-program-two-side>
<program>
<vertex-shader n="0">Aircraft/JA37/Models/Effects/displays/lcd.vert</vertex-shader>
<fragment-shader n="0">Aircraft/JA37/Models/Effects/displays/lcd.frag</fragment-shader>
<fragment-shader n="1">Shaders/noise.frag</fragment-shader>
<fragment-shader n="2">Shaders/filters-ALS.frag</fragment-shader>
</program>
<uniform>
<name>BaseTex</name>
<type>sampler-2d</type>
<value type="int">0</value>
</uniform>
<uniform>
<name>innerAngle</name>
<type>float</type>
<value>
<use>inner-angle</use>
</value>
</uniform>
<uniform>
<name>outerAngle</name>
<type>float</type>
<value>
<use>outer-angle</use>
</value>
</uniform>
<uniform>
<name>blackAngle</name>
<type>float</type>
<value>
<use>black-angle</use>
</value>
</uniform>
<uniform>
<name>use_als</name>
<type>bool</type>
<value>
<use>use-als</use>
</value>
</uniform>
<uniform>
<name>gamma</name>
<type>float</type>
<value><use>gamma</use></value>
</uniform>
<uniform>
<name>brightness</name>
<type>float</type>
<value><use>brightness</use></value>
</uniform>
<uniform>
<name>use_filtering</name>
<type>bool</type>
<value><use>use_filtering</use></value>
</uniform>
<uniform>
<name>use_night_vision</name>
<type>bool</type>
<value><use>use_night_vision</use></value>
</uniform>
<uniform>
<name>use_IR_vision</name>
<type>bool</type>
<value><use>use_IR_vision</use></value>
</uniform>
<uniform>
<name>delta_T</name>
<type>float</type>
<value><use>delta_T</use></value>
</uniform>
<uniform>
<name>fact_grey</name>
<type>float</type>
<value><use>fact_grey</use></value>
</uniform>
<uniform>
<name>fact_black</name>
<type>float</type>
<value><use>fact_black</use></value>
</uniform>
<uniform>
<name>display_xsize</name>
<type>int</type>
<value><use>display_xsize</use></value>
</uniform>
<uniform>
<name>display_ysize</name>
<type>int</type>
<value><use>display_ysize</use></value>
</uniform>
</pass>
</technique>
</PropertyList>
lcd.vert
- Code: Select all
// Author: Nikolai V. Chr.
// License: GPL v2
#version 120
varying vec3 VNormal;
varying vec3 eyeVec;
void main(void) {
vec4 ecPosition = gl_ModelViewMatrix * gl_Vertex;
eyeVec = ecPosition.xyz;
VNormal = normalize(gl_NormalMatrix * gl_Normal);
gl_Position = ftransform();
gl_ClipVertex = ecPosition;
gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;
}
lcd.frag
- Code: Select all
// Author: Nikolai V. Chr.
// License: GPL v2
#version 120
varying vec3 VNormal;
varying vec3 eyeVec;
uniform sampler2D BaseTex;
uniform float innerAngle;//inside this angle the display is perfect
uniform float outerAngle;//from inner to outer the display gets more color distorted.
uniform float blackAngle;//from outer to this angle the display gets more black. From this angle to 90 the display stays black.
uniform int use_als;
const vec4 kRGBToYPrime = vec4 (0.299, 0.587, 0.114, 0.0);
const vec4 kRGBToI = vec4 (0.596, -0.275, -0.321, 0.0);
const vec4 kRGBToQ = vec4 (0.212, -0.523, 0.311, 0.0);
const vec4 kYIQToR = vec4 (1.0, 0.956, 0.621, 0.0);
const vec4 kYIQToG = vec4 (1.0, -0.272, -0.647, 0.0);
const vec4 kYIQToB = vec4 (1.0, -1.107, 1.704, 0.0);
vec3 filter_combined (in vec3 color) ;
vec3 rotateHue (in vec4 color) {
// Convert to YIQ
float YPrime = dot (color, kRGBToYPrime);
float I = dot (color, kRGBToI);
float Q = dot (color, kRGBToQ);
// Calculate the hue and chroma
float hue = atan (Q, I);
float chroma = sqrt (I * I + Q * Q);
// Make the adjustment
hue += radians(180.0);
YPrime = 1 - YPrime;
// Convert back to YIQ
Q = chroma * sin (hue);
I = chroma * cos (hue);
// Convert back to RGB
vec4 yIQ = vec4 (YPrime, I, Q, 0.0);
color.r = dot (yIQ, kYIQToR);
color.g = dot (yIQ, kYIQToG);
color.b = dot (yIQ, kYIQToB);
// reduce contrast by alot
color.rgb = ((color.rgb - vec3(0.5,0.5,0.5)) * vec3(0.15,0.15,0.15)) + vec3(0.5,0.5,0.5);
return color.rgb;
}
// todo: rembrandt and stuff
void main (void) {
vec3 gamma = vec3(1.0/2.2);// standard monitor gamma correction
vec3 gammaInv = vec3(2.2);
vec4 texel = texture2D(BaseTex, gl_TexCoord[0].st);
vec3 eye = normalize(-eyeVec);
vec3 N = normalize(VNormal);
float angle = degrees(acos(dot(N,eye)));//angle between normal and viewer
vec3 color = vec3(0.0,0.0,0.0);
if (angle <= innerAngle) {
color = texel.rgb;
} else if (angle <= outerAngle) {
vec3 hsl = rotateHue(texel);
float amount = (angle - innerAngle)/(outerAngle-innerAngle);
color = mix(texel.rgb, hsl, amount);
} else if (angle <= blackAngle) {
vec3 hsl = rotateHue(texel);
float amount = (angle - outerAngle)/(blackAngle-outerAngle);
color = mix(hsl, vec3(0,0,0), amount);
}
color = pow(color, gammaInv);
color = color * gl_FrontMaterial.emission.rgb;
float phong = 0.0;
vec3 Lphong = normalize(gl_LightSource[0].position.xyz);
if (dot(N, Lphong) > 0.0) {
// lightsource is not behind
vec3 Rphong = normalize(-reflect(Lphong,N));
phong = pow(max(dot(Rphong,eye),0.0),gl_FrontMaterial.shininess);
phong = clamp(phong, 0.0, 1.0);
}
vec4 specular = gl_FrontMaterial.specular * gl_LightSource[0].diffuse * phong;
vec3 ambient = gl_FrontMaterial.ambient.rgb * gl_LightSource[0].ambient.rgb * gl_LightSource[0].ambient.rgb * 2;//hack but works, pitch black at night. :)
vec3 L = normalize((gl_ModelViewMatrixInverse * gl_LightSource[0].position).xyz);
N = normalize((gl_ModelViewMatrixTranspose * vec4(N,0.0)).xyz);
float nDotVP = dot(N,L);
nDotVP = max(0.0, nDotVP);
vec3 diffuse = gl_FrontMaterial.diffuse.rgb * gl_LightSource[0].diffuse.rgb * nDotVP;
color = clamp(color+specular.rgb+ambient+diffuse, 0, 1);
if (use_als > 0) {
gl_FragColor = vec4(filter_combined(pow(color,gamma)), 0.0);
} else {
gl_FragColor = vec4(pow(color,gamma), 0.0);
}
}
Edit: Now also reduces contrast. Code updated. And added some screenies below of reduced contrast at angle: