Welcome, Guest.
Username: Password: Remember me

TOPIC: Advanced Lift Gain Gamma... could use help please.

Advanced Lift Gain Gamma... could use help please. 1 year 4 months ago #1

Hi everyone,

I'm trying to better learn how shaders, and Reshade all work. As part of that, I'm putting together some customized and modified shaders. So far, I haven't had any issues, but I've been mostly limiting myself to simple things. But now I'm running into a slightly larger issue that I need some help with.

I'm trying to create a new shader, called Advanced Lift Gain Gamma, which is based off of the SweetFX shader Lift Gamma Gain v.1.1 by 3an and CeeJay.dk.

Here's what I currently understand from the code (assuming I'm understanding it correctly)
  • Lift affects darker values more strongly than lighter values (values below 1.0 will increase contrast by making darks darker, while values above 1.0 will decrease contrast by making darks lighter).
  • Gain affects lighter values more strongly than darker ones (values above 1.0 will increase contrast by making brights lighter, while calues below 1.0 will decrease contrast by making brights darker).
  • Gamma affects values differently, depending on if the settings value is greater than or lesser than 1.0, but any change from 1.0 will increase contrast (values below 1.0 will increase contrast by making darks darker, while values above 1.0 will increase contrast by making brights lighter.
  • And of course, you can alter how those changes affect each individual RGB color component.

It occurs to me that some, like myself, might be interested in being able to use the Gamma aspect to both darken darks and lighten brights, thus increasing contrast further, or alternatively, to reduce both and decrease contrast. So the first change I made was to add in a second set of Gamma code and change settings entries to include RGB_Gamma1 and RGB_Gamma2 instead of just RGB_Gamma. I also found I personally have reason to make flat +/- adjustments across the board sometimes, so I added in an RGB_Offset setting (-1.0 to 1.0) and added code to add the offset values to the color prior to returning the output. So now I have Lift, then Gain, then Gamma1, then Gamma2, then Offset all affecting the color and then the final color from that process being returned by the function.

All of that works.

But I want to also make it so that the system will automatically adjust the colors to be either lighter or darker depending on the darkness/brightness of the scene. The reason for this is that if contrasts are increased, and especially if a flat offset is applied, you could end up with adjusted scenes that are too bright (washed out) or too dark (totally in shadow) in such a way that your enhanced contrasts are lost to the overall brightness levels. So I want to make it so that if the scene is bright, everything is darkened a little, but if the scene is dark, then everything is brightened a little.

In order to do this, I need to be able to get the average luma of the scene and compare it to a baseline center point of 0.5 (unless someone has a better/different idea on how to make the comparison). The idea is that total dark would be a luma of 0.0 and total bright would be a luma 1.0, hence why 0.5 for the center point. Unfortunately, I don't know how to get the average luma of the scene, and that's what I need help with.

I looked at Deriest's Eye Adaptation code and the other comments in that thread. It looks like that code is comparing the max luma of the scene, which could be useful instead of using average luma, but if a scene has both strong brights and strong darks (high disparity), then I think it could pose problems by darkening a scene that should be left alone. Additionally, I'm not sure how to adjust the calls to my function (LiftGainGammaAdvPass) to incorporate the input that Deriest utilized (instead of "(float4 colorInput)" he uses "(in float4 pos : SV_Position, in float2 texcoord : TEXCOORD0) : SV_Target" and I'm not sure yet how to work with that).

I'd really appreciate it if someone could help me figure out how to determine the average luma of the scene. But right now I'm thinking of using Deriest's method, but duplicating the max checks and turning them into min checks, then simply calculating the average based on ((LumMax + LumMin) / 2). This would still be less than totally accurate, but at least it would take dark vs. bright disparity into account. However, if I do it that way, I still need to figure out how to properly write the function definition as well as the function calls/references so that I pass in the colorInput as well as the pos, texcoord, and target info. Or would those be unnecessary (could I just define new local variables that call those values)?

Please note that I've already added MasterEffect global textures and shaders into my Reshade/Common/Util.h file, so I should be able to easily access samplerBloom4 the way Deriest has done, and I'm assuming that I would need to change samplerColor to either RFX_backbufferColor or RFX_originalColor (backbuffer I think, but not positive at this time... and all of this is based on ReShade 0.19.2 Framework by the way).

I'd really appreciate the help.

Thanks,
Drake Phoenix

P.S. Sorry for the long post.
Last Edit: 1 year 4 months ago by DrakePhoenix.
The administrator has disabled public write access.

Advanced Lift Gain Gamma... could use help please. 1 year 4 months ago #2

OK, I've learned a little more about Deriest's code, and I'm pretty sure that the samplerBloom4 results in a highly blurred texture (hoping for confirmation/clarification on that), which allows the sample taken to be roughly average anyway. I adapted the code from MasterEffect to expand texBloomX and samplerBloomX up to X values as high as 8 (dividing the buffer dimensions by 64 at that level). This should blur/average the texture even further and allow the sample point to more accurately represent the average of the scene. I have also adapted Deriest's code to check not only the max luma, but also the min luma, and average the two together, thus making it even more likely that I've retrieved a very close approximation of the actual average luma of the scene.

I've updated my code for the shader on the whole, and would appreciate it if people could look through it really quick and let me know if they think it will achieve what I'm after (Lift as per normal, Gain as per normal, option to adjust gamma both up and down simultaneously, dynamic adjustment offset based on scene average luma, and optional flat offset adjustment).

Code follows:
Warning: Spoiler! [ Click to expand ]


That's all for now.

Thanks,
Drake Phoenix
The administrator has disabled public write access.

Advanced Lift Gain Gamma... could use help please. 1 year 4 months ago #3

  • Ganossa
  • Ganossa's Avatar
  • Offline
  • 최정장군
  • Posts: 790
  • Thank you received: 838
To debug the accuracy of your brightness detection, it is probably easiest to

return tex2D(samplerBloom8, 0.5);

In a few different scenes and compare the original image with the result of that debug.
Could you post a few comparison screens of that? I would be interested to see how accurate that can be. (unfortunately, I cannot reproduce it myself, since I do not see your samplerBloom code)
The administrator has disabled public write access.
The following user(s) said Thank You: DrakePhoenix

Advanced Lift Gain Gamma... could use help please. 1 year 4 months ago #4

Thanks for the debugging suggestion LuciferHawk.

I wasn't actually able to do it, unfortunately, because for some reason the shader fails to make any changes whatsoever. It acts as though the USE_LIFTGAINGAMMA_ADV setting is set to 0 even when it is properly set to 1. I'm not getting any compiler errors or effect errors, and not even any warnings as near as I can tell.

My other two shaders I've been working on are working just fine. And I cannot figure out why this one is refusing to actually do anything.

However, I took one of my other shaders, my HUD shader, and replaced the normal HUD texture with a full image with dimensions equal to my display resolution. But I applied the texture width and height values as BUFFER_WIDTH/64 and BUFFER_HEIGHT/64 respectively. The result was a highly blurred version of the original image texture, but not nearly averaged out. So I tested again, using a divisor of /1024 to see if I could get a better result. That result was much better, but still imperfect, so I changed the divisors to equal each dimension respectively, so BUFFER_WIDTH/BUFFER_WIDTH and BUFFER_HEIGHT/BUFFER_HEIGHT, to get a 1x1 texture based on the original. Following is what I got from this test (images stored at imageshack; board system won't let me link and display them all within img tags, says too many links... didn't think 3 was that many, but whatever).

I started with this image:
imageshack.com/a/img540/1671/dq9TRD.png

The shader output this image (the fps tracker in the right side is from Dxtory):
imageshack.com/a/img540/3162/Pzdhos.png

Using Photoshop, and the Filter -> Blur -> Average filter I get the following result:
imageshack.com/a/img540/9546/QOG5rA.png

As you can probably tell, this method (dividing down to a 1x1 texture) results in a texture that is very, very close to the actual average of all colors from the input texture. It's close enough for my purposes, especially since I'm taking both the max and the min and averaging a second time.

So if I can get the actual shader to work at all, this method should work for what I'm trying to do.

I was able to get the shader to work (excluding the scene luma-based dynamic adjustment) under SweetFX 1.5.1, but I can't get it to work under ReShade for some reason. I think it has to be a problem somewhere with my adaptation from SweetFX 1.5.1 to my ReShade version of the code, but without any error messages, I can't figure it out.

My d3d9.log file did report a single error:
18/07/2015 00:12:45:117 [13108] | ERROR | Failed to install hook for '0x6AD0D6E8' with status code 3.

My best guess is that this error is the reason my shader is failing, but the information isn't useful to me. I can't figure out for sure if the hook for "0x6AD0D6E8" is actually for my shader or for something else, and I have no idea what status code 3 means.

I'll keep trying to figure it out, but I hope someone can help me with this.

Thanks,
Drake Phoenix

P.S. Instead of dividing BUFFER_WIDTH/BUFFERWIDTH, and BUFFER_HEIGHT/BUFFER_HEIGHT, can instead simply set Width = 1; Height = 1. I have updated my code to do precisely that.
Last Edit: 1 year 4 months ago by DrakePhoenix.
The administrator has disabled public write access.

Advanced Lift Gain Gamma... could use help please. 1 year 4 months ago #5

OK, I tried rebooting my system and then disabling Dxtory, then tried my shader again. Again it fails to do anything.

The d3d9.log file is still showing an error installing hook with status code 3. You can view my entire d3d9.log file at pastebin (the complete file won't fit here in spoiler/code tags). The memory address location is different. Not sure if that matters.

Later,
Drake Phoenix
The administrator has disabled public write access.

Advanced Lift Gain Gamma... could use help please. 1 year 4 months ago #6

  • crosire
  • crosire's Avatar
  • Offline
  • Posts: 2453
  • Thank you received: 1393
DrakePhoenix wrote:
My d3d9.log file did report a single error:
18/07/2015 00:12:45:117 [13108] | ERROR | Failed to install hook for '0x6AD0D6E8' with status code 3.
That's a ReShade hooking error and has nothing to do with your shader. It means some other software probably already hooked D3D and ReShade now fails to do the same. Without a complete tracelog that address is relativly useless to me though, the tracelog contains a table at the beginning which resolves addresses to the actual function names.
Cheers, crosire =)
The administrator has disabled public write access.

Advanced Lift Gain Gamma... could use help please. 1 year 4 months ago #7

  • Ganossa
  • Ganossa's Avatar
  • Offline
  • 최정장군
  • Posts: 790
  • Thank you received: 838
You should try with moving pictures. I doubt you get the photoshop blur with that method but rather a fraction of your image (which might or might not be representative). This will work for some static pictures (like your example) but I would guess it flickers a lot in a game. I still do not know your algorithm so there is no way for me to test it (I only checked the average of your example and that was accurate but that is also due to that specific picture ;) )

Try this one for example:


I will show you what I mean.

This is a picture from the new offline preview rendering the lion picture from above. I added a algorithm that outputs the average rgb values of a image and created from that a small rectangle that you can see on the upper right corner. The top part of the image returns the result of my own bright detection algorithm (though I had to increase the brightness a bit due to the way I calculate brightness). The bottom part is the image "blurred" by reducing the texture size as you did. I multiplied the brightness by 100 to show you that the actual result is pretty much black.
Anyway, your algorithm might still differ from what I think but try test it yourself :)
Last Edit: 1 year 4 months ago by Ganossa.
The administrator has disabled public write access.

