|
![](/i/fill.gif) |
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
|
![](/i/fill.gif) |