use*_*677 3 c++ opengl trigonometry rotational-matrices glm-math
我有一个单位立方体,我想转换它以连接两个点。我是 OpenGL 的新手,只知道线性代数的最基本部分。我试图模仿类似于极坐标的东西来连接点。当 Z 轴和另一个轴发生变化时,我当前的实现不起作用。我也尝试过mat = glm::lookAt(center, terminal, y_axis);,但我没有成功。
这来自位于schedule_edge_update().
auto const initial = p1;
auto const terminal = p2;
auto const distance = glm::distance(initial, terminal);
auto const length = distance * 0.5f;
auto const center = (initial + terminal) / 2.f;
auto const rejection = terminal - initial;
auto const delta = glm::normalize(rejection);
auto mat = glm::mat4(1);
// translate
mat = glm::translate(mat, center);
// rotate
auto const phi_hyp = glm::length(glm::vec2(delta.x, delta.z));
if (phi_hyp != 0.0f) {
auto phi = acosf(delta.x / phi_hyp);
mat = glm::rotate(mat, phi, y_axis);
}
auto const theta_hyp = glm::length(glm::vec2(delta.x, delta.y));
if (theta_hyp != 0.0f) {
auto theta = acosf(delta.x / theta_hyp);
theta *= delta.x > 0 ? -1.0f : 1.0f;
mat = glm::rotate(mat, theta, z_axis);
}
// scale
edges->add_matrix(glm::scale(mat, glm::vec3(length, 0.05f, 0.01f)));
Run Code Online (Sandbox Code Playgroud)
当一个矩阵被添加到edges它时,它会排队等待缓冲以进行实例渲染。
这是我的测试点和我制作的一个大立方体。

这是它不起作用的示例。起点标记为 p1,终点标记为 p2。不连接任何点的线应该连接 p1 和 p2。

这是另一个例子,但这个例子标有 p1 和 p2 的坐标。p1 和 p2 的不同之处在于 Y 和 Z 的变化。但是,我的代码将立方体(在平移之后)绕 y 轴旋转 90 度。然后是缩放它。您可以判断它已旋转,因为它在轴之一(旋转前的 y 轴)上更宽。

// Test points
auto const A = glm::vec3(-10.0f, -10.0f, -20.0f);
auto const B = glm::vec3(+10.0f, -10.0f, -20.0f);
auto const C = glm::vec3(+10.0f, +10.0f, -20.0f);
auto const D = glm::vec3(+00.0f, +10.0f, -20.0f);
auto const E = glm::vec3(+05.0f, +05.0f, -20.0f);
auto const F = glm::vec3(+00.0f, +00.0f, -30.0f);
auto const G = glm::vec3(-10.0f, -10.0f, -30.0f);
auto const H = glm::vec3(+55.0f, -15.0f, -60.0f);
auto const I = glm::vec3(+55.0f, -05.0f, -70.0f);
get_nodes().emplace_back(A);
get_nodes().emplace_back(B);
get_nodes().emplace_back(C);
get_nodes().emplace_back(D);
get_nodes().emplace_back(E);
get_nodes().emplace_back(F);
get_nodes().emplace_back(G);
get_nodes().emplace_back(H);
get_nodes().emplace_back(I);
get_edges().emplace_back(A, B);
get_edges().emplace_back(B, C);
get_edges().emplace_back(C, D);
get_edges().emplace_back(D, E);
get_edges().emplace_back(E, F);
get_edges().emplace_back(F, G);
get_edges().emplace_back(G, H);
get_edges().emplace_back(H, I);
// Big cube
auto const C0 = glm::vec3(-5.0f, -5.0f, -5.0f);
auto const C1 = glm::vec3(-5.0f, -5.0f, +5.0f);
auto const C2 = glm::vec3(-5.0f, +5.0f, -5.0f);
auto const C3 = glm::vec3(-5.0f, +5.0f, +5.0f);
auto const C4 = glm::vec3(+5.0f, -5.0f, -5.0f);
auto const C5 = glm::vec3(+5.0f, -5.0f, +5.0f);
auto const C6 = glm::vec3(+5.0f, +5.0f, -5.0f);
auto const C7 = glm::vec3(+5.0f, +5.0f, +5.0f);
get_nodes().emplace_back(C0);
get_nodes().emplace_back(C1);
get_nodes().emplace_back(C2);
get_nodes().emplace_back(C3);
get_nodes().emplace_back(C4);
get_nodes().emplace_back(C5);
get_nodes().emplace_back(C6);
get_nodes().emplace_back(C7);
get_edges().emplace_back(C0, C1);
get_edges().emplace_back(C0, C2);
get_edges().emplace_back(C0, C4);
get_edges().emplace_back(C1, C3);
get_edges().emplace_back(C1, C5);
get_edges().emplace_back(C2, C3);
get_edges().emplace_back(C2, C6);
get_edges().emplace_back(C3, C7);
get_edges().emplace_back(C4, C5);
get_edges().emplace_back(C4, C6);
get_edges().emplace_back(C5, C7);
get_edges().emplace_back(C6, C7);
schedule_node_update();
schedule_edge_update();
Run Code Online (Sandbox Code Playgroud)
auto constexpr A = vec3(-0.5f, 0.0f, 0.0f);
auto constexpr B = vec3(+0.5f, 0.0f, 0.0f);
auto const C = p1;
auto const D = p2;
auto M = mat4(1.0f);
// Translate
auto const center = 0.5 * (C + D);
M = translate(M, center);
// Rotate
auto constexpr p = B - A;
auto const q = D - C;
auto const n = cross(p, q);
if (n != vec3()) {
auto const a = angle(normalize(p), normalize(q));
M = rotate(M, a, n);
}
// Scale
auto constexpr thickness = 0.05f;
M = scale(M, vec3(0.5f * distance(C, D), thickness, thickness));
edges->add_matrix(M);
Run Code Online (Sandbox Code Playgroud)