Advanced Lift Gain Gamma... could use help please. 1 year 4 months ago #8

OK, first let's talk about the averaging algorithm (I'll post another reply about the code issues, which I managed to get working)...

I'm not really following you, LuciferHawk. I don't really see how moving images would affect my average determination very much.

My algorithm is very simple... take Texture A (namely the image data present in the buffer at the time the function is run), resize it to 1 pixel by 1 pixel, then sample from that 1x1 texture. Since it's based on the current scene and is processed along with other post processing shaders at every frame (as far as I know), there's no real option for flickering unless the scene itself is flickering for some reason. Also, I've noticed no flickering so far in my testing, even transitioning from a very bright scene to a very dark one and vice versa. So I don't really see an issue there. If there's something I'm missing (totally possible) about how the ReShade system pulls the buffer that would make moving images a problem for accurate sampling, then by all means point it out (but please try to dumb down the explanation to the level of an HLSL beginner as much as possible).

The full code isn't fit for publication, but here's the very basics:
texture texBloom10 { Width = 1; Height = 1; Format = RENDERMODE;}; //rendermode is previously defined and variable, can be RGBA8, RGBA16, or RGBA32. I'm thinking of simply setting it to RGBA8 as the other bit depths aren't really needed for this purpose.
sampler SamplerBloom10 { Texture = texBloom10; }; //SamplerBloom10 and texBloom10 are adapted from code taken from MasterEffect suite
float4 Lum = tex2D(SamplerBloom10, 0.5); //this line adapted from code taken from Deriest's Eye Adaptation.

