寻找四元数,表示从一个向量到另一个向量的变换
Finding quaternion, representing transformation from one vector to another
简介
以前,我 asked a question 将 rgb 三元数转换为四元数。在那个问题之后我设法得到了单位四元数,但我怀疑它们的内部结构。没有简单的方法来操作它们,并且将 luma 和 chroma 分开,因为它们是单位长度的四元数。根据我的感觉,亮度应该用实部或整数来编码;而颜色“chroma”信息应该在虚部进行编码。
今天我决定改进一下,采用另一种方法,不同于上面 link 中的第一种方法。我认为它可以成功,因为四元数不仅可以存储旋转(单位四元数),还可以存储比例。首先,我将从解释我的下一个想法开始。我将在以下解释中使用 GLSL 着色器语法。
方法描述和问题正文。
对于图像的某些像素,让我们在单位立方体中设想一个 3D 向量 vec3 u
,其中正坐标位于封闭范围 [0.0, 1.0] 内,代表完整 rgb 色彩空间。因此,现在 u
的坐标、u.x
、u.y
和 u.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",您可以证明这一点。
你如何检查你的答案是否正确?
确实,如果您设法来回转换,您将获得初始值这一事实会产生检查方法。所以检查条件是对于任何非零长度v
,u
必须总是等于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(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) )
:
我的尝试:
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));
}
简介
以前,我 asked a question 将 rgb 三元数转换为四元数。在那个问题之后我设法得到了单位四元数,但我怀疑它们的内部结构。没有简单的方法来操作它们,并且将 luma 和 chroma 分开,因为它们是单位长度的四元数。根据我的感觉,亮度应该用实部或整数来编码;而颜色“chroma”信息应该在虚部进行编码。
今天我决定改进一下,采用另一种方法,不同于上面 link 中的第一种方法。我认为它可以成功,因为四元数不仅可以存储旋转(单位四元数),还可以存储比例。首先,我将从解释我的下一个想法开始。我将在以下解释中使用 GLSL 着色器语法。
方法描述和问题正文。
对于图像的某些像素,让我们在单位立方体中设想一个 3D 向量 vec3 u
,其中正坐标位于封闭范围 [0.0, 1.0] 内,代表完整 rgb 色彩空间。因此,现在 u
的坐标、u.x
、u.y
和 u.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",您可以证明这一点。
你如何检查你的答案是否正确?
确实,如果您设法来回转换,您将获得初始值这一事实会产生检查方法。所以检查条件是对于任何非零长度v
,u
必须总是等于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(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) )
:
我的尝试:
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));
}