code snippets, stubs and sketches
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

392 lines
11 KiB

// ray marching code from
// http://jamie-wong.com/2016/07/15/ray-marching-signed-distance-functions/
// https://www.shadertoy.com/view/Xtd3z7
// SDF shapes from
// https://iquilezles.org/www/articles/distfunctions/distfunctions.htm
#ifdef GL_ES
precision mediump float;
#endif
#define PI 3.1415926535897932384626433832795
#define TWO_PI 6.2831853071795864769252867665590
uniform vec2 u_resolution;
uniform float u_time;
uniform sampler2D u_tex0;
// hash based 3d value noise
// function taken from https://www.shadertoy.com/view/XslGRr
// Created by inigo quilez - iq/2013
// License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License.
float vnhash( float n )
{
return fract(sin(n)*43758.5453);
}
float vnoise( vec3 x )
{
// The noise function returns a value in the range -1.0f -> 1.0f
vec3 p = floor(x);
vec3 f = fract(x);
f = f*f*(3.0-2.0*f);
float n = p.x + p.y*57.0 + 113.0*p.z;
return mix(mix(mix( vnhash(n+0.0), vnhash(n+1.0),f.x),
mix( vnhash(n+57.0), vnhash(n+58.0),f.x),f.y),
mix(mix( vnhash(n+113.0), vnhash(n+114.0),f.x),
mix( vnhash(n+170.0), vnhash(n+171.0),f.x),f.y),f.z);
}
//
// Description : GLSL 2D simplex noise function
// Author : Ian McEwan, Ashima Arts
// Maintainer : ijm
// Lastmod : 20110822 (ijm)
// License :
// Copyright (C) 2011 Ashima Arts. All rights reserved.
// Distributed under the MIT License. See LICENSE file.
// https://github.com/ashima/webgl-noise
//
// Some useful functions
vec3 mod289(vec3 x) { return x - floor(x * (1.0 / 289.0)) * 289.0; }
vec2 mod289(vec2 x) { return x - floor(x * (1.0 / 289.0)) * 289.0; }
vec3 permute(vec3 x) { return mod289(((x*34.0)+1.0)*x); }
float noise(vec2 v) {
// Precompute values for skewed triangular grid
const vec4 C = vec4(0.211324865405187,
// (3.0-sqrt(3.0))/6.0
0.366025403784439,
// 0.5*(sqrt(3.0)-1.0)
-0.577350269189626,
// -1.0 + 2.0 * C.x
0.024390243902439);
// 1.0 / 41.0
// First corner (x0)
vec2 i = floor(v + dot(v, C.yy));
vec2 x0 = v - i + dot(i, C.xx);
// Other two corners (x1, x2)
vec2 i1 = vec2(0.0);
i1 = (x0.x > x0.y)? vec2(1.0, 0.0):vec2(0.0, 1.0);
vec2 x1 = x0.xy + C.xx - i1;
vec2 x2 = x0.xy + C.zz;
// Do some permutations to avoid
// truncation effects in permutation
i = mod289(i);
vec3 p = permute(
permute( i.y + vec3(0.0, i1.y, 1.0))
+ i.x + vec3(0.0, i1.x, 1.0 ));
vec3 m = max(0.5 - vec3(
dot(x0,x0),
dot(x1,x1),
dot(x2,x2)
), 0.0);
m = m*m ;
m = m*m ;
// Gradients:
// 41 pts uniformly over a line, mapped onto a diamond
// The ring size 17*17 = 289 is close to a multiple
// of 41 (41*7 = 287)
vec3 x = 2.0 * fract(p * C.www) - 1.0;
vec3 h = abs(x) - 0.5;
vec3 ox = floor(x + 0.5);
vec3 a0 = x - ox;
// Normalise gradients implicitly by scaling m
// Approximation of: m *= inversesqrt(a0*a0 + h*h);
m *= 1.79284291400159 - 0.85373472095314 * (a0*a0+h*h);
// Compute final noise value at P
vec3 g = vec3(0.0);
g.x = a0.x * x0.x + h.x * x0.y;
g.yz = a0.yz * vec2(x1.x,x2.x) + h.yz * vec2(x1.y,x2.y);
return 130.0 * dot(m, g);
}
// -------------- RAYMARCHING BOILERPLATE ---------------------------------------
const int MAX_MARCHING_STEPS = 255;
const float MIN_DIST = 0.0;
const float MAX_DIST = 100.0;
const float EPSILON = 0.0001;
float sphereSDF(vec3 p) {
return length(p) - 1.0;
}
float sceneSDF(vec3 samplePoint);
float shortestDistanceToSurface(vec3 eye, vec3 marchingDirection, float start, float end) {
float depth = start;
for (int i = 0; i < MAX_MARCHING_STEPS; i++) {
float dist = sceneSDF(eye + depth * marchingDirection);
if (dist < EPSILON) {
return depth;
}
depth += dist;
if (depth >= end) {
return end;
}
}
return end;
}
vec3 rayDirection(float fieldOfView, vec2 size, vec2 fragCoord) {
vec2 xy = fragCoord - size / 2.0;
float z = size.y / tan(radians(fieldOfView) / 2.0);
return normalize(vec3(xy, -z));
}
vec3 estimateNormal(vec3 p) {
return normalize(vec3(
sceneSDF(vec3(p.x + EPSILON, p.y, p.z)) - sceneSDF(vec3(p.x - EPSILON, p.y, p.z)),
sceneSDF(vec3(p.x, p.y + EPSILON, p.z)) - sceneSDF(vec3(p.x, p.y - EPSILON, p.z)),
sceneSDF(vec3(p.x, p.y, p.z + EPSILON)) - sceneSDF(vec3(p.x, p.y, p.z - EPSILON))
));
}
float phongContribForLight(float k_d, vec3 p, vec3 eye, vec3 lightPos) {
vec3 N = estimateNormal(p);
vec3 L = normalize(lightPos - p);
vec3 V = normalize(eye - p);
vec3 R = normalize(reflect(-L, N));
float dotLN = dot(L, N);
float dotRV = dot(R, V);
// Light not visible from this point on the surface
if (dotLN < 0.0) {
return 0.0;
}
// Light reflection in opposite direction as viewer,
// apply only diffuse component
if (dotRV < 0.0) {
return (k_d * dotLN);
}
return (k_d * dotLN );
}
mat4 viewMatrix(vec3 eye, vec3 center, vec3 up) {
// Based on gluLookAt man page
vec3 f = normalize(center - eye);
vec3 s = normalize(cross(f, up));
vec3 u = cross(s, f);
return mat4(
vec4(s, 0.0),
vec4(u, 0.0),
vec4(-f, 0.0),
vec4(0.0, 0.0, 0.0, 1)
);
}
// ------------------- FUNCTIONS -------------------------------
float lfo_ramp( in float speed ){ return fract(u_time*speed); }
float lfo_tri( in float speed ){ return abs( (fract(u_time*speed) * 2.0) - 1.0 ); }
float lfo_sin( in float speed ){ return (sin(u_time*speed*TWO_PI)*0.5 + 0.5); }
float rand(vec2 st, float t){
return fract(sin(dot(st.xy + fract(t*0.0013) ,vec2(12.9898,78.233))) * 43758.5453);
}
float rand( in float i, in float t ){
return fract(sin(dot( vec2(i, t), vec2(12.9898,78.233))) * 43758.5453);
}
mat2 rotate2d( in float _angle ){
return mat2(cos(_angle),-sin(_angle), sin(_angle),cos(_angle));
}
vec2 rotated( vec2 _st, in float _angle ){
_st -= 0.5;
_st *= rotate2d( _angle );
_st += 0.5;
return _st;
}
// ------------------- 3D SDFs ---------------------------------
float sdBox( vec3 p, vec3 b ) {
vec3 q = abs(p) - b;
return length(max(q,0.0)) + min(max(q.x,max(q.y,q.z)),0.0);
}
// ---- Platonic solids ----
// by decrooks on shadertoy
// https://www.shadertoy.com/view/MtV3Dy
//Golden mean and inverse - for the icosohedron and dodecadron
#define PHI 1.6180339887
#define INV_PHI 0.6180339887
float plane( vec3 p, vec3 origin, vec3 normal ){
return dot(p - origin,normal);
}
float doubleplane( vec3 p, vec3 origin, vec3 normal ){
return max(dot(p - origin,normal),dot(-p - origin,normal));
}
float sdIcosahedron( vec3 p, float d ){
float h=1.0/sqrt(3.0);
//Same idea as above, using the vertices of the dodecahedron
vec3 v1 = h* vec3(1.0,1.0,1.0);
vec3 v2 = h* vec3(-1.0,1.0,1.0);
vec3 v3 = h* vec3(-1.0,1.0,-1.0);
vec3 v4 = h* vec3(1.0,1.0,-1.0);
vec3 v5 = h* vec3(0.0,INV_PHI,PHI);
vec3 v6 = h* vec3(0.0,INV_PHI,-PHI);
float ds = doubleplane(p,d*v1,v1);
//max == intesect objects
ds = max(doubleplane(p,d*v2,v2),ds);
ds = max(doubleplane(p,d*v3,v3),ds);
ds = max(doubleplane(p,d*v4,v4),ds);
ds = max(doubleplane(p,d*v5,v5),ds);
ds = max(doubleplane(p,d*v6,v6),ds);
//plus cyclic permutaions of v5 and v6:
ds = max(doubleplane(p,d*v5.zxy,v5.zxy),ds);
ds = max(doubleplane(p,d*v5.yzx,v5.yzx),ds);
ds = max(doubleplane(p,d*v6.zxy,v6.zxy),ds);
ds = max(doubleplane(p,d*v6.yzx,v6.yzx),ds);
return ds;
}
vec3 rotateX(vec3 p, float theta) {
float c = cos(theta);
float s = sin(theta);
mat4 m = mat4(
vec4(1.0, 0.0, 0.0, 0.0),
vec4(0.0, c, -s, 0.0),
vec4(0.0, s, c, 0.0),
vec4(0.0, 0.0, 0.0, 1.0)
);
vec4 p4 = m * vec4(p, 1.0);
return p4.xyz;
}
vec3 rotateY(vec3 p, float theta) {
float c = cos(theta);
float s = sin(theta);
mat4 m = mat4(
vec4(c, 0.0, s, 0.0),
vec4(0.0, 1.0, 0.0, 0.0),
vec4(-s, 0.0, c, 0.0),
vec4(0.0, 0.0, 0.0, 1.0)
);
vec4 p4 = m * vec4(p, 1.0);
return p4.xyz;
}
vec3 rotateZ( vec3 p, float theta) {
float c = cos(theta);
float s = sin(theta);
mat4 m = mat4(
vec4(c, -s, 0.0, 0.0),
vec4(s, c, 0.0, 0.0),
vec4(0.0, 0.0, 1.0, 0.0),
vec4(0.0, 0.0, 0.0, 1.0)
);
vec4 p4 = m * vec4(p, 1.0);
return p4.xyz;
}
vec3 rotate(vec3 p, vec3 ax, float ro) {
return mix(dot(ax, p)*ax, p, cos(ro)) + cross(ax,p)*sin(ro);
}
vec3 opRepLim( in vec3 p, in float c, in vec3 l ){
vec3 q = p-c*clamp(round(p/c),-l,l);
return q;
}
// ------------------- SHADER ----------------------------------
uniform float u_grid_x;
uniform float u_grid_y;
float custom_dither( float x, vec2 st ) {
x *= 2.0;
vec2 grid;
grid.x = fract( st.x * (0.12 + lfo_tri(0.003123)*0.23));
grid.y = fract( st.y * (0.12 + lfo_tri(0.0005622)*0.23));
return step( grid.x, x ) * step(grid.y, x);
}
void main(){
float a3d = 0.0;
float dit = 0.0;
// ------ raymarching parameters ------
float distance = 70.0;
float K_a = 0.05; // ambient gradient
float K_d = 0.9; // light gradient
vec3 light_pos = vec3( 2.0, 0.0, 4.0 );
float clok = u_time * 0.2;
float theta = lfo_ramp( 0.03 ) * TWO_PI;
vec3 camera = vec3( 3.0, 0.0, 0.0);
vec3 look_at = vec3( 0, 0, 0 );
// ------ more raymarching boilerplate ------
vec2 st = gl_FragCoord.xy/u_resolution;
vec3 viewDir = rayDirection(distance, u_resolution.xy, gl_FragCoord.xy);
mat4 viewToWorld = viewMatrix(camera, look_at, vec3(0.0, 1.0, 0.0));
vec3 worldDir = (viewToWorld * vec4(viewDir, 0.0)).xyz;
float dist = shortestDistanceToSurface(camera, worldDir, MIN_DIST, MAX_DIST);
if (dist < MAX_DIST - EPSILON) {
vec3 p = camera + dist * worldDir;
a3d = K_a;
a3d += phongContribForLight(K_d, p, camera, light_pos );
dit = custom_dither( a3d, gl_FragCoord.xy );
gl_FragColor = vec4(vec3(dit), 1.0 );
}else{
gl_FragColor = vec4(0,0,0,0);
}
}
float sceneSDF(vec3 samplePoint) {
float theta = -u_time * 0.0625 * TWO_PI;
vec3 sz = vec3( 0.06 );
vec3 rp;
rp = rotateY( samplePoint.xyz, theta);
rp = rotateZ( rp, theta * 0.3 );
//rp = rotate( samplePoint.xyz, vec3(0, 1, 0), u_time );
//rp = rotate( rp, vec3(1, 0, 0), u_time * 0.6 );
//vec3 p = opRepLim( rotated.xyz, 0.12 + u_mod, vec3( 2.0 ) );
//return sdBox( p, sz );
return sdIcosahedron( rp, 0.3 );
}