mirror of
https://github.com/id-Software/DOOM-3-BFG.git
synced 2025-04-24 02:32:18 +00:00
Optimized Filmic Dithering with precalculated Blue Noise
This commit is contained in:
parent
9931fab681
commit
99235ec92c
7 changed files with 66058 additions and 92 deletions
|
@ -285,3 +285,17 @@ float InterleavedGradientNoise( float2 uv )
|
|||
return rnd;
|
||||
}
|
||||
|
||||
// RB: the golden ratio is useful to animate Blue noise
|
||||
const float c_goldenRatioConjugate = 0.61803398875;
|
||||
|
||||
|
||||
// RB: very efficient white noise without sine https://www.shadertoy.com/view/4djSRW
|
||||
#define HASHSCALE3 float3(443.897, 441.423, 437.195)
|
||||
|
||||
float3 Hash33( float3 p3 )
|
||||
{
|
||||
p3 = fract( p3 * HASHSCALE3 );
|
||||
p3 += dot( p3, p3.yxz + 19.19 );
|
||||
return fract( ( p3.xxy + p3.yxx ) * p3.zyx );
|
||||
}
|
||||
|
||||
|
|
|
@ -63,11 +63,13 @@ struct PS_OUT
|
|||
|
||||
float BlueNoise( float2 n, float x )
|
||||
{
|
||||
float noise = tex2D( samp6, ( n.xy / 256.0 ) ).r;
|
||||
float2 uv = n.xy * rpJitterTexOffset.xy;
|
||||
|
||||
noise = fract( noise + 0.61803398875 * rpJitterTexOffset.z * x );
|
||||
float noise = tex2D( samp6, uv ).r;
|
||||
|
||||
noise = RemapNoiseTriErp( noise );
|
||||
noise = fract( noise + c_goldenRatioConjugate * rpJitterTexOffset.w * x );
|
||||
|
||||
//noise = RemapNoiseTriErp( noise );
|
||||
|
||||
//noise = noise * 2.0 - 1.0;
|
||||
|
||||
|
@ -309,7 +311,7 @@ void main( PS_IN fragment, out PS_OUT result )
|
|||
//float4 jitterTC = ( fragment.position * rpScreenCorrectionFactor ) + rpJitterTexOffset;
|
||||
//float random = tex2D( samp6, jitterTC.xy ).x;
|
||||
|
||||
float random = BlueNoise( fragment.position.xy * 1.0, 100.0 );
|
||||
float random = BlueNoise( fragment.position.xy, 100.0 );
|
||||
|
||||
//float random = InterleavedGradientNoise( fragment.position.xy );
|
||||
|
||||
|
@ -372,6 +374,7 @@ void main( PS_IN fragment, out PS_OUT result )
|
|||
half3 specularColor = specMapSRGB.rgb; // RB: should be linear but it looks too flat
|
||||
#endif
|
||||
|
||||
//diffuseColor = half3( 1.0 );
|
||||
|
||||
// RB: compensate r_lightScale 3 and the division of Pi
|
||||
//lambert *= 1.3;
|
||||
|
|
|
@ -46,7 +46,7 @@ struct PS_OUT
|
|||
};
|
||||
// *INDENT-ON*
|
||||
|
||||
#define USE_CHROMATIC_ABERRATION 1
|
||||
#define USE_CHROMATIC_ABERRATION 0
|
||||
#define Chromatic_Amount 0.075
|
||||
|
||||
#define USE_TECHNICOLOR 0 // [0 or 1]
|
||||
|
@ -238,7 +238,7 @@ float PhotoLuma( float3 c )
|
|||
|
||||
float BlueNoise( float2 n, float x )
|
||||
{
|
||||
float noise = tex2D( samp1, ( n.xy / 512.0 ) * 1.0 ).r;
|
||||
float noise = tex2D( samp1, ( n.xy * rpJitterTexOffset.xy ) * 1.0 ).r;
|
||||
|
||||
noise = fract( noise + 0.61803398875 * rpJitterTexOffset.z * x );
|
||||
|
||||
|
@ -253,15 +253,17 @@ float BlueNoise( float2 n, float x )
|
|||
|
||||
float3 BlueNoise3( float2 n, float x )
|
||||
{
|
||||
float3 noise = tex2D( samp1, ( n.xy / 512.0 ) * 1.0 ).rgb;
|
||||
float2 uv = n.xy * rpJitterTexOffset.xy;
|
||||
|
||||
noise = fract( noise + 0.61803398875 * rpJitterTexOffset.z * x );
|
||||
float3 noise = tex2D( samp1, uv ).rgb;
|
||||
|
||||
noise.x = RemapNoiseTriErp( noise.x );
|
||||
noise.y = RemapNoiseTriErp( noise.y );
|
||||
noise.z = RemapNoiseTriErp( noise.z );
|
||||
noise = fract( noise + c_goldenRatioConjugate * rpJitterTexOffset.w * x );
|
||||
|
||||
noise = noise * 2.0 - 1.0;
|
||||
//noise.x = RemapNoiseTriErp( noise.x );
|
||||
//noise.y = RemapNoiseTriErp( noise.y );
|
||||
//noise.z = RemapNoiseTriErp( noise.z );
|
||||
|
||||
//noise = noise * 2.0 - 1.0;
|
||||
|
||||
return noise;
|
||||
}
|
||||
|
@ -320,44 +322,44 @@ float Step2( float2 uv, float n )
|
|||
// Used for stills.
|
||||
float3 Step3( float2 uv )
|
||||
{
|
||||
#if 1
|
||||
#if 0
|
||||
float a = Step2( uv, 0.07 );
|
||||
float b = Step2( uv, 0.11 );
|
||||
float c = Step2( uv, 0.13 );
|
||||
|
||||
return float3( a, b, c );
|
||||
#else
|
||||
//float a = BlueNoise( uv, 0.07 );
|
||||
//float b = BlueNoise( uv, 0.11 );
|
||||
//float c = BlueNoise( uv, 0.13 );
|
||||
float3 noise = BlueNoise3( uv, 0.0 );
|
||||
|
||||
//float a = 1.0, b = 2.0, c = -12.0;
|
||||
//return ( 1.0 / ( a * 4.0 + b * 4.0 - c ) ) * float3( BlueNoise( uv, 0.0 ) );
|
||||
return BlueNoise3( uv, 0.0 );
|
||||
noise.x = RemapNoiseTriErp( noise.x );
|
||||
noise.y = RemapNoiseTriErp( noise.y );
|
||||
noise.z = RemapNoiseTriErp( noise.z );
|
||||
|
||||
noise = noise * 2.0 - 1.0;
|
||||
|
||||
return noise;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Used for temporal dither.
|
||||
float3 Step3T( float2 uv )
|
||||
{
|
||||
#if 1
|
||||
#if 0
|
||||
float a = Step2( uv, 0.07 * fract( rpJitterTexOffset.z ) );
|
||||
float b = Step2( uv, 0.11 * fract( rpJitterTexOffset.z ) );
|
||||
float c = Step2( uv, 0.13 * fract( rpJitterTexOffset.z ) );
|
||||
|
||||
return float3( a, b, c );
|
||||
#else
|
||||
float a = BlueNoise( uv + 0.07, 1.0 );
|
||||
float b = BlueNoise( uv + 0.11, 1.0 );
|
||||
float c = BlueNoise( uv + 0.13, 1.0 );
|
||||
float3 noise = BlueNoise3( uv, 1.0 );
|
||||
|
||||
//return BlueNoise3( uv + 0.07, 1.0 );
|
||||
return float3( a, b, c );
|
||||
noise.x = RemapNoiseTriErp( noise.x );
|
||||
noise.y = RemapNoiseTriErp( noise.y );
|
||||
noise.z = RemapNoiseTriErp( noise.z );
|
||||
|
||||
//float a = 1.0, b = 2.0, c = -2.0, d = -12.0;
|
||||
noise = noise * 2.0 - 1.0;
|
||||
|
||||
//float3 step2 = ( 1.0 / ( a * 4.0 + b * 4.0 - c ) ) * BlueNoise3( uv, 55.0 );
|
||||
//return step2 * ( 1.0 / ( a * 4.0 + b * 4.0 - d ) ) * BlueNoise3( uv, 55.0 );
|
||||
return noise;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -368,12 +370,10 @@ void DitheringPass( inout float4 fragColor )
|
|||
{
|
||||
float2 uv = fragment.position.xy * 1.0;
|
||||
float2 uv2 = fragment.texcoord0;
|
||||
//float2 uv3 = float2( uv2.x, 1.0 - uv2.y );
|
||||
|
||||
float3 color = fragColor.rgb;
|
||||
//float3 color = tex2D(samp0, uv2).rgb;
|
||||
|
||||
#if 0
|
||||
#if 1
|
||||
// BOTTOM: Show bands.
|
||||
if( uv2.y >= 0.975 )
|
||||
{
|
||||
|
@ -450,6 +450,205 @@ void DitheringPass( inout float4 fragColor )
|
|||
|
||||
|
||||
|
||||
#define ANIMATE_NOISE 1
|
||||
#define TARGET_BITS 4 // 2^3 = 8 dithered to this many bits
|
||||
#define DITHER_IN_LINEAR_SPACE 0
|
||||
|
||||
//----------------------------------------------------------------------------------------
|
||||
|
||||
/*
|
||||
Items of note!
|
||||
|
||||
* The blue noise texture sampling should be set to "nearest" (not mip map!) and repeat
|
||||
|
||||
* you should calculate the uv to use based on the pixel coordinate and the size of the blue noise texture.
|
||||
* aka you should tile the blue noise texture across the screen.
|
||||
* blue noise actually tiles really well unlike white noise.
|
||||
|
||||
* A blue noise texture is "low discrepancy over space" which means there are fewer visible patterns than white noise
|
||||
* it also gives more even coverage vs white noise. no clumps or voids.
|
||||
|
||||
* In an attempt to make it also blue noise over time, you can add the golden ratio and frac it.
|
||||
* that makes it lower discrepancy over time, but makes it less good over space.
|
||||
* thanks to r4unit for that tip! https://twitter.com/R4_Unit
|
||||
|
||||
* Animating the noise in this demo makes the noise basically disappear imo, it's really nice!
|
||||
|
||||
For more information:
|
||||
|
||||
What the heck is blue nois:
|
||||
https://blog.demofox.org/2018/01/30/what-the-heck-is-blue-noise/
|
||||
|
||||
Low discrepancy sequences:
|
||||
https://blog.demofox.org/2017/05/29/when-random-numbers-are-too-random-low-discrepancy-sequences/
|
||||
|
||||
You can get your own blue noise textures here:
|
||||
http://momentsingraphics.de/?p=127
|
||||
|
||||
*/
|
||||
void DitheringPassDemoFox( inout float4 fragColor )
|
||||
{
|
||||
// texture color
|
||||
float2 uv = fragment.position.xy;
|
||||
float2 uv2 = fragment.texcoord0;
|
||||
float3 fg = fragColor.rgb;
|
||||
|
||||
float3 color = fg;
|
||||
|
||||
#if 1
|
||||
// TOP: show bands
|
||||
if( uv2.y >= 0.975 )
|
||||
{
|
||||
color = float3( uv2.x );
|
||||
color = floor( color * STEPS + Step3( uv ) * 4.0 ) * ( 1.0 / ( STEPS - 1.0 ) );
|
||||
}
|
||||
else if( uv2.y >= 0.95 )
|
||||
{
|
||||
color = float3( uv2.x );
|
||||
color = floor( color * STEPS ) * ( 1.0 / ( STEPS - 1.0 ) );
|
||||
}
|
||||
else if( uv2.y >= 0.925 )
|
||||
{
|
||||
color = float3( uv2.x );
|
||||
color = floor( color * STEPS + Step3T( uv ) * 4.0 ) * ( 1.0 / ( STEPS - 1.0 ) );
|
||||
}
|
||||
// BOTTOM: show dither texture
|
||||
else if( uv2.y >= 0.9 )
|
||||
{
|
||||
color = Step3( uv ).rgb;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
// right of the screen is dithered using white noise to a fewer number of bits per color channel
|
||||
if( uv2.x > 3.0 / 4.0 )
|
||||
{
|
||||
// get white noise "random" number
|
||||
#if ANIMATE_NOISE
|
||||
float3 whiteNoise = Hash33( float3( uv, rpJitterTexOffset.w / 256.0 ) );
|
||||
#else
|
||||
float3 whiteNoise = Hash33( float3( uv, 0.0 ) );
|
||||
#endif
|
||||
|
||||
// dither to the specified number of bits, using sRGB conversions if desired
|
||||
#if DITHER_IN_LINEAR_SPACE
|
||||
fg = pow( fg, float3( 2.2 ) );
|
||||
#endif
|
||||
|
||||
float scale = exp2( float( TARGET_BITS ) ) - 1.0;
|
||||
color = floor( fg * scale + whiteNoise ) / scale;
|
||||
|
||||
#if DITHER_IN_LINEAR_SPACE
|
||||
color = pow( col, 1.0 / float3( 2.2 ) );
|
||||
#endif
|
||||
}
|
||||
// middle right of the screen is dithered using blue noise to a fewer number of bits per color channel
|
||||
else if( uv2.x > 2.0 / 4.0 )
|
||||
{
|
||||
float3 blueNoise = BlueNoise3( uv, 1.0 );
|
||||
|
||||
// dither to the specified number of bits, using sRGB conversions if desired
|
||||
#if DITHER_IN_LINEAR_SPACE
|
||||
fg = pow( fg, float3( 2.2 ) );
|
||||
#endif
|
||||
|
||||
float scale = exp2( float( TARGET_BITS ) ) - 1.0;
|
||||
color = floor( fg * scale + blueNoise ) / scale;
|
||||
|
||||
#if DITHER_IN_LINEAR_SPACE
|
||||
color = pow( color, 1.0 / float3( 2.2 ) );
|
||||
#endif
|
||||
}
|
||||
// middle left of the screen is quantized but not dithered
|
||||
else if( uv2.x > 1.0 / 4.0 )
|
||||
{
|
||||
// dither to the specified number of bits, using sRGB conversions if desired
|
||||
#if DITHER_IN_LINEAR_SPACE
|
||||
fg = pow( fg, float3( 2.2 ) );
|
||||
#endif
|
||||
|
||||
float scale = exp2( float( TARGET_BITS ) ) - 1.0;
|
||||
color = floor( fg * scale + 0.5f ) / scale;
|
||||
|
||||
#if DITHER_IN_LINEAR_SPACE
|
||||
color = pow( color, 1.0 / float3( 2.2 ) );
|
||||
#endif
|
||||
}
|
||||
// left side of screen is left alone for comparison
|
||||
else
|
||||
{
|
||||
color = fg;
|
||||
}
|
||||
|
||||
if( abs( uv2.x - 1.0 / 4.0 ) < 0.001 || abs( uv2.x - 2.0 / 4.0 ) < 0.001 || abs( uv2.x - 3.0 / 4.0 ) < 0.001 )
|
||||
{
|
||||
color = float3( 0.0, 1.0, 0.0 );
|
||||
}
|
||||
}
|
||||
|
||||
fragColor.rgb = color;
|
||||
}
|
||||
|
||||
void DitheringPassSlim( inout float4 fragColor )
|
||||
{
|
||||
// texture color
|
||||
float2 uv = fragment.position.xy;
|
||||
float2 uv2 = fragment.texcoord0;
|
||||
float3 fg = fragColor.rgb;
|
||||
|
||||
float3 color = fg;
|
||||
|
||||
#if 0
|
||||
if( uv2.y >= 0.975 )
|
||||
{
|
||||
// source signal
|
||||
color = float3( uv2.x );
|
||||
}
|
||||
else if( uv2.y >= 0.95 )
|
||||
{
|
||||
color = float3( uv2.x );
|
||||
|
||||
// quantized signal
|
||||
float scale = exp2( float( TARGET_BITS ) ) - 1.0;
|
||||
color = floor( color * scale + 0.0f ) / scale;
|
||||
}
|
||||
else if( uv2.y >= 0.925 )
|
||||
{
|
||||
// dithered quantized signal
|
||||
color = float3( uv2.x );
|
||||
color = floor( color * STEPS + Step3T( uv ) * 4.0 ) * ( 1.0 / ( STEPS - 1.0 ) );
|
||||
}
|
||||
else if( uv2.y >= 0.9 )
|
||||
{
|
||||
// dither texture
|
||||
color = Step3( uv ).rgb;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
float3 noise = BlueNoise3( uv, 1.0 );
|
||||
|
||||
//noise.x = RemapNoiseTriErp( noise.x );
|
||||
//noise.y = RemapNoiseTriErp( noise.y );
|
||||
//noise.z = RemapNoiseTriErp( noise.z );
|
||||
|
||||
// dither to the specified number of bits, using sRGB conversions if desired
|
||||
#if DITHER_IN_LINEAR_SPACE
|
||||
fg = pow( fg, float3( 2.2 ) );
|
||||
#endif
|
||||
|
||||
float scale = exp2( float( TARGET_BITS ) ) - 1.0;
|
||||
color = floor( fg * scale + noise ) / scale;
|
||||
|
||||
#if DITHER_IN_LINEAR_SPACE
|
||||
color = pow( color, 1.0 / float3( 2.2 ) );
|
||||
#endif
|
||||
}
|
||||
|
||||
fragColor.rgb = color;
|
||||
}
|
||||
|
||||
|
||||
void main( PS_IN fragment, out PS_OUT result )
|
||||
{
|
||||
float2 tCoords = fragment.texcoord0;
|
||||
|
@ -470,7 +669,7 @@ void main( PS_IN fragment, out PS_OUT result )
|
|||
#endif
|
||||
|
||||
#if USE_DITHERING
|
||||
DitheringPass( color );
|
||||
DitheringPassSlim( color );
|
||||
#endif
|
||||
|
||||
result.color = color;
|
||||
|
|
65549
neo/renderer/Image_blueNoiseVC_2.h
Normal file
65549
neo/renderer/Image_blueNoiseVC_2.h
Normal file
File diff suppressed because it is too large
Load diff
|
@ -36,8 +36,8 @@ If you have questions concerning this license or the applicable additional terms
|
|||
#include "SMAA/AreaTex.h"
|
||||
#include "SMAA/SearchTex.h"
|
||||
#include "Image_brdfLut.h"
|
||||
#include "Image_blueNoiseVC_1M.h" // 256^2 R8 data
|
||||
//#include "Image_blueNoiseVC_2.h" // 512^2 RGB8 data
|
||||
//#include "Image_blueNoiseVC_1M.h" // 256^2 R8 data
|
||||
#include "Image_blueNoiseVC_2.h" // 512^2 RGB8 data
|
||||
|
||||
#define DEFAULT_SIZE 16
|
||||
|
||||
|
@ -695,7 +695,7 @@ static void R_CreateBlueNoise256Image( idImage* image )
|
|||
{
|
||||
for( int y = 0; y < BLUENOISE_TEX_HEIGHT; y++ )
|
||||
{
|
||||
#if 0
|
||||
#if 1
|
||||
data[x][y][0] = blueNoiseTexBytes[ y * BLUENOISE_TEX_PITCH + x * 3 + 0 ];
|
||||
data[x][y][1] = blueNoiseTexBytes[ y * BLUENOISE_TEX_PITCH + x * 3 + 1 ];
|
||||
data[x][y][2] = blueNoiseTexBytes[ y * BLUENOISE_TEX_PITCH + x * 3 + 2 ];
|
||||
|
|
|
@ -1681,18 +1681,16 @@ void idRenderBackend::RenderInteractions( const drawSurf_t* surfList, const view
|
|||
SetFragmentParm( RENDERPARM_JITTERTEXSCALE, jitterTexScale ); // rpJitterTexScale
|
||||
|
||||
float jitterTexOffset[4];
|
||||
jitterTexOffset[0] = 1.0f / globalImages->blueNoiseImage256->GetUploadWidth();
|
||||
jitterTexOffset[1] = 1.0f / globalImages->blueNoiseImage256->GetUploadWidth();
|
||||
|
||||
if( r_shadowMapRandomizeJitter.GetBool() )
|
||||
{
|
||||
jitterTexOffset[0] = ( rand() & 255 ) / 255.0;
|
||||
jitterTexOffset[1] = ( rand() & 255 ) / 255.0;
|
||||
|
||||
jitterTexOffset[2] = Sys_Milliseconds() / 1000.0f;
|
||||
jitterTexOffset[3] = tr.frameCount % 64;
|
||||
}
|
||||
else
|
||||
{
|
||||
jitterTexOffset[0] = 0;
|
||||
jitterTexOffset[1] = 0;
|
||||
jitterTexOffset[2] = 0.0f;
|
||||
jitterTexOffset[3] = 0.0f;
|
||||
}
|
||||
|
@ -4990,7 +4988,6 @@ void idRenderBackend::DrawScreenSpaceAmbientOcclusion( const viewDef_t* _viewDef
|
|||
#endif
|
||||
SetVertexParms( RENDERPARM_MODELMATRIX_X, viewDef->unprojectionToCameraRenderMatrix[0], 4 );
|
||||
|
||||
const static int BLUENOISE_SIZE = 256;
|
||||
const float jitterSampleScale = 1.0f;
|
||||
|
||||
float jitterTexScale[4];
|
||||
|
@ -5001,13 +4998,13 @@ void idRenderBackend::DrawScreenSpaceAmbientOcclusion( const viewDef_t* _viewDef
|
|||
SetFragmentParm( RENDERPARM_JITTERTEXSCALE, jitterTexScale ); // rpJitterTexScale
|
||||
|
||||
float jitterTexOffset[4];
|
||||
jitterTexOffset[0] = 1.0f / BLUENOISE_SIZE;
|
||||
jitterTexOffset[1] = 1.0f / BLUENOISE_SIZE;
|
||||
jitterTexOffset[0] = 1.0f / globalImages->blueNoiseImage256->GetUploadWidth();
|
||||
jitterTexOffset[1] = 1.0f / globalImages->blueNoiseImage256->GetUploadHeight();
|
||||
|
||||
if( r_shadowMapRandomizeJitter.GetBool() )
|
||||
{
|
||||
jitterTexOffset[2] = Sys_Milliseconds() / 1000.0f;
|
||||
jitterTexOffset[3] = tr.frameCount % 64;
|
||||
jitterTexOffset[3] = tr.frameCount % 256;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -6147,29 +6144,17 @@ void idRenderBackend::PostProcess( const void* data )
|
|||
|
||||
renderProgManager.BindShader_PostProcess();
|
||||
|
||||
const static int BLUENOISE_SIZE = 256;
|
||||
|
||||
// screen power of two correction factor
|
||||
float screenCorrectionParm[4];
|
||||
screenCorrectionParm[0] = 1.0f / BLUENOISE_SIZE;
|
||||
screenCorrectionParm[1] = 1.0f / BLUENOISE_SIZE;
|
||||
screenCorrectionParm[2] = 1.0f;
|
||||
screenCorrectionParm[3] = 1.0f;
|
||||
SetFragmentParm( RENDERPARM_SCREENCORRECTIONFACTOR, screenCorrectionParm ); // rpScreenCorrectionFactor
|
||||
|
||||
float jitterTexOffset[4];
|
||||
jitterTexOffset[0] = 1.0f / globalImages->blueNoiseImage256->GetUploadWidth();
|
||||
jitterTexOffset[1] = 1.0f / globalImages->blueNoiseImage256->GetUploadHeight();
|
||||
|
||||
if( r_shadowMapRandomizeJitter.GetBool() )
|
||||
{
|
||||
jitterTexOffset[0] = ( rand() & 255 ) / 255.0;
|
||||
jitterTexOffset[1] = ( rand() & 255 ) / 255.0;
|
||||
|
||||
jitterTexOffset[2] = Sys_Milliseconds() / 1000.0f;
|
||||
jitterTexOffset[3] = tr.frameCount % 64;
|
||||
jitterTexOffset[3] = tr.frameCount % 256;
|
||||
}
|
||||
else
|
||||
{
|
||||
jitterTexOffset[0] = 0;
|
||||
jitterTexOffset[1] = 0;
|
||||
jitterTexOffset[2] = 0.0f;
|
||||
jitterTexOffset[3] = 0.0f;
|
||||
}
|
||||
|
|
|
@ -299,6 +299,20 @@ static const cgShaderDef_t cg_renderprogs[] =
|
|||
" return rnd;\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"// RB: the golden ratio is useful to animate Blue noise\n"
|
||||
"const float c_goldenRatioConjugate = 0.61803398875;\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"// RB: very efficient white noise without sine https://www.shadertoy.com/view/4djSRW\n"
|
||||
"#define HASHSCALE3 float3(443.897, 441.423, 437.195)\n"
|
||||
"\n"
|
||||
"float3 Hash33( float3 p3 )\n"
|
||||
"{\n"
|
||||
" p3 = fract( p3 * HASHSCALE3 );\n"
|
||||
" p3 += dot( p3, p3.yxz + 19.19 );\n"
|
||||
" return fract( ( p3.xxy + p3.yxx ) * p3.zyx );\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"\n"
|
||||
|
||||
},
|
||||
|
@ -9851,11 +9865,13 @@ static const cgShaderDef_t cg_renderprogs[] =
|
|||
"\n"
|
||||
"float BlueNoise( float2 n, float x )\n"
|
||||
"{\n"
|
||||
" float noise = tex2D( samp6, ( n.xy / 256.0 ) ).r;\n"
|
||||
" float2 uv = n.xy * rpJitterTexOffset.xy;\n"
|
||||
"\n"
|
||||
" noise = fract( noise + 0.61803398875 * rpJitterTexOffset.z * x );\n"
|
||||
" float noise = tex2D( samp6, uv ).r;\n"
|
||||
"\n"
|
||||
" noise = RemapNoiseTriErp( noise );\n"
|
||||
" noise = fract( noise + c_goldenRatioConjugate * rpJitterTexOffset.w * x );\n"
|
||||
"\n"
|
||||
" //noise = RemapNoiseTriErp( noise );\n"
|
||||
"\n"
|
||||
" //noise = noise * 2.0 - 1.0;\n"
|
||||
"\n"
|
||||
|
@ -10097,7 +10113,7 @@ static const cgShaderDef_t cg_renderprogs[] =
|
|||
" //float4 jitterTC = ( fragment.position * rpScreenCorrectionFactor ) + rpJitterTexOffset;\n"
|
||||
" //float random = tex2D( samp6, jitterTC.xy ).x;\n"
|
||||
"\n"
|
||||
" float random = BlueNoise( fragment.position.xy * 1.0, 100.0 );\n"
|
||||
" float random = BlueNoise( fragment.position.xy, 100.0 );\n"
|
||||
"\n"
|
||||
" //float random = InterleavedGradientNoise( fragment.position.xy );\n"
|
||||
"\n"
|
||||
|
@ -10160,6 +10176,7 @@ static const cgShaderDef_t cg_renderprogs[] =
|
|||
" half3 specularColor = specMapSRGB.rgb; // RB: should be linear but it looks too flat\n"
|
||||
"#endif\n"
|
||||
"\n"
|
||||
" //diffuseColor = half3( 1.0 );\n"
|
||||
"\n"
|
||||
" // RB: compensate r_lightScale 3 and the division of Pi\n"
|
||||
" //lambert *= 1.3;\n"
|
||||
|
@ -10638,7 +10655,7 @@ static const cgShaderDef_t cg_renderprogs[] =
|
|||
"};\n"
|
||||
"// *INDENT-ON*\n"
|
||||
"\n"
|
||||
"#define USE_CHROMATIC_ABERRATION 1\n"
|
||||
"#define USE_CHROMATIC_ABERRATION 0\n"
|
||||
"#define Chromatic_Amount 0.075\n"
|
||||
"\n"
|
||||
"#define USE_TECHNICOLOR 0 // [0 or 1]\n"
|
||||
|
@ -10830,7 +10847,7 @@ static const cgShaderDef_t cg_renderprogs[] =
|
|||
"\n"
|
||||
"float BlueNoise( float2 n, float x )\n"
|
||||
"{\n"
|
||||
" float noise = tex2D( samp1, ( n.xy / 512.0 ) * 1.0 ).r;\n"
|
||||
" float noise = tex2D( samp1, ( n.xy * rpJitterTexOffset.xy ) * 1.0 ).r;\n"
|
||||
"\n"
|
||||
" noise = fract( noise + 0.61803398875 * rpJitterTexOffset.z * x );\n"
|
||||
"\n"
|
||||
|
@ -10845,15 +10862,17 @@ static const cgShaderDef_t cg_renderprogs[] =
|
|||
"\n"
|
||||
"float3 BlueNoise3( float2 n, float x )\n"
|
||||
"{\n"
|
||||
" float3 noise = tex2D( samp1, ( n.xy / 512.0 ) * 1.0 ).rgb;\n"
|
||||
" float2 uv = n.xy * rpJitterTexOffset.xy;\n"
|
||||
"\n"
|
||||
" noise = fract( noise + 0.61803398875 * rpJitterTexOffset.z * x );\n"
|
||||
" float3 noise = tex2D( samp1, uv ).rgb;\n"
|
||||
"\n"
|
||||
" noise.x = RemapNoiseTriErp( noise.x );\n"
|
||||
" noise.y = RemapNoiseTriErp( noise.y );\n"
|
||||
" noise.z = RemapNoiseTriErp( noise.z );\n"
|
||||
" noise = fract( noise + c_goldenRatioConjugate * rpJitterTexOffset.w * x );\n"
|
||||
"\n"
|
||||
" noise = noise * 2.0 - 1.0;\n"
|
||||
" //noise.x = RemapNoiseTriErp( noise.x );\n"
|
||||
" //noise.y = RemapNoiseTriErp( noise.y );\n"
|
||||
" //noise.z = RemapNoiseTriErp( noise.z );\n"
|
||||
"\n"
|
||||
" //noise = noise * 2.0 - 1.0;\n"
|
||||
"\n"
|
||||
" return noise;\n"
|
||||
"}\n"
|
||||
|
@ -10912,44 +10931,44 @@ static const cgShaderDef_t cg_renderprogs[] =
|
|||
"// Used for stills.\n"
|
||||
"float3 Step3( float2 uv )\n"
|
||||
"{\n"
|
||||
"#if 1\n"
|
||||
"#if 0\n"
|
||||
" float a = Step2( uv, 0.07 );\n"
|
||||
" float b = Step2( uv, 0.11 );\n"
|
||||
" float c = Step2( uv, 0.13 );\n"
|
||||
"\n"
|
||||
" return float3( a, b, c );\n"
|
||||
"#else\n"
|
||||
" //float a = BlueNoise( uv, 0.07 );\n"
|
||||
" //float b = BlueNoise( uv, 0.11 );\n"
|
||||
" //float c = BlueNoise( uv, 0.13 );\n"
|
||||
" float3 noise = BlueNoise3( uv, 0.0 );\n"
|
||||
"\n"
|
||||
" //float a = 1.0, b = 2.0, c = -12.0;\n"
|
||||
" //return ( 1.0 / ( a * 4.0 + b * 4.0 - c ) ) * float3( BlueNoise( uv, 0.0 ) );\n"
|
||||
" return BlueNoise3( uv, 0.0 );\n"
|
||||
" noise.x = RemapNoiseTriErp( noise.x );\n"
|
||||
" noise.y = RemapNoiseTriErp( noise.y );\n"
|
||||
" noise.z = RemapNoiseTriErp( noise.z );\n"
|
||||
"\n"
|
||||
" noise = noise * 2.0 - 1.0;\n"
|
||||
"\n"
|
||||
" return noise;\n"
|
||||
"#endif\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"// Used for temporal dither.\n"
|
||||
"float3 Step3T( float2 uv )\n"
|
||||
"{\n"
|
||||
"#if 1\n"
|
||||
"#if 0\n"
|
||||
" float a = Step2( uv, 0.07 * fract( rpJitterTexOffset.z ) );\n"
|
||||
" float b = Step2( uv, 0.11 * fract( rpJitterTexOffset.z ) );\n"
|
||||
" float c = Step2( uv, 0.13 * fract( rpJitterTexOffset.z ) );\n"
|
||||
"\n"
|
||||
" return float3( a, b, c );\n"
|
||||
"#else\n"
|
||||
" float a = BlueNoise( uv + 0.07, 1.0 );\n"
|
||||
" float b = BlueNoise( uv + 0.11, 1.0 );\n"
|
||||
" float c = BlueNoise( uv + 0.13, 1.0 );\n"
|
||||
" float3 noise = BlueNoise3( uv, 1.0 );\n"
|
||||
"\n"
|
||||
" //return BlueNoise3( uv + 0.07, 1.0 );\n"
|
||||
" return float3( a, b, c );\n"
|
||||
" noise.x = RemapNoiseTriErp( noise.x );\n"
|
||||
" noise.y = RemapNoiseTriErp( noise.y );\n"
|
||||
" noise.z = RemapNoiseTriErp( noise.z );\n"
|
||||
"\n"
|
||||
" //float a = 1.0, b = 2.0, c = -2.0, d = -12.0;\n"
|
||||
" noise = noise * 2.0 - 1.0;\n"
|
||||
"\n"
|
||||
" //float3 step2 = ( 1.0 / ( a * 4.0 + b * 4.0 - c ) ) * BlueNoise3( uv, 55.0 );\n"
|
||||
" //return step2 * ( 1.0 / ( a * 4.0 + b * 4.0 - d ) ) * BlueNoise3( uv, 55.0 );\n"
|
||||
" return noise;\n"
|
||||
"#endif\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
|
@ -10960,12 +10979,10 @@ static const cgShaderDef_t cg_renderprogs[] =
|
|||
"{\n"
|
||||
" float2 uv = fragment.position.xy * 1.0;\n"
|
||||
" float2 uv2 = fragment.texcoord0;\n"
|
||||
" //float2 uv3 = float2( uv2.x, 1.0 - uv2.y );\n"
|
||||
"\n"
|
||||
" float3 color = fragColor.rgb;\n"
|
||||
" //float3 color = tex2D(samp0, uv2).rgb;\n"
|
||||
"\n"
|
||||
"#if 0\n"
|
||||
"#if 1\n"
|
||||
"// BOTTOM: Show bands.\n"
|
||||
" if( uv2.y >= 0.975 )\n"
|
||||
" {\n"
|
||||
|
@ -11042,6 +11059,205 @@ static const cgShaderDef_t cg_renderprogs[] =
|
|||
"\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"#define ANIMATE_NOISE 1\n"
|
||||
"#define TARGET_BITS 4 // 2^3 = 8 dithered to this many bits\n"
|
||||
"#define DITHER_IN_LINEAR_SPACE 0\n"
|
||||
"\n"
|
||||
"//----------------------------------------------------------------------------------------\n"
|
||||
"\n"
|
||||
"/*\n"
|
||||
"Items of note!\n"
|
||||
"\n"
|
||||
"* The blue noise texture sampling should be set to \"nearest\" (not mip map!) and repeat\n"
|
||||
"\n"
|
||||
"* you should calculate the uv to use based on the pixel coordinate and the size of the blue noise texture.\n"
|
||||
" * aka you should tile the blue noise texture across the screen.\n"
|
||||
" * blue noise actually tiles really well unlike white noise.\n"
|
||||
"\n"
|
||||
"* A blue noise texture is \"low discrepancy over space\" which means there are fewer visible patterns than white noise\n"
|
||||
" * it also gives more even coverage vs white noise. no clumps or voids.\n"
|
||||
"\n"
|
||||
"* In an attempt to make it also blue noise over time, you can add the golden ratio and frac it.\n"
|
||||
" * that makes it lower discrepancy over time, but makes it less good over space.\n"
|
||||
" * thanks to r4unit for that tip! https://twitter.com/R4_Unit\n"
|
||||
"\n"
|
||||
"* Animating the noise in this demo makes the noise basically disappear imo, it's really nice!\n"
|
||||
"\n"
|
||||
"For more information:\n"
|
||||
"\n"
|
||||
"What the heck is blue nois:\n"
|
||||
"https://blog.demofox.org/2018/01/30/what-the-heck-is-blue-noise/\n"
|
||||
"\n"
|
||||
"Low discrepancy sequences:\n"
|
||||
"https://blog.demofox.org/2017/05/29/when-random-numbers-are-too-random-low-discrepancy-sequences/\n"
|
||||
"\n"
|
||||
"You can get your own blue noise textures here:\n"
|
||||
"http://momentsingraphics.de/?p=127\n"
|
||||
"\n"
|
||||
"*/\n"
|
||||
"void DitheringPassDemoFox( inout float4 fragColor )\n"
|
||||
"{\n"
|
||||
" // texture color\n"
|
||||
" float2 uv = fragment.position.xy;\n"
|
||||
" float2 uv2 = fragment.texcoord0;\n"
|
||||
" float3 fg = fragColor.rgb;\n"
|
||||
"\n"
|
||||
" float3 color = fg;\n"
|
||||
"\n"
|
||||
"#if 1\n"
|
||||
" // TOP: show bands\n"
|
||||
" if( uv2.y >= 0.975 )\n"
|
||||
" {\n"
|
||||
" color = float3( uv2.x );\n"
|
||||
" color = floor( color * STEPS + Step3( uv ) * 4.0 ) * ( 1.0 / ( STEPS - 1.0 ) );\n"
|
||||
" }\n"
|
||||
" else if( uv2.y >= 0.95 )\n"
|
||||
" {\n"
|
||||
" color = float3( uv2.x );\n"
|
||||
" color = floor( color * STEPS ) * ( 1.0 / ( STEPS - 1.0 ) );\n"
|
||||
" }\n"
|
||||
" else if( uv2.y >= 0.925 )\n"
|
||||
" {\n"
|
||||
" color = float3( uv2.x );\n"
|
||||
" color = floor( color * STEPS + Step3T( uv ) * 4.0 ) * ( 1.0 / ( STEPS - 1.0 ) );\n"
|
||||
" }\n"
|
||||
" // BOTTOM: show dither texture\n"
|
||||
" else if( uv2.y >= 0.9 )\n"
|
||||
" {\n"
|
||||
" color = Step3( uv ).rgb;\n"
|
||||
" }\n"
|
||||
" else\n"
|
||||
"#endif\n"
|
||||
" {\n"
|
||||
" // right of the screen is dithered using white noise to a fewer number of bits per color channel\n"
|
||||
" if( uv2.x > 3.0 / 4.0 )\n"
|
||||
" {\n"
|
||||
" // get white noise \"random\" number\n"
|
||||
"#if ANIMATE_NOISE\n"
|
||||
" float3 whiteNoise = Hash33( float3( uv, rpJitterTexOffset.w / 256.0 ) );\n"
|
||||
"#else\n"
|
||||
" float3 whiteNoise = Hash33( float3( uv, 0.0 ) );\n"
|
||||
"#endif\n"
|
||||
"\n"
|
||||
" // dither to the specified number of bits, using sRGB conversions if desired\n"
|
||||
"#if DITHER_IN_LINEAR_SPACE\n"
|
||||
" fg = pow( fg, float3( 2.2 ) );\n"
|
||||
"#endif\n"
|
||||
"\n"
|
||||
" float scale = exp2( float( TARGET_BITS ) ) - 1.0;\n"
|
||||
" color = floor( fg * scale + whiteNoise ) / scale;\n"
|
||||
"\n"
|
||||
"#if DITHER_IN_LINEAR_SPACE\n"
|
||||
" color = pow( col, 1.0 / float3( 2.2 ) );\n"
|
||||
"#endif\n"
|
||||
" }\n"
|
||||
" // middle right of the screen is dithered using blue noise to a fewer number of bits per color channel\n"
|
||||
" else if( uv2.x > 2.0 / 4.0 )\n"
|
||||
" {\n"
|
||||
" float3 blueNoise = BlueNoise3( uv, 1.0 );\n"
|
||||
"\n"
|
||||
" // dither to the specified number of bits, using sRGB conversions if desired\n"
|
||||
"#if DITHER_IN_LINEAR_SPACE\n"
|
||||
" fg = pow( fg, float3( 2.2 ) );\n"
|
||||
"#endif\n"
|
||||
"\n"
|
||||
" float scale = exp2( float( TARGET_BITS ) ) - 1.0;\n"
|
||||
" color = floor( fg * scale + blueNoise ) / scale;\n"
|
||||
"\n"
|
||||
"#if DITHER_IN_LINEAR_SPACE\n"
|
||||
" color = pow( color, 1.0 / float3( 2.2 ) );\n"
|
||||
"#endif\n"
|
||||
" }\n"
|
||||
" // middle left of the screen is quantized but not dithered\n"
|
||||
" else if( uv2.x > 1.0 / 4.0 )\n"
|
||||
" {\n"
|
||||
" // dither to the specified number of bits, using sRGB conversions if desired\n"
|
||||
"#if DITHER_IN_LINEAR_SPACE\n"
|
||||
" fg = pow( fg, float3( 2.2 ) );\n"
|
||||
"#endif\n"
|
||||
"\n"
|
||||
" float scale = exp2( float( TARGET_BITS ) ) - 1.0;\n"
|
||||
" color = floor( fg * scale + 0.5f ) / scale;\n"
|
||||
"\n"
|
||||
"#if DITHER_IN_LINEAR_SPACE\n"
|
||||
" color = pow( color, 1.0 / float3( 2.2 ) );\n"
|
||||
"#endif\n"
|
||||
" }\n"
|
||||
" // left side of screen is left alone for comparison\n"
|
||||
" else\n"
|
||||
" {\n"
|
||||
" color = fg;\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" if( abs( uv2.x - 1.0 / 4.0 ) < 0.001 || abs( uv2.x - 2.0 / 4.0 ) < 0.001 || abs( uv2.x - 3.0 / 4.0 ) < 0.001 )\n"
|
||||
" {\n"
|
||||
" color = float3( 0.0, 1.0, 0.0 );\n"
|
||||
" }\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" fragColor.rgb = color;\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"void DitheringPassSlim( inout float4 fragColor )\n"
|
||||
"{\n"
|
||||
" // texture color\n"
|
||||
" float2 uv = fragment.position.xy;\n"
|
||||
" float2 uv2 = fragment.texcoord0;\n"
|
||||
" float3 fg = fragColor.rgb;\n"
|
||||
"\n"
|
||||
" float3 color = fg;\n"
|
||||
"\n"
|
||||
"#if 0\n"
|
||||
" if( uv2.y >= 0.975 )\n"
|
||||
" {\n"
|
||||
" // source signal\n"
|
||||
" color = float3( uv2.x );\n"
|
||||
" }\n"
|
||||
" else if( uv2.y >= 0.95 )\n"
|
||||
" {\n"
|
||||
" color = float3( uv2.x );\n"
|
||||
"\n"
|
||||
" // quantized signal\n"
|
||||
" float scale = exp2( float( TARGET_BITS ) ) - 1.0;\n"
|
||||
" color = floor( color * scale + 0.0f ) / scale;\n"
|
||||
" }\n"
|
||||
" else if( uv2.y >= 0.925 )\n"
|
||||
" {\n"
|
||||
" // dithered quantized signal\n"
|
||||
" color = float3( uv2.x );\n"
|
||||
" color = floor( color * STEPS + Step3T( uv ) * 4.0 ) * ( 1.0 / ( STEPS - 1.0 ) );\n"
|
||||
" }\n"
|
||||
" else if( uv2.y >= 0.9 )\n"
|
||||
" {\n"
|
||||
" // dither texture\n"
|
||||
" color = Step3( uv ).rgb;\n"
|
||||
" }\n"
|
||||
" else\n"
|
||||
"#endif\n"
|
||||
" {\n"
|
||||
" float3 noise = BlueNoise3( uv, 1.0 );\n"
|
||||
"\n"
|
||||
" //noise.x = RemapNoiseTriErp( noise.x );\n"
|
||||
" //noise.y = RemapNoiseTriErp( noise.y );\n"
|
||||
" //noise.z = RemapNoiseTriErp( noise.z );\n"
|
||||
"\n"
|
||||
" // dither to the specified number of bits, using sRGB conversions if desired\n"
|
||||
"#if DITHER_IN_LINEAR_SPACE\n"
|
||||
" fg = pow( fg, float3( 2.2 ) );\n"
|
||||
"#endif\n"
|
||||
"\n"
|
||||
" float scale = exp2( float( TARGET_BITS ) ) - 1.0;\n"
|
||||
" color = floor( fg * scale + noise ) / scale;\n"
|
||||
"\n"
|
||||
"#if DITHER_IN_LINEAR_SPACE\n"
|
||||
" color = pow( color, 1.0 / float3( 2.2 ) );\n"
|
||||
"#endif\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" fragColor.rgb = color;\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"void main( PS_IN fragment, out PS_OUT result )\n"
|
||||
"{\n"
|
||||
" float2 tCoords = fragment.texcoord0;\n"
|
||||
|
@ -11062,7 +11278,7 @@ static const cgShaderDef_t cg_renderprogs[] =
|
|||
"#endif\n"
|
||||
"\n"
|
||||
"#if USE_DITHERING\n"
|
||||
" DitheringPass( color );\n"
|
||||
" DitheringPassSlim( color );\n"
|
||||
"#endif\n"
|
||||
"\n"
|
||||
" result.color = color;\n"
|
||||
|
|
Loading…
Reference in a new issue