§ О чем речь
Это продолжение той же самой темы, что была раннее описана мной, но я теперь немного расширю сферу применения. В прошлый раз я вывел формулы, которые пересекают линию с плоскостью, но так, что линия исходит из точки (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 являются вектором, перпендикулярным плоскости, то есть, из этого вектора можно найти вектор нормали:
§ Код
Ниже представлена функция для расчета параметров треугольника:struct vec2 { float x, y; }; struct vec3 { float x, y, z; }; struct vec3uv { float x, y, z, u, v; }; struct trig { vec3uv a, b, c; vec3 D, U, V, T; vec3 tu, tv; vec3 AP; }; void calc_triangle(trig& T, vec3 P) { vec3 AB = {T.b.x - T.a.x, T.b.y - T.a.y, T.b.z - T.a.z}; vec3 AC = {T.c.x - T.a.x, T.c.y - T.a.y, T.c.z - T.a.z}; vec3 AP = {P.x - T.a.x, P.y - T.a.y, P.z - T.a.z}; T.D = { AB.z*AC.y - AB.y*AC.z, AB.x*AC.z - AB.z*AC.x, AB.y*AC.x - AB.x*AC.y }; T.U = { AC.y*AP.z - AP.y*AC.z, AP.x*AC.z - AC.x*AP.z, AC.x*AP.y - AP.x*AC.y }; T.V = { AP.y*AB.z - AB.y*AP.z, AB.x*AP.z - AP.x*AB.z, AP.x*AB.y - AB.x*AP.y }; T.T = { AB.y*AC.z - AC.y*AB.z, AC.x*AB.z - AB.x*AC.z, AB.x*AC.y - AC.x*AB.y }; // Текстуры T.tu = {T.a.u, T.b.u - T.a.u, T.c.u - T.a.u}; T.tv = {T.a.v, T.b.v - T.a.v, T.c.v - T.a.v}; T.AP = AP; }Так можно задать треугольник
T; vec3 org = {0, 0, 0}; T.a = {-1, 1, 0, 0, 0}; T.b = { 1, 1, 0, 255, 0}; T.c = { 1, -1, 0, 255, 255}; calc_triangle(T, org);trig Здесь org - это точка, откуда смотрит камера.
Таким образом вычисляются точки текстуры и растеризуется
for (int y = -100; y < 100; y++) for (int x = -160; x < 160; x++) { int cl = 0; // Вектор вида vec3 vec = { (float)x / 100, (float)y / 100, 1.0}; // Поворот вектора float dx = vec.x; float dy = vec.y; float dz = vec.z; // Тест пересечения u, v, t float u = T.U.x*dx + T.U.y*dy + T.U.z*dz; float v = T.V.x*dx + T.V.y*dy + T.V.z*dz; float d = T.D.x*dx + T.D.y*dy + T.D.z*dz; float t = T.T.x*T.AP.x + T.T.y*T.AP.y + T.T.z*T.AP.z; if (u + v < d && u >= 0 && v >= 0 && t < 0) { u /= d; v /= d; // Рассчитать позицию текстуры float tx = T.tu.x + T.tu.y*u + T.tu.z*v; float ty = T.tv.x + T.tv.y*u + T.tv.z*v; cl = 256*((int)tx^(int)ty); } pset(160 + x, 100 - y, cl); }