Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*************************************************************************************\
- * Alien Vision Shader for Natural Selection 2 *
- * To be used with Dark Vision Mod for Natural Selection 2 *
- * Steam Workshop: http://steamcommunity.com/sharedfiles/filedetails/?id=108510422 *
- * Forum: http://forums.unknownworlds.com/discussion/comment/2068226/#Comment_2068226 *
- * Example Video: http://www.youtube.com/watch?v=xXRCpaSsp_I *
- * *
- * Author: Ineluki80 *
- * Date: 2013-01-29 *
- * Version: v0.3 *
- * *
- * Features: *
- * - short sighted aliens using depth of field technique ( Tiefenunschärfe ) *
- * - Insectoide compound eyes using a hexagonal lattice *
- * - Refraction and dispersion for eye vision *
- * - brightness correction in dark spaces *
- * - sonar sight using sound pulses with exponential decay and distance based *
- * resolution, rainbow coloured *
- * - importance highlighting for biological and technological compounds *
- * *
- \*************************************************************************************/
- struct VS_INPUT
- {
- float3 ssPosition : POSITION;
- float2 texCoord : TEXCOORD0;
- float4 color : COLOR0;
- };
- struct VS_OUTPUT
- {
- float4 ssPosition : POSITION;
- float2 texCoord : TEXCOORD0;
- float4 color : COLOR0;
- };
- struct PS_INPUT
- {
- float2 texCoord : TEXCOORD0;
- float4 color : COLOR0;
- };
- texture baseTexture;
- texture depthTexture;
- float time;
- float startTime;
- float amount;
- sampler baseTextureSampler = sampler_state
- {
- texture = (baseTexture);
- AddressU = Wrap;
- AddressV = Wrap;
- MinFilter = Linear;
- MagFilter = Linear;
- MipFilter = Linear;
- SRGBTexture = False;
- };
- sampler depthTextureSampler = sampler_state
- {
- texture = (depthTexture);
- AddressU = Clamp;
- AddressV = Clamp;
- MinFilter = Linear;
- MagFilter = Linear;
- MipFilter = None;
- SRGBTexture = False;
- };
- VS_OUTPUT SFXBasicVS(VS_INPUT input)
- {
- VS_OUTPUT output;
- output.ssPosition = float4(input.ssPosition, 1);
- output.texCoord = input.texCoord;
- output.color = input.color;
- return output;
- }
- // Function to calculate optic dispersion
- // - Refraction in the eye is a function of the place where the light hits it
- // - Dispersion: Light of several wavelengths is affected in separate ways
- float4 OpticDispersion( float2 texCoord ) { // Take the texture coordinates (interval[0..1]) and return a colour value
- float r = tex2D(depthTextureSampler, texCoord).r; // Get the distance to the pixel
- float px = (texCoord.x-0.5)*2; // calculate the X coordinate in interval [-1.0 .. 1.0]
- float py = (texCoord.y-0.5)*2; // calculate the Y coordinate in interval [-1.0 .. 1.0]
- float xyr = px*px + py*py; // Get the square of the radius in the XY plane
- float pz = sqrt( r*r - xyr ); // Reconstruct the original Z value from Distance and XY coordinates
- xyr = sqrt( xyr ); // Calculate the radius in the XY plane from its square
- float ef = exp(-xyr/3); // Anisotropy Effect Factor increases with XY plane radius
- //if ( r < 0.4 ) { ef = pow(ef,1/3); } // If it is the mouth, we reduce the effect because otherwise it looks ugly
- float4 c; c.a = 0; // C holds the return colour. Its alpha value is zero
- // Red, green, and blue light obeys separate refraction constants. We use Refraction constants smaller than 1.0, so the effect is bigger on red and smaller on blue light.
- // Also the effect is more pronounced in the outer parts of the eye, so the refraction constants are multiplied by the radial effect factor ef.
- // We apply some refration based on the XYZ pixel coordinate relative to the Z normal vector (XY plane), and look where the new vector is located in the texture.
- // To get valid texture coordinates, they have to be transformed into interval [0..1] again, and, to be sure, the value is cut outside this interval by clamp.
- c.r = tex2D(baseTextureSampler, clamp(refract(float3(px, py, pz), float3(0,0,1), 0.980*ef), -1.0, 1.0).xy/2.0+0.5).r;
- c.g = tex2D(baseTextureSampler, clamp(refract(float3(px, py, pz), float3(0,0,1), 0.990*ef), -1.0, 1.0).xy/2.0+0.5).g;
- c.b = tex2D(baseTextureSampler, clamp(refract(float3(px, py, pz), float3(0,0,1), 0.999*ef), -1.0, 1.0).xy/2.0+0.5).b;
- return c; // Finally, we return the calculated colour.
- }
- // Function to calculate optic distortion by refraction
- float2 OpticDistortion( float2 texCoord, float refconst ) { // Take texture coordinates (interval[0..1]) and refraction constant, return new coordinates
- float r = tex2D(depthTextureSampler, texCoord).r; // Get the distance to the pixel
- float px = (texCoord.x-0.5)*2; // calculate the X coordinate in interval [-1.0 .. 1.0]
- float py = (texCoord.y-0.5)*2; // calculate the Y coordinate in interval [-1.0 .. 1.0]
- float xyr = px*px + py*py; // Get the square of the radius in the XY plane
- float pz = sqrt( r*r - xyr ); // Reconstruct the original Z value from Distance and XY coordinates
- xyr = sqrt( xyr ); // Calculate the radius in the XY plane from its square
- float ef = exp(-xyr/3); // Anisotropy Effect Factor increases with XY plane radius
- //if ( r < 0.4 ) { ef = pow(ef,1/3); } // If it is the mouth, we reduce the effect because otherwise it looks ugly
- return clamp(refract(float3(px, py, pz), float3(0,0,1), refconst*ef), -1.0, 1.0).xy/2.0+0.5; // Finally, we return the new coordinates
- }
- float4 SFXDarkVisionPS(PS_INPUT input) : COLOR0
- {
- // Get the depth and importance information
- float2 depthMap = tex2D(depthTextureSampler, input.texCoord).rg; // this texture contains the depth information in r and importance factor in g
- // Depth of field effect "Tiefenunschärfe"
- // - aliens are short sighted, pixels are increasingly blurred with respect to distance in a hexagonal shape
- const float d = 0.0050 * (1-exp(-depthMap.r/15.0)); // Blurring is affected by distance up to a maximal value
- const float sqrt3over2 = sqrt(3)/2.0; // This factor is needed for the hexagon coordinates
- /*
- * // Tiefenunschärfe (Depth of field) without Optic Dispersion - using original texture
- * float4 outputPixel = ( tex2D(baseTextureSampler, input.texCoord + float2(+d,0)) + // Colour information of the six corners of a hexagon
- * tex2D(baseTextureSampler, input.texCoord + float2(+d/2,+d*sqrt3over2)) + // (size varying with distance) is used to blurr the texture
- * tex2D(baseTextureSampler, input.texCoord + float2(-d/2,+d*sqrt3over2)) + // by taking the mean of the colours. By this, bright spots
- * tex2D(baseTextureSampler, input.texCoord + float2(+d/2,-d*sqrt3over2)) + // will be blurred into a hexagonal shape because their information
- * tex2D(baseTextureSampler, input.texCoord + float2(-d/2,-d*sqrt3over2)) + // is used in several pixels throughout the texture.
- * tex2D(baseTextureSampler, input.texCoord + float2(-d,0))
- * ) / 6.0;
- */
- // Tiefenunschärfe (Depth of field) including Optic Dispersion - using refraction transformed texture
- float4 outputPixel = ( OpticDispersion(input.texCoord + float2(+d,0)) + // Colour information of the six corners of a hexagon
- OpticDispersion(input.texCoord + float2(+d/2,+d*sqrt3over2)) + // (size varying with distance) is used to blurr the texture
- OpticDispersion(input.texCoord + float2(-d/2,+d*sqrt3over2)) + // by taking the mean of the colours. By this, bright spots
- OpticDispersion(input.texCoord + float2(+d/2,-d*sqrt3over2)) + // will be blurred into a hexagonal shape because their information
- OpticDispersion(input.texCoord + float2(-d/2,-d*sqrt3over2)) + // is used in several pixels throughout the texture.
- OpticDispersion(input.texCoord + float2(-d,0)) // Instead of the original texture, its colour information is
- ) / 6.0; // previously transformed by the OpticDispersion function.
- // Darkness correction
- float v = length(outputPixel); // colour brightness is tuned using a polynomial
- outputPixel = outputPixel*(0.05*v+0.94+0.01/v); // which limits darkness and is near linear otherwise
- // Insectoid Eyes
- const float grain = 50.0; // granularity of the eyes .. how many cells per row and column
- const float4 delta = float4(-1.0,0.0,1.0,0.0)/3; // offset for the different colour channels
- float x = (input.texCoord.x) * grain; // X and Y coordinates within the granularity
- float y = (input.texCoord.y) * grain;
- float4 eyePattern = 0.5+0.3*pow(fmod(delta+x,1.0) * // creates a hexagonal grid, slightly dislocated for all colour channels
- fmod(grain+delta+x/2+y*sqrt3over2,1.0) * // The power function is used to limit the brightness contrast to the
- fmod(grain+delta+x/2-y*sqrt3over2,1.0),1.3); // edges instead of a linear interpolation
- // Edge Highlighting
- float offset = 0.0010; // offset is the difference between two pixels for which we do an edge test.
- float4 ETest = float4(
- tex2D(depthTextureSampler, input.texCoord + float2(-offset,0)).r, // we get the depth value of each pixel around the one we want to shade
- tex2D(depthTextureSampler, input.texCoord + float2(+offset,0)).r, // above in -x, now in +x direction
- tex2D(depthTextureSampler, input.texCoord + float2(0,-offset)).r, // now in -y, next in +y direction
- tex2D(depthTextureSampler, input.texCoord + float2(0,+offset)).r
- );
- const float falloff = 10.0 / log(2); // edge intensity is halved for each 10 units, so it's 1/4 for 20 units, 1/8 for 30 units, ...
- float edge = saturate ( // edge is the highlight amount of each pixel, has values between 0 and 1
- length(ETest-depthMap.r)*exp(-depthMap.r/falloff) // An edge is a pixel whose distance to its neighbours, scaled by the
- ); // exponential perception factor, is bigger than 1.0
- // In addition to sharp edges, we can add a little bit of area coloring using optic distortion based blurring
- ETest = float4(
- tex2D(depthTextureSampler, OpticDistortion(input.texCoord + float2(-offset,0),0.990)).r,
- tex2D(depthTextureSampler, OpticDistortion(input.texCoord + float2(+offset,0),0.990)).r,
- tex2D(depthTextureSampler, OpticDistortion(input.texCoord + float2(0,-offset),0.990)).r,
- tex2D(depthTextureSampler, OpticDistortion(input.texCoord + float2(0,+offset),0.990)).r
- );
- edge += 0.1* saturate(length(ETest-depthMap.r)*exp(-depthMap.r/falloff));
- // Sonar effect // By applying a time modified pulse using a slater function, we can
- float sonar = 0.02+0.73*exp(-abs(depthMap.r-fmod(50*(time-startTime),100.0))/10.0); // emulate a sonar. Sound travels 50 units per second, pulses are 10 units long
- // and travel 100 units before the next pulse is emitted.
- // Minimum brightness is 2%, maximum brightness is 75%.
- // Importance highlighting
- float4 edgeColor; // This will hold the colour of the edge based on information content.
- if ( depthMap.g > 0.5 && depthMap.r > 0.4 ) { // If the pixel belongs to something important (bio, tech, marines, etc)
- edgeColor = float4( 2.97, 0.37, -0.13, 0.0 ) * depthMap.g; // and the distance is bigger than 0.4 units (so we ignore our snoute).
- outputPixel = outputPixel + 0.1*edgeColor; // We set the edge colour to a bright orange weighted by importance, and
- edge = edge * 5.0; // overlay the object colour with that orange, too. Finally we add some
- } else { // glow effect to the edges by oversaturating them via a huge factor.
- edgeColor = (1+cos((sonar+float4(0,1,2,0)/3)*3.1415927*2))/2; // If the object is not important, edge colour is a rainbow coloured pulse.
- }
- // Adding all information together
- return outputPixel*eyePattern + edge*edgeColor*sonar; // We overlay the rendered scene with our eyePattern and add coloured edges.
- // Finally, we return the calculated colour as result.
- }
- technique SFXDarkVision
- {
- pass p0
- {
- ZEnable = False;
- ZWriteEnable = False;
- VertexShader = compile vs_3_0 SFXBasicVS();
- PixelShader = compile ps_3_0 SFXDarkVisionPS();
- CullMode = None;
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement