POV-Ray : Newsgroups : povray.off-topic : WebGL Server Time
11 Oct 2026 14:34:48 EDT (-0400)
  WebGL (Message 1 to 28 of 28)  
From: Orchid Win7 v1
Subject: WebGL
Date: 5 Jun 2016 10:05:26
Message: <575431a6$1@news.povray.org>
Hey guys. Remember this?

http://madebyevan.com/webgl-path-tracing/

Yeah, well now there's this:

http://jonathan-olson.com/tesserace/tests/3d.html

Firstly, it looks a bit less like a computer simulation and more like 
the Real World. Only a bit, but hey.

My favourite feature is that you can adjust the lens aperture and focus 
distance. I was just wondering whether you could accurately simulate 
depth of field using path tracing! Now we just need to be able to change 
the focal length of the lens too... (There are also options for 
adjusting the exposure.)

For a camera nerd, this is quite fun! (Well, it beats Nikon's "lens 
simulator", which just shows a static JPEG with variable magnification!)

Sometimes I really wish I knew how to do this stuff for myself...

What *would* be interesting is to see how this handles a scene of 
non-trivial complexity. I'm going to say "like a glacier"...


Post a reply to this message

From: Orchid Win7 v1
Subject: Re: WebGL
Date: 5 Jun 2016 10:11:27
Message: <5754330f$1@news.povray.org>
On 05/06/2016 03:05 PM, Orchid Win7 v1 wrote:

> What *would* be interesting is to see how this handles a scene of
> non-trivial complexity. I'm going to say "like a glacier"...

...well, there is this:

http://reindernijhoff.net/2015/04/realtime-webgl-path-tracer/

Granted, it's grainy as *hell*, but at a tiny resolution it's watchable.

Maybe give it ten years, and the GPU will have enough horsepower for 
people to actually put this stuff in game engines.

Maybe.


Post a reply to this message

From: scott
Subject: Re: WebGL
Date: 6 Jun 2016 08:36:10
Message: <57556e3a@news.povray.org>
> My favourite feature is that you can adjust the lens aperture and focus
> distance. I was just wondering whether you could accurately simulate
> depth of field using path tracing! Now we just need to be able to change
> the focal length of the lens too... (There are also options for
> adjusting the exposure.)
>
> For a camera nerd, this is quite fun! (Well, it beats Nikon's "lens
> simulator", which just shows a static JPEG with variable magnification!)
>
> Sometimes I really wish I knew how to do this stuff for myself...

Follow a tutorial on WebGL - or if you want to skip all the html/js 
boilerplate stuff you'll need to know, go straight to something like 
shadertoy. There are plenty of examples, and shadertoy now supports 
reading back pixels from previous frames, so you can do 
multi-frame-averaging for path-tracing amongst other effects.

Building a lens simulator (with real-time path-traced results) sounds 
feasible and very interesting.


Post a reply to this message

From: Orchid Win7 v1
Subject: Re: WebGL
Date: 8 Jun 2016 13:06:27
Message: <57585093$1@news.povray.org>
On 06/06/2016 01:36 PM, scott wrote:
>> Sometimes I really wish I knew how to do this stuff for myself...
>
> Follow a tutorial on WebGL - or if you want to skip all the html/js
> boilerplate stuff you'll need to know, go straight to something like
> shadertoy. There are plenty of examples, and shadertoy now supports
> reading back pixels from previous frames, so you can do
> multi-frame-averaging for path-tracing amongst other effects.
>
> Building a lens simulator (with real-time path-traced results) sounds
> feasible and very interesting.

Well, I went to the ShaderToy website... and discovered that apparently 
Opera has WebGL support that's flaky as *hell*! The number of times I 
have to close and reopen the browser to turn WebGL back on...

Some of the shaders on offer are absurd. I saw one that was a real-time 
simulation of waves crashing on a giant sea... fractal wave 
distribution, subsurface scattering, specular highlights... and wondered 
why the hell they don't put this in games yet!

But mostly, attempting to browse the shaders just broke Opera.

After about an hour of squinting at the sparse ShaderToy documentation 
and making some educated guesses, I did eventually manage to build a 
trivial ray-tracer that runs in real-time. I have no idea how to do 
random number generation yet, but we'll see...


Post a reply to this message

From: scott
Subject: Re: WebGL
Date: 9 Jun 2016 03:11:22
Message: <5759169a$1@news.povray.org>
> After about an hour of squinting at the sparse ShaderToy documentation
> and making some educated guesses, I did eventually manage to build a
> trivial ray-tracer that runs in real-time.

Come on, make it public and post the link then for all to see :-)

I had a bit more of a think about how you might do a lens simulation. 
You start by firing the ray from a random point within the pixel on the 
sensor, and fire it at a random point on the surface of the first lens 
element. Then follow that ray through the lenses (assume no reflection 
for speed here), if it gets too far from the lens axis then return 
black, otherwise once it gets out of the end of the lenses and into the 
scene do the raytrace as normal.

With the above you should be able to move about individual lens elements 
in almost real time (it might take a second or two to smooth out the noise).

 > I have no idea how to do
> random number generation yet, but we'll see...

Yes that is tricky, but I'm sure you've already looked at other shaders 
there to see how they do it. Something involving the sine of the 
coordinates multiplied by some huge value IIRC.


Post a reply to this message

From: Orchid Win7 v1
Subject: Re: WebGL
Date: 9 Jun 2016 13:53:43
Message: <5759ad27$1@news.povray.org>
On 09/06/2016 08:11 AM, scott wrote:
>> After about an hour of squinting at the sparse ShaderToy documentation
>> and making some educated guesses, I did eventually manage to build a
>> trivial ray-tracer that runs in real-time.
>
> Come on, make it public and post the link then for all to see :-)

