/////////////////////////////////////////////////////////////////////////// // // fragment program in charge of the rendering of the particles // Different versions are available, depending on which extensions are enabled. // /////////////////////////////////////////////////////////////////////////// // data comming out from the vertex program struct sortie { float4 position : POSITION; float2 texCoords0 : TEXCOORD0; float2 texCoords1 : TEXCOORD1; float4 posworld : TEXCOORD2; float4 normale : TEXCOORD3; float3 eyetovert : TEXCOORD4; float4 www : WPOS; }; #define PI 3.1415926535 #define FOVyCam PI/3.0 #define FOVyRtt 15.0*PI/18.0 #define I_REFRACT_EAU 1.33 #define ILLUM_FACT 2.0 //////////////////////////////////////////////// //////////////////////////////////////////////// // Lighting function //////////////////////////////////////////////// //////////////////////////////////////////////// float4 lightMe( sortie IN, uniform float4x4 worldview, float4 origColor, float4 lightPos, float4 lightCol, float attenuation) { float4 distant = lightPos - IN.posworld; float distFact = 1.0 - min(sqrt(dot(distant.xyz, distant.xyz)) / attenuation, 1.0); distant.xyz = normalize(mul(worldview, distant).xyz); distant.x = 1.0; float4 result; float4 a1, a2, a3; a1 = lightCol * distFact * dot(- normalize(IN.eyetovert.xyz), IN.normale.xyz); a2 = max(0, dot(distant.xyz, IN.normale.xyz)); a3 = max(0, dot(normalize(distant.xz), -normalize(IN.normale.xz)) * (1.0 - dot(distant.xyz, -IN.normale.xyz))); result = a1 * (a2 + a3); return result; } //////////////////////////////////////////////// //////////////////////////////////////////////// // entry point using regular raindrops, and light //////////////////////////////////////////////// //////////////////////////////////////////////// float4 main_noStreaks_Light(sortie IN, uniform float nbLights, uniform float4x4 worldview, uniform float4 colAmb, uniform sampler2D image : TEXUNIT0, uniform sampler2D texPos : TEXUNIT1, uniform sampler2D masque : TEXUNIT2, uniform sampler2D lightInfoTexture : TEXUNIT3) : COLOR { float4 couleur; float4 retour; float4 colMasque = tex2D(masque, IN.texCoords0); if (colMasque.r < 0.2 && colMasque.g < 0.2 && colMasque.b < 0.2) retour.a = 0; else { retour.a = 1; float3 refrac = (colMasque.xyz - 0.5) / 2.0; float2 coords = 0.5 - (0.5 - IN.texCoords1 + refrac.xy / refrac.z) * tan(FOVyCam / 2.0) / tan(FOVyRtt / 2.0) ; couleur.rgb = tex2D(image, coords).rgb; if (coords.x > 1.0 || coords.y > 1.0 || coords.x < 0.0 || coords.y < 0.0) { // we're going out of the texture ! couleur.rgb=float3(0, 0, 1); } IN.normale.z = 1.0 - sqrt(IN.normale.x * IN.normale.x + IN.normale.y * IN.normale.y); IN.normale.w = 1.0; //lighting retour = couleur * colAmb; for (int l = 0 ; l < nbLights ; l++) { float lightRow = l * (1.0 / nbLights) + (0.5 / nbLights); float4 lightCol = tex2D(lightInfoTexture, float2(1.0 / 8.0, lightRow)); float4 lightPos = tex2D(lightInfoTexture, float2(3.0 / 8.0, lightRow)); float4 lightDir = tex2D(lightInfoTexture, float2(5.0 / 8.0, lightRow)); float lightCut = tex2D(lightInfoTexture, float2(7.0 / 8.0, lightRow)).r; float lightAtt = tex2D(lightInfoTexture, float2(7.0 / 8.0, lightRow)).g; float4 illum = lightMe(IN, worldview, couleur, lightPos, lightCol, lightAtt); // let's check if the particle is within the lighting cone if ( dot( normalize(IN.posworld.xyz - lightPos.xyz) , normalize(lightDir.xyz) ) > cos (lightCut * PI / 180.0) ) { retour += illum * ILLUM_FACT; } } } return retour; } //////////////////////////////////////////////// //////////////////////////////////////////////// // entry point using snow, and light //////////////////////////////////////////////// //////////////////////////////////////////////// float4 main_Snow_Light(sortie IN, uniform float nbLights, uniform float4x4 worldview, uniform float4 colAmb, uniform sampler2D image : TEXUNIT0, uniform sampler2D texPos : TEXUNIT1, uniform sampler2D lightInfoTexture : TEXUNIT2) : COLOR { float4 couleur; float4 retour; retour = tex2D(image, IN.texCoords0) * colAmb; if (retour.a > 0.01) { for (int l = 0 ; l < nbLights ; l++) { float lightRow = l * (1.0 / nbLights) + (0.5 / nbLights); float4 lightCol = tex2D(lightInfoTexture, float2(1.0 / 8.0, lightRow)); float4 lightPos = tex2D(lightInfoTexture, float2(3.0 / 8.0, lightRow)); float4 lightDir = tex2D(lightInfoTexture, float2(5.0 / 8.0, lightRow)); float lightCut = tex2D(lightInfoTexture, float2(7.0 / 8.0, lightRow)).r; float lightAtt = tex2D(lightInfoTexture, float2(7.0 / 8.0, lightRow)).g; float4 illum = lightMe(IN, worldview, couleur, lightPos, lightCol, lightAtt); // let's check if the snowflake particle is within the lighting cone if ( dot( normalize(IN.posworld.xyz - lightPos.xyz) , normalize(lightDir.xyz) ) > cos (lightCut * PI / 180.0) ) { retour.xyz *= illum.xyz * ILLUM_FACT; } } } return retour; } #define DISCRETIZATION 10.0 //////////////////////////////////////////////// //////////////////////////////////////////////// // entry point using streaks, and light //////////////////////////////////////////////// //////////////////////////////////////////////// float4 main_Streaks_Light(sortie IN, uniform float nbLights, uniform float4x4 worldview, uniform float4 colAmb, uniform sampler2D image : TEXUNIT0, uniform sampler2D texPos : TEXUNIT1, uniform sampler2D masque : TEXUNIT2, uniform sampler2D shape : TEXUNIT3, uniform sampler2D lightInfoTexture : TEXUNIT4) : COLOR { float4 couleur = float4(0, 0, 0, 0); float4 retour = float4(0, 0, 0, 0); float4 colTexture, colTemp; float4 colMasque; float effective_discretization; int i, l; float3 refrac; float2 coords; float lightRow; float4 lightCol; float4 lightPos; float4 lightDir; float lightCut; float lightAtt; float4 illum; float4 shapeAlpha = tex2D(shape, 1.0 - IN.texCoords0); IN.normale.z = 1.0 - sqrt(IN.normale.x * IN.normale.x + IN.normale.y * IN.normale.y); IN.normale.w = 1.0; if (shapeAlpha.r > 0.2 && shapeAlpha.g > 0.2 && shapeAlpha.b > 0.2 ) { effective_discretization = 0; for (i=0 ; i < DISCRETIZATION ; i++) { colMasque = tex2D(masque, float2(IN.texCoords0.x, (i + 1) / (DISCRETIZATION + 1))); // is this pixel valid to throw a ray ? if (colMasque.r > 0.1 || colMasque.g > 0.1 || colMasque.b > 0.1) { refrac = (colMasque.xyz - 0.5) / 2.0; coords = 0.5 - (0.5 - IN.texCoords1 + refrac.xy / refrac.z) * tan(FOVyCam / 2.0) / tan(FOVyRtt / 2.0) ; colTexture = tex2D(image, coords); couleur += colTexture; effective_discretization++; } } colTemp = couleur / (effective_discretization); // lighting retour = colTemp * colAmb; for (l = 0 ; l < nbLights ; l++) { lightRow = l * (1.0 / nbLights) + (0.5 / nbLights); lightCol = tex2D(lightInfoTexture, float2(1.0 / 8.0, lightRow)); lightPos = tex2D(lightInfoTexture, float2(3.0 / 8.0, lightRow)); lightDir = tex2D(lightInfoTexture, float2(5.0 / 8.0, lightRow)); lightCut = tex2D(lightInfoTexture, float2(7.0 / 8.0, lightRow)).r; lightAtt = tex2D(lightInfoTexture, float2(7.0 / 8.0, lightRow)).g; illum = lightMe(IN, worldview, colTemp, lightPos, lightCol, lightAtt); // let's check if the particle is within the lighting cone if ( dot( normalize(IN.posworld.xyz - lightPos.xyz) , normalize(lightDir.xyz) ) > cos (lightCut * PI / 180.0) ) { retour += illum * ILLUM_FACT; } } // alpha blend it a little with the background scene retour.a = 0.6 - abs(IN.texCoords0.x - 0.5) * 1.2; } return retour; } //////////////////////////////////////////////// //////////////////////////////////////////////// // entry point using regular raindrops, without light //////////////////////////////////////////////// //////////////////////////////////////////////// float4 main_noStreaks_noLight(sortie IN, uniform sampler2D image : TEXUNIT0, uniform sampler2D masque : TEXUNIT2) : COLOR { float4 couleur; float4 colMasque = tex2D(masque, IN.texCoords0); if (colMasque.r < 0.2 && colMasque.g < 0.2 && colMasque.b < 0.2) couleur.a = 0; else { couleur.a = 1; float3 refrac = (colMasque.xyz - 0.5) / 2.0; float2 coords = 0.5 - (0.5 - IN.texCoords1 + refrac.xy / refrac.z) * tan(FOVyCam / 2.0) / tan(FOVyRtt / 2.0) ; couleur.rgb = tex2D(image, coords).rgb; } return couleur; } //////////////////////////////////////////////// //////////////////////////////////////////////// // entry point using snow, without light //////////////////////////////////////////////// //////////////////////////////////////////////// float4 main_Snow_noLight(sortie IN, uniform sampler2D image : TEXUNIT0) : COLOR { return tex2D(image, IN.texCoords0); } //////////////////////////////////////////////// //////////////////////////////////////////////// // entry point using streaks, without light //////////////////////////////////////////////// //////////////////////////////////////////////// float4 main_Streaks_noLight(sortie IN, uniform sampler2D image : TEXUNIT0, uniform sampler2D masque : TEXUNIT2, uniform sampler2D shape : TEXUNIT3) : COLOR { float4 couleur = float4(0, 0, 0, 0); float4 colMasque; float4 shapeAlpha = tex2D(shape, IN.texCoords0); if (shapeAlpha.r > 0.2 && shapeAlpha.g > 0.2 && shapeAlpha.b > 0.2 ) { for (int i=0 ; i <= DISCRETIZATION ; i++) { colMasque = tex2D(masque, float2(IN.texCoords0.x, i / DISCRETIZATION)); float3 refrac = (colMasque.xyz - 0.5) / 2.0; float2 coords = 0.5 - (0.5 - IN.texCoords1 + refrac.xy / refrac.z) * tan(FOVyCam / 2.0) / tan(FOVyRtt / 2.0) ; couleur.rgb = couleur.rgb + tex2D(image, coords).rgb; } couleur = couleur / (DISCRETIZATION + 1); couleur.a = 1.0 - abs(IN.texCoords0.x - 0.5) * 2.0; } return couleur; }