Вычисление трехмерных координат на единичной сфере из 2D-точки - PullRequest
5 голосов
/ 28 августа 2011

У меня есть квадратное растровое изображение круга, и я хочу вычислить нормали всех пикселей в этом круге, как если бы это была сфера радиусом 1:

enter image description here

Сфера / круг центрированы в растровом изображении.

Какое уравнение для этого?

Ответы [ 4 ]

8 голосов
/ 28 августа 2011

Не знаю много о том, как люди программируют трехмерные вещи, поэтому я просто приведу чистую математику и надеюсь, что это полезно.

Сфера радиуса 1 с центром в начале координат - это множество точек, удовлетворяющих:

x 2 + y 2 + z 2 = 1

Мы хотим, чтобыТрехмерные координаты точки на сфере, где известны x и y.Итак, просто решите для z:

z = ± sqrt (1 - x 2 - y 2 ).

Теперь давайте рассмотрим единичный вектор, направленный наружу из сферы.Это единичная сфера, поэтому мы можем просто использовать вектор от начала координат до (x, y, z), что, конечно,.

Теперь нам нужно уравнение касательной плоскости к сфере в точке (x, y, z), но для этого будут использоваться собственные переменные x, y и z, поэтому вместо этого я сделаю этокасательная к сфере в (х 0 , у 0 , z 0 ).Это просто:

x 0 x + y 0 y + z 0 z = 1

Надеюсь, это поможет.


(OP):

Вы имеете в виду что-то вроде:

const int R = 31, SZ = power_of_two(R*2);
std::vector<vec4_t> p;
for(int y=0; y<SZ; y++) {
    for(int x=0; x<SZ; x++) {
        const float rx = (float)(x-R)/R, ry = (float)(y-R)/R;
        if(rx*rx+ry*ry > 1) { // outside sphere
            p.push_back(vec4_t(0,0,0,0));
        } else {
            vec3_t normal(rx,sqrt(1.-rx*rx-ry*ry),ry);
            p.push_back(vec4_t(normal,1));
        }
    }
}

Это делает хорошую сферическую штриховкуесли я буду относиться к нормам как к цветам и притворять их;это правильно?


(TZ)

Извините, я не знаком с этими аспектами C ++.Я не очень часто использовал этот язык в последнее время.

1 голос
/ 28 августа 2011

Эта формула часто используется для эффекта "поддельного envmapping".

double x = 2.0 * pixel_x / bitmap_size - 1.0;
double y = 2.0 * pixel_y / bitmap_size - 1.0;
double r2 = x*x + y*y;
if (r2 < 1)
{
    // Inside the circle
    double z = sqrt(1 - r2);
    .. here the normal is (x, y, z) ...
}
1 голос
/ 28 августа 2011

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

В этом случае вам нужен тест пересечения лучей и сфер:

http://www.siggraph.org/education/materials/HyperGraph/raytrace/rtinter1.htm

Ваши лучи будут простыми перпендикулярными лучами, основанными на ваших U / V координатах (раз два, так как ваша сфера имеет диаметр 2). Это даст вам передние точки на сфере.

Оттуда рассчитайте нормали, как показано ниже (point - origin, радиус уже равен 1 единице).

Разорвано по ссылке выше:

Вы должны объединить два уравнения:

  • Луч: R (t) = R0 + t * Rd, t> 0 с R0 = [X0, Y0, Z0] и Rd = [Xd, Yd, Zd]
  • Сфера: S = множество точек [xs, ys, zs], где (xs - xc) 2 + (ys - yc) 2 + (zs - zc) 2 = Sr2

Для этого вычислите ваш луч (x * pixel / width, y * pixel / width, z: 1), затем:

  • A = Xd ^ 2 + Yd ^ 2 + Zd ^ 2
  • B = 2 * (Xd * (X0 - Xc) + Yd * (Y0 - Yc) + Zd * (Z0 - Zc))
  • C = (X0 - Xc) ^ 2 + (Y0 - Yc) ^ 2 + (Z0 - Zc) ^ 2 - Sr ^ 2

Вставить в квадратное уравнение:

  • t0, t1 = (- B + (B ^ 2 - 4 * C) ^ 1/2) / 2

Проверьте дискриминант (B ^ 2 - 4 * C), и если настоящий корень, пересечение:

  • Ri = [xi, yi, zi] = [x0 + xd * ti, y0 + yd * ti, z0 + zd * ti]

И нормаль поверхности:

  • SN = [(xi - xc) / Sr, (yi - yc) / Sr, (zi - zc) / Sr]

Все это:

Итак, поскольку мы говорим о единичных значениях и лучах, которые указывают прямо на Z (без компонента x или y), мы можем значительно сократить эти уравнения:

Ray:

  • X0 = 2 * пиксельX / ширина
    Y0 = 2 * пиксельY / высота
    Z0 = 0

  • Xd = 0
    Yd = 0
    Zd = 1

Сфера:

  • Xc = 1
    Yc = 1
    Zc = 1

Факторы:

  • A = 1 (единичный луч)
  • B
    = 2 * (0 + 0 + (0 - 1))
    = -2 (без компонента x / y)
  • C
    = (X0 - 1) ^ 2 + (Y0 - 1) ^ 2 + (0 - 1) ^ 2 - 1
    = (X0 - 1) ^ 2 + (Y0 - 1) ^ 2

  • дискриминантный
    = (-2) ^ 2 - 4 * 1 * C
    = 4 - 4 * C

Отсюда:

If discriminant < 0:
  Z = ?, Normal = ?
Else:
  t = (2 + (discriminant) ^ 1 / 2) / 2
If t < 0 (hopefully never or always the case)
  t = -t

Тогда:

  • Z: т
  • Nx: Си - 1
    Ny: Yi - 1
    Nz: т - 1

Еще дальше вареные:

Интуитивно понятно, что C (X^2 + Y^2) и квадратный корень - самые выдающиеся фигуры. Если бы у меня было лучшее воспоминание о моей математике (в частности, о преобразованиях по показателям сумм), я бы поспорил, что смогу вывести это из того, что дал вам Том Зич. Поскольку я не могу, я просто оставлю это, как указано выше.

1 голос
/ 28 августа 2011

Очевидно, что вы ограничены предположением, что все точки находятся на одной половине сферы или аналогичных, из-за отсутствующего измерения.Кроме того, это довольно просто.

Середина круга имеет нормальную поверхность, обращенную точно внутрь или наружу, перпендикулярно плоскости, на которой нарисован круг.

Каждая точка на краю круга обращена в сторону от середины, и, таким образом, вы можете рассчитать нормаль для этого.

Для любой точки между серединой и краем вы используетеРасстояние от середины и несколько простых триггеров (что ускользает от меня на данный момент).Лерп в некоторых точках примерно точен, но не совсем то, что вам нужно, так как это кривая.Тем не менее, простая кривая, и вы знаете начальные и конечные значения, поэтому вычисление их должно принимать только простое уравнение.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...