I'm sure you've all seen a white sphere with some coloured lights. :-P

> I had a bit more of a think about how you might do a lens simulation.
> You start by firing the ray from a random point within the pixel on the
> sensor, and fire it at a random point on the surface of the first lens
> element. Then follow that ray through the lenses (assume no reflection
> for speed here), if it gets too far from the lens axis then return
> black, otherwise once it gets out of the end of the lenses and into the
> scene do the raytrace as normal.
>
> With the above you should be able to move about individual lens elements
> in almost real time (it might take a second or two to smooth out the
> noise).

That sounds quite complex. (In particular, it seems to require me to 
actually design a real lens assembly, and implement real refraction.)

I was thinking more along the lines of a camera entity that fires rays 
in a pattern that matches a theoretical ideal lens. But I need to figure 
out the equations for that first...

>> I have no idea how to do
>> random number generation yet, but we'll see...
>
> Yes that is tricky, but I'm sure you've already looked at other shaders
> there to see how they do it. Something involving the sine of the
> coordinates multiplied by some huge value IIRC.

Yeah, not just a random number per pixel, but *multiple* random numbers! 
Multiple, statistically-independent numbers... This is not trivial.


Post a reply to this message

From: Orchid Win7 v1
Subject: Re: WebGL
Date: 9 Jun 2016 14:00:16
Message: <5759aeb0$1@news.povray.org>
On 08/06/2016 06:06 PM, Orchid Win7 v1 wrote:
> After about an hour of squinting at the sparse ShaderToy documentation
> and making some educated guesses, I did eventually manage to build a
> trivial ray-tracer that runs in real-time. I have no idea how to do
> random number generation yet, but we'll see...

Yesterday I had another go at this, and hit a show-stopping snag: No 
flow control.

It seems that implementing reflection is essentially impossible. You 
can't do recursive functions. You can't do arrays. [Well, you can... but 
the array indices must be known at compile-time, thus negating all 
possible advantages of arrays.] You can't do while-loops with 
complicated break or continue conditions. You can't do function 
pointers... In short, it seems that all code jumps and data accesses 
must be statically known at compile-time.

Obviously, the rendering equation is inherently recursive. You fire a 
ray, which spawns further rays with are recursively traced like the 
first one. But without the ability to dynamically trace different 
primitives differently, or apply different surface characteristics 
dynamically, or basically do *anything* dynamically... You end up 
basically needing to write some kind of engine to *generate* the WebGL 
code, hard-coded to the particular geometry of your scene.

I see now why no computer game will ever use this technology. It's fast 
because it's *completely inflexible*.

I am now baffled as to how all the *other* people managed to do so much 
cool stuff in a language that abhors conditional branching... Clearly 
I'm going to have to cheat and look at the source code. But I fear I 
won't be able to comprehend any of it.

In summary, it appears that implementing reflection is mathematically 
impossible. I may perhaps still be able to realise my dream of rendering 
depth of field effects realistically. (Although without a nice detailed 
scene to look at, it might be rather disappointing...)


Post a reply to this message

From: Orchid Win7 v1
Subject: Re: WebGL
Date: 9 Jun 2016 14:46:06
Message: <5759b96e$1@news.povray.org>
On 09/06/2016 06:53 PM, Orchid Win7 v1 wrote:
> On 09/06/2016 08:11 AM, scott wrote:
>>> After about an hour of squinting at the sparse ShaderToy documentation
>>> and making some educated guesses, I did eventually manage to build a
>>> trivial ray-tracer that runs in real-time.
>>
>> Come on, make it public and post the link then for all to see :-)
>
> I'm sure you've all seen a white sphere with some coloured lights. :-P

OK, here ya go:

struct Ray
{
     vec3 S, D;
};

vec3 RayPoint(in Ray ray, in float t)
{
     return ray.S + ray.D*t;
}

Ray Camera(in vec2 uv)
{
     Ray ray;
     ray.S = vec3(0, 0, -5);
     ray.D = vec3(uv.x, uv.y, 1);
     return ray;
}

struct Sphere
{
     vec3 C;
     float R;
     float R2;
};

Sphere MakeSphere(vec3 center, float radius)
{
     return Sphere(center, radius, radius*radius);
}

float IsectSphere(in Ray ray, in Sphere sphere)
{
     // (P - C)^2 = r^2
     // (P - C)^2 - r^2 = 0
     // ((Dt + S) - C)^2 - r^2 = 0
     // (Dt + S - C)^2 - r^2 = 0
     // (Dt + V)^2 - r^2 = 0
     // D^2 t^2 + 2DVt + V^2 - r^2 = 0

     vec3 V = ray.S - sphere.C;
     float a = dot(ray.D, ray.D);
     float b = 2.0*dot(V, ray.D);
     float c = dot(V, V) - sphere.R2;

     float det = b*b - 4.0*a*c;
     if (det >= 0.0)
     {
         return (0.0 - b - sqrt(det))/(2.0*a);
     }
     else
     {
         return -1.0;
     }
}

