我有三维网格,我想将每个面部画成一个二维形状。
我想到的是: 对于每张脸 1.进入脸部正常 2.从法向量得到一个旋转矩阵 3.将每个顶点乘以旋转矩阵,以获得'2d like'平面中的顶点 4.从变换顶点获得2个坐标
我不知道这是否是最好的方法,所以欢迎任何建议。
目前我正试图从法线向量中获取旋转矩阵, 我该怎么做?
更新
以下是我需要的直观解释:
目前我有四边形,但没有问题 将它们转换成三角形。
我想旋转一个面的顶点,这样 其中一个维度变得扁平化。
我还需要存储脸部的原始3d旋转。 我想这将是面部的反向旋转 正常。
我想我在太空中有点迷失了:)
这是我使用Processing做的基本原型:
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);
}
更新
很抱歉,如果我变得烦人,但我似乎没有得到它。
这是使用Blender的API的一些python:
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网格的第一面:
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. Blender的Matrix支持*运算符2.在Blender的坐标系Z点向上。它看起来像一个右手系统,在X上旋转90度。
由于
答案 0 :(得分:2)
这对我来说看起来很合理。以下是获取rotation matrix from normal vector的方法。法线是矢量。角度为0.您可能需要反向旋转。
你的网格是否是三角形的?我假设是。如果是这样,你可以这样做,没有旋转矩阵。让脸部的点数为A,B,C
。取脸的任意两个顶点,例如A
和B
。沿向量AB
定义x轴。 A
位于0,0
。 B
位于0,|AB|
。可以使用C
和AC
(使用点积得到的)和长度AB
之间的角度从三角学确定|AC|
。
答案 1 :(得分:1)
您正确创建了m矩阵。这是与您的法向量对应的旋转。您可以使用此矩阵的反转来“解旋”您的点。 face2d
的法线将是x
,即沿x轴指向。因此,相应地提取您的2D坐标。 (这假设你的四边形大致是平面的。)
我不知道你正在使用的库(Processing),所以我只是假设有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...
}
答案 2 :(得分:0)
对于面v0-v1-v3-v2向量v3-v0,v3-v2和面法线已经形成旋转矩阵,将2d面变换为3d面。
Matrix表示坐标系。每行(或列,取决于符号)对应于新坐标系内的轴坐标系。 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脸。
我有三维网格,我想将每个面部画成一个二维形状。
我怀疑UV unwrapping algorithms比尝试从3d脸上获取旋转矩阵更接近你想要达到的目的。
答案 3 :(得分:0)
这很容易实现:(注:“面部”是指“三角形”)
结果是将您的3D脸部投影到2d空间,就好像您正在看它们完全正交而没有任何透视干扰。最终坐标将在标准化的屏幕坐标中,其中(-1,-1)是左下角,(0,0)是中心,(1,1)是右上角。