рисовать 3D лица как 2d - PullRequest
3 голосов
/ 17 июля 2010

У меня есть 3d-сетка, и я хотел бы нарисовать каждую грань в двухмерной форме.

Я имею в виду следующее: для каждой грани 1. получить доступ к грани, нормальной 2. получить матрицу вращения изнормальный вектор 3. умножить каждую вершину на матрицу вращения, чтобы получить вершины в плоскости, подобной 2d, получить 2 координаты из преобразованных вершин

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

В данный момент я пытаюсь получить матрицу вращения из вектора нормалей, как мне это сделать?

ОБНОВЛЕНИЕ:

Вот наглядное объяснение того, что мне нужно:

3d to 2d

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

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

Мне также нужно сохранить оригинальное трехмерное вращение лица.Я предполагаю, что это было бы обратное вращение лица в норме.

Я думаю, что я немного потерян в пространстве:)

Вот базовый прототип, который я сделал, используя Обработка :

void setup(){
  size(400,400,P3D);
  background(255);
  stroke(0,0,120);
  smooth();
  fill(0,120,0);

  PVector x = new PVector(1,0,0);
  PVector y = new PVector(0,1,0);
  PVector z = new PVector(0,0,1);

  PVector n  = new PVector(0.378521084785,0.925412774086,0.0180059205741);//normal
  PVector p0 = new PVector(0.372828125954,-0.178844243288,1.35241031647);
  PVector p1 = new PVector(-1.25476706028,0.505195975304,0.412718296051);
  PVector p2 = new PVector(-0.372828245163,0.178844287992,-1.35241031647);
  PVector p3 = new PVector(1.2547672987,-0.505196034908,-0.412717700005);

  PVector[] face = {p0,p1,p2,p3};
  PVector[] face2d = new PVector[4];
  PVector   nr = PVector.add(n,new PVector());//clone normal

  float rx = degrees(acos(n.dot(x)));//angle between normal and x axis
  float ry = degrees(acos(n.dot(y)));//angle between normal and y axis
  float rz = degrees(acos(n.dot(z)));//angle between normal and z axis

  PMatrix3D r = new PMatrix3D();
  //is this ok, or should I drop the builtin function, and add 
  //the rotations manually
  r.rotateX(rx);
  r.rotateY(ry);
  r.rotateZ(rz);

  print("original: ");println(face);
  for(int i = 0 ; i < 4; i++){
    PVector rv = new PVector();
    PVector rn = new PVector();
    r.mult(face[i],rv);
    r.mult(nr,rn);
    face2d[i] = PVector.add(face[i],rv);
  }
  print("rotated: ");println(face2d);
  //draw
  float scale = 100.0;
  translate(width * .5,height * .5);//move to centre, Processing has 0,0 = Top,Lef
  beginShape(QUADS);
  for(int i = 0 ; i < 4; i++){
   vertex(face2d[i].x * scale,face2d[i].y * scale,face2d[i].z * scale);
  }
  endShape();
  line(0,0,0,nr.x*scale,nr.y*scale,nr.z*scale);

  //what do I do with this ?
  float c = cos(0), s = sin(0);
  float x2 = n.x*n.x,y2 = n.y*n.y,z2 = n.z*n.z; 
  PMatrix3D m = new PMatrix3D(x2+(1-x2)*c,  n.x*n.y*(1-c)-n.z*s,  n.x*n.z*(1-c)+n.y*s,  0,
                              n.x*n.y*(1-c)+n.z*s,y2+(1-y2)*c,n.y*n.z*(1-c)-n.x*s,0,
                              n.x*n.y*(1-c)-n.y*s,n.x*n.z*(1-c)+n.x*s,z2-(1-z2)*c,0,
                              0,0,0,1);
}

Обновление

Извините, если меня раздражает, но, похоже, я не понимаю.

Вот немногоPython с использованием API Blender :

import Blender
from Blender import *
import math
from math import sin,cos,radians,degrees

def getRotMatrix(n):
    c = cos(0)
    s = sin(0)
    x2 = n.x*n.x
    y2 = n.y*n.y
    z2 = n.z*n.z
    l1 = x2+(1-x2)*c, n.x*n.y*(1-c)+n.z*s, n.x*n.y*(1-c)-n.y*s
    l2 = n.x*n.y*(1-c)-n.z*s,y2+(1-y2)*c,n.x*n.z*(1-c)+n.x*s
    l3 = n.x*n.z*(1-c)+n.y*s,n.y*n.z*(1-c)-n.x*s,z2-(1-z2)*c
    m = Mathutils.Matrix(l1,l2,l3)
    return m

