4 Commits

Author SHA1 Message Date
5bba0801f4 Add readme details. 2020-03-04 12:39:40 -05:00
b89b124693 Create README.md 2020-03-04 12:30:36 -05:00
a2f6416903 Merge remote-tracking branch 'origin/master' 2019-02-07 23:38:31 -05:00
2298a4fef9 realtime rotations 2019-02-07 23:38:05 -05:00
8 changed files with 205 additions and 32 deletions

21
README.md Normal file
View File

@@ -0,0 +1,21 @@
# hopf-fibration
Generate images of the hopf fibration.
![zoomed](images/zoomed.png)
## Usage
Hold keys `Q`, `W`, `E`, `A`, `S`, `D` to select from the six planes of rotation, and use the scroll wheel to rotate the fibration through the selected plane. The resulting Hopf links are stereographically projected into 3D space, and the resulting circles are rendered orthographically on screen.
Hold left-control `LCTL` and scroll to zoom in on the fibration. This affects only the orthographic rendering, not the fibration itself.
![default](images/default.png)
![rotated](images/rotated.png)
---
## More information
[Wikipedia: Hopf Fibration](https://en.wikipedia.org/wiki/Hopf_fibration)

BIN
images/default.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

BIN
images/rotated.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

BIN
images/zoomed.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

View File

@@ -10,7 +10,6 @@ namespace ga {
Vec(float x, float y, float z, float w) :
x(x), y(y), z(z), w(w) {}
};
struct Bivec {
@@ -29,11 +28,11 @@ namespace ga {
namespace unit {
Vec x() { return Vec(1, 0, 0, 0); };
Vec y() { return Vec(1, 0, 0, 0); };
Vec y() { return Vec(0, 1, 0, 0); };
Vec z() { return Vec(1, 0, 0, 0); };
Vec z() { return Vec(0, 0, 1, 0); };
Vec w() { return Vec(1, 0, 0, 0); };
Vec w() { return Vec(0, 0, 0, 1); };
Bivec xy() { return Bivec(1, 0, 0, 0, 0, 0); }
@@ -46,6 +45,8 @@ namespace ga {
Bivec xz() { return Bivec(0, 0, 0, 0, 1, 0); }
Bivec yw() { return Bivec(0, 0, 0, 0, 0, 1); }
Mat identity() { return Mat(x(), y(), z(), w()); }
}
float length2(Vec v) {
@@ -93,6 +94,28 @@ namespace ga {
c * v.yw);
}
Vec mul(Mat m, Vec v) {
return add(add(mul(v.x, m.x), mul(v.y, m.y)), add(mul(v.z, m.z), mul(v.w, m.w)));
}
Mat mul(Mat m, Mat n) {
return Mat(
mul(m, n.x),
mul(m, n.y),
mul(m, n.z),
mul(m, n.w)
);
}
Mat mul(float c, Mat m) {
return Mat(
mul(c, m.x),
mul(c, m.y),
mul(c, m.z),
mul(c, m.w)
);
}
Vec normalize(Vec v) {
return mul(1 / length(v), v);
}
@@ -101,21 +124,42 @@ namespace ga {
return mul(1 / length(v), v);
}
Vec tform(float c, Vec v) {
}
Vec tform(Vec u, Vec v) {
}
Vec tform(Bivec u, Vec v) {
}
Mat matrix(float c) {
// c as a transformation
// scale by c
return Mat(Vec(c, 0, 0, 0), Vec(0, c, 0, 0), Vec(0, 0, c, 0), Vec(0, 0, 0, c));
auto m = unit::identity();
m.x = tform(c, m.x);
m.y = tform(c, m.y);
m.z = tform(c, m.z);
m.w = tform(c, m.w);
return m;
}
Mat matrix(Vec v) {
// v as a transformation
// reflect along v
return matrix(1); // todo reflection
auto m = unit::identity();
m.x = tform(v, m.x);
m.y = tform(v, m.y);
m.z = tform(v, m.z);
m.w = tform(v, m.w);
return m;
}
Mat rotor(Bivec v) {
// v as a transformation
// rotate along v
return matrix(1);
Mat matrix(Bivec v) {
auto m = unit::identity();
m.x = tform(v, m.x);
m.y = tform(v, m.y);
m.z = tform(v, m.z);
m.w = tform(v, m.w);
return m;
}
}

View File

@@ -2,6 +2,8 @@
#define PI 3.14159
uniform float bright;
in vec4 pos;
in vec4 pos4;
in vec4 pos3;
@@ -11,7 +13,8 @@ out vec4 color;
void main() {
float light = -pos3.y / 10 + .5;
vec3 col = vec3(1);
vec3 col = vec3(bright);
color = vec4(col * light, 1);
//color = vec4(col * light, 1);
color = vec4(col, 1);
}

View File

@@ -1,6 +1,6 @@
#version 440
#define CIRCLE_RES 64
#define CIRCLE_RES 128
#define PI 3.14159
layout(points) in;

View File

@@ -121,13 +121,17 @@ struct HopfCircle {
struct State {
GLuint vao{};
GLuint vbo{}, ubo{};
GLuint unif_bright{};
GLuint ubo_bp = 1;
GLuint prog{};
std::vector<HopfCircle> circles{};
ga::Mat rot = ga::unit::identity();
float view = 4.f;
float t = 0;
float dt = 0;
void regen() {
circles.clear();
@@ -136,10 +140,10 @@ struct State {
const int M = 4;
const float PAD = 0.0125;
for (int k = 0; k <= N; ++k) {
for (int j = 0; j <= M; ++j) {
float xi = 2 * PI * k / N;
float eta = (PI / 2 - 2 * PAD) * j / M + PAD;
for (int x = 0; x <= N; ++x) {
for (int e = 1; e < M; ++e) {
float xi = 2 * PI * x / N;
float eta = (PI / 2 - 2 * PAD) * e / M + PAD;
circles.emplace_back(xi, eta);
}
}
@@ -152,6 +156,10 @@ struct State {
explicit State(GLFWwindow *window) {
printf("vendor: %s\nrenderer: %s\n", glGetString(GL_VENDOR), glGetString(GL_RENDERER));
float lw[2];
glGetFloatv(GL_LINE_WIDTH_RANGE, lw);
printf("line width range: %.2f to %.2f\n", lw[0], lw[1]);
glGenBuffers(1, &vbo);
glGenBuffers(1, &ubo);
glGenVertexArrays(1, &vao);
@@ -165,6 +173,8 @@ struct State {
GLuint fs = util::buildShader(GL_FRAGMENT_SHADER, "fs", {"shaders/main.frag"});
prog = util::buildProgram(false, "prog", {vs, gs, fs});
unif_bright = (GLuint) glGetUniformLocation(prog, "bright");
glBindVertexArray(vao);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
@@ -204,17 +214,11 @@ struct State {
glBindBuffer(GL_UNIFORM_BUFFER, ubo);
util::bufferData<ga::Mat>(GL_UNIFORM_BUFFER, {
ga::Mat(
ga::Vec(1.f / 4 / ar, 0, 0, 0),
ga::Vec(1.f / view / ar, 0, 0, 0),
ga::Vec(0, 0, 1.f / 10, 0),
ga::Vec(0, 1.f / 4, 0, 0),
ga::Vec(0, 1.f / view, 0, 0),
ga::Vec(0, 0, 0, 1.f)),
ga::Mat(
ga::Vec(c, 0, 0, s),
ga::Vec(0, c_, s_, 0),
ga::Vec(0, -s_, c_, 0),
ga::Vec(-s, 0, 0, c)
)
rot
}, GL_STREAM_DRAW);
glBindBuffer(GL_UNIFORM_BUFFER, 0);
}
@@ -226,12 +230,20 @@ struct State {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glDepthFunc(GL_LEQUAL);
glUseProgram(prog);
glBindVertexArray(vao);
glEnable(GL_DEPTH_TEST);
glPointSize(5);
glLineWidth(5);
glLineWidth(10);
glUniform1f(unif_bright, 0);
glDrawArrays(GL_POINTS, 0, (unsigned) circles.size());
glLineWidth(1);
glUniform1f(unif_bright, 1);
glDrawArrays(GL_POINTS, 0, (unsigned) circles.size());
glBindVertexArray(0);
glUseProgram(0);
@@ -239,10 +251,100 @@ struct State {
glfwSwapBuffers(window);
}
void on_scroll(GLFWwindow *window, double xoffset, double yoffset) {
printf("scroll %.2f %.2f\n", xoffset, yoffset);
int xw = glfwGetKey(window, GLFW_KEY_Q);
int yw = glfwGetKey(window, GLFW_KEY_W);
int zw = glfwGetKey(window, GLFW_KEY_E);
int xy = glfwGetKey(window, GLFW_KEY_A);
int yz = glfwGetKey(window, GLFW_KEY_S);
int zx = glfwGetKey(window, GLFW_KEY_D);
int zoom = glfwGetKey(window, GLFW_KEY_LEFT_CONTROL);
float t = (float) yoffset * PI / 48;
float c = std::cos(t);
float s = std::sin(t);
if (xw) {
rot = ga::mul(rot, ga::Mat(
ga::Vec(c, 0, 0, s),
ga::Vec(0, 1, 0, 0),
ga::Vec(0, 0, 1, 0),
ga::Vec(-s, 0, 0, c)
));
}
if (yw) {
rot = ga::mul(rot, ga::Mat(
ga::Vec(1, 0, 0, 0),
ga::Vec(0, c, 0, s),
ga::Vec(0, 0, 1, 0),
ga::Vec(0, -s, 0, c)
));
}
if (zw) {
rot = ga::mul(rot, ga::Mat(
ga::Vec(1, 0, 0, 0),
ga::Vec(0, 1, 0, 0),
ga::Vec(0, 0, c, s),
ga::Vec(0, 0, -s, c)
));
}
if (xy) {
rot = ga::mul(rot, ga::Mat(
ga::Vec(c, s, 0, 0),
ga::Vec(-s, c, 0, 0),
ga::Vec(0, 0, 1, 0),
ga::Vec(0, 0, 0, 1)
));
}
if (yz) {
rot = ga::mul(rot, ga::Mat(
ga::Vec(1, 0, 0, 0),
ga::Vec(0, c, s, 0),
ga::Vec(0, -s, c, 0),
ga::Vec(0, 0, 0, 1)
));
}
if (zx) {
rot = ga::mul(rot, ga::Mat(
ga::Vec(c, 0, -s, 0),
ga::Vec(0, 1, 0, 0),
ga::Vec(s, 0, c, 0),
ga::Vec(0, 0, 0, 1)
));
}
if (zoom) {
view *= 1 - t / 5;
}
std::ofstream matfile;
matfile.open("matrix.txt");
matfile << "vec((\n";
matfile << "vec((" << rot.x.x << ", " << rot.x.y << ", " << rot.x.z << ", " << rot.x.w << ")),\n";
matfile << "vec((" << rot.y.x << ", " << rot.y.y << ", " << rot.y.z << ", " << rot.y.w << ")),\n";
matfile << "vec((" << rot.z.x << ", " << rot.z.y << ", " << rot.z.z << ", " << rot.z.w << ")),\n";
matfile << "vec((" << rot.w.x << ", " << rot.w.y << ", " << rot.w.z << ", " << rot.w.w << ")),\n";
matfile << ")),";
matfile.close();
}
void deinit(GLFWwindow *window) {
}
};
void scroll_callback(GLFWwindow *window, double xoffset, double yoffset) {
auto *state = (State *) glfwGetWindowUserPointer(window);
state->on_scroll(window, xoffset, yoffset);
}
void run() {
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 4);
@@ -259,6 +361,9 @@ void run() {
glfwSwapInterval(0);
auto state = State(window);
glfwSetWindowUserPointer(window, &state);
glfwSetScrollCallback(window, scroll_callback);
double time = glfwGetTime();
int frame = 0;