§ О чем речь
Это продолжение той же самой темы, что была раннее описана мной, но я теперь немного расширю сферу применения. В прошлый раз я вывел формулы, которые пересекают линию с плоскостью, но так, что линия исходит из точки (0,0,0), а теперь я поправлю формулы так, чтобы можно было рассчитать любую исходящую линию для расчета пересечений.§ Вывод формулы
Задаем снова параметрические уравнения для плоскости и прямой:- Плоскость
- Прямая
Требуется найти u,v,t. Здесь (u,v) будет найденной текстурной позицией, а t - расстоянием от точки P до точки M. Прямая задается вектором PN и позицией P. То есть при t=0, M будет равно P.
Теперь, для того, чтобы параметры, необходимо приравнять оба уравнения между собой, отчего получится:
Здесь вектор AP это разность между точкой P (начала прямой) и точкой A (треугольник). Если разложить покомпонентно, то получим вот такую систему линейных алгебраических уравнений (СЛАУ):
§ Нахождение решений
Чтобы найти u,v,t необходимо применить формулу Крамера, которую уже неоднократно применяли. Для начала, надо вычислить детерминант:Он будет равен:
Вообще, каждый раз коэффициенты для треугольника для этого детерминанта не надо высчитывать, они могут быть рассчитаны только один раз на всю сцену. Меняется только лишь PN. И потому их достаточно высчитать лишь единожды. Пересчитывание этих коэффициентов может быть только тогда, когда как-то меняется положение треугольника в пространстве.
Теперь ищется u:
, ,
ПолучаетсяВ данном случае, для t менять коэффициенты требуется только при перемещении точки вида относительно треугольника. То есть, фактически, один раз на фрейм.
Стоит обратить внимание, что вектор это разница между точкой исходящего луча и точкой A в треугольнике.
Внимательно отмечу что коэффициенты для t являются вектором, перпендикулярным плоскости, то есть, из этого вектора можно найти вектор нормали:
§ Код
Ниже представлена функция для расчета параметров треугольника:1struct vec2 { float x, y; }; 2struct vec3 { float x, y, z; }; 3struct vec3uv { float x, y, z, u, v; }; 4 5struct trig { 6 7 vec3uv a, b, c; 8 vec3 D, U, V, T; 9 vec3 tu, tv; 10 vec3 AP; 11}; 12 13void calc_triangle(trig& T, vec3 P) { 14 15 vec3 AB = {T.b.x - T.a.x, T.b.y - T.a.y, T.b.z - T.a.z}; 16 vec3 AC = {T.c.x - T.a.x, T.c.y - T.a.y, T.c.z - T.a.z}; 17 vec3 AP = {P.x - T.a.x, P.y - T.a.y, P.z - T.a.z}; 18 19 T.D = { 20 AB.z*AC.y - AB.y*AC.z, 21 AB.x*AC.z - AB.z*AC.x, 22 AB.y*AC.x - AB.x*AC.y 23 }; 24 25 T.U = { 26 AC.y*AP.z - AP.y*AC.z, 27 AP.x*AC.z - AC.x*AP.z, 28 AC.x*AP.y - AP.x*AC.y 29 }; 30 31 T.V = { 32 AP.y*AB.z - AB.y*AP.z, 33 AB.x*AP.z - AP.x*AB.z, 34 AP.x*AB.y - AB.x*AP.y 35 }; 36 37 T.T = { 38 AB.y*AC.z - AC.y*AB.z, 39 AC.x*AB.z - AB.x*AC.z, 40 AB.x*AC.y - AC.x*AB.y 41 }; 42 43 // Текстуры 44 T.tu = {T.a.u, T.b.u - T.a.u, T.c.u - T.a.u}; 45 T.tv = {T.a.v, T.b.v - T.a.v, T.c.v - T.a.v}; 46 T.AP = AP; 47}Так можно задать треугольник
1trig T; 2vec3 org = {0, 0, 0}; 3 4T.a = {-1, 1, 0, 0, 0}; 5T.b = { 1, 1, 0, 255, 0}; 6T.c = { 1, -1, 0, 255, 255}; 7 8calc_triangle(T, org);Здесь org - это точка, откуда смотрит камера.
Таким образом вычисляются точки текстуры и растеризуется
1for (int y = -100; y < 100; y++) 2for (int x = -160; x < 160; x++) { 3 4 int cl = 0; 5 6 // Вектор вида 7 vec3 vec = { (float)x / 100, (float)y / 100, 1.0}; 8 9 // Поворот вектора 10 float dx = vec.x; 11 float dy = vec.y; 12 float dz = vec.z; 13 14 // Тест пересечения u, v, t 15 float u = T.U.x*dx + T.U.y*dy + T.U.z*dz; 16 float v = T.V.x*dx + T.V.y*dy + T.V.z*dz; 17 float d = T.D.x*dx + T.D.y*dy + T.D.z*dz; 18 float t = T.T.x*T.AP.x + T.T.y*T.AP.y + T.T.z*T.AP.z; 19 20 if (u + v < d && u >= 0 && v >= 0 && t < 0) { 21 22 u /= d; 23 v /= d; 24 25 // Рассчитать позицию текстуры 26 float tx = T.tu.x + T.tu.y*u + T.tu.z*v; 27 float ty = T.tv.x + T.tv.y*u + T.tv.z*v; 28 29 cl = 256*((int)tx^(int)ty); 30 } 31 32 pset(160 + x, 100 - y, cl); 33}