-
Notifications
You must be signed in to change notification settings - Fork 31
/
Copy pathindex.html
311 lines (266 loc) · 42.2 KB
/
index.html
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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
<style>
body {
background: #FFF;
color: #222;
padding: 50px;
font: 14px/20px sans-serif;
}
@media (prefers-color-scheme: dark) {
body {
background: #222;
color: #FFF;
}
}
a {
color: inherit;
}
.intro,
.extensions {
max-width: 800px;
margin: 0 auto;
}
.input-output {
max-width: 1100px;
margin: 0 auto;
display: flex;
}
.input,
.output {
vertical-align: top;
display: inline-block;
width: 50%;
box-sizing: border-box;
}
.input {
padding-right: 15px;
}
.output {
padding-left: 15px;
}
h1 {
text-align: center;
margin-bottom: 50px;
font-size: 30px;
line-height: 36px;
}
h2 {
margin-top: 80px;
}
textarea {
max-width: 800px;
width: 100%;
height: 300px;
padding: 10px;
color: inherit;
border: none;
border-radius: 5px;
background: rgba(191, 191, 191, 0.2);
}
pre {
margin: 30px;
}
textarea,
pre {
font: 12px Monaco, monospace;
}
@media (max-width: 800px) {
.input-output {
flex-direction: column;
}
.input,
.output {
width: 100%;
}
.input {
padding-right: 0;
}
.output {
padding-left: 0;
}
}
</style>
<title>GLSL type checker, formatter, and minifier online demo</title>
<body>
<div class="intro">
<h1>GLSL type checker, formatter, and minifier online demo</h1>
<p>
GLSLX is a type checker, code formatter, and minifier/obfuscator for WebGL GLSL code. Straight-forward type
checking makes it possible to catch GLSL errors using continuous integration. Because it actually parses and
understands the code, the minification should be much more robust than other minifiers based on regular
expressions. It doesn't include a preprocessor because it's meant to be used after the preprocessing step. It also
includes automatic insertion of "#extension" statements so their absence can't mess stuff up.
</p>
<p>
The compiler is <a href="https://www.npmjs.org/package/glslx">published on npm</a> and is also available as an <a
href="glslx.js">independent download</a>. That one file works in the browser, as a command-line node script, and
as a node module that can be required by other code. The source code lives at <a
href="https://github.com/evanw/glslx">https://github.com/evanw/glslx</a>.
</p>
</div>
<div class="input-output">
<div class="input">
<h2>Input</h2>
<textarea id="input" autofocus>uniform sampler2D texture;
uniform vec4 color;
attribute vec2 position;
varying vec2 coord;
export void vertex() {
coord = position;
gl_Position = vec4( position*2.0 - 1.0, 0.0,1.0 );
}
export void colorFragment() {
gl_FragColor = color;
}
export void textureFragment() {
gl_FragColor = texture2D(texture, coord);
}
</textarea>
<p>
Load example:
<a href="javascript:void 0" id="bugs">Bugs</a>
<a href="javascript:void 0" id="protophore">Protophore</a>
<a href="javascript:void 0" id="cyclic">Cyclic Redundancy Engine</a>
</p>
<p>
<button id="codeFormatter">Run code formatter</button>
</p>
</div>
<div class="output">
<h2>Output</h2>
<textarea id="output" readonly></textarea>
<p>
Flags:
<label><input id="disableRewriting" type="checkbox" checked> Compact syntax tree</label>
<label><input id="prettyPrint" type="checkbox" checked> Remove whitespace</label>
<label><input id="keepSymbols" type="checkbox" checked> Trim variables</label>
<br>
Rename:
<label><input id="renameAll" type="radio" name="rename" checked> All</label>
<label><input id="renameInternalOnly" type="radio" name="rename"> Internal only</label>
<label><input id="renameNone" type="radio" name="rename"> None</label>
<br>
Format:
<label><input id="formatJSON" type="radio" name="format" checked> JSON</label>
<label><input id="formatJS" type="radio" name="format"> JS</label>
<label><input id="formatCPP" type="radio" name="format"> C++</label>
<label><input id="formatSkew" type="radio" name="format"> Skew</label>
<label><input id="formatRust" type="radio" name="format"> Rust</label>
</p>
</div>
</div>
<div class="extensions">
<h2>Syntax Extensions</h2>
<p>
I call this language GLSLX because it extends GLSL with some additional syntax. The main feature is the "export"
modifier, which allows multiple shaders to be specified from the same file that all reuse the same code. Each
export function becomes the "main" function in a separate shader.
</p>
<pre>// Simple modifier syntax
export void vertexShader() {}
// Modifier block syntax
export {
void vertexShader() {}
void fragmentShader() {}
}</pre>
<p>
API declarations can be done with the "import" modifier. See the compiler's <a
href="https://github.com/evanw/glslx/tree/master/src/core/api.sk">API declarations</a> for more examples.
</p>
<pre>// Simple modifier syntax
import float sin(float x);
// Modifier block syntax
import {
float cos(float x);
vec2 cos(vec2 x);
vec3 cos(vec3 x);
vec4 cos(vec4 x);
}</pre>
<p>
Extensions can be declared with an "#extension" block.
</p>
<pre>#extension GL_EXT_frag_depth {
float gl_FragDepthEXT;
}</pre>
</div>
</body>
<script src="glslx.js"></script>
<script>
(function () {
var input = document.getElementById('input');
var output = document.getElementById('output');
var options = {};
codeFormatter.onclick = function () {
input.value = GLSLX.format(input.value);
};
function option(id) {
function update() {
options[id] = !input.checked;
}
var input = document.getElementById(id);
input.onchange = function () {
update();
compile();
};
update();
}
option('disableRewriting');
option('prettyPrint');
option('keepSymbols');
function rename(id, name) {
function update() {
if (input.checked) {
options.renaming = name;
}
}
var input = document.getElementById(id);
input.onchange = function () {
update();
compile();
};
update();
}
rename('renameAll', 'all');
rename('renameInternalOnly', 'internal-only');
rename('renameNone', 'none');
function format(id, name) {
function update() {
if (input.checked) {
options.format = name;
}
}
var input = document.getElementById(id);
input.onchange = function () {
update();
compile();
};
update();
}
format('formatJSON', 'json');
format('formatJS', 'js');
format('formatCPP', 'c++');
format('formatSkew', 'skew');
format('formatRust', 'rust');
function example(id, content) {
document.getElementById(id).onclick = function () {
input.focus();
input.value = content;
compile();
input.selectionStart = input.selectionEnd = 0;
};
}
example('bugs', 'uniform float time;\nvarying vec4 _color;\n\nvoid main() {\n vec4 color;\n color.rgg = _color.rgb;\n color.a = fade;\n gl_FragColor = mix(vec3(1, 0, 0), color, 0.5 + 0.5 * sin(time));\n}\n');
example('protophore', '// From: https://www.shadertoy.com/view/XljGDz\n\n// These are automatically defined by Shadertoy\nimport {\n uniform vec3 iResolution; // viewport resolution (in pixels)\n uniform float iGlobalTime; // shader playback time (in seconds)\n uniform float iTimeDelta; // render time (in seconds)\n uniform int iFrame; // shader playback frame\n uniform float iChannelTime[4]; // channel playback time (in seconds)\n uniform vec3 iChannelResolution[4]; // channel resolution (in pixels)\n uniform vec4 iMouse; // mouse pixel coords. xy: current (if MLB down), zw: click\n uniform sampler2D iChannel0; // input channel. XX = 2D/Cube\n uniform sampler2D iChannel1; // input channel. XX = 2D/Cube\n uniform sampler2D iChannel2; // input channel. XX = 2D/Cube\n uniform sampler2D iChannel3; // input channel. XX = 2D/Cube\n uniform vec4 iDate; // (year, month, day, time in seconds)\n uniform float iSampleRate; // sound sample rate (i.e., 44100)\n}\n\n/*--------------------------------------------------------------------------------------\nLicense CC0 - http://creativecommons.org/publicdomain/zero/1.0/\nTo the extent possible under law, the author(s) have dedicated all copyright and related and neighboring rights to this software to the public domain worldwide. This software is distributed without any warranty.\n----------------------------------------------------------------------------------------\n^This means do anything you want with this code. Because we are programmers, not lawyers.\n\n-Otavio Good\n*/\n\n// Number of times the fractal repeats\nconst int RECURSION_LEVELS = 4;\n// Animation splits the sphere in different directions\n// This ended up running a significantly slower fps and not looking very different. :(\nconst bool SPLIT_ANIM = false;\n\nfloat localTime = 0.0;\nfloat marchCount;\n\nfloat PI=3.14159265;\n\nvec3 saturate(vec3 a) { return clamp(a, 0.0, 1.0); }\nvec2 saturate(vec2 a) { return clamp(a, 0.0, 1.0); }\nfloat saturate(float a) { return clamp(a, 0.0, 1.0); }\n\nvec3 RotateX(vec3 v, float rad)\n{\n float cos = cos(rad);\n float sin = sin(rad);\n return vec3(v.x, cos * v.y + sin * v.z, -sin * v.y + cos * v.z);\n}\nvec3 RotateY(vec3 v, float rad)\n{\n float cos = cos(rad);\n float sin = sin(rad);\n return vec3(cos * v.x - sin * v.z, v.y, sin * v.x + cos * v.z);\n}\nvec3 RotateZ(vec3 v, float rad)\n{\n float cos = cos(rad);\n float sin = sin(rad);\n return vec3(cos * v.x + sin * v.y, -sin * v.x + cos * v.y, v.z);\n}\n\n\n/*vec3 GetEnvColor(vec3 rayDir, vec3 sunDir)\n{\n vec3 tex = textureCube(iChannel0, rayDir).xyz;\n tex = tex * tex; // gamma correct\n return tex;\n}*/\n\n// This is a procedural environment map with a giant overhead softbox,\n// 4 lights in a horizontal circle, and a bottom-to-top fade.\nvec3 GetEnvColor2(vec3 rayDir, vec3 sunDir)\n{\n // fade bottom to top so it looks like the softbox is casting light on a floor\n // and it\'s bouncing back\n vec3 final = vec3(1.0) * dot(-rayDir, sunDir) * 0.5 + 0.5;\n final *= 0.125;\n // overhead softbox, stretched to a rectangle\n if ((rayDir.y > abs(rayDir.x)*1.0) && (rayDir.y > abs(rayDir.z*0.25))) final = vec3(2.0)*rayDir.y;\n // fade the softbox at the edges with a rounded rectangle.\n float roundBox = length(max(abs(rayDir.xz/max(0.0,rayDir.y))-vec2(0.9, 4.0),0.0))-0.1;\n final += vec3(0.8)* pow(saturate(1.0 - roundBox*0.5), 6.0);\n // purple lights from side\n final += vec3(8.0,6.0,7.0) * saturate(0.001/(1.0 - abs(rayDir.x)));\n // yellow lights from side\n final += vec3(8.0,7.0,6.0) * saturate(0.001/(1.0 - abs(rayDir.z)));\n return vec3(final);\n}\n\n/*vec3 GetEnvColorReflection(vec3 rayDir, vec3 sunDir, float ambient)\n{\n vec3 tex = textureCube(iChannel0, rayDir).xyz;\n tex = tex * tex;\n vec3 texBack = textureCube(iChannel0, rayDir).xyz;\n vec3 texDark = pow(texBack, vec3(50.0)).zzz; // fake hdr texture\n texBack += texDark*0.5 * ambient;\n return texBack*texBack*texBack;\n}*/\n\nvec3 camPos = vec3(0.0), camFacing;\nvec3 camLookat=vec3(0,0.0,0);\n\n// polynomial smooth min (k = 0.1);\nfloat smin( float a, float b, float k )\n{\n float h = clamp( 0.5+0.5*(b-a)/k, 0.0, 1.0 );\n return mix( b, a, h ) - k*h*(1.0-h);\n}\n\nvec2 matMin(vec2 a, vec2 b)\n{\n if (a.x < b.x) return a;\n else return b;\n}\n\nfloat spinTime;\nvec3 diagN = normalize(vec3(-1.0));\nfloat cut = 0.77;\nfloat inner = 0.333;\nfloat outness = 1.414;\nfloat finWidth;\nfloat teeth;\nfloat globalTeeth;\n\nvec2 sphereIter(vec3 p, float radius, float subA)\n{\n finWidth = 0.1;\n teeth = globalTeeth;\n float blender = 0.25;\n vec2 final = vec2(1000000.0, 0.0);\n for (int i = 0; i < RECURSION_LEVELS; i++)\n {\nif (SPLIT_ANIM) {\n // rotate top and bottom of sphere opposite directions\n p = RotateY(p, spinTime*sign(p.y)*0.05/blender);\n}\n // main sphere\n float d = length(p) - radius*outness;\nif (SPLIT_ANIM) {\n // subtract out disc at the place where rotation happens so we don\'t have artifacts\n d = max(d, -(max(length(p) - radius*outness + 0.1, abs(p.y) - finWidth*0.25)));\n}\n\n // calc new position at 8 vertices of cube, scaled\n vec3 corners = abs(p) + diagN * radius;\n float lenCorners = length(corners);\n // subtract out main sphere hole, mirrored on all axises\n float subtracter = lenCorners - radius * subA;\n // make mirrored fins that go through all vertices of the cube\n vec3 ap = abs(-p) * 0.7071; // 1/sqrt(2) to keep distance field normalized\n subtracter = max(subtracter, -(abs(ap.x-ap.y) - finWidth));\n subtracter = max(subtracter, -(abs(ap.y-ap.z) - finWidth));\n subtracter = max(subtracter, -(abs(ap.z-ap.x) - finWidth));\n // subtract sphere from fins so they don\'t intersect the inner spheres.\n // also animate them so they are like teeth\n subtracter = min(subtracter, lenCorners - radius * subA + teeth);\n // smoothly subtract out that whole complex shape\n d = -smin(-d, subtracter, blender);\n //vec2 sphereDist = sphereB(abs(p) + diagN * radius, radius * inner, cut); // recurse\n // do a material-min with the last iteration\n final = matMin(final, vec2(d, float(i)));\n\nif (!SPLIT_ANIM) {\n corners = RotateY(corners, spinTime*0.25/blender);\n}\n // Simple rotate 90 degrees on X axis to keep things fresh\n p = vec3(corners.x, corners.z, -corners.y);\n // Scale things for the next iteration / recursion-like-thing\n radius *= inner;\n teeth *= inner;\n finWidth *= inner;\n blender *= inner;\n }\n // Bring in the final smallest-sized sphere\n float d = length(p) - radius*outness;\n final = matMin(final, vec2(d, 6.0));\n return final;\n}\n\nvec2 DistanceToObject(vec3 p)\n{\n vec2 distMat = sphereIter(p, 5.2 / outness, cut);\n return distMat;\n}\n\n// dirVec MUST BE NORMALIZED FIRST!!!!\nfloat SphereIntersect(vec3 pos, vec3 dirVecPLZNormalizeMeFirst, vec3 spherePos, float rad)\n{\n vec3 radialVec = pos - spherePos;\n float b = dot(radialVec, dirVecPLZNormalizeMeFirst);\n float c = dot(radialVec, radialVec) - rad * rad;\n float h = b * b - c;\n if (h < 0.0) return -1.0;\n return -b - sqrt(h);\n}\n\nexport void mainImage( out vec4 fragColor, in vec2 fragCoord )\n{\n localTime = iGlobalTime - 0.0;\n // ---------------- First, set up the camera rays for ray marching ----------------\n vec2 uv = fragCoord.xy/iResolution.xy * 2.0 - 1.0;\n float zoom = 1.7;\n uv /= zoom;\n\n // Camera up vector.\n vec3 camUp=vec3(0,1,0);\n\n // Camera lookat.\n camLookat=vec3(0,0.0,0);\n\n // debugging camera\n float mx=iMouse.x/iResolution.x*PI*2.0-0.7 + localTime*3.1415 * 0.0625*0.666;\n float my=-iMouse.y/iResolution.y*10.0 - sin(localTime * 0.31)*0.5;//*PI/2.01;\n camPos += vec3(cos(my)*cos(mx),sin(my),cos(my)*sin(mx))*(12.2);\n\n // Camera setup.\n vec3 camVec=normalize(camLookat - camPos);\n vec3 sideNorm=normalize(cross(camUp, camVec));\n vec3 upNorm=cross(camVec, sideNorm);\n vec3 worldFacing=(camPos + camVec);\n vec3 worldPix = worldFacing + uv.x * sideNorm * (iResolution.x/iResolution.y) + uv.y * upNorm;\n vec3 rayVec = normalize(worldPix - camPos);\n\n // ----------------------------------- Animate ------------------------------------\n localTime = iGlobalTime*0.5;\n // This is a wave function like a triangle wave, but with flat tops and bottoms.\n // period is 1.0\n float rampStep = min(3.0,max(1.0, abs((fract(localTime)-0.5)*1.0)*8.0))*0.5-0.5;\n rampStep = smoothstep(0.0, 1.0, rampStep);\n // lopsided triangle wave - goes up for 3 time units, down for 1.\n float step31 = (max(0.0, (fract(localTime+0.125)-0.25)) - min(0.0,(fract(localTime+0.125)-0.25))*3.0)*0.333;\n\n spinTime = step31 + localTime;\n //globalTeeth = 0.0 + max(0.0, sin(localTime*3.0))*0.9;\n globalTeeth = rampStep*0.99;\n cut = max(0.48, min(0.77, localTime));\n // --------------------------------------------------------------------------------\n vec2 distAndMat = vec2(0.5, 0.0);\n float t = 0.0;\n //float inc = 0.02;\n float maxDepth = 24.0;\n vec3 pos = vec3(0,0,0);\n marchCount = 0.0;\n // intersect with sphere first as optimization so we don\'t ray march more than is needed.\n float hit = SphereIntersect(camPos, rayVec, vec3(0.0), 5.6);\n if (hit >= 0.0)\n {\n t = hit;\n // ray marching time\n for (int i = 0; i < 290; i++) // This is the count of the max times the ray actually marches.\n {\n pos = camPos + rayVec * t;\n // *******************************************************\n // This is _the_ function that defines the "distance field".\n // It\'s really what makes the scene geometry.\n // *******************************************************\n distAndMat = DistanceToObject(pos);\n // adjust by constant because deformations mess up distance function.\n t += distAndMat.x * 0.7;\n //if (t > maxDepth) break;\n if ((t > maxDepth) || (abs(distAndMat.x) < 0.0025)) break;\n marchCount+= 1.0;\n }\n }\n else\n {\n t = maxDepth + 1.0;\n distAndMat.x = 1000000.0;\n }\n // --------------------------------------------------------------------------------\n // Now that we have done our ray marching, let\'s put some color on this geometry.\n\n vec3 sunDir = normalize(vec3(3.93, 10.82, -1.5));\n vec3 finalColor = vec3(0.0);\n\n // If a ray actually hit the object, let\'s light it.\n //if (abs(distAndMat.x) < 0.75)\n if (t <= maxDepth)\n {\n // calculate the normal from the distance field. The distance field is a volume, so if you\n // sample the current point and neighboring points, you can use the difference to get\n // the normal.\n vec3 smallVec = vec3(0.005, 0, 0);\n vec3 normalU = vec3(distAndMat.x - DistanceToObject(pos - smallVec.xyy).x,\n distAndMat.x - DistanceToObject(pos - smallVec.yxy).x,\n distAndMat.x - DistanceToObject(pos - smallVec.yyx).x);\n\n vec3 normal = normalize(normalU);\n\n // calculate 2 ambient occlusion values. One for global stuff and one\n // for local stuff\n float ambientS = 1.0;\n ambientS *= saturate(DistanceToObject(pos + normal * 0.1).x*10.0);\n ambientS *= saturate(DistanceToObject(pos + normal * 0.2).x*5.0);\n ambientS *= saturate(DistanceToObject(pos + normal * 0.4).x*2.5);\n ambientS *= saturate(DistanceToObject(pos + normal * 0.8).x*1.25);\n float ambient = ambientS * saturate(DistanceToObject(pos + normal * 1.6).x*1.25*0.5);\n ambient *= saturate(DistanceToObject(pos + normal * 3.2).x*1.25*0.25);\n ambient *= saturate(DistanceToObject(pos + normal * 6.4).x*1.25*0.125);\n ambient = max(0.035, pow(ambient, 0.3)); // tone down ambient with a pow and min clamp it.\n ambient = saturate(ambient);\n\n // calculate the reflection vector for highlights\n vec3 ref = reflect(rayVec, normal);\n ref = normalize(ref);\n\n // Trace a ray for the reflection\n float sunShadow = 1.0;\n float iter = 0.1;\n vec3 nudgePos = pos + normal*0.02; // don\'t start tracing too close or inside the object\n for (int i = 0; i < 40; i++)\n {\n float tempDist = DistanceToObject(nudgePos + ref * iter).x;\n sunShadow *= saturate(tempDist*50.0);\n if (tempDist <= 0.0) break;\n //iter *= 1.5; // constant is more reliable than distance-based\n iter += max(0.00, tempDist)*1.0;\n if (iter > 4.2) break;\n }\n sunShadow = saturate(sunShadow);\n\n // ------ Calculate texture color ------\n vec3 texColor;\n texColor = vec3(1.0);// vec3(0.65, 0.5, 0.4)*0.1;\n texColor = vec3(0.85, 0.945 - distAndMat.y * 0.15, 0.93 + distAndMat.y * 0.35)*0.951;\n if (distAndMat.y == 6.0) texColor = vec3(0.91, 0.1, 0.41)*10.5;\n //texColor *= mix(vec3(0.3), vec3(1.0), tex3d(pos*0.5, normal).xxx);\n texColor = max(texColor, vec3(0.0));\n texColor *= 0.25;\n\n // ------ Calculate lighting color ------\n // Start with sun color, standard lighting equation, and shadow\n vec3 lightColor = vec3(0.0);// sunCol * saturate(dot(sunDir, normal)) * sunShadow*14.0;\n // sky color, hemisphere light equation approximation, ambient occlusion\n lightColor += vec3(0.1,0.35,0.95) * (normal.y * 0.5 + 0.5) * ambient * 0.2;\n // ground color - another hemisphere light\n lightColor += vec3(1.0) * ((-normal.y) * 0.5 + 0.5) * ambient * 0.2;\n\n\n // finally, apply the light to the texture.\n finalColor = texColor * lightColor;\n //if (distAndMat.y == ceil(mod(localTime, 4.0))) finalColor += vec3(0.0, 0.41, 0.72)*0.925;\n\n // reflection environment map - this is most of the light\n vec3 refColor = GetEnvColor2(ref, sunDir)*sunShadow;\n finalColor += refColor * 0.35 * ambient;// * sunCol * sunShadow * 9.0 * texColor.g;\n\n // fog\n finalColor = mix(vec3(1.0, 0.41, 0.41) + vec3(1.0), finalColor, exp(-t*0.0007));\n // visualize length of gradient of distance field to check distance field correctness\n //finalColor = vec3(0.5) * (length(normalU) / smallVec.x);\n }\n else\n {\n finalColor = GetEnvColor2(rayVec, sunDir);// + vec3(0.1, 0.1, 0.1);\n }\n //finalColor += marchCount * vec3(1.0, 0.3, 0.91) * 0.001;\n\n // vignette?\n //finalColor *= vec3(1.0) * saturate(1.0 - length(uv/2.5));\n //finalColor *= 1.95;\n\n // output the final color with sqrt for "gamma correction"\n fragColor = vec4(sqrt(clamp(finalColor, 0.0, 1.0)),1.0);\n}');
example('cyclic', '// From: https://www.shadertoy.com/view/XtjXWD\n\n// These are automatically defined by Shadertoy\nimport {\n uniform vec3 iResolution; // viewport resolution (in pixels)\n uniform float iGlobalTime; // shader playback time (in seconds)\n uniform float iTimeDelta; // render time (in seconds)\n uniform int iFrame; // shader playback frame\n uniform float iChannelTime[4]; // channel playback time (in seconds)\n uniform vec3 iChannelResolution[4]; // channel resolution (in pixels)\n uniform vec4 iMouse; // mouse pixel coords. xy: current (if MLB down), zw: click\n uniform sampler2D iChannel0; // input channel. XX = 2D/Cube\n uniform sampler2D iChannel1; // input channel. XX = 2D/Cube\n uniform sampler2D iChannel2; // input channel. XX = 2D/Cube\n uniform sampler2D iChannel3; // input channel. XX = 2D/Cube\n uniform vec4 iDate; // (year, month, day, time in seconds)\n uniform float iSampleRate; // sound sample rate (i.e., 44100)\n}\n\n/*--------------------------------------------------------------------------------------\nLicense CC0 - http://creativecommons.org/publicdomain/zero/1.0/\nTo the extent possible under law, the author(s) have dedicated all copyright and related and neighboring rights to this software to the public domain worldwide. This software is distributed without any warranty.\n----------------------------------------------------------------------------------------\n^ This means do ANYTHING YOU WANT with this code. Because we are programmers, not lawyers.\n-Otavio Good\n*/\n\n// ---------------- Config ----------------\n// This is an option that lets you render high quality frames for screenshots. It enables\n// stochastic antialiasing and motion blur automatically for any shader.\nconst bool NON_REALTIME_HQ_RENDER = false;\nconst float frameToRenderHQ = 15.1; // Time in seconds of frame to render\nconst float antialiasingSamples = 16.0; // 16x antialiasing - too much might make the shader compiler angry.\n\nconst bool MANUAL_CAMERA = false;\n\n\n// --------------------------------------------------------\n// These variables are for the non-realtime block renderer.\nfloat localTime = 0.0;\nfloat seed = 1.0;\n\n// Animation variables\nfloat fade = 1.0;\nfloat exposure = 1.0;\n\n// other\nfloat marchCount = 0.0;\n\n// ---- noise functions ----\nfloat v31(vec3 a)\n{\n return a.x + a.y * 37.0 + a.z * 521.0;\n}\nfloat v21(vec2 a)\n{\n return a.x + a.y * 37.0;\n}\nfloat Hash11(float a)\n{\n return fract(sin(a)*10403.9);\n}\nfloat Hash21(vec2 uv)\n{\n float f = uv.x + uv.y * 37.0;\n return fract(sin(f)*104003.9);\n}\nvec2 Hash22(vec2 uv)\n{\n float f = uv.x + uv.y * 37.0;\n return fract(cos(f)*vec2(10003.579, 37049.7));\n}\nvec2 Hash12(float f)\n{\n return fract(cos(f)*vec2(10003.579, 37049.7));\n}\n\nconst float PI=3.14159265;\n\nvec3 saturate(vec3 a) { return clamp(a, 0.0, 1.0); }\nvec2 saturate(vec2 a) { return clamp(a, 0.0, 1.0); }\nfloat saturate(float a) { return clamp(a, 0.0, 1.0); }\n\nvec3 RotateX(vec3 v, float rad)\n{\n float cos = cos(rad);\n float sin = sin(rad);\n return vec3(v.x, cos * v.y + sin * v.z, -sin * v.y + cos * v.z);\n}\nvec3 RotateY(vec3 v, float rad)\n{\n float cos = cos(rad);\n float sin = sin(rad);\n return vec3(cos * v.x - sin * v.z, v.y, sin * v.x + cos * v.z);\n}\nvec3 RotateZ(vec3 v, float rad)\n{\n float cos = cos(rad);\n float sin = sin(rad);\n return vec3(cos * v.x + sin * v.y, -sin * v.x + cos * v.y, v.z);\n}\n\n// Make a procedural environment map with a giant softbox light.\nvec3 GetEnvColor2(vec3 rayDir)\n{\n // fade bottom to top so it looks like the softbox is casting light on a floor\n // and it\'s bouncing back\n vec3 final = vec3(1.0) * dot(rayDir, /*sunDir*/ vec3(0.0, 1.0, 0.0)) * 0.5 + 0.5;\n final *= 0.25;\n // overhead softbox, stretched to a rectangle\n if ((rayDir.y > abs(rayDir.x)*1.0) && (rayDir.y > abs(rayDir.z*0.25))) final = vec3(2.0)*rayDir.y;\n // fade the softbox at the edges with a rounded rectangle.\n float roundBox = length(max(abs(rayDir.xz/max(0.0,rayDir.y))-vec2(0.9, 4.0),0.0))-0.1;\n final += vec3(0.8)* pow(saturate(1.0 - roundBox*0.5), 6.0);\n // purple lights from side\n //final += vec3(8.0,6.0,7.0) * saturate(0.001/(1.0 - abs(rayDir.x)));\n // yellow lights from side\n //final += vec3(8.0,7.0,6.0) * saturate(0.001/(1.0 - abs(rayDir.z)));\n return vec3(final);\n}\n\n// min function that supports materials in the y component\nvec2 matmin(vec2 a, vec2 b)\n{\n if (a.x < b.x) return a;\n else return b;\n}\n\n// ---- shapes defined by distance fields ----\n// See this site for a reference to more distance functions...\n// http://iquilezles.org/www/articles/distfunctions/distfunctions.htm\n\n// signed box distance field\nfloat sdBox(vec3 p, vec3 radius)\n{\n vec3 dist = abs(p) - radius;\n return min(max(dist.x, max(dist.y, dist.z)), 0.0) + length(max(dist, 0.0));\n}\n\n// capped cylinder distance field\nfloat cylCap(vec3 p, float r, float lenRad)\n{\n float a = length(p.xy) - r;\n a = max(a, abs(p.z) - lenRad);\n return a;\n}\n\nfloat cyl(vec3 p, float rad)\n{\n return length(p.xy) - rad;\n}\n\nfloat sdTorus(vec3 p, vec2 radOuterInner)\n{\n vec2 cylAndHeight = vec2(length(p.xz) - radOuterInner.x, p.y);\n return length(cylAndHeight) - radOuterInner.y;\n}\n\nfloat sSphere(vec3 p, float rad)\n{\n return length(p) - rad;\n}\n\n// k should be negative. -4.0 works nicely.\n// smooth blending function\nfloat smin(float a, float b, float k)\n{\n return log2(exp2(k*a)+exp2(k*b))/k;\n}\n\nfloat Repeat(float a, float len)\n{\n return mod(a, len) - 0.5 * len;\n}\n\nvec3 RadialRepeat(vec3 p, float ang)\n{\n float len = length(p.xz);\n float a = atan(p.z, p.x);// / PI;\n a = Repeat(a, PI/ang);\n return vec3(cos(a)*len, p.y, sin(a)*len);\n}\n\nfloat MakeGear(vec3 p, float rad, float side)\n{\n p = RotateZ(p, -localTime + PI * 0.2 + (side-1.0)*0.39);\n p.xzy = RadialRepeat(p.xzy, 2.0);\n float gear = sdTorus((p - vec3(1.5, 0.0, 0.0)).xzy, vec2(rad-0.3, 0.1));\n return gear;\n}\n\n// This is the distance function that defines all the scene\'s geometry.\n// The input is a position in space.\n// The output is the distance to the nearest surface and a material index.\nvec2 DistanceToObject(vec3 p)\n{\n // make a box where the space is subdivided around in a circle.\n // Then subtract out a few cylinders to get the dynamic ball-roller.\n vec3 orig = p;\n p += vec3(0.0, 0.0, 0.0);\n float wobble = -localTime * 4.0 - PI*0.5;\n vec3 wobble2 = vec3(cos(wobble), 0.0, sin(wobble))*0.5;\n p += wobble2;\n vec2 distAndMat = vec2(0.0);\n float a = atan(p.z, p.x);// / PI;\n vec3 rep = RadialRepeat(p, 4096.0);\n distAndMat.x = length(rep- vec3(3.5, 0.0, 0.0)) - 0.4;\n a = (a+0.5);\n rep = RotateZ(rep - vec3(3.5, 0.0, 0.0), localTime+a*0.25) + vec3(3.5, 0.0, 0.0);\n distAndMat.x = sdBox(rep - vec3(3.5, 0.0, 0.0), vec3(0.95,0.95,2.9));\n distAndMat.x = max(distAndMat.x, -cyl(rep - vec3(3.5, 0.0, 0.0), 0.9));\n\n float crad = 1.38;\n float disp = 2.0;\n vec3 railMirror = vec3(rep.x - 3.5, abs(rep.y) - disp, rep.z);\n distAndMat.x = max(distAndMat.x, -cyl(railMirror, crad));\n railMirror = vec3(abs(rep.x - 3.5) - disp, rep.y, rep.z);\n distAndMat.x = max(distAndMat.x, -cyl(railMirror, crad));\n //distAndMat.x = max(distAndMat.x, -cyl(rep - vec3(3.5, -disp, 0.0), crad));\n //distAndMat.x = max(distAndMat.x, -cyl(rep - vec3(3.5, disp, 0.0), crad));\n //distAndMat.x = max(distAndMat.x, -cyl(rep - vec3(3.5+disp, 0.0, 0.0), crad));\n //distAndMat.x = max(distAndMat.x, -cyl(rep - vec3(3.5-disp, 0.0, 0.0), crad));\n\n // Make the ball and material. Rotate it around.\n float ball = length(RotateY(p, localTime*4.0) - vec3(-2.57, 0.73, 0.0)) - 0.7;\n distAndMat = matmin(distAndMat, vec2(ball, 1.0));\n\n // Make the clover-gears\n vec3 gPos = orig;\n float side = sign(gPos.x);\n gPos.x = abs(gPos.x);\n gPos -= vec3(3.4 - wobble2.x/1.414*side, -3.3, 0.0);\n float gear = MakeGear(gPos, crad, side);\n distAndMat = matmin(distAndMat, vec2(gear, 4.0));\n\n // Make the torus and supports\n float torus = sdTorus(orig + vec3(0.0 + wobble2.x/1.414, 3.3, 0.0), vec2(3.4, 0.32));\n vec3 mirror = orig;\n mirror.z = abs(mirror.z);\n vec3 blobPos = (mirror + vec3(wobble2.x, 3.3, -3.4)).zxy;\n float blob = sdTorus(blobPos, vec2(0.4, 0.15));\n torus = min(torus, cylCap(blobPos + vec3(-0.4, 0.0, 8.0), 0.15, 8.0));\n torus = min(torus, blob);\n distAndMat = matmin(distAndMat, vec2(torus, 5.0));\n\n // Make the middle spiral and the turntable base\n vec3 warp = RotateY(orig, localTime*4.0);\n float p0 = p.y;\n float p1 = p.y;\n float w2 = warp.y+PI*0.34;\n float spiral = length(warp.xz + vec2(cos(w2), sin(w2))*((p0*p0)*0.07) ) - 0.2;\n float spiral2 = length(warp.xz + vec2(-cos(w2), -sin(w2))*(((p1)*(p1))*0.05) ) - 0.1;\n spiral = min(spiral, spiral2);\n spiral *= 0.35;\n spiral = max(spiral, abs(p.y)-6.5);\n float base = min(spiral, (length(orig.xz) + orig.y*2.0)*0.5+4.7);\n base = max(base, cylCap(orig.xzy + vec3(0.0, 0.0, 6.6+4.0), 5.22, 4.4));\n base = max(base, -sdTorus(orig + vec3(0.0, 6.25, 0.0), vec2(3.1, 0.0625)));\n vec3 mirrorOrig = vec3(orig.x, abs(orig.z) - 3.9, orig.y);\n base = max(base, -cyl(mirrorOrig, 0.7));\n spiral = min(base, spiral);\n distAndMat = matmin(distAndMat, vec2(spiral, 2.0));\n\n return distAndMat;\n}\n\n// Input is UV coordinate of pixel to render.\n// Output is RGB color.\nvec3 RayTrace(in vec2 fragCoord )\n{\n marchCount = 0.0;\n fade = 1.0;\n\n vec3 camPos, camUp, camLookat;\n // ------------------- Set up the camera rays for ray marching --------------------\n // Map uv to [-1.0..1.0]\n vec2 uv = fragCoord.xy/iResolution.xy * 2.0 - 1.0;\n uv /= 2.0; // zoom in\n\nif (MANUAL_CAMERA) {\n // Camera up vector.\n camUp=vec3(0,1,0);\n\n // Camera lookat.\n camLookat=vec3(0,-1.5,0);\n\n // debugging camera\n float mx=-iMouse.x/iResolution.x*PI*2.0;\n float my=iMouse.y/iResolution.y*3.14*0.95 + PI/2.0;\n camPos = vec3(cos(my)*cos(mx),sin(my),cos(my)*sin(mx))*12.0;\n} else {\n // Do the camera fly-by animation and different scenes.\n // Time variables for start and end of each scene\n const float t0 = 0.0;\n const float t1 = 12.0;\n const float t2 = 20.0;\n const float t3 = 38.0;\n // Repeat the animation after time t3\n localTime = fract(localTime / t3) * t3;\n if (localTime < t1)\n {\n float time = localTime - t0;\n float alpha = time / (t1 - t0);\n fade = saturate(time);\n fade *= saturate(t1 - localTime);\n camPos = vec3(0.0, -8.0, -8.0);\n camPos.x -= smoothstep(0.0, 1.0, alpha) * 5.0;\n camPos.y += smoothstep(0.0, 1.0, alpha) * 9.0;\n camPos.z -= smoothstep(0.0, 1.0, alpha) * 6.0;\n camUp=vec3(0,1,0);\n camLookat=vec3(0,-2.5,1.5);\n } else if (localTime < t2)\n {\n float time = localTime - t1;\n float alpha = time / (t2 - t1);\n fade = saturate(time);\n fade *= saturate(t2 - localTime);\n camPos = vec3(12.0, 8.3, -0.5);\n camPos.y -= alpha * 5.5;\n camPos.x = cos(alpha*1.0) * 5.2;\n camPos.z = sin(alpha*1.0) * 5.2;\n camUp=normalize(vec3(0,1,-0.5 + alpha * 0.5));\n camLookat=vec3(0,1.0,-0.5);\n } else if (localTime < t3)\n {\n float time = localTime - t2;\n float alpha = time / (t3 - t2);\n fade = saturate(time);\n fade *= saturate(t3 - localTime);\n camPos = vec3(-9.0, 1.3, -10.0);\n camPos.y -= alpha * 8.0;\n camPos.x += alpha * 7.0;\n camUp=normalize(vec3(0,1,0.0));\n camLookat=vec3(0.0,-2.0,0.0);\n }\n}\n\n // Camera setup for ray tracing / marching\n vec3 camVec=normalize(camLookat - camPos);\n vec3 sideNorm=normalize(cross(camUp, camVec));\n vec3 upNorm=cross(camVec, sideNorm);\n vec3 worldFacing=(camPos + camVec);\n vec3 worldPix = worldFacing + uv.x * sideNorm * (iResolution.x/iResolution.y) + uv.y * upNorm;\n vec3 rayVec = normalize(worldPix - camPos);\n\n // ----------------------------- Ray march the scene ------------------------------\n vec2 distAndMat; // Distance and material\n float t = 0.05;\n const float maxDepth = 22.0; // farthest distance rays will travel\n vec3 pos = vec3(0.0);\n const float smallVal = 0.00625;\n // ray marching time\n for (int i = 0; i <180; i++) // This is the count of the max times the ray actually marches.\n {\n marchCount+=1.0;\n // Step along the ray.\n pos = (camPos + rayVec * t);\n // This is _the_ function that defines the "distance field".\n // It\'s really what makes the scene geometry. The idea is that the\n // distance field returns the distance to the closest object, and then\n // we know we are safe to "march" along the ray by that much distance\n // without hitting anything. We repeat this until we get really close\n // and then break because we have effectively hit the object.\n distAndMat = DistanceToObject(pos);\n\n // move down the ray a safe amount\n t += distAndMat.x;\n // If we are very close to the object, let\'s call it a hit and exit this loop.\n if ((t > maxDepth) || (abs(distAndMat.x) < smallVal)) break;\n }\n\n // --------------------------------------------------------------------------------\n // Now that we have done our ray marching, let\'s put some color on this geometry.\n vec3 finalColor = vec3(0.0);\n\n // If a ray actually hit the object, let\'s light it.\n if (t <= maxDepth)\n {\n float dist = distAndMat.x;\n // calculate the normal from the distance field. The distance field is a volume, so if you\n // sample the current point and neighboring points, you can use the difference to get\n // the normal.\n vec3 smallVec = vec3(smallVal, 0, 0);\n vec3 normalU = vec3(dist - DistanceToObject(pos - smallVec.xyy).x,\n dist - DistanceToObject(pos - smallVec.yxy).x,\n dist - DistanceToObject(pos - smallVec.yyx).x);\n vec3 normal = normalize(normalU);\n\n // calculate the reflection vector for highlights\n vec3 ref = reflect(rayVec, normal);\n\n // Trace a relection ray\n float refShadow = 1.0;\n float iter = 0.01;\n vec3 nudgePos = pos + normal*0.002; // don\'t start tracing too close or inside the object\n for (int i = 0; i < 40; i++)\n {\n vec3 shadowPos = nudgePos + ref * iter;\n vec2 tempDistAndMat = DistanceToObject(shadowPos);\n refShadow *= saturate(tempDistAndMat.x*150.0); // Shadow hardness\n if (tempDistAndMat.x <= 0.0) break;\n\n iter += max(0.05, tempDistAndMat.x);\n if (iter > 7.5) break;\n }\n refShadow = saturate(refShadow);\n\n // ------ Calculate texture color ------\n vec3 texColor = vec3(0.95, 1.0, 1.0);\n if (distAndMat.y == 2.0) texColor = vec3(0.5, 0.3, 0.3)*0.03;\n if (distAndMat.y == 0.0) texColor = vec3(0.3,0.25,0.25)*0.1;\n if (distAndMat.y == 1.0) texColor = vec3(0.2, 0.3, 0.71)*0.1;\n if (distAndMat.y == 4.0) texColor = vec3(0.01, 0.01, 0.01)*0.2;\n if (distAndMat.y == 5.0) texColor = vec3(1.0, 1.0, 1.0)*0.0015;\n texColor = saturate(texColor);\n\n // ------ Calculate lighting color ------\n vec3 lightColor = vec3(0.0);\n // Add sky color with ambient acclusion\n lightColor += (/*skyCol */ saturate(normal.y *0.5+0.5))*2.5;\n\n // finally, apply the light to the texture.\n finalColor = texColor * lightColor;\n if (distAndMat.y == 1.0) finalColor += vec3(0.5, 0.1, 0.3)*0.5*dot(normal, -rayVec);\n //vec3 refColor = GetEnvMapSkyline(ref, sunDir, pos.y-1.5)*max(0.2,sunShadow);\n vec3 refColor = GetEnvColor2(ref) * (refShadow + 0.5) * 0.5;\n if (distAndMat.y == 0.0) refColor *= vec3(1.0, 0.5, 0.2)*3.0*dot(normal, -rayVec);\n if (distAndMat.y == 5.0) refColor *= vec3(0.7, 0.75, 0.82)*1.0*dot(normal, -rayVec);\n float fresnel = saturate(1.0 - dot(-rayVec, normal));\n fresnel = mix(0.5, 1.0, fresnel);\n finalColor += refColor * fresnel * 0.8;\n\n // visualize length of gradient of distance field to check distance field correctness\n //finalColor = vec3(0.5) * (length(normalU) / smallVec.x);\n //finalColor = vec3(marchCount)/255.0;\n //finalColor = normal * 0.5 + 0.5;\n }\n else\n {\n // Our ray trace hit nothing, so draw background.\n finalColor = GetEnvColor2(rayVec);\n }\n finalColor += marchCount *vec3(1.0, 0.5, 0.7)*0.001;\n\n // vignette?\n finalColor *= vec3(1.0) * saturate(1.0 - length(uv/2.5));\n finalColor *= exposure;\n\n // output the final color without gamma correction - will do gamma later.\n return vec3(clamp(finalColor, 0.0, 1.0)*saturate(fade));\n}\n\n// This function breaks the image down into blocks and scans\n// through them, rendering 1 block at a time. It\'s for non-\n// realtime things that take a long time to render.\n\n// This is the frame rate to render at. Too fast and you will\n// miss some blocks.\nconst float blockRate = 20.0;\nvoid BlockRender(in vec2 fragCoord)\n{\n // blockSize is how much it will try to render in 1 frame.\n // adjust this smaller for more complex scenes, bigger for\n // faster render times.\n const float blockSize = 64.0;\n // Make the block repeatedly scan across the image based on time.\n float frame = floor(iGlobalTime * blockRate);\n vec2 blockRes = floor(iResolution.xy / blockSize) + vec2(1.0);\n // ugly bug with mod.\n //float blockX = mod(frame, blockRes.x);\n float blockX = fract(frame / blockRes.x) * blockRes.x;\n //float blockY = mod(floor(frame / blockRes.x), blockRes.y);\n float blockY = fract(floor(frame / blockRes.x) / blockRes.y) * blockRes.y;\n // Don\'t draw anything outside the current block.\n if ((fragCoord.x - blockX * blockSize >= blockSize) ||\n (fragCoord.x - (blockX - 1.0) * blockSize < blockSize) ||\n (fragCoord.y - blockY * blockSize >= blockSize) ||\n (fragCoord.y - (blockY - 1.0) * blockSize < blockSize))\n {\n discard;\n }\n}\n\nexport void mainImage( out vec4 fragColor, in vec2 fragCoord )\n{\nif (NON_REALTIME_HQ_RENDER) {\n // Optionally render a non-realtime scene with high quality\n BlockRender(fragCoord);\n}\n\n // Do a multi-pass render\n vec3 finalColor = vec3(0.0);\nif (NON_REALTIME_HQ_RENDER) {\n for (float i = 0.0; i < antialiasingSamples; i++)\n {\n const float motionBlurLengthInSeconds = 1.0 / 60.0;\n // Set this to the time in seconds of the frame to render.\n localTime = frameToRenderHQ;\n // This line will motion-blur the renders\n localTime += Hash11(v21(fragCoord + seed)) * motionBlurLengthInSeconds;\n // Jitter the pixel position so we get antialiasing when we do multiple passes.\n vec2 jittered = fragCoord.xy + vec2(\n Hash21(fragCoord + seed),\n Hash21(fragCoord*7.234567 + seed)\n );\n // don\'t antialias if only 1 sample.\n if (antialiasingSamples == 1.0) jittered = fragCoord;\n // Accumulate one pass of raytracing into our pixel value\n finalColor += RayTrace(jittered);\n // Change the random seed for each pass.\n seed *= 1.01234567;\n }\n // Average all accumulated pixel intensities\n finalColor /= antialiasingSamples;\n} else {\n // Regular real-time rendering\n localTime = iGlobalTime;\n finalColor = RayTrace(fragCoord);\n}\n\n fragColor = vec4(sqrt(clamp(finalColor, 0.0, 1.0)),1.0);\n}\n');
function compile() {
var result = GLSLX.compile(input.value, options);
if (result.output) {
output.value = result.output;
} else {
output.value = result.log;
}
}
input.oninput = compile;
input.focus();
compile();
})();
</script>