Later processing is performed on, or uses values from, Lum. Including determining max brightness of r, g, and b compared to one another, and min brightness (determined in much the same way), and getting the average of the two.

I took your lion pic with black background and downloaded it. I then loaded it into Photoshop and performed the same basic algorithm (prior to determining min and max brightness amounts): resized it down to 1x1 (unconstrained proportions) using "Bicubic Sharpener" resampling method, then zoomed in as close as possible. I did not apply any blurring or other filters or changes. It looked like a pretty accurate average to me (in fact, I also checked using Blur -> Average, and found the results indistinguishable). I blew that result back up to the original 1024x768 size so you could see it.

Following is the resulting "texture" that would otherwise be sampled using the method I'm using:


In other words, based on my limited understanding of the HLSL code and Reshade both, If the scene in the buffer looked exactly like that picture, then the content of texBloom10 would be a 1x1 texture that looks like the image linked above. I checked this again in my test code and as near as I could tell got the same result (except stretched to 1920x1080). So as an algorithm to determine the average color, and subsequently the average luma of a scene, I think it works pretty well (at least so far).

Admittedly, you can't verify that yourself completely without my full code, so feel free not to take my word for it. But I do intend to release the code for this (and my other two shaders) as a small shader pack in the Presentation forum once I get them more thoroughly tested and clean up and optimize the code a bit (my coding style is very messy, and I'm new to HLSL).

Anyway, that's it for now, on this subject at least.

Thanks,
Drake Phoenix.
Last Edit: 1 year 4 months ago by DrakePhoenix.
The administrator has disabled public write access.

Advanced Lift Gain Gamma... could use help please. 1 year 4 months ago #9

Now as to the code error issues...


I'm not sure what would be causing the hook error I referred to before. I'll post a pastebin or similar of the entire log file on another run sometime later (probably not for another day or so).

But regardless of the error, I was able to get the code working.

I had a previous version of the code working properly as a part of the SweetFX suite. And I mean SweetFX within ReShade Framework, not an older, standalone version, like 1.5.1. The problem of it failing started after I had tried to separate it out into my own shader suite (a separate folder within the ReShade folder). I looked at code from other shaders to try and get this set up correctly, and was able to properly and effectively port over my other two shaders, which both worked fine. So I double-checked my code changes comparing my old SweetFX version of my shader to my new separated version, and found a rather serious logic error.

When it comes to coding (in any language, whether it's VB, C, C++, C#, LUA, or HLSL, all of which besides HLSL I have at least novice level experience with), logic errors are always by biggest weakness. And it is a BIG weakness. It also, unfortunately is what I find to be the most difficult to debug.

Anyway, I was able to correct the error, and got my version of the shader working... mostly. I found that while it worked, I wasn't happy with the output results, regardless of variables settings values. I determined that the chief cause of this was that I used too simple an implementation. After having determined the scene's average luma (within a reasonable margin of error as far as I can tell), I processed Lift, Gain, Gamma1, and Gamma2 normally, and then to the result added the Offset value and the dynamic adjustment value (dynamic adjustment being determined based on the scene's average luma relative to a mid point of 0.5). This resulted in aberrant distortions in final pixel colors in the final output image.

I weakened the strength of the dynamic adjustment, and also set it up to apply to each stage, instead of only the final one. So now, instead of merely resulting in a flat increase or decrease to color values, it will instead result in changes to Lift, Gain, Gamma1, Gamma2, and Offset, all across the board, but will apply that adjustment to a weaker extent at each phase.

This has produced results that I am much more happy with.


So, long story short (too late, I know, sorry)... Hook error may still be coming up, and if so I'll post about it at a later time (probably in its own thread), but functionality of my shader is fixed and it is now working the way I want it to.


Thanks for the help :)
Drake Phoenix
Last Edit: 1 year 4 months ago by DrakePhoenix.
The administrator has disabled public write access.

Advanced Lift Gain Gamma... could use help please. 1 year 4 months ago #10

  • Ganossa
  • Ganossa's Avatar
  • Offline
  • 최정장군
  • Posts: 790
  • Thank you received: 838
Hey DrakePhoenix :) Don't get me wrong, I would be very happy if reducing texture size would lead to an average (it would make things much easier for me too). That is the main reason I come here to talk about it :lol:
Anyway, with the information you gave above, I should at least be able to reproduce your average algorithm (since you said there is no additional blur passes or similar applied).

Here is the code (embedded in the custom shader) I used (according to what you posted) for retrieving the "average" from the 1x1 texture:
NAMESPACE_ENTER(CFX)

#include CFX_SETTINGS_DEF

#if (USE_CUSTOM == 1)

texture texBloom10 { Width = 1; Height = 1; Format = RGBA32F;}; 
sampler SamplerBloom10 { Texture = texBloom10; };   