scn = Scene.GetCurrent()
ob = scn.objects.active.getData(mesh=True)#access mesh

out = ob.name+'\n'
#face0
f = ob.faces[0]
n = f.v[0].no
out += 'face: ' + str(f)+'\n'
out += 'normal: ' + str(n)+'\n'

m = getRotMatrix(n)
m.invert()

rvs = []
for v in range(0,len(f.v)):
    out += 'original vertex'+str(v)+': ' + str(f.v[v].co) + '\n'
    rvs.append(m*f.v[v].co)

out += '\n'
for v in range(0,len(rvs)):
    out += 'original vertex'+str(v)+': ' + str(rvs[v]) + '\n'

f = open('out.txt','w')
f.write(out)
f.close

Все, что я делаю, - это получить текущий объект, получить доступ к первому лицу, получить нормаль, получить вершины, вычислить матрицу вращения,инвертировать его, затем умножить на каждую вершину.Наконец, я пишу простой вывод.

Вот вывод для плоскости по умолчанию, для которой я повернул все вершины вручную на 30 градусов:

Plane.008
face: [MFace (0 3 2 1) 0]
normal: [0.000000, -0.499985, 0.866024](vector)
original vertex0: [1.000000, 0.866025, 0.500000](vector)
original vertex1: [-1.000000, 0.866026, 0.500000](vector)
original vertex2: [-1.000000, -0.866025, -0.500000](vector)
original vertex3: [1.000000, -0.866025, -0.500000](vector)

rotated vertex0: [1.000000, 0.866025, 1.000011](vector)
rotated vertex1: [-1.000000, 0.866026, 1.000012](vector)
rotated vertex2: [-1.000000, -0.866025, -1.000012](vector)
rotated vertex3: [1.000000, -0.866025, -1.000012](vector)

Вот первая грань знаменитой сетки Сюзанны:

Suzanne.001
face: [MFace (46 0 2 44) 0]
normal: [0.987976, -0.010102, 0.154088](vector)
original vertex0: [0.468750, 0.242188, 0.757813](vector)
original vertex1: [0.437500, 0.164063, 0.765625](vector)
original vertex2: [0.500000, 0.093750, 0.687500](vector)
original vertex3: [0.562500, 0.242188, 0.671875](vector)

rotated vertex0: [0.468750, 0.242188, -0.795592](vector)
rotated vertex1: [0.437500, 0.164063, -0.803794](vector)
rotated vertex2: [0.500000, 0.093750, -0.721774](vector)
rotated vertex3: [0.562500, 0.242188, -0.705370](vector)

Вершины из сетки Plane.008 изменены, а из сетки Suzanne.001 - нет.Разве они не должны?Стоит ли ожидать получения нулей на одной оси?Как только я получил матрицу вращения из вектора нормалей, каково вращение по x, y, z?

Примечание: 1. Матрица Блендера поддерживает оператор * 2. В системе координат БлендераZ точка вверх.Это похоже на правую систему, повернутую на 90 градусов по X.

Спасибо

Ответы [ 4 ]

2 голосов
/ 17 июля 2010

Это выглядит разумно для меня. Вот как получить матрицу вращения из нормального вектора . Нормаль это вектор. Угол равен 0. Вы, вероятно, хотите обратное вращение.

Ваша сетка триангулирована? Я предполагаю, что это так. Если это так, вы можете сделать это без матрицы вращения. Пусть точки лица будут A,B,C. Возьмите любые две вершины лица, скажем A и B. Определить ось х вдоль вектора AB. A находится на 0,0. B находится на 0,|AB|. C можно определить по тригонометрии, используя угол между AC и AB (который вы получите с помощью точечного произведения) и длину |AC|.

1 голос
/ 17 июля 2010

Вы правильно создали матрицу m.Это вращение, которое соответствует вашему нормальному вектору.Вы можете использовать обратную матрицу, чтобы «развернуть» ваши точки.Нормаль face2d будет x, т. Е. Точка вдоль оси x.Поэтому извлеките ваши 2d координаты соответственно.(Предполагается, что ваш четырехугольник приблизительно плоский.)

Я не знаю, какую библиотеку вы используете (Обработка), поэтому я просто предполагаю, что есть методы для m.invert () и оператор для примененияматрица вращения в точку.Их, конечно, можно назвать чем-то другим.К счастью, обратная сторона матрицы чистого вращения - это ее транспонирование, и умножение матрицы и вектора легко выполнить вручную, если вам нужно.

