Add 3D logo
This change adds a 3d rendering of the Zuul logo. Change-Id: I56d311c95dac678057a440878ac2f8b24d7be977
This commit is contained in:
parent
f1ee08440b
commit
65e8417661
BIN
media/zuul.mp4
Normal file
BIN
media/zuul.mp4
Normal file
Binary file not shown.
396
tools/zuul.glsl
Normal file
396
tools/zuul.glsl
Normal file
@ -0,0 +1,396 @@
|
||||
/* Zuul-ci pyramid logo in 3D
|
||||
Copyright © 2019 Tristan De Cacqueray
|
||||
SPDX short identifier: MIT & CC-BY-NC-SA-4.0
|
||||
|
||||
Code is mainly based on
|
||||
https://www.shadertoy.com/view/Xds3zN
|
||||
Uploaded by iq in 2013-03-25
|
||||
|
||||
and
|
||||
|
||||
https://www.shadertoy.com/view/ldKGWW
|
||||
Uploaded by wjbgrafx on 2016-02-04
|
||||
|
||||
More resources:
|
||||
http://www.iquilezles.org/www/material/nvscene2008/rwwtt.pdf
|
||||
http://www.iquilezles.org/www/articles/distfunctions/distfunctions.htm
|
||||
*/
|
||||
|
||||
// Set to 1 if too slow
|
||||
#define AA 4
|
||||
|
||||
// Uncomment to add scene elements
|
||||
// #define SKY
|
||||
// #define MONSTER
|
||||
// #define FLOOR
|
||||
|
||||
// Params
|
||||
uniform vec3 iResolution;
|
||||
uniform float iTime;
|
||||
uniform vec4 iMouse;
|
||||
|
||||
const vec3 cam = vec3(0., -.2, -2.);
|
||||
#define PI 3.141592653589793
|
||||
#define PITCH 0.428
|
||||
#define YAW -0.8
|
||||
#define DEG60 0.866025
|
||||
|
||||
// Primitives
|
||||
const mat3 rotX180 = mat3(1.0, 0.0, 0.0,
|
||||
0.0, cos(PI), sin(PI),
|
||||
0.0, -sin(PI), cos(PI));
|
||||
|
||||
float smin(float a, float b, float k) {
|
||||
float h = clamp(0.5 + 0.5 * (b - a) / k, 0.0, 1.0);
|
||||
return mix(b, a, h) - k * h * (1.0 - h);
|
||||
}
|
||||
|
||||
vec2 opU(vec2 d1, vec2 d2) {
|
||||
return (d1.x < d2.x) ? d1 : d2;
|
||||
}
|
||||
|
||||
float pMirror(inout float p, float dist) {
|
||||
float s = sign(p);
|
||||
p = abs(p) - dist;
|
||||
return s;
|
||||
}
|
||||
|
||||
float sdPlane(vec3 p) {
|
||||
return p.y;
|
||||
}
|
||||
|
||||
float sdTriPrism(vec3 p, vec2 h) {
|
||||
vec3 q = abs(p);
|
||||
return max(q.z - h.y,
|
||||
max(q.x * 0.4 + p.y * 0.5, -p.y) - h.x * 0.5);
|
||||
}
|
||||
|
||||
float sdPrismZ(vec3 p, float angleRads, float height, float depth) {
|
||||
vec3 q = abs(p);
|
||||
return max(q.z - depth,
|
||||
max(q.x * angleRads + p.y * 0.5, -p.y) - height * 0.5);
|
||||
}
|
||||
|
||||
float sdPrismX(vec3 p, float angleRads, float height, float depth) {
|
||||
vec3 q = abs(p);
|
||||
return max(q.x - depth,
|
||||
max(q.z * angleRads + p.y * 0.5, -p.y) - height * 0.5);
|
||||
}
|
||||
|
||||
float sdPyramid(vec3 p, float angleRads, float height, float depth) {
|
||||
vec3 q = abs(p);
|
||||
return max(sdPrismX(p, angleRads, height, depth),
|
||||
sdPrismZ(p, angleRads, height, depth));
|
||||
}
|
||||
|
||||
float sdBox(vec3 p, vec3 b) {
|
||||
vec3 d = abs(p) - b;
|
||||
return min(max(d.x, max(d.y, d.z)), 0.0) + length(max(d, 0.0));
|
||||
}
|
||||
|
||||
float dot2(vec3 v) {
|
||||
return dot(v,v);
|
||||
}
|
||||
|
||||
float udTriangle(vec3 p, vec3 a, vec3 b, vec3 c) {
|
||||
vec3 ba = b - a; vec3 pa = p - a;
|
||||
vec3 cb = c - b; vec3 pb = p - b;
|
||||
vec3 ac = a - c; vec3 pc = p - c;
|
||||
vec3 nor = cross(ba, ac);
|
||||
|
||||
return sqrt(
|
||||
(sign(dot(cross(ba,nor),pa)) +
|
||||
sign(dot(cross(cb,nor),pb)) +
|
||||
sign(dot(cross(ac,nor),pc)) < 2.0)
|
||||
?
|
||||
min(min(
|
||||
dot2(ba*clamp(dot(ba,pa)/dot2(ba),0.0,1.0)-pa),
|
||||
dot2(cb*clamp(dot(cb,pb)/dot2(cb),0.0,1.0)-pb)),
|
||||
dot2(ac*clamp(dot(ac,pc)/dot2(ac),0.0,1.0)-pc))
|
||||
:
|
||||
dot(nor,pa)*dot(nor,pa)/dot2(nor));
|
||||
}
|
||||
|
||||
// Zuul logo primitives
|
||||
float sdHollowPyramid(vec3 p) {
|
||||
float pyramid = sdPyramid(p, DEG60, 1.0, 1.0);
|
||||
pyramid = max(pyramid, -sdPyramid(p - vec3(0.0, 0., 0.5), DEG60, .9, .9));
|
||||
pyramid = max(pyramid, -sdBox(p, vec3(.45, 0.45, 0.45)));
|
||||
return pyramid;
|
||||
}
|
||||
|
||||
float sdHollowBox(vec3 pos, vec3 size, float hole) {
|
||||
float box = sdBox(pos, size);
|
||||
box = max(box, -sdBox(pos, size * vec3(2., hole, hole)));
|
||||
box = max(box, -sdBox(pos, size * vec3(hole, hole, 2.)));
|
||||
return box;
|
||||
}
|
||||
|
||||
float sdInnerFrame(vec3 pos) {
|
||||
float left = sdHollowBox(pos + vec3(0.06, .1, .0), vec3(.39, .48, .45), 0.87);
|
||||
float right = sdHollowBox(pos + vec3(.0, .1, -.06), vec3(.45, .48, .39), 0.87);
|
||||
return left < right ? left : right;
|
||||
}
|
||||
|
||||
float sdPilar(vec3 pos) {
|
||||
return sdBox(pos + vec3(.000, .15, -.424), vec3(.026, .35, .026));
|
||||
}
|
||||
|
||||
float sdRoof(vec3 pos) {
|
||||
return sdTriPrism((pos - vec3(.44, .492, .0)) * rotX180, vec2(.05, .45));
|
||||
}
|
||||
|
||||
float sdZuul(vec3 pos) {
|
||||
vec3 p = pos;
|
||||
pMirror(p.x, 0.0);
|
||||
pMirror(p.z, 0.0);
|
||||
float pyramid = sdHollowPyramid(p);
|
||||
float mainBox = sdHollowBox(p, vec3(.45, .517, .45), 0.87);
|
||||
float innerBox = sdInnerFrame(p);
|
||||
float lowerPlateau = sdBox(p - vec3(.0, .21, .0), vec3(.45, .026, .45));
|
||||
float pilar = sdPilar(p);
|
||||
float entranceWall = udTriangle(
|
||||
p, vec3(.78, -.45, .45), vec3(.39, -.45, .451), vec3(.39, .34, .451));
|
||||
float roof = sdRoof(p);
|
||||
|
||||
float closer = pyramid;
|
||||
closer = smin(closer, lowerPlateau, .01);
|
||||
closer = smin(closer, entranceWall, .01);
|
||||
closer = closer < mainBox ? closer : mainBox;
|
||||
closer = closer < roof ? closer : roof;
|
||||
closer = closer < innerBox ? closer : innerBox;
|
||||
closer = closer < pilar ? closer : pilar;
|
||||
float socle = sdBox(pos + vec3(.0, .6, .0), vec3(2., .1, 2.));
|
||||
return max(closer, -socle);
|
||||
}
|
||||
|
||||
#ifdef MONSTER
|
||||
// Julia - Quaternion
|
||||
// https://www.shadertoy.com/view/MsfGRr
|
||||
const int numIterations = 11;
|
||||
|
||||
vec4 qsqr(vec4 a) {
|
||||
return vec4(a.x*a.x - a.y*a.y - a.z*a.z - a.w*a.w,
|
||||
2.0*a.x*a.y,
|
||||
2.0*a.x*a.z,
|
||||
2.0*a.x*a.w);
|
||||
}
|
||||
|
||||
float juliaQ(vec3 p, vec4 c) {
|
||||
vec4 z = vec4(p, 0.0) * 3.6;
|
||||
float md2 = 20.0;
|
||||
float mz2 = dot(z, z);
|
||||
|
||||
vec4 trap = vec4(abs(z.xyz), dot(z, z));
|
||||
|
||||
for (int i=0; i < numIterations; i++) {
|
||||
md2 *= 4.0 * mz2;
|
||||
z = qsqr(z) + c;
|
||||
trap = min(trap, vec4(abs(z.xyz), dot(z, z)));
|
||||
mz2 = dot(z, z);
|
||||
if (mz2 > 4.0)
|
||||
break;
|
||||
}
|
||||
return 0.25 * sqrt(mz2 / md2) * log(mz2);
|
||||
}
|
||||
#endif
|
||||
|
||||
// The scene
|
||||
vec2 scene(vec3 pos) {
|
||||
vec2 res = vec2(sdZuul(pos), 29.);
|
||||
#ifdef FLOOR
|
||||
float plane = sdPlane(pos + vec3(.0, 1., .0));
|
||||
// Does not work well, but tries to remove the floor when under it...
|
||||
if (plane > .0)
|
||||
res = opU(res, vec2(plane, 1.));
|
||||
#endif
|
||||
#ifdef MONSTER
|
||||
vec4 c = 0.45*cos(vec4(0.5,3.9,1.4,1.1) + (iTime*1.5)*vec4(1.2,1.7,1.3,2.5)) - vec4(0.3,0.0,0.0,0.0);
|
||||
res = opU(res, vec2(juliaQ(pos + vec3(.0, .13, .0), c), 49.));
|
||||
#endif
|
||||
return res;
|
||||
}
|
||||
|
||||
vec3 calcNormal(vec3 pos) {
|
||||
vec2 e = vec2(1.0, -1.0) * 0.5773 * 0.0005;
|
||||
return normalize(e.xyy * scene(pos + e.xyy).x +
|
||||
e.yyx * scene(pos + e.yyx).x +
|
||||
e.yxy * scene(pos + e.yxy).x +
|
||||
e.xxx * scene(pos + e.xxx).x);
|
||||
}
|
||||
|
||||
float calcAO(vec3 pos, vec3 nor) {
|
||||
float occ = 0.0;
|
||||
float sca = 1.0;
|
||||
for (int i=0; i < 5; i++) {
|
||||
float hr = 0.01 + 0.12 * float(i) / 4.0;
|
||||
vec3 aopos = nor * hr + pos;
|
||||
float dd = scene(aopos).x;
|
||||
occ += -(dd - hr) * sca;
|
||||
sca *= 0.95;
|
||||
}
|
||||
return clamp(1.0 - 3.0 * occ, 0.0, 1.0);
|
||||
}
|
||||
|
||||
vec2 castRay(vec3 ro, vec3 rd) {
|
||||
const float tmin = 0.2;
|
||||
const float tmax = 20.0;
|
||||
float t = tmin;
|
||||
float m;
|
||||
for (int i=0; i < 300; i++) {
|
||||
vec2 res = scene(ro + rd * t);
|
||||
if (res.x < 0.0001 ||
|
||||
t > tmax) break;
|
||||
t += res.x;
|
||||
m = res.y;
|
||||
}
|
||||
if (t > tmax) m = -1.0;
|
||||
return vec2(t, m);
|
||||
}
|
||||
|
||||
// Improved soft shadow by Sebastian Aaltonen
|
||||
// From: http://www.iquilezles.org/www/articles/rmshadows/rmshadows.htm
|
||||
float calcSoftshadow(vec3 ro, vec3 rd, float mint, float maxt) {
|
||||
float k = 32.;
|
||||
float res = 1.0;
|
||||
float ph = 1e20;
|
||||
for (float t=mint; t < maxt;) {
|
||||
float h = scene(ro + rd * t).x;
|
||||
if (h < 0.001)
|
||||
return 0.0;
|
||||
float y = h * h / (2.0 * ph);
|
||||
float d = sqrt(h * h - y * y);
|
||||
res = min(res, k * d / max(0.0, t-y));
|
||||
ph = h;
|
||||
t += h;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
#ifdef FLOOR
|
||||
// http://iquilezles.org/www/articles/checkerfiltering/checkerfiltering.htm
|
||||
float checkersGradBox(vec2 p) {
|
||||
// filter kernel
|
||||
vec2 w = fwidth(p) + 0.001;
|
||||
// analytical integral (box filter)
|
||||
vec2 i = 2.0*(abs(fract((p-0.5*w)*0.5)-0.5)-abs(fract((p+0.5*w)*0.5)-0.5))/w;
|
||||
// xor pattern
|
||||
return 0.5 - 0.5*i.x*i.y;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef SKY
|
||||
vec3 skyColor(vec3 rd) {
|
||||
float offset = (.95 - clamp(rd.y, 0.0, 0.2))*.7;
|
||||
return vec3(.5)+vec3(.5)*cos(6.28*(vec3(1.)*offset+vec3(0.0,0.10,0.20)));
|
||||
}
|
||||
#endif
|
||||
|
||||
vec3 render(vec3 ro, vec3 rd) {
|
||||
vec3 col = vec3(.0);
|
||||
#ifdef SKY
|
||||
col = skyColor(rd);
|
||||
#endif
|
||||
vec2 res = castRay(ro, rd);
|
||||
float t = res.x;
|
||||
float m = res.y;
|
||||
|
||||
if (m > 0.) {
|
||||
vec3 pos = ro + t * rd;
|
||||
vec3 nor = calcNormal(pos);
|
||||
vec3 ref = reflect(rd, nor);
|
||||
col = 0.45 + 0.35*sin(vec3(0.0001,0.004,0.04)*(m-1.0));
|
||||
#ifdef FLOOR
|
||||
if (m < 1.5) {
|
||||
float f = checkersGradBox(5.0*pos.xz);
|
||||
col = 0.01 + f*vec3(0.1);
|
||||
}
|
||||
#endif
|
||||
// lightning
|
||||
float occ = calcAO(pos, nor);
|
||||
vec3 lig = normalize(vec3(0.25, 0.7, -1.));
|
||||
vec3 hal = normalize(lig - rd);
|
||||
float amb = clamp(0.5 + 0.5 * nor.y, 0.0, 1.0);
|
||||
float dif = clamp(dot(nor, lig), 0.0, 1.0);
|
||||
float bac = clamp(dot(nor, normalize(vec3(-lig.x, 0.0, -lig.z))),
|
||||
0.0, 1.0)*clamp(1.0 - pos.y, 0.0, 1.0);
|
||||
float dom = smoothstep(-0.2, 0.2, ref.y);
|
||||
float fre = pow(clamp(1.0+dot(nor,rd),0.0,1.0), 2.0);
|
||||
|
||||
dif *= calcSoftshadow(pos, lig, 0.02, 2.5) * 0.2;
|
||||
dom *= calcSoftshadow(pos, ref, 0.02, 2.5);
|
||||
|
||||
float spe = pow(clamp(dot(nor, hal), 0.0, 1.0), 16.0);
|
||||
spe *= dif * (0.04 + 0.96 * pow(clamp(1.0 + dot(hal, rd), 0.0, 1.0), 5.0));
|
||||
|
||||
vec3 lin = vec3(0.0);
|
||||
lin += 3.30 * dif * vec3(1.00, 0.80, 0.55);
|
||||
lin += 0.40 * amb * vec3(0.40, 0.60, 1.00) * occ;
|
||||
lin += 0.40 * dom * vec3(0.40, 0.60, 1.00) * occ;
|
||||
lin += 0.50 * bac * vec3(0.25, 0.25, 0.25) * occ;
|
||||
lin += 0.25 * fre * vec3(1.00, 1.00, 1.00) * occ;
|
||||
col *= lin;
|
||||
col += 50.0 * spe * vec3(1.00, 0.90, 0.70);
|
||||
col = mix(col, vec3(.0), 1.0 - exp(-0.0002 * t * t * t));
|
||||
}
|
||||
#ifdef SKY
|
||||
// fog
|
||||
float rayDist = length(ro + rd * t);
|
||||
col = mix(col, skyColor(rd), 1.0 - 1.0 / exp(rayDist * 0.05));
|
||||
#endif
|
||||
return vec3(clamp(col, 0.0, 1.0));
|
||||
}
|
||||
|
||||
float smoothStair(float frame) {
|
||||
return frame - sin(frame) / 1.9;
|
||||
}
|
||||
|
||||
mat3 camRotation() {
|
||||
float yaw, pitch;
|
||||
if (iMouse.z > 0.0) {
|
||||
yaw = (iMouse.x / iResolution.x - 0.5) * 4.;
|
||||
pitch = (iMouse.y / iResolution.y - 0.5) * 4.;
|
||||
} else {
|
||||
yaw = -.35 + smoothStair(iTime * 2.) / 2.;
|
||||
pitch = PITCH;
|
||||
}
|
||||
return mat3(1.0, 0.0, 0.0,
|
||||
0.0, cos(pitch), -sin(pitch),
|
||||
0.0, sin(pitch), cos(pitch)) *
|
||||
mat3(cos(yaw), 0.0, sin(yaw),
|
||||
0.0, 1.0, 0.0,
|
||||
-sin(yaw), 0.0, cos(yaw));
|
||||
}
|
||||
|
||||
void mainImage(out vec4 fragColor, in vec2 fragCoord) {
|
||||
mat3 rot = camRotation();
|
||||
vec3 tot = vec3(0.0);
|
||||
#if AA > 1
|
||||
for(int m=0; m < AA; m++)
|
||||
for(int n=0; n < AA; n++) {
|
||||
vec2 o = vec2(float(m), float(n)) / float(AA) - 0.5;
|
||||
vec2 uv = (gl_FragCoord.xy+o) / iResolution.xy*2.-1.;
|
||||
#else
|
||||
vec2 uv = gl_FragCoord.xy / iResolution.xy*2.-1.;
|
||||
#endif
|
||||
|
||||
uv.y *= iResolution.y / iResolution.x;
|
||||
|
||||
vec3 dir = normalize(vec3(uv, 1.)) * rot;
|
||||
vec3 pos = cam * rot;
|
||||
|
||||
vec3 col = render(pos, dir);
|
||||
// gamma
|
||||
col = pow(col, vec3(0.4));
|
||||
|
||||
tot += col;
|
||||
#if AA > 1
|
||||
}
|
||||
tot /= float(AA * AA);
|
||||
#endif
|
||||
fragColor = vec4(tot, 1.0);
|
||||
}
|
||||
|
||||
void main(void) {
|
||||
mainImage(gl_FragColor, gl_FragCoord.xy);
|
||||
}
|
40
tools/zuul.py
Executable file
40
tools/zuul.py
Executable file
@ -0,0 +1,40 @@
|
||||
# Zuul-ci pyramid logo in 3D
|
||||
# SPDX short identifier: MIT
|
||||
|
||||
"""Render the zuul.glsl shader to a zuul.mp4 file at 25 fps"""
|
||||
|
||||
from subprocess import Popen
|
||||
import numpy as np
|
||||
from glumpy import app, gl, gloo
|
||||
from PIL import Image
|
||||
|
||||
RES = [500, 500]
|
||||
ROTATION = 2
|
||||
FPS = 25
|
||||
|
||||
vertex = "attribute vec2 p; void main(void) {gl_Position = vec4(p, 0.0, 1.0);}"
|
||||
fragment = open("zuul.glsl").read()
|
||||
window = app.Window(width=RES[0], height=RES[1])
|
||||
program = gloo.Program(vertex, fragment, count=4)
|
||||
program['p'] = [(-1, -1), (-1, +1), (+1, -1), (+1, +1)]
|
||||
program['iResolution'] = RES + [0]
|
||||
gl.glEnable(gl.GL_BLEND)
|
||||
gl.glBlendFunc(gl.GL_SRC_ALPHA, gl.GL_ONE_MINUS_SRC_ALPHA)
|
||||
backend = app.__backend__
|
||||
clock = app.__init__(backend=backend, framerate=FPS)
|
||||
pixels = np.zeros((RES[0], RES[1] * 3), dtype=np.uint8)
|
||||
|
||||
for i in range(int(np.pi * ROTATION * FPS)):
|
||||
window.activate()
|
||||
window.clear()
|
||||
program["iTime"] = i / FPS
|
||||
program.draw(gl.GL_TRIANGLE_STRIP)
|
||||
gl.glReadPixels(
|
||||
0, 0, RES[0], RES[1], gl.GL_RGB, gl.GL_UNSIGNED_BYTE, pixels)
|
||||
image = Image.frombytes(
|
||||
"RGB", RES, np.ascontiguousarray(np.flip(pixels, 0)))
|
||||
image.save("%03d.png" % (i + 1), 'png')
|
||||
backend.process(clock.tick())
|
||||
|
||||
Popen(["ffmpeg", "-y", "-r", str(FPS), "-i", "%03d.png", "-pix_fmt", "yuv420p",
|
||||
"zuul.mp4"]).wait()
|
Loading…
Reference in New Issue
Block a user