【问题标题】:Finding quaternion, representing transformation from one vector to another寻找四元数,表示从一个向量到另一个向量的转换
【发布时间】:2019-04-01 18:41:56
【问题描述】:

简介。

以前,我 asked a questionrgb 三元数转换为四元数。在那个问题之后,我设法得到了单位四元数,但我怀疑它们的内部结构。没有简单的方法来操作它们,并将 lumachroma 分开,因为它们是单位长度的四元数。根据我的感觉,亮度应该以实部或整幅度编码;并且颜色“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 definedq2c(q, v) == (q*vec4(v, 0.0))*q'。这里,“*”运算符表示quaternion multiplication;让它成为一个函数vec4 qmul(in vec4 q1, in vec4 q2)。并且“q'”表示qconjugate,让它成为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)——对应的“颜色到四元数”转换器。

请注意,您不应在没有充分理由的情况下触摸q2c()。例如,其逻辑中存在严重错误,导致“无法解决任务”,您可以证明这一点。


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

确实,如果您设法来回转换,则检查方法将源于您将获得初始值的事实。所以检查条件是对于任何非零长度vu 必须始终等于q2c(c2q(u, v), v)v 的长度必须非零,因为不能“缩放零”来获得“某物”。

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

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

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

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

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


c2q()尝试大厅

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

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

让我们继续吧!

  • 最初我认为这必须有效: vec4(cross(u, v), dot(u, v)):

  • SE answers 之一: vec4( cross(u, v), sqrt( dot(u, u) * dot(v, v) ) + dot(u, v) ):

  • 在他的提示下“不要忘记规范化 q”: normalize(vec4( cross(u, v), sqrt( dot(u, u) * dot(v, v) ) + dot(u, v) )):

  • @minorlogic 的评论,似乎更近了一步: 将所有q 的组件按sqrt( length(v)/length(u) ) 缩放vec4(cross(u, v), dot(u, v)) * sqrt( length(u)/length(v) ):

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

【问题讨论】:

  • 与链接相比,qmul 存在 (+/-) 差异。
  • @Rabbid76 不是它,而是q2c() 的乘法顺序:q * v * q'q' * v * q。交换它,您将获得反向旋转和 RGB -> CMY 颜色偏移。我设法在一个小时左右后找到它。此外,规则已更改,问题现在变得更加有趣和互动 ;-)
  • @minorlogic 经过测试,出现在“耻辱大厅”部分以及链接问题部分。你有没有试过阅读这个问题?))或者只是搜索 SE,希望重复? ;-p
  • 这是描述问题的正确解决方案。所以 1. 检查你的实现是否有错误?测试结果 quat 是否将 "u" 转为 "v" 2. 如果运行良好,验证问题是否正确制定

标签: colors linear-algebra transformation quaternions


【解决方案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));
}

【讨论】:

  • 更近了!尝试更改v,您会发现颜色会有所不同。试试看,比如const vec3 v = vec3(0.0, 1.0, 0.0);,你马上就会看到。
  • @xakepp35 现在好点了吗?我已经修复了黑暗
  • 是的,但目标是检查 u == q2c(c2q(u, v), v) 是否满足
  • 换句话说,对于任何v输出必须与输入相同v=(0.0, 0.0, 0.0)除外
  • 那是因为无论旋转和缩放哪个初始向量v,你都应该把原来的u取回来..
猜你喜欢
  • 2013-07-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-08-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多