void PS_Custom0(float4 vpos : SV_Position, float2 texcoord : TEXCOORD, out float4 lum : SV_Target0)
{
	lum = tex2D(RFX_originalColor, texcoord);
}

float4 PS_Custom1(float4 vpos : SV_Position, float2 texcoord : TEXCOORD) : SV_Target
{
	if(texcoord.y < 0.333) return tex2D(SamplerBloom10, 0.5);
	else if(texcoord.y < 0.666) return tex2D(RFX_backbufferColor, texcoord);
	else return tex2D(RFX_originalColor, texcoord);
}

technique Custom_Tech <bool enabled = RFX_Start_Enabled; int toggle = Custom_ToggleKey; >
{
	pass CustomPass0
	{
		VertexShader = RFX_VS_PostProcess;
		PixelShader = PS_Custom0;
		RenderTarget = texBloom10;
	}

	pass CustomPass1
	{
		VertexShader = RFX_VS_PostProcess;
		PixelShader = PS_Custom1;
	}
}

#endif

#include CFX_SETTINGS_UNDEF

NAMESPACE_LEAVE()

It is very simple code. For the output I divided the screen into 3 sections.
The top section displays the "average" result from the 1x1 texture which you use as input for your algorithm.
The middle section displays the (correct) average estimation from another shader.
The bottom section displays the original image.

To show you what I meant with flickering, I recorded Warframe with MSI-Afterburner while displaying those 3 sections:


Again, I would like to find a simple solution too and point me in the right direction if you think the code you used works differently. However, if that 1x1 "average" is input for your algorithm, then its not getting what it should.
If you want I can explain more what it actually is you get back with that algorithm but since you said I should keep it simple, I will stop explaining from here :)
The administrator has disabled public write access.

Advanced Lift Gain Gamma... could use help please. 1 year 4 months ago #11

OK, I think I'm starting to understand a little better where you're coming from, and I definitely see the flickering you're talking about. Though I haven't noticed it in my output from my shader, that may be because the results of my attempted method to get average is applied in a subtle way to the final output image.

Give me some time to write up a second debug subroutine, and see if I can verify my method's output a little better. If I can, I'll record a vid of splitscreen output and post it. My system isn't very powerful, so recording vid tends to kill my frame rate, but I'll see what I can do. Also, I don't have a youtube account and don't plan to set one up, so I'll probably just post the vid (if I can get one) to MegaShares and link it.

This may take me a few days.

Later,
Drake Phoenix
Last Edit: 1 year 4 months ago by DrakePhoenix.
The administrator has disabled public write access.

Advanced Lift Gain Gamma... could use help please. 1 year 4 months ago #12

Hmmm...

Well, no vid, at this point (still working on writing a different debug concept).

But I took your code, pasted it over into Custom.h, and enabled it (disabled my own shader). Then ran it on Guild Wars 2. The result was a flickering upper third of the screen, but middle third just showed the unaltered original image, same as the bottom third (so RFX_backbufferColor appears to be identical to RFX_originalColor, at least if no other shaders are running). I didn't get anything different in the middle third like your vid showed (did you have another shader running concurrently?). I then altered the code to use my luma determination, and checked again. Still received flickering at the top third (no changes to middle third), but instead of getting a color I got a greyscale-only result based on the brightness of the color (this is expected, as I took my determined luma average and applied it to the all three of the r, g, and b color values for the output color).

The altered code is as follows:
Warning: Spoiler! [ Click to expand ]


Also, using my HUD shader to overlay a simple crosshair texture I was able to track where the center point of the screen was quite well, and what color the pixel was under that point. I noticed that the top third of the screen (my luma average determination result) shows the color (or luma, with the full determination in place) of the center point of the screen image. So if the pixel under the screen center is black, top third of screen is black, if it's white, then white, if it's a medium blue, then a medium grey result, etc.

Considering the way textures blurred in my other tests, I find this odd. But it basically means that texBloom10 does not actually first retrieve the full scene from the buffer. I think that instead texBloom10 is merely setting up the structure of an undefined texture source. No source is given.

So if a source is provided for such a 1x1 texture, and that source is an image file, then it takes the image and resizes it down to fit the dimensions specified. This results in considerable blurring/averaging. But if there is no source, then all it does is set up a blank 1x1 texture for later use, and the sampler I think then fills it. Since the sampler is sampling only the single pixel at the screen center, then all we get is the screen center color.