float Illuminate(vec3 light, vec3 surface, vec3 normal)
{
     vec3 d = light - surface;
     return dot(normalize(d), normalize(normal));
}

vec2 MapScreen(vec2 xy)
{
     return (xy - iResolution.xy/2.0) / iResolution.y;
}

vec2 MapScreenExact(vec2 xy)
{
     return (xy - iResolution.xy/2.0) / iResolution.xy;
}

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
     Sphere s1 = MakeSphere(vec3(MapScreenExact(iMouse.xy)*4.0, 0), 1.0);

     vec3 l1 = vec3(-5, +5, -3); // Red
     vec3 l2 = vec3(+5, +5, -3); // Green
     vec3 l3 = vec3( 0, -5, -3); // Blue

     Ray cr = Camera(MapScreen(fragCoord.xy));
     float t = IsectSphere(cr, s1);

     if (t > 0.0)
     {
         vec3 surface = RayPoint(cr, t);
         vec3 normal = surface - s1.C;
         float b1 = Illuminate(l1, surface, normal);
         float b2 = Illuminate(l2, surface, normal);
         float b3 = Illuminate(l3, surface, normal);
         fragColor = vec4(b1, b2, b3, 1);
     }
     else
     {
         fragColor = vec4(0, 0, 0, 0);
     }
}

Copy & paste into the ShaderToy website and hit Go. You can click on the 
image to move the sphere around. (It doesn't follow your cursor exactly 
because of the perspective transformation.)


Post a reply to this message

From: scott
Subject: Re: WebGL
Date: 10 Jun 2016 02:59:11
Message: <575a653f$1@news.povray.org>
> In summary, it appears that implementing reflection is mathematically
> impossible. I may perhaps still be able to realise my dream of rendering
> depth of field effects realistically. (Although without a nice detailed
> scene to look at, it might be rather disappointing...)

Obviously it's not, because there are plenty of shadertoy examples 
showing it:

https://www.shadertoy.com/view/4ssGWX

Surfaces that reflect *OR* refract are trivial:

for(i=0;i<MAX_TRACE_DEPTH;i++)
{
   intersect = Trace( ray );
   if( REFLECT(intersect) ) ray = ReflectRay(ray , intersect);
   if( REFRACT(intersect) ) ray = RefractRay(ray , intersect);
}

To do surfaces that do both you need to choose randomly at each 
intersection which ray to follow (weighted appropriately depending on 
the material) and then average over a larger number of samples. You can 
either do many samples per frame (but obviously this gets slow for 
complex scenes), or what is commonly done is to average over many frames 
(and reset the average if the camera is moved). Or both.


Post a reply to this message

From: Orchid Win7 v1
Subject: Re: WebGL
Date: 10 Jun 2016 03:23:54
Message: <575a6b0a@news.povray.org>
On 10/06/2016 07:59 AM, scott wrote:
>> In summary, it appears that implementing reflection is mathematically
>> impossible. I may perhaps still be able to realise my dream of rendering
>> depth of field effects realistically. (Although without a nice detailed
>> scene to look at, it might be rather disappointing...)
>
> Obviously it's not, because there are plenty of shadertoy examples
> showing it:
>
> https://www.shadertoy.com/view/4ssGWX

Interesting. On my browser, that just crashes.

> Surfaces that reflect *OR* refract are trivial:
>
> for(i=0;i<MAX_TRACE_DEPTH;i++)
> {
> intersect = Trace( ray );
> if( REFLECT(intersect) ) ray = ReflectRay(ray , intersect);
> if( REFRACT(intersect) ) ray = RefractRay(ray , intersect);
> }

The difficulty is figuring out what surface was hit just from the 
intersection coordinates. And perhaps a perfect reflection isn't so 
hard, but I wanted to have the colour change slightly on each 
reflection... but I can't figure out how to stack up the colour changes 
until you get to the end of the reflection chain, and then unstack them 
again.

> To do surfaces that do both you need to choose randomly at each
> intersection which ray to follow (weighted appropriately depending on
> the material) and then average over a larger number of samples. You can
> either do many samples per frame (but obviously this gets slow for
> complex scenes), or what is commonly done is to average over many frames
> (and reset the average if the camera is moved). Or both.

Still trying to work out how you "average over several frames". 
ShaderToy is great fun, but so *utterly* undocumented... it's quite hard 
to figure out how to do anything.


Post a reply to this message

From: scott
Subject: Re: WebGL
Date: 10 Jun 2016 03:28:32
Message: <575a6c20$1@news.povray.org>
>> I'm sure you've all seen a white sphere with some coloured lights. :-P
>
> OK, here ya go:

Welcome to the dark side...   :-)


Post a reply to this message

From: scott
Subject: Re: WebGL
Date: 10 Jun 2016 03:33:33
Message: <575a6d4d$1@news.povray.org>
> That sounds quite complex. (In particular, it seems to require me to
> actually design a real lens assembly, and implement real refraction.)

Yes I realised that later too, Google didn't seem to throw up any real 
data on proper lens design (for pretty obvious reasons), only very 
simple examples. Still it might be interesting, and you never know if 
you made it slick enough one of the big lens manufacturers may show some 
interest in you or your code.

> I was thinking more along the lines of a camera entity that fires rays
> in a pattern that matches a theoretical ideal lens. But I need to figure
> out the equations for that first...

