寻找四元数,表示从一个向量到另一个向量的变换

Finding quaternion, representing transformation from one vector to another

简介

以前,我 asked a questionrgb 三元数转换为四元数。在那个问题之后我设法得到了单位四元数,但我怀疑它们的内部结构。没有简单的方法来操作它们,并且将 lumachroma 分开,因为它们是单位长度的四元数。根据我的感觉,亮度应该用实部或整数来编码;而颜色“chroma”信息应该在虚部进行编码。

今天我决定改进一下,采用另一种方法,不同于上面 link 中的第一种方法。我认为它可以成功,因为四元数不仅可以存储旋转(单位四元数),还可以存储比例。首先,我将从解释我的下一个想法开始。我将在以下解释中使用 GLSL 着色器语法。


方法描述和问题正文。

对于图像的某些像素,让我们在单位立方体中设想一个 3D 向量 vec3 u,其中正坐标位于封闭范围 [0.0, 1.0] 内,代表完整 rgb 色彩空间。因此,现在 u 的坐标、u.xu.yu.z 将相应地表示该像素的红色、绿色和蓝色值。然后让我们取一个纯白色的矢量const vec3 v = vec3(1.0, 1.0, 1.0);。让我们定义一些四元数 q,这样我们的向量 u 就是“v,用四元数 q 旋转和缩放”。简单来说,q必须回答"How to transform v, in order to get initially conceived color u?"这个问题。让我们为 "rotate and scale" 操作引入函数:vec3 q2c(in vec4 q, in vec3 v)。我将其称为 "quaternion-to-color" 转换器。

q2c(q, v)很简单,just as defined: q2c(q, v) == (q*vec4(v, 0.0))*q'. Here, the "*" operator denotes quaternion multiplication; Lets make it a function vec4 qmul(in vec4 q1, in vec4 q2). And "q'" denotes q's conjugate,写vec4 qconj(in vec4 q)吧。省略它们的简单实现(您可以在完整源代码中找到),我们将使用经典代码:

vec4 q2c(in vec4 q, in vec3 v) {
    return qmul(qmul(q, vec4(v, 0.0)), qconj(q));
}

现在我们有了 q2c(q,v) 函数,它通过旋转和缩放一些选定的 3D 矢量 v.

将四元数 q 转换为颜色

问题是如何找到那个四元数q

从程序员的角度来看,目标是编写反向函数vec4 c2q(in vec3 u, in vec3 v) - 相应的"color to quaternion"转换器。

请注意,如果没有充分的理由,您不应该触摸 q2c()。例如,其逻辑中存在严重错误,导致 "impossibility to solve task",您可以证明这一点。


你如何检查你的答案是否正确?

确实,如果您设法来回转换,您将获得初始值这一事实会产生检查方法。所以检查条件是对于任何非零长度vu必须总是等于q2c(c2q(u, v), v)v 必须有非零长度,因为不能 "scale zero" 得到 "something".

为了方便起见,我准备了 testing program,使用 shadertoy.com 服务。

你需要一台像样的电脑,有可用的互联网连接和一个支持 webGL 的网络浏览器(我正在使用 Chrome)。程序应该可以在任何 GPU 上运行,甚至可以嵌入到英特尔的处理器中。它甚至适用于我的低端智能手机!

为了测试您的答案,您应该将建议的公式(以 GLSL 语法编写)放入 c2q() 函数中。然后按应用按钮,您的更改将生效:

左边的图像表示一些未更改的源像素。右半部分将包含像素,前后变换 q2c(c2q())。显然,两半在视觉上必须相等,你不应该注意到任何垂直线。一些小的数学(不明显的)错误 可能会出现 ,但这只是由于浮点的性质 - 它的有限精度和可能的舍入错误。

随意编辑和试验,更改只会在您的计算机上本地完成,您不会破坏任何东西。如果视频在第一次打开时没有播放(shadertoy 错误)- 尝试 pause/unpause 它。享受吧!


大厅 c2q() 次尝试

如果一切正确,图像(处理过的)的右侧应该与左侧(原始)相等。在这里,我将回顾不同的结果,这些结果是通过在 c2q() 实现中放置一些东西而不是 xxxxx 获得的:

vec4 c2q(vec3 u, vec3 v) {
    return xxxxx;
}

让我们继续!

我的尝试:

vec4 c2q(vec3 u, vec3 v) {
    float norm_q = sqrt(length(u) / length(v));
    vec4 u4 = vec4(normalize(u), 0.0);
    vec4 v4 = vec4(normalize(v), 0.0);
    return norm_q * (qmul(u4, v4 + u4) / length(v4 + u4));
}