This raises the question, for me, of how can we get an image source of the frame buffer contents? Also, would it need to be retrieved, stored to a file, and then the file used as the source for the texBloom10 texture (or whatever other name is used for it)? If we can provide the frame buffer contents in full as an image source to the texBloom10 texture, then I think compressing down to a 1x1 texture size would still work. So how can we get the frame buffer contents into such a source format?

Also, on another note, what is the other shader that you borrowed code from to get your actual average for your middle third output in that vid? I'd like to look through that code (it may be beyond my skills to understand much/most of it right now, but I'd like to try).

This also raises the question of why was I able to get my code to work in a way such that I was happy with the results? I'm not sure of the answer to that. But I suspect it may have to do with the other shaders I was running at the same time (I was more concerned about total combined final results as opposed to single shader final results).


That's all for now.

Later,
Drake Phoenix
Last Edit: 1 year 4 months ago by DrakePhoenix.
The administrator has disabled public write access.

Advanced Lift Gain Gamma... could use help please. 1 year 4 months ago #13

  • Ganossa
  • Ganossa's Avatar
  • Offline
  • 최정장군
  • Posts: 790
  • Thank you received: 838
I might not answer your post content one by one due to the size but I will try to explain a few things that might help you out :)

I indeed already wrote a heavily optimized bright detection algorithm which is part of the ambient light shader (GemFX). That is -somewhat modified- the result in the middle part. It is also used to control the "ENB" palette shader, the HeatHaze shader and several Bloom shader. It is currently not properly detached from the AL shader but its on the to do list so you (and others) can simply grep the result of that algorithm. However, I was curious if there was an even cheaper way, which I is why I checked here :D

With "source provided for a 1x1 texture" do you mean that you set the scale of an image you loaded into a texture to 1x1?

In PS_Custom0
What we have in the code there is a render target for the pixel shader. The shader writes the from the original image sampled pixels to texBloom10 (its render target). If we set the render target's size lower than the original, we get the original stored in a lower resolution.

In PS_Custom1
We write that low resolution result back to screen but since we only have a fraction of the original information stored in that texture, several pixels on screen get the same value of one pixel in the stored texture. That indeed looks a bit like "square" blur (if we remain the ratio between width and height). It is not an average though, rather an abstraction of the original image. Hence, a 1x1 texture only stores the smallest amount of information of an image which is not anymore representative for its original.

A little illustration of abstraction:

Original Image -> 5x5 -> 3x3 -> 2x2


1x1 would be a black result for this example.

Hope that cleared things up a bit :)
Last Edit: 1 year 4 months ago by Ganossa.
The administrator has disabled public write access.

Advanced Lift Gain Gamma... could use help please. 1 year 4 months ago #14

OK, thanks, I'll look into it some more.

By "source provided for a 1x1 texture", I merely meant that if you already have a full texture, not merely a single pixel sample or a single RGBA color value, and then try to load that source into texBloom10 (when texBloom10 has a 1x1 dimension), then it appears to essentially compress the image data into that single pixel size, resulting in an approximate average of what the original had been. At least this is how it seems to behave when the source is an actual image file. So the question I have, basically, is how can we get the full frame buffer and treat it as a complete image-file-like texture?

As for that compression being more of an abstraction... that's true enough, but the end result seems to be roughly equivalent to, or at least highly similar to, a fully blurred average of all present colors. The only way to get a complete and absolutely true average would be sample each and every pixel, add them together at each iteration, and then divide the result by the total number of pixels. That would be highly inefficient in terms of performance, as I'm sure you're quite perfectly aware.

But for my general purposes for this shader I'm working on, an abstraction is perfectly acceptable. The problem again is how to get the full frame buffer data treated as a single source image texture, and then compress it down to 1x1.

As to your code... I think the fact that you're filling the texBloom10 render target with the output from a pixel shader is part of the issue with the results. The output of the pixel shader is basically just the value for a single pixel at a time, right? So if you take a single pixel and stuff it into a 1x1 texture structure, then nothing has changed. What's needed is to get a complete texture of a size at least as large as the screen/display resolution, and then smash that inside that 1x1 dimension to get the abstracted combination of the original. Maybe that's what you do in your AL code, but I kind of doubt it from what you've said so far (I get the impression you aimed for a more accurate average than that).