所以问题归结为:
我知道 4 点A,B,C,D,我想计算将转换A,B为C,D.
这可以像这样完成。假设我们像这样转换点:
M * A = C
M * B = D
Run Code Online (Sandbox Code Playgroud)
M我们要计算的变换矩阵在哪里。有无数种可能的解决方案(因为线AB可以在其自身的轴上进行任何旋转)
如果你稍微剖析一下 M,它只是知道位置、方向和比例的问题。
规模是最简单的
它只是变换前后线长的比率。
scale = |CD|/|AB|
Run Code Online (Sandbox Code Playgroud)方向
它由单位基向量表示。我们可以利用这样一个事实,即 AB 和 CD 只有一次旋转(所有其他旋转仅产生无限数量的解),因此我们可以仅旋转AB之间的角度AB,CD围绕垂直于两者的轴AB,CD。我们可以通过平行于AB, 的单位向量之间的点积 acos 获得角度CD。唯一的问题是不会给我们旋转方向,所以我们需要测试两种可能性(CW,CCW)。
所以:
axis = cross(B-A,D-C)
angle = +/- acos(dot(B-A,D-C) / |B-A|*|D-C|)
Run Code Online (Sandbox Code Playgroud)翻译
这个很简单,我们只是A在M没有翻译的情况下进行转换,让我们调用它A',然后只需更正结果位置,使其变为C。
M_origin += C-A'
Run Code Online (Sandbox Code Playgroud)
请注意,应直接设置平移,而不是应用平移矩阵。那些通常在本地坐标系[LCS]中转换,这涉及首先将差异转换为它。在这种情况下使用
translate(Inverse(M)*(C-A'))
Run Code Online (Sandbox Code Playgroud)
或者
translate(M*(C-A'))
Run Code Online (Sandbox Code Playgroud)
取决于使用的符号。
这里的小C++/VCL/旧 GL示例:
M * A = C
M * B = D
Run Code Online (Sandbox Code Playgroud)
忽略与 VCL 相关的东西。您可以在此处找到 GL 支持功能:
这里唯一重要的东西是compute_M()与全局变量一起。
如果您需要实现,您可以在上面的链接 QA 中找到这些实现,向量数学函数已被注释(因此您可以将其转换为 GLM)。它基本上需要。为简单起见,我使用了 GL 原生旋转(注意它们是度数而不是弧度)。
这里预览:
red 是原始立方体green 是原始对角线 ABblue 被转换为立方体 Myellow 是想要对角线 CD如您所见,它匹配。
如果您需要对齐的不仅仅是一条线,您需要添加更多的对齐信息(例如 2 条线(3 点))等。有关更多信息,请参阅: