186 lines
No EOL
5 KiB
GLSL
186 lines
No EOL
5 KiB
GLSL
// Taken from: https://www.shadertoy.com/view/ldy3DR
|
|
//
|
|
// Created by Sam Gondelman on 6/9/2016
|
|
// Copyright 2016 High Fidelity, Inc.
|
|
//
|
|
// Distributed under the Apache License, Version 2.0.
|
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
|
//
|
|
|
|
// Raymarching constants
|
|
const float TMAX = 250.0;
|
|
const int MAX_STEPS = 200;
|
|
const float DIST_THRESHOLD = 0.00001;
|
|
|
|
// Math constants
|
|
const float PI = 3.14159265359;
|
|
const float EPS = 0.0001;
|
|
const float FLT_MAX = 1.0 / 0.000000000001; // hacky but GLSL doesn't have a FLT_MAX by default
|
|
|
|
vec3 SUN_DIR = normalize(vec3(-0.5, -1.0, -1.0));
|
|
|
|
#define clamp01(a) clamp(a, 0.0, 1.0)
|
|
|
|
struct Ray {
|
|
vec3 src;
|
|
vec3 dir;
|
|
float t;
|
|
vec3 pos;
|
|
vec3 nor;
|
|
int matID;
|
|
int iter;
|
|
};
|
|
|
|
// GLSL default parameters don't seem to work so this is for any call to map
|
|
// where you don't actually care about the material of what you hit
|
|
int junkMatID;
|
|
|
|
// Primitives
|
|
// http://iquilezles.org/www/articles/distfunctions/distfunctions.htm
|
|
float sphere(vec3 p, float r) {
|
|
return length(p) - r;
|
|
}
|
|
|
|
float cylinder(vec3 p, float r, float h) {
|
|
vec2 d = abs(vec2(length(p.xz),p.y)) - vec2(r, h);
|
|
return min(max(d.x,d.y),0.0) + length(max(d,0.0));
|
|
}
|
|
|
|
float roundedBox(vec3 p, vec3 dim, float r) {
|
|
vec3 d = abs(p) - dim;
|
|
return length(max(d,vec3(0.0))) - r;
|
|
}
|
|
|
|
float coneSection(vec3 p, float h, float r1, float r2) {
|
|
float d1 = -p.y - h;
|
|
float q = p.y - h;
|
|
float si = 0.5*(r1-r2)/h;
|
|
float d2 = max(sqrt(dot(p.xz,p.xz)*(1.0-si*si)) + q*si - r2, q);
|
|
return length(max(vec2(d1,d2),0.0)) + min(max(d1,d2), 0.0);
|
|
}
|
|
|
|
float subtraction(float d1, float d2) {
|
|
return max(-d1,d2);
|
|
}
|
|
|
|
float blend(float a, float b, float k) {
|
|
float h = clamp(mix(1.0, (b-a)/k, 0.5), 0.0, 1.0);
|
|
return mix(b, a, h) - k*h*(1.0-h);
|
|
}
|
|
|
|
void propose(inout float val, inout int matID, float proposedVal, int proposedMatID) {
|
|
if (proposedVal < val) {
|
|
val = proposedVal;
|
|
matID = proposedMatID;
|
|
}
|
|
}
|
|
|
|
float map(vec3 p, inout int matID) {
|
|
float res = FLT_MAX;
|
|
|
|
propose(res, matID, blend(coneSection(p-vec3(0.0, 0.0, 0.0), 0.3, 1.0, 0.5),
|
|
coneSection(p-vec3(0.0, 0.6, 0.0), 0.3, 0.8, 1.0), 0.5), 1);
|
|
|
|
propose(res, matID, coneSection(p-vec3(0.0, 1.2, 0.0), 0.6, 1.0, 0.5), 2);
|
|
|
|
return res;
|
|
}
|
|
|
|
vec3 calculateNormal(vec3 pos) {
|
|
const vec3 e = vec3(EPS, 0.0, 0.0);
|
|
float p = map(pos, junkMatID);
|
|
return normalize(vec3(map(pos + e.xyy, junkMatID) - p,
|
|
map(pos + e.yxy, junkMatID) - p,
|
|
map(pos + e.yyx, junkMatID) - p));
|
|
}
|
|
|
|
// Lighting
|
|
float directionalLightDiffuse(vec3 nor, vec3 ldir) {
|
|
return clamp01(dot(nor, -ldir));
|
|
}
|
|
|
|
// Coloring different materials
|
|
vec3 grey(Ray ray) {
|
|
return vec3(0.8);
|
|
}
|
|
|
|
vec3 glass(Ray ray) {
|
|
return vec3(0.5, 0.0, 0.0);
|
|
}
|
|
|
|
vec4 computeColor(Ray ray) {
|
|
vec3 col = vec3(0.0);
|
|
float alpha = 1.0;
|
|
|
|
// Switch on matID
|
|
if (ray.matID == 0) {
|
|
discard; // transparent background
|
|
} else if (ray.matID == 1){
|
|
col = grey(ray);
|
|
} else if (ray.matID == 2){
|
|
col = glass(ray);
|
|
alpha = 0.5;
|
|
}
|
|
|
|
// Default lighting
|
|
float sunLight = directionalLightDiffuse(ray.nor, SUN_DIR);
|
|
col = col * (0.8 * sunLight + 0.1);
|
|
|
|
return vec4(col, alpha);
|
|
}
|
|
|
|
vec4 raymarch(inout Ray ray) {
|
|
float h = 1.0;
|
|
float t = 0.0;
|
|
for(int i = 0; i < MAX_STEPS; i++) {
|
|
h = map(ray.src + t*ray.dir, ray.matID);
|
|
t += h;
|
|
ray.iter = i;
|
|
if (t > TMAX || h < DIST_THRESHOLD) break;
|
|
}
|
|
ray.t = t;
|
|
ray.pos = ray.src + ray.t*ray.dir;
|
|
ray.nor = calculateNormal(ray.pos);
|
|
int missed = int(step(TMAX, ray.t));
|
|
ray.matID = (1 - missed) * ray.matID;
|
|
ray.nor *= float(1-missed);
|
|
return computeColor(ray);
|
|
}
|
|
|
|
vec4 render(Ray ray, inout float dist) {
|
|
vec4 result = raymarch(ray);
|
|
dist = ray.t;
|
|
return clamp01(result);
|
|
}
|
|
|
|
vec4 getProceduralColor(inout float dist) {
|
|
Ray ray;
|
|
ray.pos = vec3(0.0);
|
|
ray.nor = vec3(0.0);
|
|
ray.matID = 0;
|
|
ray.t = 0.0;
|
|
|
|
vec3 worldEye = getEyeWorldPos();
|
|
// this will make it movable, scalable, and rotatable
|
|
// vec3 ro = _position.xyz;
|
|
// vec3 eye = (inverse(iWorldOrientation) * (worldEye - iWorldPosition)) / iWorldScale;
|
|
|
|
vec3 ro = iWorldOrientation * (_position.xyz * iWorldScale) + iWorldPosition; // world position of the current fragment
|
|
vec3 eye = worldEye;
|
|
|
|
vec3 rd = normalize(ro - eye); // ray from camera eye to ro
|
|
ray.src = eye;
|
|
ray.dir = rd;
|
|
|
|
return render(ray, dist);
|
|
}
|
|
|
|
|
|
float getProceduralColors(inout vec3 diffuse, inout vec3 specular, inout float shininess) {
|
|
float dist;
|
|
vec4 color = getProceduralColor(dist);
|
|
diffuse = color.rgb;
|
|
specular = color.rgb;
|
|
shininess = 0.5;
|
|
return color.a;
|
|
} |