Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- ////////////////////////////////////////////////////////////////////////////////////////////////
- //
- // TakenFrame.fx ver0.0.1 コマ撮りエフェクト
- // 作成: 針金P( 舞力介入P氏のGaussian.fx改変 )
- //
- // 上記の改変: わたり
- //
- // Modified from LimitedFrame.fx
- // AutoBrightness.fx
- //
- ////////////////////////////////////////////////////////////////////////////////////////////////
- /******************
- Camera position and velocity
- Current position
- Current time
- Old position
- Old velocity
- Old time (elapsed time?)
- Pre-pass:
- Compute current velocity from current and old position, and old or elapsed time
- Compute current acceleration from current and old velocity
- Write current velocity, acceleration, position, and maybe time. Maybe a second pass if you can't sample from the texture you're writing to.
- Main pass: sample acceleration. No need to check time if only one effect updates the texture.
- ******************/
- /****************
- Color adjustment steps
- Create mipmaps for original texture? Probably not
- Smaller texture: sample from original, use very high gamma (but also limit the input, because some input values could be 100+). Output with miplevels if this works; probably needs to.
- Option for a single value or grid of values? Just in the form of texture size? Size defined as integer instead of relative to full size. Final tiny texture at this size that takes multiple samples from the intermediate, smaller texture; samples probably biased towards center.
- This creates 'average brightness weighted toward peak'. Compare to previous, stored frame and access current acceleration. (Could access previous acceleration to measure 'jolt' or whatever, and use like (current acceleration - previous acceleration * 0.8), but acceleration is probably fine.)
- Move values stored in previous brightness frame towards current frame based on acceleration; high acceleration = larger move. Store the result, which is updated average brightness after camera shift. *'Un-gamma' it after the adjustment, important for flickering.
- Brightness is aimed at a value (could check notes here). For all pixels, adjust pixel value towards the goal. Around goal there is a zone of 'no change'. But supposed to retain blacks or something. Maybe do slight hue adjustment by adjusting each channel separately, and also adjust the average of all channels.
- For 'gamma', instead of val^x, maybe val*min(val,0.9)^x (and still limit val to something like 2). Try to find objects in the scene that are pure white, but aren't lights, so a saturated backdrop doesn't have too much influence.
- Configurable variables:
- - Highest color before adjust starts. 90~95% would be good, 100% for minimum change.
- - The 'gamma' which biases average towards bright pixels; changing this likely requires changing target brightness.
- - How much to adjust color channels separately, causing hue change.
- - Target brightness and acceptable range etc.
- - Desaturation strength to keep maximum channel below 1 by bringing all values in a pixel towards their average (gamma matters here~).
- - A matrix or something so red and blue correlate more strongly with green than each other when desaturating?
- Could attempt to avoid highest value (1) or not. Probably not, based on video example:
- Sanny, 法法, 開場舞 Pentax 097 台北資訊月 2012.12.07 Taiwan dancer
- youtube.com/watch?v=Neaob9PGxQc
- Consider 'reencode with color adjustment notes.txt'
- RGB can have different acceptable zones than the average. Could use alpha channel for average, to avoid having to compute it for every pixel?
- Storing 'target adjustment' instead of 'current brightness' makes the auto-adjust more responsive when going from too dark to too bright.
- As a post-effect with an .x accessory, can just have control to change target brightness and maybe other settings.
- ACCESSORY CONTROLS:
- Tr: fades effect linearly. 0 is equivalent to off (but still uses CPU)
- Si: Adjusts target brightness.
- X position: How quickly brightness adjusts to screen contents. Increment of 10 = adjust speed doubles or halves.
- Acceleration-based adjustment starts at around 2g (~20 m/s^2) but varies based on fps, because so does acceleration.
- ****************/
- // Camera data pass has no settings, except SyncInEditMode being true or false. Settings for brightness adjustment:
- // {1,1} for no variation across screen
- #define BRIGHT_DIMENSIONS {4,4}
- // Maximum pixel value before blurring to find average
- #define DETECT_LIMIT 2.0
- // Makes bright areas 'spread', sort of. Higher = spread more. Normal gamma would be like 1.2 because it's also multiplied by min(val, 0.9).
- #define BRIGHT_BIAS 3.0
- // float3(...) instead of {...} works better I think? Can't use {} inside an expression? A 'macro' has parantheses directly after the keyword.
- #define TARGET_COLOR float3(0.7,0.7,0.7)
- // Shouldn't be 1 because models tend to have high emissive color. Modifies target color. Note interaction with things like a shader that adds blue on opposite side if light is yellow (= low blue). One problem is that some things, like skydomes, don't vary with light. Another problem is that most models saturate before full light is reached, so increasing light would actually ... darken the scene? Or it's fine? But this filter is supposed to have a time-delay effect, so adjustment for lighting should be for target color, not measured current color. (I was just saying some things here and was wrong. Version 2 adjusts current color.) Divide by zero if weight = 1 and a light component = 0, so don't. *Back to version 1, no division yet.
- #define LIGHTING_WEIGHT 0.2
- // So 'no change' is closer to the default ~155 lighting setting
- #define LIGHT_MULTIPLIER 1.35
- // Color channels are adjusted this amount towards target before being adjusted together. (Before desaturation to avoid out-of-range values.) Can range from 0 to 1. If at 1, no zone of 'no change'.
- #define HUE_ADJUST_STRENGTH 0.3
- // Hue can go this amount up, or reciprocal of this value down. Minimum 1. Comment out in code to disable (cleaner than extra #ifdef statements)
- #define HUE_ADJUST_LIMIT 1.3
- // 'LUM' stands for either luma or luminance, not sure. Average brightness (but not combined using gamma, so it's probably luma)
- #define LUM_ADJUST_STRENGTH 0.7
- // Prevent or slow adjust from reaching its ideal brightness when stationary, set to 1 or more. Uses reciprocal as well.
- #define LUM_STATIONARY_BUFFER 1.1
- /////////////////////////
- // Color adjustment stuff
- // Color increases above this limit are reduced
- #define REDUCE_BRIGHTNESS_LIMIT 0.9
- // Attempt to limit colors to this using desaturation after reducing bright colors. Could be above 1.
- #define DESAT_COLOR_LIMIT 0.9
- // Math stuff, maybe redundant. Ranges from 0 to 1, lower = greater desaturation. 'Distance' from average can be multiplied by this.
- #define MIN_DESAT_RATIO 0.2
- // Limit desaturation strength, maybe redundant with previous but affects all desaturated pixels. Ranges from 0 to 1, used for linear interpolation.
- #define DESAT_STRENGTH 0.7
- float3 CameraPosition : POSITION < string Object = "Camera"; >;
- float3 LightAmbient : AMBIENT < string Object = "Light"; >;
- // .x controls
- float alpha1 : CONTROLOBJECT < string name = "(self)"; string item = "Tr"; >;
- float SizeX10 : CONTROLOBJECT < string name = "(self)"; string item = "Si"; >; // Value in interface times 10
- float AdjustSpeedX : CONTROLOBJECT < string name = "(self)"; string item = "X"; >;
- static float AdjustSpeed = pow(2,AdjustSpeedX/10);
- // Linear interpolation from third term 0 to 1
- static float3 TargetColorNoAlpha = lerp(TARGET_COLOR, TARGET_COLOR * LightAmbient * LIGHT_MULTIPLIER, LIGHTING_WEIGHT) * SizeX10 / 10;
- static float4 TargetColor = float4(TargetColorNoAlpha, (TargetColorNoAlpha.r + TargetColorNoAlpha.g + TargetColorNoAlpha.b)/3);
- // Version 2, use lighting to adjust average color instead of target color
- //static float TargetColor = TARGET_COLOR * SizeX10 / 10;
- // Back to version 1.
- // Math here is more efficient than later?
- // If true, no change to brightness when paused
- float fTime : TIME <bool SyncInEditMode=false;>;
- float elaTime : ELAPSEDTIME <bool SyncInEditMode=false;>;
- // スクリーンサイズ
- float2 ViewportSize : VIEWPORTPIXELSIZE;
- static float2 ViewportOffset = (float2(0.5,0.5)/ViewportSize);
- static float2 ViewportOffset2 = (float2(0.5,0.5)/ViewportSize) * 4;
- static float2 BrightDimensions = BRIGHT_DIMENSIONS; //??
- static float2 ViewportOffset3 = (float2(0.5,0.5)/BrightDimensions);
- static float2 HalfOffset = ViewportOffset3 / 2;
- static float2 CameraViewportOffset = float2(0.5,0.5)/float2(3,1);
- float Script : STANDARDSGLOBAL <
- string ScriptOutput = "color";
- string ScriptClass = "scene";
- string ScriptOrder = "postprocess";
- > = 0.8;
- // レンダリングターゲットのクリア値
- float4 ClearColor = {1,1,1,1};
- float ClearDepth = 1.0;
- //////////////////////////////////////
- shared texture CameraData : RENDERCOLORTARGET
- <
- int Width=3;
- int Height=1;
- //string Format = "A16R16G16B16F" ;
- string Format = "A16B16G16R16F" ;
- //bool antialias = false; // Doesn't fix problem of Tex > 0
- >;
- sampler CameraDataSampler = sampler_state //Used as both Sampler1D and Sampler2D
- {
- Texture = <CameraData>;
- AddressU = CLAMP;
- AddressV = CLAMP;
- MinFilter = NONE;
- MagFilter = NONE;
- MipFilter = NONE;
- };
- /* //Unnecessary
- texture CameraDataDepthBuffer : RenderDepthStencilTarget <
- int Width=3;
- int Height=1;
- string Format = "D24S8";
- >;
- */
- shared texture CameraDataTransfer : RENDERCOLORTARGET
- <
- int Width=3;
- int Height=1;
- string Format = "A16B16G16R16F" ;
- >;
- sampler CameraDataTransferSamp = sampler_state
- {
- Texture = <CameraDataTransfer>;
- AddressU = CLAMP;
- AddressV = CLAMP;
- MinFilter = NONE;
- MagFilter = NONE;
- MipFilter = NONE;
- };
- ////////////////////////////////////////////////////////////////////////////////////////////////
- struct VS_OUTPUT_CAMERA {
- float4 Pos : POSITION;
- //int Tex : TEXCOORD0;
- //nointerpolation int Tex : TEXCOORD0; // Doesn't change warnings
- float4 Tex : TEXCOORD0;
- };
- ////////////////////////////////////////////////////////////////////////////////////////////////
- // 画面更新時刻の計算
- VS_OUTPUT_CAMERA VS_UpdateCameraData(float4 Pos : POSITION, float2 Tex : TEXCOORD0)
- {
- VS_OUTPUT_CAMERA Out = (VS_OUTPUT_CAMERA)0;
- Out.Pos = Pos;
- //Out.Tex = (int)(Tex * 3 + 0.1); //No offset. Rounding problem?
- Out.Tex.a = Tex.x; // Used for switch statement
- Out.Tex.rgb = float3(0.5/3, 1.5/3, 2.5/3); // Fix for dependent texture?
- return Out;
- }
- // Not tested: whether a separate texture and pass for each pixel is slower than 'if' statements
- float4 PS_UpdateCameraData(float4 Tex: TEXCOORD0) : COLOR
- {
- float3 PrevPosition = tex1D(CameraDataSampler, Tex.r).rgb;
- float3 PrevVelocity = tex1D(CameraDataSampler, Tex.g).rgb;
- float3 PrevAccel = tex1D(CameraDataSampler, Tex.b).rgb;
- // "Warning X3509: tex1D will be considered dependent since texcoord was not declared as at least float2"
- // Dependent texture read: https://stackoverflow.com/questions/1054096/what-is-a-dependent-texture-read
- // "Branch flow control consumes resources, excessive use can lead to compile errors"
- // So we just compute all the values every time, and select the right one. Boolean '?:' computes both sides because vector operation. No wait, we do multiple passes and textures. Or not.
- // Maybe "'if' is slow" because it delays texture lookup? (Untested.) But wouldn't lead to compilation errors.
- float3 CurrentPosition = elaTime ? CameraPosition : PrevPosition;
- float3 CurrentVelocity = elaTime ? (CurrentPosition - PrevPosition) / elaTime : PrevVelocity; // Do some stuff if SyncInEditMode=true and time hasn't changed
- float3 CurrentAccel = elaTime ? (CurrentVelocity - PrevVelocity) / elaTime : PrevAccel; // If we stored the most recent valid elaTime, could calculate accel here but it would be wrong for frame skipping
- float4 Out = 0;
- //[branch] switch (Tex) //Untested
- /*
- switch ( floor(Tex.a * 3.0 + 0.1) )
- {
- case 0.0: Out.rgb = CurrentPosition;
- case 1.0: Out.rgb = CurrentVelocity;
- case 2.0: Out.rgb = CurrentAccel;
- }
- */
- // "error X3548: in PS_2_0 uints can only be used with known-positive values, use int if possible"
- // All sides are calculated for '?:' but no calculation is done here anyway. I guess Tex.a == 0 doesn't work here.
- //Out.rgb = Tex.a == 0 ? CurrentPosition : Tex.a < 0.4 ? CurrentVelocity : CurrentAccel;
- // If first pixel uses CurrentVelocity, ... I guess it makes sense for it to 'drift'? As in, after compiling, first few frames are more reasonable but it quickly becomes super-extreme.
- // Value of Tex for first pixel is about 0.0026041. It's probably 1/384 = 1/256 * 2/3, though it's more like 0.002604141 and 1/384 is 0.002604167. 1/(255*1.5) is a significantly worse match. Using (Pos.x / 2 + 0.5) has same result; same with trying 'nointerpolation' which might not even work.
- // Tex.a < 0.002604141 is false for first pixel.
- // Tex.a < 0.002604142 is true for first pixel.
- Out.rgb = Tex.a < 0.1 ? CurrentPosition : Tex.a < 0.4 ? CurrentVelocity : CurrentAccel;
- //Out.rgb = CurrentPosition;
- return Out;
- }
- ////////////////////////////////////////////////////////
- // オリジナルの描画結果を記録するためのレンダーターゲット
- texture2D ScnMap : RENDERCOLORTARGET <
- float2 ViewPortRatio = {1.0,1.0};
- int MipLevels = 2; //From 1
- //string Format = "A16R16G16B16F" ;
- string Format = "A16B16G16R16F" ;
- >;
- sampler2D ScnSamp = sampler_state {
- texture = <ScnMap>;
- MinFilter = LINEAR;
- MagFilter = LINEAR;
- MipFilter = POINT;
- AddressU = CLAMP;
- AddressV = CLAMP;
- };
- texture2D DepthBuffer : RENDERDEPTHSTENCILTARGET <
- //float2 ViewPortRatio = {1, 1};
- // These numbers don't matter ??
- int2 Dimensions = {1, 1};
- string Format = "D24S8";
- >;
- // フレームを保持するためのレンダーターゲット
- texture2D SmallGammaScreen : RENDERCOLORTARGET <
- // "Error: failed to create texture (parameter: 'SmallGammaScreen'): Invalid call (8876086C)"
- //float2 ViewPortRatio = {0.25,0.25};
- int2 Dimensions = {128, 128};
- int MipLevels = 0; //All
- string Format = "A16B16G16R16F" ;
- >;
- sampler2D SmallGammaSamp = sampler_state {
- texture = <SmallGammaScreen>;
- MinFilter = LINEAR;
- MagFilter = LINEAR;
- MipFilter = NONE;
- AddressU = CLAMP;
- AddressV = CLAMP;
- };
- // Without this, screen is black
- /*
- texture2D SmallGammaDepth : RENDERDEPTHSTENCILTARGET <
- //float2 ViewPortRatio = {0.25,0.25};
- int2 Dimensions = {128, 128};
- string Format = "D24S8";
- >;
- */
- texture2D TinyScreenCurrent : RENDERCOLORTARGET <
- int2 Dimensions = BRIGHT_DIMENSIONS;
- int MipLevels = 1;
- string Format = "A16B16G16R16F" ;
- >;
- sampler2D TinySampCurrent = sampler_state {
- texture = <TinyScreenCurrent>;
- MinFilter = LINEAR;
- MagFilter = LINEAR;
- MipFilter = NONE;
- AddressU = CLAMP;
- AddressV = CLAMP;
- };
- /*
- texture2D TinyDepth : RENDERDEPTHSTENCILTARGET <
- //float2 ViewPortRatio = {0.25,0.25};
- int2 Dimensions = BRIGHT_DIMENSIONS;
- string Format = "D24S8";
- >;
- */
- texture2D TinyScreenPrev : RENDERCOLORTARGET <
- int2 Dimensions = BRIGHT_DIMENSIONS;
- int MipLevels = 1;
- string Format = "A16B16G16R16F" ;
- >;
- sampler2D TinySampPrev = sampler_state {
- texture = <TinyScreenPrev>;
- MinFilter = NONE;
- MagFilter = NONE;
- MipFilter = NONE;
- AddressU = CLAMP;
- AddressV = CLAMP;
- };
- /*******************
- No good place to put this. Problems diagnosed when getting this effect to work:
- 1) Fixing error messages. Most significant was changing to shader model 3_0 for tex2Dlod. Suspected lack of depth buffer for smaller screens was causing other problems, but seems it probably isn't.
- 2) Apparently, ScriptExternal=Color does not create mipmaps; this explains why AutoLuminous object effect has passes named "create mipmaps" and stuff. Even with mipmaps specified, they are not created. If tex2Dlod is used, the sample is just black.
- 3) Didn't set output Tex in ... ok, it is set ?? Differences in 'return tex2D(ScnSamp, Tex) > 0;' for different pixel shaders? Further testing.
- *******************/
- ////////////////////////////////////////////////////////////////////////////////////////////////
- struct VS_OUTPUT {
- float4 Pos : POSITION;
- float2 Tex : TEXCOORD0;
- };
- ////////////////////////////////////////////////////////////////////////////////////////////////
- // コマ撮り共通頂点シェーダ
- VS_OUTPUT VS_Screen(float4 Pos : POSITION, float2 Tex : TEXCOORD0, uniform float2 Offset)
- {
- VS_OUTPUT Out = (VS_OUTPUT)0;
- Out.Pos = Pos;
- //Out.Tex = Tex.xy + ViewportOffset;
- Out.Tex = Tex.xy + Offset;
- // For testing
- //Out.Tex = float2(0.5,0.5);
- return Out;
- }
- // フレームを保持
- float4 PS_CopyFrame(float2 Tex: TEXCOORD0, uniform sampler2D ThisSampler) : COLOR
- {
- float4 Color = tex2D(ThisSampler, Tex);
- return Color;
- }
- // Shrink frame and use gamma
- float4 PS_GammaShrink(float2 Tex: TEXCOORD0) : COLOR
- {
- float4 Color = tex2Dlod(ScnSamp, float4(Tex,0,2)); // Miplevel 2 from base image
- Color.rgb = min(Color.rgb, DETECT_LIMIT);
- // Copy from sRGB
- Color.rgb = (Color.rgb + 0.1 ) / 1.1;
- Color.rgb = min(Color.rgb,0.9) * pow(Color.rgb, BRIGHT_BIAS);
- // For testing
- //return 1;
- return Color;
- }
- float4 PS_TinyBlur(float2 Tex: TEXCOORD0) : COLOR
- {
- float4 Color = 0;
- // Guessing which miplevel to use. Don't want to sample a 2x2 miplevel here!
- Color.rgb += tex2Dlod(SmallGammaSamp, float4(Tex,0,5)).rgb;
- Color.rgb += tex2Dlod(SmallGammaSamp, float4(Tex + HalfOffset,0,5)).rgb;
- Color.rgb += tex2Dlod(SmallGammaSamp, float4(Tex - HalfOffset,0,5)).rgb;
- Color.rgb += tex2Dlod(SmallGammaSamp, float4(Tex + HalfOffset * float2(1,-1),0,5)).rgb;
- Color.rgb += tex2Dlod(SmallGammaSamp, float4(Tex + HalfOffset * float2(-1,1),0,5)).rgb;
- float2 Tex2 = (Tex + float2(0.5,0.5)) / 2; // Halfway to center
- Color.rgb += tex2Dlod(SmallGammaSamp, float4(Tex2 + HalfOffset * float2(0.8,0),0,5)).rgb;
- Color.rgb += tex2Dlod(SmallGammaSamp, float4(Tex2 + HalfOffset * float2(-0.8,0),0,5)).rgb;
- Color.rgb += tex2Dlod(SmallGammaSamp, float4(Tex2 + HalfOffset * float2(0,0.8),0,5)).rgb;
- Color.rgb += tex2Dlod(SmallGammaSamp, float4(Tex2 + HalfOffset * float2(0,-0.8),0,5)).rgb;
- Color.rgb /= 9; // number of samples used
- // For testing
- //return (tex2Dlod(SmallGammaSamp, float4(Tex,0,5)).r > 0.0001); // False
- //return (tex2Dlod(SmallGammaSamp, float4(Tex,0,5)).r > 0.00001); // True
- float4 OldAdjust = tex2D(TinySampPrev, Tex); // Was called OldColor
- // Working with gamma numbers is too hard, even if it leads to 'darker screen during flicking or strobing'
- Color.rgb = pow(Color.rgb, 1 / (1 + BRIGHT_BIAS));
- // Copy from sRGB
- Color.rgb = Color.rgb * 1.1 - 0.1;
- // For testing
- //return tex2D(ScnSamp, saturate(Tex) * 0.0138 );
- return tex2D(ScnSamp, saturate(Tex) * 0.0139 );
- //return Color.r;
- //return float4(Color.rgb, (Color.r + Color.g + Color.b) / 3);
- // Adjustable target color from lighting and control mean we have to store the average lighting, instead of the adjustment. But 'no change zone' can be closeness of approach to current lighting, instead of whether current lighting is close to target. Or, light adjustment could be to current average color here, instead of to target level (which affects meaning of previous average color).
- //Color.rgb /= lerp(1, LightAmbient * LIGHT_MULTIPLIER, LIGHTING_WEIGHT);
- /*
- same adjustment as if target level was being reduced
- if target level was reduced from 0.5 to 0.01, to do the same change by adjusting Color, would have to multiply by 50?
- let's just subtract it. But wait, if measured color becomes really low, then base screen must be multiplied by really high number to reach target level.
- */
- // Back to version 1, where we store the adjustment.
- //Color.a = (Color.r + Color.g + Color.b) / 3; //No gamma as a test. Now done later.
- float4 Adjust;
- // Simplest version, and wrong because it duplicates rgb and a, where 'a' adjusts all channels.
- //Adjust = TargetColor / Color;
- // 'Adjust' is target adjustment if the current frame was repeated for a long time. Limited hue adjustment is similar to modifying target color based on light.
- Adjust.rgb = (TargetColor.rgb / Color.rgb - 1) * HUE_ADJUST_STRENGTH + 1; // Compiler should optimize/simplify
- Adjust.rgb = min(Adjust.rgb, HUE_ADJUST_LIMIT);
- Adjust.rgb = max(Adjust.rgb, 1.0 / HUE_ADJUST_LIMIT);
- // This MIGHT be a problem when lum adjustment assumes that chroma adjustment has already taken place, when in fact it's delayed. Best would probably be to ... do it differently.
- Color.rgb *= Adjust.rgb;
- Color.a = (Color.r + Color.g + Color.b) / 3;
- // Discussion! If 'safe zone' is around target color, then scene movements and lighting fluctuations near that color lead to no adjustment change, but elsewhere they do. This could look weird (notice the lack of adjustments in certain situations). Alternative is 'decay towards Adjust from OldAdjust stops at some distance from Adjust, so any lighting level can become the new normal.' Also, rgb adjust should decay more slowly than 'a' (affects all) adjust.
- Adjust.a = (TargetColor.a / Color.a - 1) * LUM_ADJUST_STRENGTH + 1;
- float3 Accel = tex2D(CameraDataSampler, 2.5f/3).rgb;
- // Discussion! Sudden camera movement: 1/30 sec, camera moves 0.1. Velocity 3 units/sec, acceleration 90 units/sec^2. 60 fps, same velocity, half^W (this stands for delete word) double acceleration. Rotating with r=10 and t=2, velocity ~31, acceleration something like 70~100 units/sec^2. (Normal model height is ~20 units maybe)
- // Coefficient. length() is probably slower, even though this is 1~16 pixels. But accel can be negative, unlike color values. Acceleration of 2700 = jump 3 units in 1/30 sec. If adjacent registered camera frames aren't interpolated, 60 fps has 4x (four times) the acceleration here.
- //float AccelCoeff = saturate( ((Accel.x + Accel.y + Accel.z) - 200) / 2500);
- //float AccelCoeff = saturate( (length(Accel) - 200) / 2500);
- // At 6 fps with old computer and complicated ('heavy') effects, in 1/6 sec, camera moves 0.5, vel 3, accel 15. Detection is harder. Estimate. Could put this math in CameraData shader instead, but would have to rename stuff to be accurate. This exaggerates rotational acceleration at low fps since it normally doesn't vary with fps, but lerp with low AccelCoeff is less influential at low fps too.
- float AccelCoeff = saturate( (length(Accel) - 200) / 2500 * max(min(abs(elaTime),0.25), 1.0/60) * 30 );
- OldAdjust = all(OldAdjust.rgba == 0) ? 1 : OldAdjust; // Untested. Initialize at 1.
- // When camera is stationary.
- float4 stationary;
- //float4 difference = OldAdjust - Adjust; // For sign maybe?
- //float4 ratio = Adjust / OldAdjust;
- bool4 isGreater = Adjust > OldAdjust;
- float closeLimit;
- closeLimit = isGreater.a ? max(Adjust.a / LUM_STATIONARY_BUFFER, OldAdjust.a) : min(Adjust.a * LUM_STATIONARY_BUFFER, OldAdjust.a); // Both sides are computed.
- float4 targetValue;
- // Lum (.a) adjusts in about 2 seconds (estimation is hard), chroma adjusts slower
- float4 channelSpeed = {0.2, 0.2, 0.2, 1.0};
- // sign() returns 0 if they're equal. Maybe root of ratio, like (Adjust/OldAdjust)^0.5 would be better here, but that's much harder to understand and probably slightly slower.
- targetValue = OldAdjust + ((Adjust - OldAdjust) * 0.5 + sign(Adjust - OldAdjust) * 0.05 ) * elaTime * AdjustSpeed * channelSpeed;
- targetValue = isGreater ? min(targetValue, Adjust) : max(targetValue,Adjust); // Tested per component (4) of isGreater
- // Adjustment for luma advances at very slow speed inside the buffer
- stationary.a = targetValue.a - (targetValue.a - closeLimit) * 0.9;
- stationary.rgb = targetValue.rgb;
- // Linear interpolation~ not using coefficient as a coefficient but that's fine
- Adjust = lerp(stationary, Adjust, AccelCoeff);
- return Adjust;
- }
- //////////////////////////////////////
- // Apply the adjustment
- /*
- struct VS_OUTPUT_DRAW {
- float4 Pos : POSITION;
- float2 Tex : TEXCOORD0;
- //float2 TexSmall : TEXCOORD1;
- };
- VS_OUTPUT_DRAW VS_Screen(float4 Pos : POSITION, float2 Tex : TEXCOORD0)
- {
- VS_OUTPUT Out = (VS_OUTPUT)0;
- Out.Pos = Pos;
- Out.Tex = Tex.xy + ViewportOffset;
- // Maybe should modify coordinates so it doesn't use, or uses less of, the outermost half-pixels. Wait, this is wrong anyway. Only need one tex coordinate.
- //Out.TexSmall = Tex.xy + ViewportOffset3;
- return Out;
- }
- */
- // 画面の更新 *Adjust colors, not just update screen
- float4 PS_DrawFrame(float2 Tex: TEXCOORD0) : COLOR
- {
- float4 OrigColor = tex2D(ScnSamp, Tex);
- // Use TinySampCurrent because it has a linear filter, while previous has no/point filter. rgb is per-channel, '.a' is adjustment to all.
- float4 Adjust = tex2D(TinySampCurrent, Tex);
- float3 TestColor;
- TestColor = OrigColor.rgb * Adjust.rgb * Adjust.a;
- // No gamma because don't understand how it affects this
- float3 IncreaseOverLimit = max( max(TestColor - REDUCE_BRIGHTNESS_LIMIT, 0) - max(OrigColor.rgb - REDUCE_BRIGHTNESS_LIMIT, 0), 0);
- // We make something up
- IncreaseOverLimit = (sqrt(IncreaseOverLimit + 0.04) - 0.2) / 2.5; // Derivative is 1/x^.5 * 0.5? For x = 0.01, derivative is 5? For 0.04, derivative 2.5; with this, input of 0.1 goes to 0.070, .05 goes to 0.04, 0.5 goes to 0.214, 0.25 goes to 0.135
- // Hopefully we won't need the previous value again
- //TestColor = max(TestColor, REDUCE_BRIGHTNESS_LIMIT) + IncreaseOverLimit;
- // I think that was wrong but don't completely understand it.
- TestColor = min(TestColor, REDUCE_BRIGHTNESS_LIMIT) + IncreaseOverLimit;
- // Gamma is more influential here but still not using it
- float averageColor = (TestColor.r + TestColor.g + TestColor.b) / 3;
- averageColor = min(averageColor, DESAT_COLOR_LIMIT); // So the next step is positive or 0. Was '1' before, instead of DESAT_COLOR_LIMIT
- // Bring components towards average color based on something
- float DesatRatio = 1 - ( max(TestColor.r - DESAT_COLOR_LIMIT, 0) + max(TestColor.g - DESAT_COLOR_LIMIT, 0) + max(TestColor.r - DESAT_COLOR_LIMIT, 0) ) / ( max(TestColor.r - averageColor, 0) + max(TestColor.g - averageColor, 0) + max(TestColor.b - averageColor, 0) ); // Was '1' instead of DESAT_COLOR_LIMIT
- // Test: {0, 0.7, 1.4}, ratio is (1 - 0.4/0.7) = 0.43. {0, 1, 1.4}, ratio is (1 - 0.4/0.8) = 0.5.
- DesatRatio = max(DesatRatio, MIN_DESAT_RATIO);
- // I think it's fine to use the adjusted average here. Could make white (1,1,1) darker.
- float3 Desaturated = averageColor + (TestColor - averageColor) * DesatRatio;
- // Linear interpolation. Ok, DESAT_STRENGTH in this step instead of previous means it reduces the effect of limiting averageColor to DESAT_COLOR_LIMIT or, previously, 1. Not using gamma means dark components stay darker? Not sure.
- float4 Color = float4(lerp(TestColor, Desaturated, DESAT_STRENGTH), OrigColor.a);
- // For bug fixing
- //Color.rgb = tex1D(CameraDataSampler, 0).rgb;
- //Color.rgb = CameraPosition > 1 ? 1 : 0;
- //Color.rgb = elaTime ? 0 : 1;
- //Color.rgb = TestColor;
- //Color.rgb = OrigColor.rgb * Adjust.rgb * Adjust.a;
- Color.rgb = Adjust.a;
- //Color.rgb = tex2Dlod(ScnSamp, float4(Tex,0,2));
- Color.rgb = lerp(OrigColor.rgb,Color.rgb,alpha1);
- // No attempt to un-tint background color or whatever. Meant for videos anyway, so alpha should really be 1.
- return Color;
- }
- ////////////////////////////////////////////////////////////////////////////////////////////////
- // テクニック
- technique MainTec <
- string Script =
- "RenderColorTarget0=CameraData;" //CameraDataTransfer
- //"RenderDepthStencilTarget=CameraDataDepthBuffer;"
- "Pass=WriteAccel;"
- //"RenderColorTarget0=CameraData;"
- //"Pass=CopyAccel;"
- "RenderColorTarget0=ScnMap;"
- "RenderDepthStencilTarget=DepthBuffer;"
- "ClearSetColor=ClearColor;"
- "ClearSetDepth=ClearDepth;"
- "Clear=Color;"
- "Clear=Depth;"
- "ScriptExternal=Color;"
- "RenderColorTarget0=SmallGammaScreen;"
- //"RenderDepthStencilTarget=DepthBuffer;"
- "Pass=GammaShrink;"
- "RenderColorTarget0=TinyScreenCurrent;"
- //"RenderDepthStencilTarget=TimeDepthBuffer;"
- "Pass=TinyBlur;"
- "RenderColorTarget0=TinyScreenPrev;"
- "Pass=CopyBlur;"
- "RenderColorTarget0=;"
- //"RenderDepthStencilTarget=;"
- "Pass=DrawObject;"
- ;>
- /*
- * disable z-write
- Offset, ThisSampler
- if can't pass static variable as argument to shader, might have to pass something like 1, 0.25, -128 for viewport size, where negative = integer size and positive = ratio of viewportsize
- */
- {
- pass WriteAccel < string Script= "Draw=Buffer;"; > {
- ALPHABLENDENABLE = FALSE;
- ALPHATESTENABLE = FALSE;
- ZWRITEENABLE = false;
- ZENABLE = false;
- VertexShader = compile vs_2_0 VS_UpdateCameraData();
- PixelShader = compile ps_2_0 PS_UpdateCameraData();
- }
- /*
- pass CopyAccel < string Script= "Draw=Buffer;"; > {
- ALPHABLENDENABLE = FALSE;
- ALPHATESTENABLE = FALSE;
- ZWRITEENABLE = false;
- ZENABLE = false;
- VertexShader = compile vs_2_0 VS_Screen(CameraViewportOffset);
- PixelShader = compile ps_2_0 PS_CopyFrame(CameraDataTransferSamp);
- }
- */
- pass GammaShrink < string Script= "Draw=Buffer;"; > {
- ALPHABLENDENABLE = FALSE;
- ALPHATESTENABLE = FALSE;
- ZWRITEENABLE = false;
- ZENABLE = false;
- // texlod requires shader model 3_0
- VertexShader = compile vs_3_0 VS_Screen(ViewportOffset2);
- PixelShader = compile ps_3_0 PS_GammaShrink();
- }
- pass TinyBlur < string Script= "Draw=Buffer;"; > {
- ALPHABLENDENABLE = FALSE;
- ALPHATESTENABLE = FALSE;
- ZWRITEENABLE = false;
- ZENABLE = false;
- VertexShader = compile vs_3_0 VS_Screen(ViewportOffset3);
- PixelShader = compile ps_3_0 PS_TinyBlur();
- }
- pass CopyBlur < string Script= "Draw=Buffer;"; > {
- ALPHABLENDENABLE = FALSE;
- ALPHATESTENABLE = FALSE;
- ZWRITEENABLE = false;
- ZENABLE = false;
- VertexShader = compile vs_2_0 VS_Screen(ViewportOffset3);
- PixelShader = compile ps_2_0 PS_CopyFrame(TinySampCurrent);
- }
- pass DrawObject < string Script= "Draw=Buffer;"; > {
- ALPHABLENDENABLE = FALSE;
- ALPHATESTENABLE = FALSE;
- ZWRITEENABLE = false;
- ZENABLE = false;
- VertexShader = compile vs_2_0 VS_Screen(ViewportOffset);
- PixelShader = compile ps_2_0 PS_DrawFrame();
- }
- }
- ////////////////////////////////////////////////////////////////////////////////////////////////
Advertisement
Add Comment
Please, Sign In to add comment