Look through the POV source? :-)

> Yeah, not just a random number per pixel, but *multiple* random numbers!
> Multiple, statistically-independent numbers... This is not trivial.

Exactly, poor RNGs in these sorts of things can cause some bizarre 
artefacts.


Post a reply to this message

From: scott
Subject: Re: WebGL
Date: 10 Jun 2016 03:50:04
Message: <575a712c$1@news.povray.org>
>> Obviously it's not, because there are plenty of shadertoy examples
>> showing it:
>>
>> https://www.shadertoy.com/view/4ssGWX
>
> Interesting. On my browser, that just crashes.

Odd. But then you did say half the examples on shadertoy didn't work on 
whatever browser you had. Tried Chrome/IE?

> The difficulty is figuring out what surface was hit just from the
> intersection coordinates.

You could have an intersection struct with surface normal and material 
ID in it as well.

> And perhaps a perfect reflection isn't so
> hard, but I wanted to have the colour change slightly on each
> reflection... but I can't figure out how to stack up the colour changes
> until you get to the end of the reflection chain, and then unstack them
> again.

You need to keep track of a "cumulative coefficient of reflection" value 
as you go (make it a vec3 if you want coloured reflections):

vec3 CCOR = vec3(1,1,1);
vec3 colour = vec3(0,0,0);
for(int i=0;i<MAX_TRACE_DEPTH;i++)
{
   isect = Raytrace();
   colour += CCOR * isect.diffuse_colour;
   CCOR *= isect.reflection_colour;
}


Post a reply to this message

From: Orchid Win7 v1
Subject: Re: WebGL
Date: 10 Jun 2016 14:03:43
Message: <575b00ff$1@news.povray.org>
>> Interesting. On my browser, that just crashes.
>
> Odd. But then you did say half the examples on shadertoy didn't work on
> whatever browser you had. Tried Chrome/IE?

Yeah, it seems the smaller examples run just fine, but bigger ones freak 
it out. In particular, browsing the shaders seems to try to run too many 
shaders at once and break Opera. (And once it's broken, only restarting 
the browser will fix it. It just doesn't *try* any more.)

>> The difficulty is figuring out what surface was hit just from the
>> intersection coordinates.
>
> You could have an intersection struct with surface normal and material
> ID in it as well.

Material ID is something I hadn't thought of. (I'm trying to do a 
checkerboard for the ground, which makes calculating the colour... 
interesting.)

> You need to keep track of a "cumulative coefficient of reflection" value
> as you go (make it a vec3 if you want coloured reflections):
>
> vec3 CCOR = vec3(1,1,1);
> vec3 colour = vec3(0,0,0);
> for(int i=0;i<MAX_TRACE_DEPTH;i++)
> {
> isect = Raytrace();
> colour += CCOR * isect.diffuse_colour;
> CCOR *= isect.reflection_colour;
> }

I'm thinking about the associative/distributive property of the reals, 
though... If one object adds 4% blue and then reflects 95%, and the next 
object adds %6 yellow and reflects 50%, and the final object is green, 
you need

   ((green * 50%) + 6% yellow) * 95% + 4% blue

but the algorithm above gives

   ((4% blue * 95%) + 6% yellow) * 50% + green

which I don't think simplifies to the same result. You'd have to neither 
trace all the rays backwards (i.e., from scene to camera), which is 
laughably inefficient, or somehow store a history (array?) of all the 
intermediate steps so you can reverse them...

...then again, I think I'll just give up on reflection, and see if I can 
make the lens work with a checkerboard. :-P


Post a reply to this message

From: Orchid Win7 v1
Subject: Re: WebGL
Date: 10 Jun 2016 14:06:39
Message: <575b01af$1@news.povray.org>
On 10/06/2016 08:33 AM, scott wrote:
>> That sounds quite complex. (In particular, it seems to require me to
>> actually design a real lens assembly, and implement real refraction.)
>
> Yes I realised that later too, Google didn't seem to throw up any real
> data on proper lens design (for pretty obvious reasons), only very
> simple examples. Still it might be interesting, and you never know if
> you made it slick enough one of the big lens manufacturers may show some
> interest in you or your code.

Pfft. I doubt anything I'll ever do will be "slick". But maybe I can 
make something interesting.

(Would be nice if ShaderToy would let you add sliders to control your 
shader!)

>> I was thinking more along the lines of a camera entity that fires rays
>> in a pattern that matches a theoretical ideal lens. But I need to figure
>> out the equations for that first...
>
> Look through the POV source? :-)

Any idea where in the 25,000,000 LoC I should start looking?

