552 lines
No EOL
18 KiB
GLSL
552 lines
No EOL
18 KiB
GLSL
// Taken from: https://www.shadertoy.com/view/XsV3zG
|
|
//
|
|
// 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
|
|
//
|
|
|
|
// Just draws the leftmost island (without noise), tree + apple, and fence
|
|
#define TEST 0
|
|
|
|
#define USE_SHADOWS 0
|
|
|
|
// 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
|
|
|
|
// Raymarching constants
|
|
const float TMAX = 400.0;
|
|
const int MAX_STEPS = 250;
|
|
const float DIST_THRESHOLD = 0.00001;
|
|
|
|
// Other constants/helpers
|
|
const vec3 UP = vec3(0.0, 1.0, 0.0);
|
|
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;
|
|
|
|
// Perlin Noise
|
|
float hash(float n) { return fract(sin(n)*753.5453123); }
|
|
|
|
float interpolatedNoise2D(vec2 xy, int seed) {
|
|
vec2 p = floor(xy);
|
|
vec2 f = fract(xy);
|
|
f = f*f*(3.0-2.0*f);
|
|
|
|
float n = dot(vec3(p.xy, seed), vec3(1, 157, 141));
|
|
return mix(mix(hash(n+ 0.0), hash(n+ 1.0),f.x),
|
|
mix(hash(n+157.0), hash(n+158.0),f.x),f.y);
|
|
}
|
|
|
|
float perlinNoise2D(vec2 xy, float freq, float amp, int octaves, int seed){
|
|
float total = 0.0;
|
|
float totalScale = 0.0;
|
|
// current freq, amp, scale
|
|
vec3 currFAS = vec3(freq, amp, amp);
|
|
for(int i = 0; i < 5; i++){
|
|
total += interpolatedNoise2D(abs(xy) * currFAS.x, seed) * currFAS.y;
|
|
totalScale += currFAS.z;
|
|
currFAS *= vec3(2.0, 0.5, 0.5);
|
|
if (i >= octaves) break;
|
|
}
|
|
return amp * (total / totalScale);
|
|
}
|
|
|
|
float interpolatedNoise3D(vec3 xyz, int seed) {
|
|
vec3 p = floor(xyz);
|
|
vec3 f = fract(xyz);
|
|
f = f*f*(3.0-2.0*f);
|
|
|
|
float n = dot(vec4(p, seed), vec4(1, 433, 157, 141));
|
|
return mix(mix(mix(hash(n+ 0.0), hash(n+ 1.0),f.x),
|
|
mix(hash(n+157.0), hash(n+158.0),f.x),f.z),
|
|
mix(mix(hash(n+433.0), hash(n+434.0),f.x),
|
|
mix(hash(n+590.0), hash(n+591.0),f.x),f.z), f.y);
|
|
}
|
|
|
|
float perlinNoise3D(vec3 xyz, float freq, float amp, int octaves, int seed){
|
|
float total = 0.0;
|
|
float totalScale = 0.0;
|
|
// current freq, amp, scale
|
|
vec3 currFAS = vec3(freq, amp, amp);
|
|
for(int i = 0; i < 5; i++){
|
|
total += interpolatedNoise3D(abs(xyz) * currFAS.x, seed) * currFAS.y;
|
|
totalScale += currFAS.z;
|
|
currFAS *= vec3(2.0, 0.5, 0.5);
|
|
if (i >= octaves) break;
|
|
}
|
|
return amp * (total / totalScale);
|
|
}
|
|
|
|
// Primitives
|
|
// http://iquilezles.org/www/articles/distfunctions/distfunctions.htm
|
|
float sphere(vec3 p, float r) {
|
|
return length(p) - r;
|
|
}
|
|
|
|
float box(vec3 p, vec3 dim) {
|
|
vec3 d = abs(p) - dim;
|
|
return min(max(d.x,max(d.y,d.z)),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 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 cone(vec3 p, float r, float h) {
|
|
float d1 = -p.y - h;
|
|
float q = p.y - h;
|
|
float si = 0.5*r/h;
|
|
float d2 = max(sqrt(dot(p.xz,p.xz)*(1.0-si*si)) + q*si, q);
|
|
return length(max(vec2(d1,d2),0.0)) + min(max(d1,d2), 0.);
|
|
}
|
|
|
|
float triangularPrism(vec3 p, vec2 h, float theta) {
|
|
vec3 q = abs(p);
|
|
return max(q.z-h.y,max(q.x*sin(radians(theta))+p.y*0.5,-p.y)-h.x*0.5);
|
|
}
|
|
|
|
// CSG operations
|
|
float intersectionDist(float d1, float d2) {
|
|
return max(d1, d2);
|
|
}
|
|
|
|
float subtractionDist(float d1, float d2) {
|
|
return max(d1, -d2);
|
|
}
|
|
|
|
// Transformations
|
|
vec3 rX(vec3 p, float a) {
|
|
float c = cos(radians(a));
|
|
float s = sin(radians(a));
|
|
vec3 q = p;
|
|
p.y = c * q.y - s * q.z;
|
|
p.z = s * q.y + c * q.z;
|
|
return p;
|
|
}
|
|
|
|
vec3 rY(vec3 p, float a) {
|
|
float c = cos(radians(a));
|
|
float s = sin(radians(a));
|
|
vec3 q = p;
|
|
p.x = c * q.x + s * q.z;
|
|
p.z = -s * q.x + c * q.z;
|
|
return p;
|
|
}
|
|
|
|
float blend(float a, float b, float k) {
|
|
float h = clamp01(mix(1.0, (b-a)/k, 0.5));
|
|
return mix(b, a, h) - k*h*(1.0-h);
|
|
}
|
|
|
|
// On linux, mod doesn't work as expected for negative numbers
|
|
vec3 repeat(vec3 p, vec3 r) {
|
|
p = abs(p);
|
|
return vec3(p.x - (r.x * floor(p.x/r.x)) - 0.5*r.x,
|
|
p.y - (r.y * floor(p.y/r.y)) - 0.5*r.y,
|
|
p.z - (r.z * floor(p.z/r.z)) - 0.5*r.z);
|
|
// return mod(p, r) - 0.5*r;
|
|
}
|
|
|
|
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;
|
|
|
|
// islands offset
|
|
vec3 ip = p;
|
|
ip.y += 0.8;
|
|
|
|
#if !TEST
|
|
ip.y -= perlinNoise2D(ip.xz, 1.0, 0.3, 1, 697);
|
|
ip.y += (perlinNoise2D(ip.xz+vec2(50.0), 0.5, 5.0, 3, 769)-4.1)*(1.0-smoothstep(6.9, 7.5, ip.y));
|
|
#endif
|
|
|
|
// left island
|
|
propose(res, matID, blend(cone(rX(ip, 180.0), 10.0, 7.5),
|
|
cylinder(p-vec3(0.0, 6.5, 0.0), 13.0, 0.15), 3.0), 3);
|
|
|
|
#if !TEST
|
|
propose(res, matID, blend(cone(rX(ip-vec3(1.0, 2.5, -12.0), 180.0), 5.5, 5.0),
|
|
cylinder(p-vec3(1.0, 6.5, -12.0), 7.0, 0.15), 3.0), 3);
|
|
propose(res, matID, blend(cone(rX(ip-vec3(5.0, 4.5, -18.0), 180.0), 4.0, 3.0),
|
|
cylinder(p-vec3(5.0, 6.5, -18.0), 5.0, 0.15), 3.0), 3);
|
|
|
|
// right island
|
|
propose(res, matID, blend(cone(rX(ip-vec3(23.0, 2.5, -40.0), 180.0), 6.0, 5.0),
|
|
cylinder(p-vec3(23.0, 6.4, -40.0), 6.95, 0.2), 3.0), 3);
|
|
propose(res, matID, blend(cone(rX(ip-vec3(18.0, 4.25, -45.0), 180.0), 4.0, 3.25),
|
|
cylinder(p-vec3(18.0, 6.4, -45.0), 4.45, 0.2), 3.0), 3);
|
|
|
|
// house
|
|
vec3 z = rY(vec3(0,0,1), 50.0);
|
|
float cyl1 = cylinder(rX(rY(p-vec3(-1.0, 10.9, -3.0)+24.0*z, 35.0), 90.0), 22.1, 5.0);
|
|
float cyl2 = cylinder(rX(rY(p-vec3(-1.0, 10.9, -3.0)-24.0*z, 35.0), 90.0), 22.1, 5.0);
|
|
float house = box(rY(p-vec3(-1.0, 10.5, -3.0), 35.0), vec3(2.0, 3.0, 2.0));
|
|
house = subtractionDist(house, cyl1);
|
|
house = subtractionDist(house, cyl2);
|
|
propose(res, matID, house, 4);
|
|
float roof = blend(triangularPrism(rY(p-vec3(-1.0, 14.0, -3.0), 35.0),
|
|
vec2(1.0,2.0), 20.0),
|
|
cylinder(rX(rY(p-vec3(-1.0, 14.4, -3.0), 35.0), 90.0),
|
|
0.2, 1.7), 0.6);
|
|
propose(res, matID, roof, 5);
|
|
|
|
// chimney
|
|
propose(res, matID, roundedbox(rY(p-vec3(-0.8, 13.5, -1.0), 35.0), vec3(0.15, 1.2, 0.15), 0.05), 6);
|
|
|
|
// door
|
|
propose(res, matID, box(rY(p-vec3(-1.0, 8.5, -5.0), 35.0), vec3(0.4, 1.05, 0.4)), 7);
|
|
propose(res, matID, sphere(p-vec3(-1.0, 8.5, -5.52), 0.05), 8);
|
|
|
|
// bridge
|
|
vec3 x = rY(vec3(1,0,0), 50.0);
|
|
vec3 cen = vec3(-10.5,7.5,0.0)+36.89*x;
|
|
vec3 bp = p + vec3(0.0, 0.05, 0.0);
|
|
vec2 offset = vec2(iGlobalTime/35.0, iGlobalTime/30.0);
|
|
bp.y += perlinNoise2D(bp.xz+offset, 0.1+0.05*sin(iGlobalTime/6.0)+0.05*cos(iGlobalTime/7.0),
|
|
2.0, 1, 537)*(max(0.0, 1.0-dot(bp.xz-cen.xz,bp.xz-cen.xz)/59.0));
|
|
float bridge = box(rY(bp-cen, 40.0), vec3(0.75,1.5,7.8));
|
|
float planks = box(repeat(rY(bp-vec3(-10.5,7.5,0.0), 40.0), vec3(0.0,0.0,0.3)),
|
|
vec3(0.5,0.05,0.125));
|
|
propose(res, matID, intersectionDist(planks, bridge), 9);
|
|
|
|
// bridge ropes
|
|
propose(res, matID, cylinder(rX(rY(bp-cen+0.45*z, 40.0), 90.0), 0.01, 7.7), 9);
|
|
propose(res, matID, cylinder(rX(rY(bp-cen-0.45*z, 40.0), 90.0), 0.01, 7.7), 9);
|
|
|
|
propose(res, matID, cylinder(rX(rY(bp-cen-0.25*x+0.47*z-UP, 40.0), 90.0), 0.03, 8.25), 9);
|
|
propose(res, matID, cylinder(rX(rY(bp-cen-0.47*z-UP, 40.0), 90.0), 0.03, 8.4), 9);
|
|
|
|
float ropes1 = cylinder(repeat(rY(bp-vec3(-10.5,8.0,0.0)+0.47*z, 40.0), vec3(0.0,0.0,0.9)), 0.02, 0.5);
|
|
float ropes2 = cylinder(repeat(rY(bp-vec3(-10.5,8.0,0.0)-0.47*z, 40.0), vec3(0.0,0.0,0.9)), 0.02, 0.5);
|
|
propose(res, matID, intersectionDist(ropes1, bridge), 9);
|
|
propose(res, matID, intersectionDist(ropes2, bridge), 9);
|
|
|
|
float disp = (sin(p.x*p.y)*sin(p.z*p.x))/40.0;
|
|
propose(res, matID, cylinder(rX(rY(p-cen+8.25*x+0.55*z-0.5*UP, 60.0), 30.0), 0.07, 0.6)+disp, 9);
|
|
propose(res, matID, cylinder(rX(rY(p-cen+8.3*x-0.54*z-0.5*UP, 75.0), -15.0), 0.07, 0.6)+disp, 9);
|
|
propose(res, matID, cylinder(rX(rY(p-cen-8.25*x+0.43*z-0.5*UP, 30.0), 30.0), 0.07, 0.65)+disp, 9);
|
|
propose(res, matID, cylinder(p-cen-8.4*x-0.47*z-0.5*UP, 0.07, 0.6)+disp, 9);
|
|
|
|
|
|
// right tree
|
|
for (int i = 0; i < 4; i++) {
|
|
float fi = float(i);
|
|
vec3 tp = p;
|
|
vec2 add = vec2(sin(p.y+fi/4.0*2.0*PI+2.0*PI*hash(36.0*fi)),
|
|
cos(p.y+fi/4.0*2.0*PI+2.0*PI*hash(83.0*fi)))/4.0;
|
|
float ystep = smoothstep(8.5, 11.0, p.y);
|
|
tp.xz += add*ystep;
|
|
propose(res, matID, cylinder(rX(rY(tp-vec3(27.0, 10.0, -42.0), 180.0*(fi-1.0)/4.0*ystep), 40.0*ystep),
|
|
0.07+(max(11.5-p.y, 0.0))/10.0, 4.0), 9);
|
|
}
|
|
|
|
// right fence
|
|
for(int i = 0; i < 6; i++) {
|
|
float fi = float(i);
|
|
vec3 off = rY(vec3(1.0,0.0,0.0), 15.0*fi-40.0);
|
|
vec3 nextOff = rY(vec3(1.0,0.0,0.0), 15.0*float(i+1)-40.0);
|
|
propose(res, matID, cylinder(p-vec3(23.0, 7.75, -40.0)-6.7*off, 0.07, 0.6), 9);
|
|
vec3 hc = rX(rY(p-vec3(23.0, 7.75, -40.0)-6.7*(off+nextOff)/2.0, 180.0 - (15.0*(fi+0.5)-40.0)), 90.0);
|
|
float a1 = 7.0*sin(fi*2320.0);
|
|
float a2 = 7.0*sin(fi*235.0);
|
|
a1 = mix(a1, -15.0, step(4.5, fi));
|
|
a2 = mix(a2, -25.0, step(4.5, fi));
|
|
propose(res, matID, cylinder(rX(hc, a1), 0.04, 0.87), 9);
|
|
propose(res, matID, cylinder(rX(hc, a2)-vec3(0.0,0.0,0.4*step(fi, 4.5)), 0.04,
|
|
0.87+0.1*step(4.5, fi)), 9);
|
|
}
|
|
|
|
#endif
|
|
|
|
// left tree
|
|
for (int i = 0; i < 5; i++) {
|
|
float fi = float(i);
|
|
vec3 tp = p;
|
|
vec2 add = vec2(sin(p.y+fi/5.0*2.0*PI+2.0*PI*hash(50.0*fi)),
|
|
cos(p.y+fi/5.0*2.0*PI+2.0*PI*hash(50.0*fi)))/4.0;
|
|
float ystep = smoothstep(9.0, 11.5, p.y);
|
|
tp.xz += add*ystep;
|
|
propose(res, matID, cylinder(rX(rY(tp-vec3(6.0, 10.5, 8.0), 360.0*fi/5.0*ystep), 40.0*ystep),
|
|
0.1+(max(11.5-p.y, 0.0))/10.0, 5.0), 9);
|
|
}
|
|
|
|
// left fence
|
|
for(int i = 0; i < 4; i++) {
|
|
float fi = float(i);
|
|
vec3 off = rY(vec3(1.0,0.0,0.0), 8.0*fi-170.0);
|
|
vec3 nextOff = rY(vec3(1.0,0.0,0.0), 8.0*float(i+1)-170.0);
|
|
propose(res, matID, cylinder(p-vec3(0.0, 7.75, 0.0)-12.5*off, 0.07, 0.6), 9);
|
|
vec3 hc = rX(rY(p-vec3(0.0, 7.75, 0.0)-12.5*(off+nextOff)/2.0, 180.0 - (8.0*(fi+0.5)-170.0)), 90.0);
|
|
float a1 = 7.0*sin(fi*2320.0);
|
|
float a2 = 7.0*sin(fi*235.0);
|
|
a1 = mix(a1, -15.0, step(2.5, fi));
|
|
a2 = mix(a2, -25.0, step(2.5, fi));
|
|
propose(res, matID, cylinder(rX(hc, a1), 0.04, 0.87), 9);
|
|
propose(res, matID, cylinder(rX(hc, a2)-vec3(0.0,0.0,0.4*step(fi, 2.5)), 0.04,
|
|
0.87+0.1*step(2.5, fi)), 9);
|
|
}
|
|
|
|
// apple
|
|
float t = max(0.0, iGlobalTime -10.0);
|
|
float appleY = min(0.5*9.81*t*t, 5.0);
|
|
propose(res, matID, sphere(p-vec3(8.0, 12.65-appleY, 7.6), 0.15), 10);
|
|
|
|
return res;
|
|
}
|
|
|
|
// Lighting
|
|
float directionalLightDiffuse(vec3 nor, vec3 ldir) {
|
|
return clamp01(dot(nor, -ldir));
|
|
}
|
|
|
|
// Effects
|
|
float softshadow(vec3 pos, vec3 ldir) {
|
|
#if USE_SHADOWS
|
|
float res = 1.0;
|
|
float t = 0.01;
|
|
for(int i = 0; i < 25; i++) {
|
|
float h = map(pos - ldir*t, junkMatID);
|
|
res = min(res, 7.0*h/t);
|
|
t += clamp(h, 0.007, 5.0);
|
|
if (h < EPS) break;
|
|
}
|
|
return clamp01(res);
|
|
#else
|
|
return 1.0;
|
|
#endif
|
|
}
|
|
|
|
// Coloring different materials
|
|
vec3 sky(vec3 dir) {
|
|
return mix(vec3(0.4, 0.7, 0.9),
|
|
vec3(0.23, 0.17, 0.13),
|
|
smoothstep(0.0, 0.7, dir.y)/2.0);
|
|
}
|
|
|
|
vec3 islands(Ray ray) {
|
|
float topStep = smoothstep(0.0, 0.2, ray.nor.y+perlinNoise2D(ray.pos.xz, 5.0, 0.4, 1, 157));
|
|
|
|
// grass
|
|
vec3 col = mix(vec3(0.38, 0.2, 0.0), vec3(0.0, 0.8, 0.2), topStep);
|
|
|
|
// rocky detail
|
|
col = mix(vec3(0.46, 0.3, 0.2), col, (topStep+smoothstep(0.01, 0.25, abs(ray.nor.y+0.707)))/2.0);
|
|
col = mix (col, vec3(0.75, 0.60, 0.36), (1.0-topStep)*perlinNoise2D(ray.pos.xz, 0.1, 0.7, 1, 987));
|
|
|
|
return col;
|
|
}
|
|
|
|
vec3 house(Ray ray) {
|
|
vec3 col = vec3(1.0);
|
|
|
|
// windows
|
|
float g = 4.0/3.0;
|
|
vec3 w = repeat(rY(ray.pos, 35.0) - vec3(g/3.0, g/1.25, g/3.0), vec3(g, 2.0, g)) + vec3(g/2.0);
|
|
float winStep = step(g/2.0, w.x)*step(0.4, w.y)*step(g/2.0, w.z);
|
|
col = mix(vec3(0.0, 0.6, 0.0), col, 1.0-winStep);
|
|
|
|
w = repeat(rY(ray.pos, 35.0) - vec3(g/1.25, g/1.25, g/1.25), vec3(g, 2.0, g)) + vec3(g/2.0);
|
|
winStep = step(g/2.0, w.x)*step(0.4, w.y)*step(g/2.0, w.z);
|
|
col = mix(vec3(0.0, 0.6, 0.0), col, 1.0-winStep);
|
|
|
|
col = mix(vec3(1.0), col, step(9.5, ray.pos.y));
|
|
|
|
// bottom moulding
|
|
float botStep = step(8.0, ray.pos.y);
|
|
col = mix(vec3(0.3, 0.5, 0.0), col, botStep);
|
|
|
|
return col;
|
|
}
|
|
|
|
vec3 roof(Ray ray) {
|
|
vec3 col = vec3(1.0);
|
|
|
|
// tan roof
|
|
col = mix(col, vec3(0.9, 0.7, 0.5), step(0.3, ray.nor.y));
|
|
|
|
// roof lines
|
|
float g = 1.0/2.0;
|
|
vec3 w = repeat(rY(ray.pos + vec3(g), 35.0), vec3(g)) + vec3(g/2.0);
|
|
float lineStep = smoothstep(0.0, 0.02, w.z)*smoothstep(g, g-0.02, w.z);
|
|
col = mix(vec3(0.6, 0.4, 0.2), col, lineStep);
|
|
|
|
// round windows
|
|
vec3 x = rY(vec3(2.0, 0.0, 0.0), 55.0);
|
|
vec3 p = ray.pos-vec3(-1.0, 14.4, -3.0)+x;
|
|
float dist2 = dot(p, p);
|
|
float roundStep = step(dist2, 0.16);
|
|
p = ray.pos-vec3(-1.0, 14.4, -3.0)-x;
|
|
dist2 = dot(p, p);
|
|
roundStep += step(dist2, 0.16);
|
|
col = mix(col, vec3(0.0, 0.6, 0.0), roundStep);
|
|
|
|
return col;
|
|
}
|
|
|
|
vec3 chimney(Ray ray) {
|
|
vec3 col = vec3(1.0, 0.0, 0.0);
|
|
|
|
// bricks
|
|
float g = 1.0/7.0;
|
|
float offset = mod(floor(ray.pos.y/g),2.0)*g/2.0;
|
|
vec3 w = repeat(rY(ray.pos + vec3(g), 35.0) - vec3(offset, 0.0, offset), vec3(g)) + vec3(g/2.0);
|
|
float lineStep = smoothstep(0.0, 0.02, w.x)*smoothstep(g, g-0.02, w.x)*
|
|
smoothstep(0.0, 0.02, w.y)*smoothstep(g, g-0.02, w.y)*
|
|
smoothstep(0.0, 0.02, w.z)*smoothstep(g, g-0.02, w.z);
|
|
col = mix(vec3(0.35, 0.2, 0.1), col, lineStep);
|
|
|
|
col = mix(vec3(0.0), col, 1.0-smoothstep(0.95, 0.99, ray.nor.y));
|
|
|
|
return col;
|
|
}
|
|
|
|
vec3 door() {
|
|
return vec3(0.0, 0.5, 0.6);
|
|
}
|
|
|
|
vec3 doorknob(Ray ray) {
|
|
vec3 col = vec3(1.0, 0.84, 0.0);
|
|
vec3 z = rY(vec3(0,0,1), 55.0);
|
|
col = mix(vec3(0.0), col, smoothstep(0.0, 0.2, abs(ray.nor.y))*smoothstep(0.0, 0.2, abs(dot(ray.nor, z))));
|
|
return col;
|
|
}
|
|
|
|
vec3 wood(Ray ray) {
|
|
vec3 col = vec3(0.6, 0.4, 0.2);
|
|
col *= perlinNoise2D(ray.pos.xz, 5.0, 1.0, 1, 487);
|
|
return col;
|
|
}
|
|
|
|
vec3 apple(Ray ray) {
|
|
vec3 col = vec3(0.8, 0.25, 0.0);
|
|
col *= perlinNoise3D(ray.nor, 4.0, 1.0, 1, 487)*1.75;
|
|
return col;
|
|
}
|
|
|
|
vec3 computeColor(Ray ray) {
|
|
vec3 col = vec3(0.0);
|
|
|
|
// Switch on matID
|
|
// a return -> different/no lighting
|
|
// no return -> default lighting
|
|
if (ray.matID == 0) {
|
|
return sky(ray.dir);
|
|
} else if (ray.matID == 2) {
|
|
col = vec3(0.5);
|
|
} else if (ray.matID == 3) {
|
|
col = islands(ray);
|
|
} else if (ray.matID == 4) {
|
|
col = house(ray);
|
|
} else if (ray.matID == 5) {
|
|
col = roof(ray);
|
|
} else if (ray.matID == 6) {
|
|
col = chimney(ray);
|
|
} else if (ray.matID == 7) {
|
|
col = door();
|
|
} else if (ray.matID == 8) {
|
|
col = doorknob(ray);
|
|
} else if (ray.matID == 9) {
|
|
col = wood(ray);
|
|
} else if (ray.matID == 10) {
|
|
col = apple(ray);
|
|
}
|
|
|
|
// Default lighting
|
|
float sunLight = directionalLightDiffuse(ray.nor, SUN_DIR);
|
|
float sunShadow = softshadow(ray.pos, SUN_DIR);
|
|
|
|
col = col * (0.8 * sunLight * sunShadow + 0.1);
|
|
|
|
return col;
|
|
}
|
|
|
|
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));
|
|
}
|
|
|
|
vec3 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) {
|
|
vec3 res = raymarch(ray);
|
|
float t1 = mix(ray.t, TMAX, step(float(ray.matID), 0.5));
|
|
return vec4(clamp01(res), t1);
|
|
}
|
|
|
|
vec4 getProceduralColor() {
|
|
Ray ray;
|
|
ray.pos = vec3(0.0);
|
|
ray.nor = vec3(0.0);
|
|
ray.matID = 0;
|
|
ray.t = 0.0;
|
|
|
|
vec3 worldEye = getEyeWorldPos();
|
|
vec3 ro = iWorldOrientation * (_position.xyz * iWorldScale) + iWorldPosition; // world position of the current fragment
|
|
vec3 eye = worldEye;
|
|
|
|
ro += vec3(130.0, 5.0, -16.0);
|
|
eye += vec3(130.0, 5.0, -16.0);
|
|
|
|
vec3 rd = normalize(ro - eye); // ray from camera eye to ro
|
|
ray.src = eye;
|
|
ray.dir = rd;
|
|
|
|
return render(ray);
|
|
}
|
|
|
|
|
|
float getProceduralColors(inout vec3 diffuse, inout vec3 specular, inout float shininess) {
|
|
vec4 color = getProceduralColor();
|
|
diffuse = color.rgb;
|
|
specular = color.rgb;
|
|
shininess = 0.5;
|
|
return 1.0;
|
|
} |