Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 5bba0801f4 | |||
| b89b124693 | |||
| a2f6416903 | |||
| 2298a4fef9 |
21
README.md
Normal file
21
README.md
Normal file
@@ -0,0 +1,21 @@
|
||||
# hopf-fibration
|
||||
|
||||
Generate images of the hopf fibration.
|
||||
|
||||

|
||||
|
||||
## 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.
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
---
|
||||
|
||||
## More information
|
||||
|
||||
[Wikipedia: Hopf Fibration](https://en.wikipedia.org/wiki/Hopf_fibration)
|
||||
BIN
images/default.png
Normal file
BIN
images/default.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 36 KiB |
BIN
images/rotated.png
Normal file
BIN
images/rotated.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 48 KiB |
BIN
images/zoomed.png
Normal file
BIN
images/zoomed.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 86 KiB |
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
#version 440
|
||||
|
||||
#define CIRCLE_RES 64
|
||||
#define CIRCLE_RES 128
|
||||
#define PI 3.14159
|
||||
|
||||
layout(points) in;
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user