(You never know, maybe there's a file named camera.c or something...)

>> Yeah, not just a random number per pixel, but *multiple* random numbers!
>> Multiple, statistically-independent numbers... This is not trivial.
>
> Exactly, poor RNGs in these sorts of things can cause some bizarre
> artefacts.

There's a couple of StackOverflow questions about this. It seems the 
best results are obtained by using an integer hash function... yet 
ShaderToy seems to not support bitwise integer operations, so that's 
kind of not an option.

That said, there's a widely used sin-based method, which gives awful 
results. But if you iterate it a few times... it's not *too* bad.

Still waiting on how you average consecutive frames.


Post a reply to this message

From: Orchid Win7 v1
Subject: Re: WebGL
Date: 10 Jun 2016 14:10:01
Message: <575b0279$1@news.povray.org>
On 10/06/2016 07:06 PM, Orchid Win7 v1 wrote:
> (You never know, maybe there's a file named camera.c or something...)

There is, in fact, a camera.cpp file.



OMG, look at this:

/// POV-Ray is based on the popular DKB raytracer version 2.12.
/// DKBTrace was originally written by David K. Buck.
/// DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins.

I am *almost certain* that the man I bought my flat from was called 
Aaron Collins... o_O


Post a reply to this message

From: Orchid Win7 v1
Subject: Re: WebGL
Date: 12 Jun 2016 08:02:44
Message: <575d4f64$1@news.povray.org>
On 10/06/2016 08:24 AM, Orchid Win7 v1 wrote:

> Still trying to work out how you "average over several frames".
> ShaderToy is great fun, but so *utterly* undocumented... it's quite hard
> to figure out how to do anything.

OK, I think I've cracked it:

If you click the "new tab" button, it gives you another shader, that 
renders to Buffer A. If you then set iChannel0 to be Buffer A, you can 
do a texture2D(iChannel0, coords) to read the previous frame's pixel value.

Now you just need to set the main image shader to be a texture2D() 
lookup on Buffer A, and you're golden.

Not what you'd call "obvious"...


Post a reply to this message

From: Orchid Win7 v1
Subject: Re: WebGL
Date: 12 Jun 2016 09:30:09
Message: <575d63e1$1@news.povray.org>
On 10/06/2016 07:10 PM, Orchid Win7 v1 wrote:
> On 10/06/2016 07:06 PM, Orchid Win7 v1 wrote:
>> (You never know, maybe there's a file named camera.c or something...)
>
> There is, in fact, a camera.cpp file.

Sadly, it contains the data structures for *describing* the camera, but 
nothing whatsoever to do with *casting rays*.

It seems *that* is in tracepixel.cpp. Looking into it further, it seems 
that TracePixel::CreateCameraRay() has a giant switch-block for every 
possible camera type, but they all end with JitterCameraRay(). This, 
seemingly, is where the focal blur stuff happens.

In full:

void TracePixel::JitterCameraRay(Ray& ray, DBL x, DBL y, size_t ray_number)
{
     DBL xjit, yjit, xlen, ylen, r;
     Vector3d temp_xperp, temp_yperp, deflection;

     r = camera.Aperture * 0.5;

     Jitter2d(x, y, xjit, yjit);
     xjit *= focalBlurData->Max_Jitter * 2.0;
     yjit *= focalBlurData->Max_Jitter * 2.0;

     xlen = r * (focalBlurData->Sample_Grid[ray_number].x() + xjit);
     ylen = r * (focalBlurData->Sample_Grid[ray_number].y() + yjit);

     // Deflect the position of the eye by the size of the aperture, and in
     // a direction perpendicular to the current direction of view.

     temp_xperp = focalBlurData->XPerp * xlen;
     temp_yperp = focalBlurData->YPerp * ylen;

     deflection = temp_xperp - temp_yperp;

     ray.Origin += deflection;

     // Deflect the direction of the ray in the opposite direction we 
deflected
     // the eye position.  This makes sure that we are looking at the 
same place
     // when the distance from the eye is equal to "Focal_Distance".

     ray.Direction *= focalBlurData->Focal_Distance;
     ray.Direction -= deflection;

     ray.Direction.normalize();
}

Good luck *ever* figuring out what the hell any of it means, of course...


Post a reply to this message

From: Orchid Win7 v1
Subject: Re: WebGL
Date: 12 Jun 2016 09:48:33
Message: <575d6831$1@news.povray.org>
On 12/06/2016 02:30 PM, Orchid Win7 v1 wrote:
> In full:
>
> void TracePixel::JitterCameraRay(Ray& ray, DBL x, DBL y, size_t ray_number)
> {
> DBL xjit, yjit, xlen, ylen, r;
> Vector3d temp_xperp, temp_yperp, deflection;
>
> r = camera.Aperture * 0.5;
>
> Jitter2d(x, y, xjit, yjit);
> xjit *= focalBlurData->Max_Jitter * 2.0;
> yjit *= focalBlurData->Max_Jitter * 2.0;
>
> xlen = r * (focalBlurData->Sample_Grid[ray_number].x() + xjit);
> ylen = r * (focalBlurData->Sample_Grid[ray_number].y() + yjit);
>
> // Deflect the position of the eye by the size of the aperture, and in
> // a direction perpendicular to the current direction of view.
>
> temp_xperp = focalBlurData->XPerp * xlen;
> temp_yperp = focalBlurData->YPerp * ylen;
>
> deflection = temp_xperp - temp_yperp;
>
> ray.Origin += deflection;
>
> // Deflect the direction of the ray in the opposite direction we deflected
> // the eye position. This makes sure that we are looking at the same place
> // when the distance from the eye is equal to "Focal_Distance".
>
> ray.Direction *= focalBlurData->Focal_Distance;
> ray.Direction -= deflection;
>
> ray.Direction.normalize();
> }
>
> Good luck *ever* figuring out what the hell any of it means, of course...

I'm not entirely sure why that method is so complicated, but it 
*appears* the key part of the algorithm is this:

ray.Origin += deflection;
ray.Direction *= focus_distance;
ray.Direction -= deflection;
ray.Direction.normalize();

The aperture determines the maximum size of deflection, and the focus 
distance is mentioned above. Plugging these two into my shader, I seem 
to be able to get it to produce blurry images focused at a specific 
distance.


Post a reply to this message

From: Orchid Win7 v1
Subject: Re: WebGL
Date: 12 Jun 2016 09:53:22
Message: <575d6952@news.povray.org>
On 12/06/2016 02:48 PM, Orchid Win7 v1 wrote:
> I'm not entirely sure why that method is so complicated, but it
> *appears* the key part of the algorithm is this:
>
> ray.Origin += deflection;
> ray.Direction *= focus_distance;
> ray.Direction -= deflection;
> ray.Direction.normalize();
>
> The aperture determines the maximum size of deflection, and the focus
> distance is mentioned above. Plugging these two into my shader, I seem
> to be able to get it to produce blurry images focused at a specific
> distance.

In case anybody cares:

float Rand(vec2 v)
{
     return fract(sin(dot(v.xy ,vec2(12.9898,78.233))) * 43758.5453);
}

float Rand(vec4 v)
{
     float a = Rand(v.xy);
     float b = Rand(v.zw);
     vec2 ab = vec2(a, b);
     float c = Rand(ab * v.xy);
     float d = Rand(ab * v.zw);
     vec2 cd = vec2(c, d);
     return Rand(ab * cd);
}



struct Ray
{
     vec3 S, D;
};

vec3 RayPoint(in Ray ray, in float t)
{
     return ray.S + ray.D*t;
}

Ray Camera(in vec2 uv)
{
     Ray ray;
     ray.S = vec3(0, 0, -5);
     ray.D = vec3(uv.x, uv.y, 1.0);

     const float Aperture = 0.2;
     const float FocusDistance = 18.0;

     float r1 = Rand(vec4(uv, 0, iGlobalTime));
     float r2 = Rand(vec4(uv, 1, iGlobalTime));
     float r3 = Rand(vec4(uv, 2, iGlobalTime));
     vec3 deflection = vec3(r1, r2, 0);
     deflection = Aperture*deflection;

     ray.S += deflection;
     ray.D *= FocusDistance;
     ray.D -= deflection;
     ray.D = normalize(ray.D);

     return ray;
}

struct Plane
{
     vec3 N;
     float D;
};

float IsectPlane(in Ray ray, in Plane plane)
{
     // NP = d
     // NP - d = 0
     // N(Dt + S) - d = 0
     // ND t + NS - d = 0
     // ND t = d - NS
     // t = (d - NS)/ND

     return (plane.D - dot(plane.N, ray.S)) / dot(plane.N, ray.D);
}

struct Sphere
{
     vec3 C;
     float R;
     float R2;
};

Sphere MakeSphere(vec3 center, float radius)
{
     return Sphere(center, radius, radius*radius);
}

float IsectSphere(in Ray ray, in Sphere sphere)
{
     // (P - C)^2 = r^2
     // (P - C)^2 - r^2 = 0
     // ((Dt + S) - C)^2 - r^2 = 0
     // (Dt + S - C)^2 - r^2 = 0
     // (Dt + V)^2 - r^2 = 0
     // D^2 t^2 + 2DVt + V^2 - r^2 = 0

     vec3 V = ray.S - sphere.C;
     float a = dot(ray.D, ray.D);
     float b = 2.0*dot(V, ray.D);
     float c = dot(V, V) - sphere.R2;

     float det = b*b - 4.0*a*c;
     if (det >= 0.0)
     {
         return (0.0 - b - sqrt(det))/(2.0*a);
     }
     else
     {
         return -1.0;
     }
}

float Illuminate(vec3 light, vec3 surface, vec3 normal)
{
     vec3 d = light - surface;
     float i = dot(normalize(d), normalize(normal));
     if (i < 0.0)
     {
         return 0.0;
     }
     return i;
}

vec2 MapScreen(vec2 xy)
{
     return (xy - iResolution.xy/2.0) / iResolution.y;
}

vec2 MapScreenExact(vec2 xy)
{
     return (xy - iResolution.xy/2.0) / iResolution.xy;
}

vec3 ColourGround(in vec3 surface, in vec3 normal)
{
     float u = floor(surface.x / 3.0);
     float v = floor(surface.z / 3.0);
     if (mod(u+v, 2.0) == 0.0)
     {
         return vec3(0.4, 0.4, 0.4);
     }
     else
     {
         return vec3(1.0, 1.0, 1.0);
     }
}

vec3 TraceRay(in Ray ray)
{
     Plane ground = Plane(vec3(0, 1, 0), -5.0);
     Sphere sphere1 = MakeSphere(vec3(MapScreenExact(iMouse.xy)*4.0, 0), 
1.0);

     float groundT  = IsectPlane(ray, ground);
     float sphere1T = IsectSphere(ray, sphere1);

     int object = 0;

     if (groundT < 0.0 && sphere1T < 0.0)
     {
         object = 0;
     }

     if (groundT > 0.0 && sphere1T < 0.0)
     {
         object = 1;
     }

     if (groundT < 0.0 && sphere1T > 0.0)
     {
         object = 2;
     }

     if (groundT > 0.0 && sphere1T > 0.0)
     {
         if (groundT < sphere1T)
         {
             object = 1;
         }
         else
         {
             object = 2;
         }
     }

     if (object == 0)
     {
         return vec3(0, 0, 0);
     }

     vec3 surface, normal, colour;

     if (object == 1)
     {
         surface = RayPoint(ray, groundT);
         normal = ground.N;
         colour = ColourGround(surface, normal);
     }

     if (object == 2)
     {
         surface = RayPoint(ray, sphere1T);
         normal = surface - sphere1.C;
         colour = vec3(1, 0, 0);
     }

     float b1 = Illuminate(vec3(0, +10, 0), surface, normal);
     return colour*vec3(b1, b1, b1);
}

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
     vec4 prev = texture2D(iChannel0, fragCoord.xy / iResolution.xy);

     Ray cr = Camera(MapScreen(fragCoord.xy));
     vec3 colour = TraceRay(cr);

     fragColor = vec4(colour/float(iFrame), 1) + prev*(1.0 - 
1.0/float(iFrame));
     fragColor = clamp(fragColor, vec4(0, 0, 0, 0), vec4(1, 1, 1, 1));
}



You'll need to configure this for frame averaging, by setting this up as 
the shader for Buffer A, and configuring iChannel0 = Buffer A. Then set 
the main shader to just render Buffer A to the screen.


Post a reply to this message

From: scott
Subject: Re: WebGL
Date: 13 Jun 2016 03:13:05
Message: <575e5d01$1@news.povray.org>
>> vec3 CCOR = vec3(1,1,1);
>> vec3 colour = vec3(0,0,0);
>> for(int i=0;i<MAX_TRACE_DEPTH;i++)
>> {
>> isect = Raytrace();
>> colour += CCOR * isect.diffuse_colour;
>> CCOR *= isect.reflection_colour;
>> }
>
> I'm thinking about the associative/distributive property of the reals,
> though... If one object adds 4% blue and then reflects 95%, and the next
> object adds %6 yellow and reflects 50%, and the final object is green,
> you need
>
>   ((green * 50%) + 6% yellow) * 95% + 4% blue
>
> but the algorithm above gives
>
>   ((4% blue * 95%) + 6% yellow) * 50% + green

No, the algorithm does give the same result as you want, step through it 
with your example:

CCOR = 100%
col = black

1st intersect:
col = black + (100%)*4% blue = 4% blue
CCOR = 100% * 95% = 95%

2nd intersect:
col = 4% blue + (95%) * 6% yellow
CCOR = 95% * 50%

3rd intersect:
col = 4% blue + (95%) * 6% yellow + (95%*50%) * green
CCOR = 95% * 50% * 0%


Post a reply to this message

From: scott
Subject: Re: WebGL
Date: 13 Jun 2016 03:47:38
Message: <575e651a$1@news.povray.org>
> You'll need to configure this for frame averaging, by setting this up as
> the shader for Buffer A, and configuring iChannel0 = Buffer A. Then set
> the main shader to just render Buffer A to the screen.

Once I realised that you need to set iChannel0 to Buffer A for both 
Buffer A and the main image, it worked a treat :-)


Post a reply to this message

From: scott
Subject: Re: WebGL
Date: 20 Jun 2016 03:00:54
Message: <576794a6$1@news.povray.org>
> Copy & paste into the ShaderToy website and hit Go. You can click on the
> image to move the sphere around. (It doesn't follow your cursor exactly
> because of the perspective transformation.)

I finally got around to porting my WebGL version (which I had to write 
because shadertoy didn't support multiple buffers back then):

https://www.shadertoy.com/view/MsySzd

BufferB is used to store the camera viewing angles and the frame number 
that the viewing angles last stopped changing (so the BufferA knows 
where to start averaging the frames from).

If it doesn't work on your GPU try reducing the number of SAMPLES (at 
the top of BufferA). The end result will be the same, it will just look 
a bit worse whilst rotating the camera.


Post a reply to this message

From: Orchid Win7 v1
Subject: Re: WebGL
Date: 20 Jun 2016 13:59:00
Message: <57682ee4$1@news.povray.org>
On 20/06/2016 08:00 AM, scott wrote:
> I finally got around to porting my WebGL version (which I had to write
> because shadertoy didn't support multiple buffers back then):

Ah yes, I thought I remembered there being prior art in this space...

> BufferB is used to store the camera viewing angles and the frame number
> that the viewing angles last stopped changing (so the BufferA knows
> where to start averaging the frames from).

Interesting. I made a version of mine that only averages together the 
previous N frames, and set the camera to rotate constantly. By changing 
N, you can choose between grainy images or a weird motion blur. Looks 
vaguely like thermal imaging, actually...

> If it doesn't work on your GPU try reducing the number of SAMPLES (at
> the top of BufferA). The end result will be the same, it will just look
> a bit worse whilst rotating the camera.

You'll be unsurprised to hear that this breaks Opera.

Looking at some of the stuff people have done, you wonder why this 
amazing tech isn't in games...

...and then you realise it doesn't scale to non-trivial geometry. I'm 
still figuring out how the GPU actually works, but it *appears* that it 
works by executing all possible code paths, and just turning off the 
cores that don't take that branch. That's find for 4 trivial primitives; 
I'm going to say it doesn't scale to hundreds of billions of objects.

Pity. It would be so cool...


Post a reply to this message

From: scott
Subject: Re: WebGL
Date: 21 Jun 2016 06:58:55
Message: <57691def@news.povray.org>
>> If it doesn't work on your GPU try reducing the number of SAMPLES (at
>> the top of BufferA). The end result will be the same, it will just look
>> a bit worse whilst rotating the camera.
>
> You'll be unsurprised to hear that this breaks Opera.

