以前,我曾asked a question将 rgb 三元数转换为四元数。在提出这个问题之后,我设法获得了单元四元数,但是我对它们的内部结构感到怀疑。没有简单的方法来操作它们,以及分隔 luma 和 chroma ,因为它们是单位长度的四元数。根据我对它的感觉,亮度应该编码为实数部分或整个大小。颜色“
今天,我决定采用另一种方法来进行改进,与上面链接中的第一种方法不同。我认为它会成功,因为四元数不仅可以存储旋转(单位四元数),而且还可以存储比例。首先是第一件事,所以我将从解释下一个想法开始。在以下说明中,我将使用 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
必须回答问题“如何转换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()
。例如,逻辑上的一个严重错误,导致“无法解决任务”,您可以证明这一点。
实际上,如果您设法来回转换,那么将获得初始值的事实将产生检查方法。因此,检查条件为对于任何非零长度v
,u
必须始终等于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), 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) ))
:
@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) )
:
答案 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));
}