-
Notifications
You must be signed in to change notification settings - Fork 3
/
emulator.glsl
127 lines (110 loc) · 3.34 KB
/
emulator.glsl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
// This file implements an emulator for a LED-Panel cube.
//
// The renderer is based upon this ray marching tutorial:
// http://jamie-wong.com/2016/07/15/ray-marching-signed-distance-functions/
//
// To use:
//
// 1. define the special rendering function:
//
// void mainCube(out vec4 fragColor, in vec3 fragCoord);
//
// 2. Define the mainImage function with include guard:
//
// #ifndef _EMULATOR
// void mainImage(out vec4 fragColor, in vec2 fragCoord) {
// mainCube(fragColor, cube_map_to_3d(fragCoord) * 2 - 1);
// }
// #endif
//
// 3. Include the emulator by prepending a separate -i option on the Shady command line:
//
// shady -i emulator.glsl -i my-animation.glsl <other options>
#define _EMULATOR
#pragma use "libcube.glsl"
#pragma map gyros=perip_mat4:/dev/ttyUSB0;230400?
// Forward declaration of the function that renders the surface of the cube.
void mainCube(out vec4 fragColor, in vec3 fragCoord);
#define EMU_GRID 64
const int EMU_MAX_MARCHING_STEPS = 255;
const float EMU_MIN_DIST = 0.0;
const float EMU_MAX_DIST = 100.0;
float emuCubeSDF(vec3 samplePoint) {
return length(max(abs(samplePoint) - vec3(0.5), 0.0));
}
float emuSceneSDF(vec3 samplePoint) {
return emuCubeSDF(samplePoint);
}
float emuShortestDistanceToSurface(vec3 eye, vec3 marchingDirection, float start, float end) {
float depth = start;
for (int i = 0; i < EMU_MAX_MARCHING_STEPS; i++) {
float dist = emuSceneSDF(eye + depth * marchingDirection);
if (dist < EPSILON) {
return depth;
}
depth += dist;
if (depth >= end) {
return end;
}
}
return end;
}
vec3 emuRayDirection(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 emuEstimateNormal(vec3 p) {
return normalize(vec3(
emuSceneSDF(vec3(p.x + EPSILON, p.y, p.z)) - emuSceneSDF(vec3(p.x - EPSILON, p.y, p.z)),
emuSceneSDF(vec3(p.x, p.y + EPSILON, p.z)) - emuSceneSDF(vec3(p.x, p.y - EPSILON, p.z)),
emuSceneSDF(vec3(p.x, p.y, p.z + EPSILON)) - emuSceneSDF(vec3(p.x, p.y, p.z - EPSILON))
));
}
vec3 emuBackground(vec2 coord) {
float s = 12;
float c = step(mod(coord.x * s + step(mod(coord.y * s, 2), 1), 2), 1);
return vec3(c * 0.5);
}
void mainImage(out vec4 fragColor, in vec2 fragCoord) {
vec3 dir = emuRayDirection(36.0, iResolution.xy, fragCoord);
vec3 eye = vec3(0.0, 0.0, 5.0);
mat3 model = mat3(gyros);
if (model == mat3(1)) {
float r = iTime * .5;
mat3 mx = mat3(
1.0, 0.0, 0.0,
0.0, cos(r), sin(r),
0.0, -sin(r), cos(r)
);
mat3 my = mat3(
cos(r), 0.0, sin(r),
0.0, 1.0, 0.0,
-sin(r), 0.0, cos(r)
);
model = my * mx;
}
eye = eye * model;
dir = dir * model;
float dist = emuShortestDistanceToSurface(eye, dir, EMU_MIN_DIST, EMU_MAX_DIST);
if (dist > EMU_MAX_DIST - EPSILON) {
// Didn't hit anything, draw the background.
float s = max(iResolution.y, iResolution.y);
fragColor = vec4(emuBackground(fragCoord / s), 1.0);
return;
}
// The closest point on the surface to the eyepoint along the view ray
vec3 p = eye + dist * dir;
#ifndef EMU_GRID
mainCube(fragColor, p);
#else
float grid = EMU_GRID;
float pixSize = .35;
vec4 sideCoord = cube_map_to_side(p);
if (length(mod(sideCoord.xy * grid, 1) - .5) < pixSize) {
mainCube(fragColor, round(p * grid - .5) / grid);
} else {
fragColor = vec4(0);
}
#endif
}