What GPU do you have? Have you tried this Chrome or IE?

> Looking at some of the stuff people have done, you wonder why this
> amazing tech isn't in games...
>
> ...and then you realise it doesn't scale to non-trivial geometry. I'm
> still figuring out how the GPU actually works, but it *appears* that it
> works by executing all possible code paths, and just turning off the
> cores that don't take that branch.

Yes, that's how I understand it too. Writing this:

if(some_condition)
  DoA();
else
  DoB();

Runs the same speed as this:

DoA();
DoB();

For "small" scenes though, this is still orders of magnitude faster than 
it would ever run on a CPU.

> That's find for 4 trivial primitives;
> I'm going to say it doesn't scale to hundreds of billions of objects.
>
> Pity. It would be so cool...

I suspect if you started to modify and optimise the hardware to cope 
better with more dynamic branching and recursion etc, you would end up 
back with a CPU :-)


Post a reply to this message

From: Orchid Win7 v1
Subject: Re: WebGL
Date: 21 Jun 2016 16:10:50
Message: <57699f4a$1@news.povray.org>
On 21/06/2016 11:58 AM, scott wrote:
>>> If it doesn't work on your GPU try reducing the number of SAMPLES (at
>>> the top of BufferA). The end result will be the same, it will just look
>>> a bit worse whilst rotating the camera.
>>
>> You'll be unsurprised to hear that this breaks Opera.
>
> What GPU do you have? Have you tried this Chrome or IE?