void setup(){
  size(400,400,P3D);
  background(255);
  stroke(0,0,120);
  smooth();
  fill(0,120,0);

  PVector x = new PVector(1,0,0);
  PVector y = new PVector(0,1,0);
  PVector z = new PVector(0,0,1);

  PVector n  = new PVector(0.378521084785,0.925412774086,0.0180059205741);//normal
  PVector p0 = new PVector(0.372828125954,-0.178844243288,1.35241031647);
  PVector p1 = new PVector(-1.25476706028,0.505195975304,0.412718296051);
  PVector p2 = new PVector(-0.372828245163,0.178844287992,-1.35241031647);
  PVector p3 = new PVector(1.2547672987,-0.505196034908,-0.412717700005);

  PVector[] face = {p0,p1,p2,p3};
  PVector[] face2d = new PVector[4];

  //what do I do with this ?
  float c = cos(0), s = sin(0);
  float x2 = n.x*n.x,y2 = n.y*n.y,z2 = n.z*n.z; 
  PMatrix3D m_inverse = 
      new PMatrix3D(x2+(1-x2)*c, n.x*n.y*(1-c)+n.z*s, n.x*n.y*(1-c)-n.y*s, 0,
                    n.x*n.y*(1-c)-n.z*s,y2+(1-y2)*c,n.x*n.z*(1-c)+n.x*s,   0,
                     n.x*n.z*(1-c)+n.y*s,n.y*n.z*(1-c)-n.x*s,z2-(1-z2)*c,  0,
                    0,0,0,1);

  face2d[0] = m_inverse * p0; // Assuming there's an appropriate operator*().
  face2d[1] = m_inverse * p1; 
  face2d[2] = m_inverse * p2;
  face2d[3] = m_inverse * p3;

  // print & draw as you did before...

}
0 голосов
/ 19 июля 2010

Этого очень легко достичь: (Примечание: под «лицом» я подразумеваю «треугольник»)

  1. Создание матрицы вида, представляющей камеру, смотрящую на лицо.
    1. Определить центр лица с помощью билинейной интерполяции.
    2. Определите нормальное лицо.
    3. Расположите камеру на нескольких устройствах в направлении, противоположном нормальному.
    4. Пусть камера посмотрит в центр лица.
    5. Установите векторную точку камеры в направлении середины любой вершины грани.
    6. Установите соотношение сторон 1.
    7. Вычислить матрицу вида, используя эти данные.
  2. Создание матрицы ортогональной проекции.
    1. Установите ширину и высоту усеченного вида достаточно большими, чтобы вместить все лицо (например, длину самого длинного участка лица).
    2. Вычислить матрицу проекции.
  3. Для каждой вершины v грани умножьте ее на обе матрицы: v * view * projection.

Результатом является проекция ваших трехмерных граней в 2-мерное пространство, как если бы вы смотрели на них точно ортогонально без каких-либо нарушений перспективы. Окончательные координаты будут в нормализованных экранных координатах, где (-1, -1) - левый нижний угол, (0, 0) - центр, а (1, 1) - верхний правый угол.

0 голосов
/ 17 июля 2010

Для граней v0-v1-v3-v2 векторы v3-v0, v3-v2 и нормаль грани уже образуют матрицу вращения, которая преобразует двумерную грань в трехмерную грань.

Матрица представляет систему координат. Каждая строка (или столбец, в зависимости от обозначения) соответствует системе координат оси в новой системе координат. 3d матрица вращения / перемещения может быть представлена ​​как:

vx.x    vx.y    vx.z    0
vy.x    vy.y    vy.z    0
vz.x    vz.y    vz.z    0
vp.x    vp.y    vp.z    1

где vx - ось x системы координат, ось vy - y, ось vz - z и vp - начало координат новой системы.

Предположим, что v3-v0 - это ось y (2-я строка), v3-v2 - ось x (1-я строка), а нормаль - ось z (3-я строка). Построить матрицу из них. Тогда инвертируй матрицу. Вы получите матрицу, которая будет вращать трехмерное лицо в двухмерное.

У меня есть 3D-сетка, и я хотел бы нарисовать каждую грань в 2D-форме.

Я подозреваю, что Ультрафиолетовое развертывание Алгоритмы ближе к тому, что вы хотите достичь, чем пытаться получить матрицу вращения от 3D лица.

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