POV-Ray : Newsgroups : povray.off-topic : WebGL : Re: WebGL Server Time
28 Jul 2024 04:30:34 EDT (-0400)
  Re: WebGL  
From: Orchid Win7 v1
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

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