lycium
|
|
« Reply #15 on: November 22, 2015, 01:35:21 AM » |
|
Just read about it and implement it From what I saw here, it uses 4 uints of state: https://en.wikipedia.org/wiki/XorshiftSo you make a buffer with 4 uints per thread (which can be lots on a GPU), and pass this buffer to your rand() function. It uses a thread ID to look up its current xyzw values, modifying them as needed before returning the random value.
|
|
|
Logged
|
|
|
|
3dickulus
|
|
« Reply #16 on: November 22, 2015, 02:08:40 AM » |
|
@lycium tnx for the link seed state with time? xorshift128plus() works in shader code? @Patryk a follow-up image of anisotropic @ 100 subframes 1.0 on the left and 16.0 on the right...
|
|
« Last Edit: November 24, 2015, 04:16:47 AM by 3dickulus »
|
Logged
|
|
|
|
Patryk Kizny
|
|
« Reply #17 on: November 22, 2015, 02:14:47 AM » |
|
@patryk so you have reverted to the original value, 43758.5453, everywhere and used 3758.5453 with IQ-Clouds only and the pixelation still exists when mipmap is disabled (default) ?
No, I did not revert as until now I did not see any drawbacks of the replacement. The problem with pixelation is NOT related at all to rand() and has been fixed thanks to disabling MIPMAP.
|
|
|
Logged
|
Visual Artist, Director & Cinematographer specialized in emerging imaging techniques.
|
|
|
lycium
|
|
« Reply #18 on: November 22, 2015, 02:22:22 AM » |
|
@lycium tnx for the link seed state with time? xorshift128plus() works in shader code? I'm not sure how best to seed xorshift, but you should be able to just use the thread ID as seed. Never used it myself, but I heard it's popular for its small amount of state and reasonably good statistical properties. As for whether or not it works in "shaders", I assume you mean GLSL. I'm not sure about the current standards, but hopefully it should be able to do proper (unsigned) integer arithmetic.
|
|
|
Logged
|
|
|
|
3dickulus
|
|
« Reply #19 on: November 22, 2015, 02:55:45 AM » |
|
@Patryk mipmap is disabled by default, as near as I can tell no textures use mipmap unless you explicitly turn it on using #TexParameter upon reviewing Qt GUI docs I find that "Mipmapping is disabled by default." @lycium after a little tinkering I get lots of these... 0(434) : warning C7548: '<<' requires "#extension GL_EXT_gpu_shader4 : enable" before use 0(434) : warning C7548: '^' requires "#extension GL_EXT_gpu_shader4 : enable" before use can this be done in a more generic and compatible way? it would be nice if it didn't rely on a specific version of GL or shader language. pow() and shift()
|
|
|
Logged
|
|
|
|
lycium
|
|
« Reply #20 on: November 22, 2015, 03:02:48 AM » |
|
I think those extensions are for integer operations, i.e. exactly what you need. It's not possible to implement those integer operations to full range in floating point without using double precision. If you can use double precision, you really should be able to use integers
|
|
|
Logged
|
|
|
|
3dickulus
|
|
« Reply #21 on: November 22, 2015, 03:11:50 AM » |
|
using ivec2 for seed and xy never considered double /* The state must be seeded so that it is not everywhere zero. */ ivec2 seed;
float xorshift128plus(void) { ivec2 s = seed; seed.x = s.y; s.x ^= s.x << 23; // a s.x ^= s.x >> 17; // b s.x ^= s.y ^ (s.y >> 26); // c seed.y = s.x; return 1.0 / (float(s.x) + float(s.y)); }
float rand(vec2 co){ // implementation found at: lumina.sourceforge.net/Tutorials/Noise.html // return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453); seed = ivec2(43758,5453); return xorshift128plus(); }
I understand that the above may loose some precision, but this is just a test to try and apply the algorithm, the bit shifts probably exceed ivec2 size. could be adjusted so we have a xorshift64plus() function ? edit: yes I know the above code doesn't work, return value alone is way too random, needs to be co.xy centric
|
|
« Last Edit: November 22, 2015, 06:45:53 AM by 3dickulus »
|
Logged
|
|
|
|
lycium
|
|
« Reply #22 on: November 22, 2015, 04:13:04 AM » |
|
I guess we have very different goals; when I use a random number generator for a statistical process (eg rendering), I want to be able to sleep at night knowing the stuff works as intended To be more specific: I would check that your uniform distribution (which is what you want from a rand() function) is indeed uniform! Otherwise everything you base on it will be all wonky and wrong... Edit: PS. We should probably split this discussion of random numbers off into a different thread, since it is unrelated to the texture mapping problem Patryk had.
|
|
|
Logged
|
|
|
|
3dickulus
|
|
« Reply #23 on: November 22, 2015, 05:17:54 AM » |
|
Could a 64bit version have a decently uniform distribution but just in a smaller window, (so to speak), my only goal is functionality, if it is just too sloppy for GLSL or DE in particular, then we leave Fragmentarium fragments as they are and keep looking and testing.
|
|
|
Logged
|
|
|
|
Syntopia
|
|
« Reply #24 on: November 22, 2015, 10:18:59 AM » |
|
A few comments about RNG's: In typical cases you draw very few random numbers per shader invocation (per frame). You are probably more interested in a good hash function than in a good RNG. It would be great if we could store the state of the RNG's between frames (for instance when doing progressive rendering or anything with multiple frames), but I don't believe it is possible in GLSL (at least it would be hard: you'd have to write to two pixel buffers: one for the image samples, and another for the RNG state - they would be the same dimensions). The biggest problem is how to seed each thread (~each pixel) on the GPU properly. Just using something like the ThreadID (which is not available in GLSL) or the screen space coordinates will give strongly correlated random number series. This is described in detail here: http://www.reedbeta.com/blog/2013/01/12/quick-and-easy-gpu-random-numbers-in-d3d11/The 'Wang hash' used to seed the RNG's in the link use 32-bit ints. Since we do not have access to the ThreadID, one possibility would be to use the screen coordinates times the current frame number, and reinterpret that as an int, using 'floatBitsToInt'. Here is some sample code: #extension GL_ARB_shader_bit_encoding : enable #extension GL_EXT_gpu_shader4 : enable #extension GL_ARB_gpu_shader5 : enable #include "2D.frag"
uint wang_hash(uint seed) { seed = (seed ^ 61u) ^ (seed >> 16u); seed *= 9u; seed = seed ^ (seed >> 4u); seed *= 0x27d4eb2du; seed = seed ^ (seed >> 15u); return seed ; }
// Wrapper for getting from float to ints. This certainly looses precision. I imagine we could do better here. float wang_hash_fp(vec2 pos) { uint ix = floatBitsToUint(pos.x); uint iy = floatBitsToUint(pos.y); // I use two hash calls to untangle pos.x and pos.y return float(wang_hash(wang_hash(ix)+iy)) / 4294967296.0; }
// old 'rand1' for comparison. float rand1(vec2 co){ return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453); }
vec3 color(vec2 z) { // return rand1(z) < 0.5 ? vec3(1.0) : vec3(0.0); return wang_hash_fp(z) < 0.5 ? vec3(1.0) : vec3(0.0); }
The above code is only for generating decent seeds. If you need to get a series of random number the xorshifts could be used starting from these seeds. I have attached a screenshot of rand1 vs wang_hash_fp - this is at zoom-level 100. As can be seen rand1 is sensitive to the input value range. However, if you adjust the input value range rand1 will be suitable for most cases (I use it as a RNG for my path tracers without any visible problems).
|
|
|
|
3dickulus
|
|
« Reply #25 on: November 22, 2015, 11:38:45 AM » |
|
Thank you Syntopia for the wang_hash snippet, I think this RNG talk stems from here... http://www.fractalforums.com/fragmentarium/updating-of-de-raytracer/msg88473/#msg88473...the clouds have parts that look like blocky marshmallows, IQ-Clouds uses a vec3 variant of rand1 and it looked like it was loosing bit precision some how so I poked around a bit and found that reducing 43758.5453 to 3758.5453 fixed this blocky artefact but not completely so I put it back and tried something else... the original... float rand(vec3 co){// implementation found at: lumina.sourceforge.net/Tutorials/Noise.html return fract(sin(dot(co*0.123,vec3(12.9898,78.233,112.166))) * 43758.5453); } my change... float rand(vec3 co){// implementation found at: lumina.sourceforge.net/Tutorials/Noise.html return fract(sin(dot(co,vec3(12.9898,78.233,112.166))) * 43758.5453); } ...this seems to allow IQ-Clouds to render with no blocky artefacts, I've had no problems with rand1(variant) function until IQ-Clouds came along, I agree, is suitable for pathtracers and I don't think the vec3 variant of rand1 is used anywhere else so felt safe to change it. My only logic for the above change was that something was getting too big or too small
|
|
« Last Edit: November 23, 2015, 12:19:18 AM by 3dickulus »
|
Logged
|
|
|
|
3dickulus
|
|
« Reply #26 on: November 22, 2015, 11:49:21 AM » |
|
@Syntopia Q:will the #extention s restrict use to only newer cards?
|
|
|
Logged
|
|
|
|
Syntopia
|
|
« Reply #27 on: November 22, 2015, 02:04:50 PM » |
|
Yep. Actually a nicer way would be to put a '#version 330' instead.
|
|
|
Logged
|
|
|
|
Crist-JRoger
|
|
« Reply #28 on: November 22, 2015, 07:06:34 PM » |
|
|
|
|
Logged
|
|
|
|
3dickulus
|
|
« Reply #29 on: November 23, 2015, 12:49:48 AM » |
|
I tried '#version 330' it complains about all the stuff that is not 3.3 but enabling the '#extension s' does not complain about the current code so I will make an effort to update Raytracer.frags. @Syntopia is it as easy as I think to create a vec3 variant?... float wang_hash_fp(vec3 pos) { uint ix = floatBitsToUint(pos.x); uint iy = floatBitsToUint(pos.y); uint iz = floatBitsToUint(pos.z); // I use three hash calls to untangle pos.xyz return float(wang_hash(wang_hash(wang_hash(ix)+iy)+iz) / 4294967296.0; } bitshifts and logic ops have got to be faster than fract(sin(dot(vec3)))
|
|
|
Logged
|
|
|
|
|