Anyway, I'll keep playing with it some, and I'll look closely through the AL code and see if I can understand any of it (I'm sure I can understand some, but I doubt it will be a lot; it may help me learn a bit at least).

Sorry if I had initially gotten your hopes up for a cheaper solution, only to show that I really know almost nothing about HLSL or 3D programming in general. Maybe one of us will have an epiphany about it later on though.

Later,
Drake Phoenix
The administrator has disabled public write access.

Advanced Lift Gain Gamma... could use help please. 1 year 4 months ago #15

  • crosire
  • crosire's Avatar
  • Offline
  • Posts: 2453
  • Thank you received: 1393
DrakePhoenix wrote:
What's needed is to get a complete texture of a size at least as large as the screen/display resolution, and then smash that inside that 1x1 dimension to get the abstracted combination of the original. Maybe that's what you do in your AL code, but I kind of doubt it from what you've said so far (I get the impression you aimed for a more accurate average than that).
Not exactly fast, but since it's only executed once, for a single pixel if the rendertarget is set to a 1x1 texture it should be fine:
float4 PS_CalcScreenAverage(float4 pos : SV_Position, float2 texcoord : TEXCOORD) : SV_Target
{
    float4 average = 0.0.xxxx;
    for (int y = 0; y < BUFFER_HEIGHT; y++)
    {
        for (int x = 0; x < BUFFER_WIDTH; x++)
        {
            average += tex2D(RFX_backbuffer, texcoord);
        }
    }
    average /= BUFFER_WIDTH * BUFFER_HEIGHT;
    return average;
}
Cheers, crosire =)
The administrator has disabled public write access.

Advanced Lift Gain Gamma... could use help please. 1 year 4 months ago #16

crosire wrote:
DrakePhoenix wrote:
What's needed is to get a complete texture of a size at least as large as the screen/display resolution, and then smash that inside that 1x1 dimension to get the abstracted combination of the original. Maybe that's what you do in your AL code, but I kind of doubt it from what you've said so far (I get the impression you aimed for a more accurate average than that).
Not exactly fast, but since it's only executed once, for a single pixel if the rendertarget is set to a 1x1 texture it should be fine:
float4 PS_CalcScreenAverage(float4 pos : SV_Position, float2 texcoord : TEXCOORD) : SV_Target
{
    float4 average = 0.0.xxxx;
    for (int y = 0; y < BUFFER_HEIGHT; y++)
    {
        for (int x = 0; x < BUFFER_WIDTH; x++)
        {
            average += tex2D(RFX_backbuffer, texcoord);
        }
    }
    average /= BUFFER_WIDTH * BUFFER_HEIGHT;
    return average;
}

If I'm reading that code correctly you're basically taking a look at every individual pixel, adding them up, then dividing by that total number of pixels.

As I said before, not very efficient. I imagine that would decimate fps performance on most machines.

But LuciferHawk's additional clarification regarding abstraction gives me another thought (see below)...

Later,
Drake Phoenix
The administrator has disabled public write access.

Advanced Lift Gain Gamma... could use help please. 1 year 4 months ago #17

LuciferHawk wrote:
... snip ...

A little illustration of abstraction:

... snip ...

Hope that cleared things up a bit :)

Yes, it clears things up more. But it also gives me an idea...

Assuming we could cheaply get the content of the frame buffer en total (which is another problem still, as crosire's method isn't what I would consider cheap), how would the abstraction look if we were to limit it partially, say down to a 3x3 texture instead of a 1x1, and then get the average by sampling, adding, and average all 9?

What I mean is, lets say we have a 3x3 abstraction as follows:
1 2 3
4 5 6
7 8 9

Then we sample through each of those pixels and average them out in a manner like crosire showed. We create a separate variable (such as a float3) and at each sample we add the color from the pixel to that variable, then after we've sampled each one and gotten the sum of them all, divide that sum by 9. That would then give us the average of the 9 pixels present in the abstraction. Since the abstraction at 3x3 should, I think, still be relatively representative of a blurred version of the original, then that average should be reasonably close to a true average of all of the colors in the scene buffer, wouldn't it? And even if we left the abstraction at a 5x5 it would still be cheaper to sample through 25 pixels than to sample through, say 2073600 (1920x1080).

I mean, if I'm understanding your example of abstraction correctly, it works fairly well down to a certain level, but then if you try to bring it down too small, down to a 1x1, then what you get is merely one of the pixels from the 2x2, instead an average of them. Or am I still not fully understanding the limits of abstraction? Is there more to the data precision loss than I'm getting a handle on?

This also raises another question for me: Is the reason my current method returns essentially the color under the screen center point due to the problem of abstraction down to 1x1 itself? In other words, could we simply set the texBloom10 dimensions to 3x3 and get what could still be a relatively representative abstraction that could then be sampled in a manner similar to what I described above?

If I have time today, I think I'll change my code to try precisely that and see what the result ends up as.

