寻找四元数,代表从一个向量到另一个向量的转化

时间:2019-04-01 18:41:56

标签: colors linear-algebra transformation quaternions

简介。

以前,我曾asked a question rgb 三元数转换为四元数。在提出这个问题之后,我设法获得了单元四元数,但是我对它们的内部结构感到怀疑。没有简单的方法来操作它们,以及分隔 luma chroma ,因为它们是单位长度的四元数。根据我对它的感觉,亮度应该编码为实数部分或整个大小。颜色“ chroma ”信息应在虚部编码。

今天,我决定采用另一种方法来进行改进,与上面链接中的第一种方法不同。我认为它会成功,因为四元数不仅可以存储旋转(单位四元数),而且还可以存储比例。首先是第一件事,所以我将从解释下一个想法开始。在以下说明中,我将使用 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必须回答问题“如何转换v,以便获得最初构想的颜色u?” 。并为该“旋转和缩放”操作引入功能:vec3 q2c(in vec4 q, in vec3 v)。我将其称为“四元数到颜色”转换器。

编写q2c(q, v)很简单,just as defined q2c(q, v) == (q*vec4(v, 0.0))*q' 。在此,“ *”运算符表示quaternion multiplication;让它成为一个函数vec4 qmul(in vec4 q1, in vec4 q2)。 “ q'”表示q的{​​{3}},让它成为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向量q将四元数v转换为颜色。

问题是如何找到四元数q

从程序员的角度来看,目标是编写反向函数vec4 c2q(in vec3 u, in vec3 v) -相应的“颜色到四元数”转换器。

请注意,如果没有充分的理由,请勿触摸q2c()。例如,逻辑上的一个严重错误,导致“无法解决任务”,您可以证明这一点。


如果答案正确,您如何检查?

实际上,如果您设法来回转换,那么将获得初始值的事实将产生检查方法。因此,检查条件为对于任何非零长度vu必须始终等于q2c(c2q(u, v), v) v的长度必须为非零,因为一个人不能“缩放零”以获得“某物”。

为了简化工作,我已经使用shadertoy.com服务准备了conjugate

您需要一台像样的计算机,能够正常工作的互联网连接,以及具有webGL支持的网络浏览器(我使用的是Chrome)。程序应该可以在任何GPU上运行,甚至可以嵌入到Intel的处理器中。它甚至可以在我的低端智能手机上使用!

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

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

可以随意进行编辑和实验,更改只能在本地计算机上完成,并且不会破坏任何内容。如果视频在第一次打开时未播放(阴影玩具错误),请尝试暂停/取消暂停它。享受吧!


尝试c2q()的人

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

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

让我们继续吧!

  • 最初,我认为这必须可行: vec4(cross(u, v), dot(u, v))enter image description here

  • enter image description here中的一个: vec4( cross(u, v), sqrt( dot(u, u) * dot(v, v) ) + dot(u, v) )SE answers

  • 他的提示是“ 别忘了标准化q ”: normalize(vec4( cross(u, v), sqrt( dot(u, u) * dot(v, v) ) + dot(u, v) ))enter image description here

  • @minorlogic的评论似乎更近了: q 缩放所有sqrt( length(v)/length(u) )的组成部分, vec4(cross(u, v), dot(u, v)) * sqrt( length(u)/length(v) )enter image description here

  • 交换比率: vec4(cross(u, v), dot(u, v)) * sqrt( length(v)/length(u) )enter image description here

1 个答案:

答案 0 :(得分:1)

我的尝试

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));
}