以前,我有asked a question将rgb三元转换为四元数。在那个问题之后我设法得到了单位四元数,但我对它们的内部结构有疑问。没有简单的方法来操作它们,并分离亮度和色度,因为它是单位长度的四元数。根据我对它的感觉,亮度应该在实际部分或整个幅度中编码;并且颜色“色度”信息应该在虚部中编码。
今天我决定改进一下,采取另一种方法,与上面链接中的第一种方法不同。我认为它可能会成功,因为四元数不仅可以存储旋转(单位四元数),还可以存储比例。首先,我将首先解释我的下一个想法。我将在以下解释中使用GLSL着色器语法。
对于图像的某些像素,让我们在单位立方体内得到一个三维矢量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
的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矢量q
,将四元数v
转换为颜色。
问题是如何找到四元数q
?
从程序员的角度来看,目标是编写反向函数vec4 c2q(in vec3 u, in vec3 v)
- 相应的“颜色到四元数”转换器。
请注意,你不应该触摸q2c()
,没有一个很好的理由。例如,其逻辑中存在严重错误,导致“无法解决任务”,您可以证明这一点。
实际上,检查方法可能源于这样一个事实,即如果你能够设法转换回来,你将得到初始值。因此检查条件是对于任何非零长度的v
,u
必须始终等于q2c(c2q(u, v), v)
。 v
必须具有非零长度,因为人们不能“缩小零”以获得“某事”。
为了方便起见,我使用shadertoy.com服务准备了testing program。
你需要一台体面的电脑,有互联网连接和支持webGL的网络浏览器(我正在使用Chrome)。程序应该适用于任何GPU,甚至嵌入到intel的处理器中。它甚至可以在我的低端智能手机上运行!
要测试你的答案,你应该把你提出的公式,用GLSL
语法编写,在c2q()
函数中。然后按应用按钮,您的更改将生效:
左侧的图像表示一些未改变的源像素。右半部分将包含由q2c(c2q())
前后转换的像素。显然,一半必须在视觉上相等,你不应该注意到任何垂直线。可能会出现一些小的数学(不明显)错误,但这只是由于浮点的性质 - 它的有限精度和可能的舍入误差。
您可以随意编辑和试验,只在本地,在您的计算机上进行更改,并且您不会破坏任何内容。如果视频没有在第一次打开时播放(shadertoy bug) - 尝试暂停/取消暂停。请享用!
c2q()
大厅尝试如果一切正确,图像的右侧(已处理的一侧)应等于左侧(原始)。在这里,我将回顾在xxxxx
实现中通过放置一些而不是c2q()
获得的不同结果:
vec4 c2q(vec3 u, vec3 v) {
return xxxxx;
}
让我们继续!
vec4(cross(u, v), dot(u, v))
:vec4( cross(u, v), sqrt( dot(u, u) * dot(v, v) ) + dot(u, v) )
:normalize(vec4( cross(u, v), sqrt( dot(u, u) * dot(v, v) ) + dot(u, v) ))
: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));
}