Реализация текстуры трассировки лучей для сфер

Я пытаюсь реализовать текстуры для сфер в моем трассировщике лучей. Мне удалось заставить что-то работать, но я не уверен в его правильности. Ниже приведен код для получения координат текстуры. На данный момент текстура случайная и генерируется во время выполнения.

virtual void GetTextureCoord(Vect hitPoint, int hres, int vres, int& x, int& y) {
    float theta = acos(hitPoint.getVectY());
    float phi   = atan2(hitPoint.getVectX(), hitPoint.getVectZ());

    if (phi < 0.0) {
        phi += TWO_PI;
    }

    float u = phi * INV_TWO_PI;
    float v = 1 - theta * INV_PI;

    y = (int) ((hres - 1) * u);
    x = (int) ((vres - 1) * v);
}

Вот так теперь выглядят сферы: введите описание изображения здесь

Мне пришлось нормализовать координаты точки попадания, чтобы сферы выглядели так. В противном случае они бы выглядели так:

введите описание изображения здесь

Была ли нормализация координат точки попадания правильным подходом, или что-то еще не работает в моем коде? Спасибо!

Вместо того, чтобы нормализовать точку попадания, я попытался перевести ее в мировое начало (как если бы центр сферы был там) и получил следующий результат:

введите описание изображения здесь

Кстати, я использую текстуру с разрешением 256x256 пикселей.


person ionutt93    schedule 17.04.2015    source источник
comment
Всегда ли hitPoint вычисляется так, как если бы сфера находилась в начале координат (а затем преобразовывалась в другом месте), или вы напрямую поддерживаете сферы, не центрированные в начале координат, в вашем тесте на пересечение? Вычисление phi и theta с использованием косинуса и тангенса дает вам значения, соответствующие сфере с центром в начале координат, поэтому, если сфера на самом деле нет, отображение координат текстуры не будет тем, что вы, вероятно, планировали.   -  person Wyzard    schedule 17.04.2015
comment
BTW, u и v - координаты текстуры, и функция для вычисления координат текстуры обычно просто возвращает их. Сопоставление их с целочисленными индексами текселей не является специфическим для сфер и должно выполняться где-то еще.   -  person Wyzard    schedule 17.04.2015
comment
У меня была аналогичная проблема, когда я генерировал текстуры во время выполнения для алгоритма штриховки в реальном времени. Моя ошибка заключалась в том, чтобы вычислять координаты текстуры в мировом пространстве, тогда как их нужно рассматривать в локальном пространстве. hitPoint находится в мире / представлении или в локальном пространстве?   -  person codingadventures    schedule 17.04.2015
comment
Я думаю, что напрямую поддерживаю сферы, не ориентированные на происхождение, в тесте на пересечение. Есть ли способ обойти это?   -  person ionutt93    schedule 17.04.2015
comment
Хит-точка находится в мировом пространстве.   -  person ionutt93    schedule 17.04.2015
comment
Думаю, я нашел решение для этого, я переместил точку попадания сферы, поскольку сфера была в мировом начале. Выложу новое изображение.   -  person ionutt93    schedule 17.04.2015


Ответы (1)


Непонятно, что вы имеете в виду под «нормализацией» точки попадания, поскольку в опубликованном вами коде нет ничего, что нормализует ее, но вы упомянули, что ваша точка попадания находится в мировом пространстве.

Кроме того, вы не сказали, какое отображение текстуры вы пытаетесь реализовать, но я предполагаю, что вы хотите, чтобы координаты текстуры U и V отображали широту и долготу на поверхности сферы.

Ваша первая проблема заключается в том, что преобразование декартовых координат в сферические требует, чтобы сфера была центрирована в начале координат в декартовом пространстве, что неверно в мировом пространстве. Если точка попадания находится в мировом пространстве, вы должны вычесть центральную точку сферы в пространстве мира, чтобы получить эффективную точку попадания в локальных координатах. (Вы уже поняли эту часть и обновили вопрос новым изображением.)

Вторая проблема заключается в том, что способ вычисления theta требует, чтобы сфера имела радиус 1, что неверно даже после того, как вы переместите центр сферы в начало координат. Помните свою тригонометрию: аргумент acos - это отношение стороны треугольника к его гипотенузе, и он всегда находится в диапазоне (-1, +1). В этом случае ваша координата Y - это сторона, а радиус сферы - гипотенуза. Таким образом, вы должны разделить на радиус сферы при вызове acos. Также рекомендуется ограничить значение диапазоном (-1, +1) на тот случай, если ошибка округления с плавающей запятой выводит его немного за пределы.

(В принципе, вам также придется разделить координаты X и Z на радиус, но вы используете их только для обратной касательной, и деление их обоих на радиус не изменит их частное и, следовательно, не изменится phi.)


Прямо сейчас ваши функции пересечения сфер и координат текстуры работают в мировом пространстве, но вы, вероятно, сочтете полезным позже реализовать матрицы преобразования, которые позволяют преобразовывать объекты из одного координатного пространства в другое. Затем вы можете изменить свои сферические функции для работы в локальном координатном пространстве, где центр является началом, а радиус равен 1, и дать каждому объекту связанную матрицу преобразования, которая отображает локальное координатное пространство в мировое координатное пространство. Это упростит ваш код пересечения луча / сферы и позволит вам удалить вычитание начала координат и деление радиуса из GetTextureCoord (поскольку они всегда (0, 0, 0) и 1 соответственно).

Чтобы пересечь луч с объектом, вы должны использовать матрицу преобразования объекта, чтобы преобразовать луч в локальное координатное пространство объекта, выполнить пересечение (и вычислить координаты текстуры) там, а затем преобразовать результат (например, точку попадания и нормаль поверхности ) обратно в мировое пространство.

person Wyzard    schedule 17.04.2015