Thanks,
Drake Phoenix
Last Edit: 1 year 4 months ago by DrakePhoenix.
The administrator has disabled public write access.

Advanced Lift Gain Gamma... could use help please. 1 year 4 months ago #18

  • Ganossa
  • Ganossa's Avatar
  • Offline
  • 최정장군
  • Posts: 790
  • Thank you received: 838
I am following the brute force approach already with an abstraction in the AL shader.
However, as you noticed too, we only need that because we render to the low res texture per pixel (otherwise 1x1 is sufficient). Therefore, I would like to go a bit further.
The problem is still that we currently do not have a method/language extension to copy the backbuffer and any existing texture into a new texture. This feature would not only solve this problem but make many other shaders much faster too (unless its also doing that per pixel internally).
I believe this is very possible in the source of the ReShade binaries (at least copying the backbuffer for each frame into a custom texture).
What do you think crosire?
Last Edit: 1 year 4 months ago by Ganossa.
The administrator has disabled public write access.

Advanced Lift Gain Gamma... could use help please. 1 year 4 months ago #19

What language are the ReShade binaries written in anyway?

If it is C++ or C# I wouldn't mind seeing the source code and poking around, just to try and learn a little more about graphics programing in general by looking through some actual code. But I understand completely, crosire, if you aren't comfortable with giving the source out.


Also, back to the subject more at hand... I tried using crosire's code for full sampling of the entire frame buffer. I received an error when it tried to run (actually, repeated errors) that the loop had attempted too many iterations. I don't recall off hand the exact error message, but it stated that the iteration limit for the shader being used or written to (or something like that) was 255. The system forcibly exited the loop once it reached that point. Because this happened multiple times, I think it was running into problems on the loop for iterating through x. Basically, it hit the first y, tried to iterate x and hit the limit, so exited the x sub-loop, then went to the next y, again tried to iterate through x and hit the limit... etc.

So I'm not sure if this was an issue with the way I implemented the code into the Custom.h, or if it is something inherent in ReShade that prevents iterations of this sort beyond 255, but I couldn't get it to work.

Also, when it was trying to work, my game froze completely (0 fps) each time it was iterating through x. This may have been due to the iteration limit error, or it may have been simply that my system was overloaded by the process each time. But it definitely wasn't working well.

I just thought you should know.


On the subject of getting the frame buffer as a texture and storing it to another texture... how do games normally present the frame buffer in the first place? We obviously can access it and the information there, because we can sample from it. This suggests to me that it is already stored as a texture in its own right, isn't it? So wouldn't we really only need a way copy the texture en total without having to sample through it? Something along the lines of (psuedo code) manipTexture = frameBufferTexture?

Also I had another thought. Probably not a very good one, because my brain doesn't seem to be working very well today (I think I'm getting sick). But for trying to determine an approximate average of the scene's colors and/or brightness, what about taking and averaging a number of random samples, instead of ordered samples or sampling the entire set? So when calling tex2D, instead of passing it 0.5 or texcoord, pass it float2(noise(xVector), noise(yVector)). Run that multiple times through an iterated for-loop.

How many randomly sampled points would be likely to be necessary to get an approximated average? Obviously the larger the number of samples, the more accurate the approximation would be, but I think at least it could be done using far fewer samples than sampling the entire frame buffer. For example, could potentially limit it to say 2000 samples as opposed to 2073600 (1920x1080 to use my own screen resolution for an example again).

Would it be accurate enough? Or would the number of random samples have to be so high that it wouldn't result in any sort of performance gain (compared to the AL method, that I haven't figured out yet)? It would be faster than fully sampling every single pixel though.


I hope all of that made sense.

Later,
Drake Phoenix
The administrator has disabled public write access.

Advanced Lift Gain Gamma... could use help please. 1 year 4 months ago #20

  • Ganossa
  • Ganossa's Avatar
  • Offline
  • 최정장군
  • Posts: 790
  • Thank you received: 838
Lets keep it simple :-)

Let me repeat my two previous questions to crosire first:

Is a copy (in source) of a renderTarget/texture to a texture with custom size internally the same as sampling it in HLSL?

If not, can we get a language feature to initiate a copy of the back buffer or any existing texture to a new arbitrary texture?


If above cannot be done, any brute force approach will have no different result than the AL implementation, only different accuracy and performance.
Reducing samples is basically that and you would not need random samples for an already random source/image.

By the way, source should mainly be C++.
The administrator has disabled public write access.
  • Page:
  • 1
  • 2