Введение.
Ранее я задавал вопрос о преобразовании rgb тройного в кватернион. После этого вопроса мне удалось получить кватернионы, но я сомневаюсь в их внутренней структуре. Не было простого способа управлять ими, а также отделять luma и chroma , поскольку это были кватернионы единичной длины. Согласно моим ощущениям, яркость должна быть закодирована либо в реальной части, либо в целой величине; И информация о цвете " chroma " должна быть закодирована в мнимой части.
Сегодня я решил улучшить ситуацию, приняв другой подход, отличный от первого в ссылке выше. Я думаю, что это может иметь успех, поскольку кватернион может хранить не только вращение (единичный кватернион), но и масштаб. Перво-наперво, поэтому я начну с объяснения моей следующей идеи. Я бы использовал синтаксис шейдера 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)
довольно проста, , как определено : q2c(q, v) == (q*vec4(v, 0.0))*q'
. Здесь оператор "*
" обозначает умножение кватернионов ; Давайте сделаем это функцией vec4 qmul(in vec4 q1, in vec4 q2)
. А "q'
" обозначает q
сопряженное , давайте сделаем это 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)
, которая преобразует кватернион q
в цвет, вращая и масштабируя выбранный трехмерный вектор v
.
Вопрос Как найти этот кватернион q
?
С точки зрения программиста цель состоит в том, чтобы написать обратную функцию vec4 c2q(in vec3 u, in vec3 v)
- соответствующий преобразователь "цвет в кватернион".
Обратите внимание, что вам не следует прикасаться к q2c()
без уважительной причины. Например, серьезная ошибка в логике, приводящая к «невозможности решить задачу», и вы можете это доказать.
Как вы можете проверить, правильный ли ваш ответ?
Действительно, метод проверки возник бы из-за того, что вы получите начальное значение, если вам удастся конвертировать вперед и назад. Таким образом, условие проверки равно . Для любой ненулевой длины v
, u
всегда должно быть равно q2c(c2q(u, v), v)
. v
должна иметь ненулевую длину, потому что нельзя «масштабировать ноль», чтобы получить «что-то».
Чтобы упростить задачу, я подготовил программу тестирования , используя сервис shadertoy.com.
Вам потребуется приличный компьютер с работающим подключением к Интернету и веб-браузер с поддержкой webGL (я использую Chrome). Программа должна работать на любом графическом процессоре, даже встроенном в процессоры Intel. Он даже работал на моем нижнем смартфоне!
Чтобы проверить свой ответ, вы должны поместить предложенную формулу, написанную в синтаксисе GLSL
, в функцию c2q()
. Затем нажмите кнопку «Применить», и ваши изменения вступят в силу: ![enter image description here](https://i.stack.imgur.com/FhoEZ.png)
Изображение слева представляет некоторые неизмененные исходные пиксели.А правая половина будет содержать пиксели, преобразованные вперед и назад на q2c(c2q())
.Очевидно, что половинки должны быть визуально равны, вы не должны заметить никакой вертикальной линии.Может возникнуть небольшая математическая (незаметная) ошибка , но только из-за природы с плавающей точкой - ее конечной точности и возможных ошибок округления.
Не стесняйтесь редактировать и экспериментировать, изменения будут внесенытолько локально, на вашем компьютере, и вы ничего не можете разрушить.Если видео не воспроизводится при первом открытии (ошибка шадертой) - попробуйте приостановить / отменить его.Наслаждайтесь!
Зал c2q()
Попытки
Если все правильно, правая сторона изображения (обработанная) должна быть равна левой стороне (оригинал).И здесь я бы рассмотрел различные результаты, которые были получены путем помещения чего-то вместо xxxxx
в реализацию c2q()
:
vec4 c2q(vec3 u, vec3 v) {
return xxxxx;
}
Давайте продолжим!
Сначала я думал, что это должно сработать: vec4(cross(u, v), dot(u, v))
: ![enter image description here](https://i.stack.imgur.com/GlZrJ.png)
Один из SE ответов : vec4( cross(u, v), sqrt( dot(u, u) * dot(v, v) ) + dot(u, v) )
: ![enter image description here](https://i.stack.imgur.com/T1jiH.png)
И с его подсказкой " Не забудьте нормализовать q ": normalize(vec4( cross(u, v), sqrt( dot(u, u) * dot(v, v) ) + dot(u, v) ))
: ![enter image description here](https://i.stack.imgur.com/5BWNB.png)
Комментарий @ minorlogic, похоже, на шаг ближе: масштабирует все компоненты q
на sqrt( length(v)/length(u) )
, vec4(cross(u, v), dot(u, v)) * sqrt( length(u)/length(v) )
: ![enter image description here](https://i.stack.imgur.com/6cikY.png)
С измененным коэффициентом: vec4(cross(u, v), dot(u, v)) * sqrt( length(v)/length(u) )
: ![enter image description here](https://i.stack.imgur.com/MQ3bk.png)