Apparently Opera is "widely known" for having rubbish WebGL support.

>> Looking at some of the stuff people have done, you wonder why this
>> amazing tech isn't in games...
>>
>> ...and then you realise it doesn't scale to non-trivial geometry. I'm
>> still figuring out how the GPU actually works, but it *appears* that it
>> works by executing all possible code paths, and just turning off the
>> cores that don't take that branch.
>
> Yes, that's how I understand it too. Writing this:
>
> if(some_condition)
> DoA();
> else
> DoB();
>
> Runs the same speed as this:
>
> DoA();
> DoB();
>
> For "small" scenes though, this is still orders of magnitude faster than
> it would ever run on a CPU.

The CPU may be superscalar, but having 4-vector float arithmetic in 
hardware, in parallel, on a bazillion cores has *got* to be faster. ;-)

>> That's find for 4 trivial primitives;
>> I'm going to say it doesn't scale to hundreds of billions of objects.
>>
>> Pity. It would be so cool...
>
> I suspect if you started to modify and optimise the hardware to cope
> better with more dynamic branching and recursion etc, you would end up
> back with a CPU :-)

I don't know. I think the main thing about the GPU is that it's SIMD. My 
CPU has 4 cores; my GPU has nearer 400. I gather that each individual 
core is actually slightly *slower* than a CPU core - it's just that 
there's a hell of a lot of them. Also that memory access patterns are 
very predictable (until you do complex texture lookups), which enables 
the memory scheduling to have massive bandwidth with all the latency 
hidden away, so you have no pipeline stalls or cache misses to worry about.

Then again, I don't design GPUs for a living, so...

I suspect there's probably a way to render complex scenes in multiple 
passes such that you can do batch rendering. I'm not sure if it'll ever 
scale to realtime.

(Doesn't Blender or something have an optional unbiased rendering engine 
for the GPU?)


Post a reply to this message

From: Orchid Win7 v1
Subject: Re: WebGL
Date: 14 Jul 2016 16:28:16
Message: <5787f5e0@news.povray.org>
On 06/06/2016 01:36 PM, scott wrote:
>> Sometimes I really wish I knew how to do this stuff for myself...
>
> Follow a tutorial on WebGL - or if you want to skip all the html/js
> boilerplate stuff you'll need to know, go straight to something like
> shadertoy. There are plenty of examples, and shadertoy now supports
> reading back pixels from previous frames, so you can do
> multi-frame-averaging for path-tracing amongst other effects.

Is there some sort of offline client program for ShaderToy? It would be 
really nice to not have to put up with the frailness of Opera, and to be 
able to easily *save* my source code, etc.

> Building a lens simulator (with real-time path-traced results) sounds
> feasible and very interesting.

I still hope to do this soon...

PS. Just for giggles, try running ShaderToy on your *phone*! It actually 
works... kinda...


Post a reply to this message

From: scott
Subject: Re: WebGL
Date: 26 Jul 2016 08:30:12
Message: <579757d4$1@news.povray.org>
> Is there some sort of offline client program for ShaderToy? It would be
> really nice to not have to put up with the frailness of Opera, and to be
> able to easily *save* my source code, etc.

Not that I'm aware of, presumably just saving the web page doesn't work? 
Why don't you use a different browser?

> PS. Just for giggles, try running ShaderToy on your *phone*! It actually
> works... kinda...

Yes I was surprised at that too, at first I thought the web site was 
just sending a static bitmap or something, but no, my £100 smartphone is 
actually running WebGL! The simple shaders run very smoothly.


Post a reply to this message

Copyright 2003-2023 Persistence of Vision Raytracer Pty. Ltd.