Digital 3D Anthropometry 4. Model Class Sungmin Kim SEOUL NATIONAL UNIVERSITY Model Class 의설계 모델링기법의개요 Introduction 3차원모델을정의하는클래스 점정보 면정보 법선벡터정보 색상정보 3차원모델과관련된기본함수 크기계산 법선벡터자동계산 이동 / 회전 기본물체만들기 데이터입출력 2
3D 물체의제작 모델링소프트웨어를사용 3D Studio Max Maya SoftImage LightWave Rhino 3D Scan Data 로부터생성 RapidForm 3 모델링기법 Surface 표면 geometry 를써서물체를표현 Surface equation 이나 mesh structure 로구성 Solid Closed volume 을가지는물체로표현 물체의외부, 표면, 내부구분이용이 Nonmanifold 점, 선, 면, 부피가혼합된모델링 Concept 디자인에적합 4
Primitive 기본물체를사용한모델링 5 Boolean Operation of Primitives Union, intersection, and difference 6
Sweeping 평면도형을이동하거나회전시켜서입체를만드는방법 7 Skinning 다수의단면을연결해서입체를형성 단면데이터를모아서인체모델을만들때사용 8
Parametric 파라미터를이용한모델링 다양한모델을쉽게만들수있음 인체모델링 의복패턴모델링 9 복셀기반모델링 공간분할방식 비트맵이미지의 3 차원확장판 물체의부피 / 질량계산에사용 상당한메모리를필요로함 10
3 각형메쉬기반모델링 Surface Model with Triangular Element XYZ Coordinate (Node) RGB Color Normal Vector V3 N3, C2 V1 V2 N1, C1 N2, C2 Texture, Sub Model 등다양한구조가있을수있음 11 기본형정의 생성자, 파괴자 class public: ; (); (&); ~(); int TPoint3D int int.h NodeNum; *Node,*Normal,*Color; ElemNum; *Elem; ::() NodeNum=0; Node=Color=Normal=0; ElemNum=0; Elem=0; ::~() if (NodeNum) delete []Node; delete []Color; delete []Normal; if (ElemNum) delete[]elem; NodeNum=ElemNum=0; Node=Color=Normal=0; Elem=0;.cpp 12
기본형정의 복제생성자 ::( &M) NodeNum=M.NodeNum; int i; if (NodeNum) Node=new TPoint3D[NodeNum]; Color=new TPoint3D[NodeNum]; Normal=new TPoint3D[NodeNum]; for(i=0;i<nodenum;i++) Node[i]=M.Node[i]; Color[i]=M.Color[i]; Normal[i]=M.Normal[i]; else Node=Color=Normal=0; ElemNum=M.ElemNum; if (ElemNum) Elem=new int[elemnum*3]; for(i=0;i<elemnum*3;i++) Elem[i]=M.Elem[i]; else Elem=0; 13 모델정의관련 void void void TPoint3D Class AssignNode(int); AssignElem(int); SetElem(int,int,int,int); void TPoint3D::Set(float X,float Y,float Z) x=x; y=y; z=z; TPoint2D Class void TPoint2D::Set(float X,float Y) x=x; y=y; void ::AssignNode(int n) NodeNum=n; Node=new TPoint3D[NodeNum]; Color=new TPoint3D[NodeNum]; Normal=new TPoint3D[NodeNum]; void ::AssignElem(int n) ElemNum=n; Elem=new int[elemnum*3]; void ::SetElem(int n,int a,int b,int c) Elem[n*3]=a; Elem[n*3+1]=b; Elem[n*3+2]=c; 14
모델크기구하기 float mx,my,mz,mx,my,mz; void GetSize(); ); void ::GetSize() mx=my=mz=100000; Mx=My=Mz=-100000; int i; for(i=0;i<nodenum;i++) if (Node[i].x<mx) mx=node[i].x; if (Node[i].y<my) my=node[i].y; if (Node[i].z<mz) mz=node[i].z; if (Node[i].x>Mx) Mx=Node[i].x; if (Node[i].y>My) My=Node[i].y; if (Node[i].z>Mz) Mz=Node[i].z; 15 법선벡터계산 void ::CalculateNormal() if (!NodeNum!ElemNum) return; int i,j; TPoint3D *N=new TPoint3D[ElemNum]; for(i=0;i<elemnum;i++) N[i]=Node[Elem[i*3]].CrossProduct(Node[Elem[i*3+2]],Node[Elem[i*3+1]]); for(i=0;i<nodenum;i++) Normal[i].Set(0,0,0); for(i=0;i<elemnum;i++) for( j=0;j<3;j++) Normal[Elem[i*3+j]].x+=N[i].x; Normal[Elem[i*3+j]].y+=N[i].y; Normal[Elem[i*3+j]].z+=N[i].z; for(i=0;i<nodenum;i++) Normal[i].Normalize(); delete []N; Face Normal by Cross Product void TPoint3D::Normalize() float l=sqrt(x*x+y*y+z*z); if (l) x/=l; y/=l; z/=l; 16
이동 void ::Move(float x,float y,float z) int i; for(i=0;i<nodenum;i++) Node[i].x+=x; Node[i].y+=y; Node[i].z+=z; void ::Centering() GetSize(); float cx=(mx+mx)/2; float cy=(my+my)/2; float cz=(mz+mz)/2; Move(-cx,-cy,-cz); 17 한점을중심으로 X, Y, Z 축주위로회전 void ::Rotate(TPoint3D &O,float x,float y,float z) int i; float cc,ss,x,y,z; if (x) cc=cos(x); ss=sin(x); for(i=0;i<nodenum;i++) Z=(Node[i].z-O.z)*cc-(Node[i].y-O.y)*ss+O.z; Y=(Node[i].z-O.z)*ss+(Node[i].y-O.y)*cc+O.y; Node[i].z=Z; Node[i].y=Y; if (y) cc=cos(y); ss=sin(y); for(i=0;i<nodenum;i++) X=(Node[i].x-O.x)*cc-(Node[i].z-O.z)*ss+O.x; Z=(Node[i].x-O.x)*ss+(Node[i].z-O.z)*cc+O.z; Node[i].x=X; Node[i].z=Z; if (z) cc=cos(z); ss=sin(z); for(i=0;i<nodenum;i++) X=(Node[i].x-O.x)*cc-(Node[i].y-O.y)*ss+O.x; Y=(Node[i].x-O.x)*ss+(Node[i].y-O.y)*cc+O.y; Node[i].x=X; Node[i].y=Y; CalculateNormal(); 18
기본물체만들기 Examples of Geometric Primitives 19 기본물체만들기 - 평면 void ::FormPlane(float xs,float zs,int nx,int nz,float r,float g,float b) int i,j; AssignNode((nx+1)*(nz+1)); AssignElem(nx*nz*2); float x,z,xstep,zstep; xstep=xs/(float)nx; zstep=zs/(float)nz; r/=255.0f; g/=255.0f; b/=255.0f; n=0; int n0,n1,n2,n3; int n=0; for(i=0;i<=nz;i++) z=zstep*(float)i; for( j=0;j<=nx;j++) x=xstep*(float)j; Node[n].Set(x,0,z); Color[n++].Set(r,g,b); for(i=0;i<nz;i++) for( j=0;j<nx;j++) n0=i*(nx+1)+j; n1=n0+1; n2=(i+1)*(nx+1)+j; n3=n2+1; SetElem(n++,n3,n1,n0); SetElem(n++,n0,n2,n3); Centering(); CalculateNormal(); 20
기본물체만들기 - 육면체 void ::FormCube(float xs,float ys,float zs,float r,float g,floatb) AssignNode(8); AssignElem(12); r/=255.0f; int i; g/=255.0f; for(i=0;i<8;i++) Color[i].Set(r,g,b); b/=255.0f; SetElem(0,7,4,5); Node[0].Set(0,0,0); SetElem(1,5,6,7); Node[1].Set(xs,0,0); SetElem(2,6,5,1); Node[2].Set(xs,ys,0); SetElem(3,1,2,6); Node[3].Set(0,ys,0); SetElem(4,2,1,0); Node[4].Set(0,0,zs); SetElem(5,0,3,2); Node[5].Set(xs,0,zs); SetElem(6,3,0,4); Node[6].Set(xs,ys,zs); SetElem(7,4,7,3); Node[7].Set(0,ys,zs); SetElem(8,3,7,6); SetElem(9,6,2,3); SetElem(10,4,0,1); SetElem(11,1,5,4); Centering(); CalculateNormal(); 21 기본물체만들기 - 구 (Homework) 파라미터» 반지름, 적도방향분할갯수, RGB 색상» 위도방향분할갯수 = 적도방향분할갯수 /2» 분할갯수는항상짝수로제한 적도방향 22
데이터불러오기 3D 데이터의종류는무궁무진함 잘알려진파일형식의경우형식을찾는것이가장바람직함» 알려져있지않은형식의경우데이터파일을관찰해보고규칙을찾아내야함» 가장중요한것은 Node 와 Element 데이터 http://www.open3mod.com 23 데이터불러오기 - ASCII 타입 PLY 의경우 ply format ascii 1.0 comment Exported by 3DM element vertex 112644 property float x property float y property float z property uchar red property uchar green property uchar blue element face 222889 property list uchar int vertex_index end_header 152.646027 1241.364136 62.522892 60 42 22 152.125336 1240.548340 60.672829 56 40 20 155.566544 1193.091797 45.029305 78 48 25... 3 112643 112642 112522 3 112521 112522 112642 3 112642 112641 112521... header information number of point 한점이 3 개의 float x,y,z 좌표와 3 개의 unsigned char (0~255) red, green, blue 색상으로구성됨 number of face vertex index list 로 face가구성됨 112,644 개의 x y z r g b 값 222,889 개의삼각형요소 (face) 정의 24
데이터불러오기 - ASCII 타입 PLY 의경우 void ::LoadFromASCIIPLY(AnsiString N) FILE *F=fopen(N.c_str(),"r"); char buf[300]; int i; for(i=0;i<3;i++) fgets(buf,300,f); // skip three lines fscanf(f,"element vertex %d\n",&nodenum); for(i=0;i<6;i++) fgets(buf,300,f); // skip six lines fscanf(f,"element face %d\n",&elemnum); for(i=0;i<2;i++) fgets(buf,300,f); // skip two lines AssignNode(NodeNum); AssignElem(ElemNum); float x,y,z; int r,g,b; for(i=0;i<nodenum;i++) fscanf(f,"%f %f %f %d %d %d\n",&x,&y,&z,&r,&g,&b); Node[i].Set(x,y,z); Color[i].Set((float)r/255.0f,(float)g/255.0f,(float)b/255.0f); int n0,n1,n2; for(i=0;i<elemnum;i++) fscanf(f,"3 %d %d %d\n",&n0,&n1,&n2); SetElem(i,n0,n1,n2); fclose(f); Centering(); CalculateNormal(); 25 데이터불러오기 - Binary 타입 PLY 의경우 UINT8[80] Header UINT32 Number of triangles foreach triangle REAL32[3] Normal vector REAL32[3] Vertex 1 REAL32[3] Vertex 2 REAL32[3] Vertex 3 UINT16 Attribute byte count end Binary STL File Format (Wikipedia) Free Hex Editor : https://mh-nexus.de/en/hxd/ 26
데이터불러오기 - Binary 타입 PLY 의경우 void ::LoadFromBinarySTL(AnsiString N) FILE *F=fopen(N.c_str(),"rb"); BYTE buf[100]; fread(buf,1,80,f); fread(&elemnum,1,4,f); NodeNum=ElemNum*3; AssignNode(NodeNum); AssignElem(ElemNum) ; int i; int attr; float nx,ny,nz,x0,y0,z0,x1,y1,z1,x2,y2,z2; int n=0,nn=0,en=0; for(i=0;i<elemnum;i++) fread(&nx,1,4,f);fread(&ny,1,4,f);fread(&nz,1,4,f); fread(&x0,1,4,f);fread(&y0,1,4,f);fread(&z0,1,4,f); fread(&x1,1,4,f);fread(&y1,1,4,f);fread(&z1,1,4,f); fread(&x2,1,4,f);fread(&y2,1,4,f);fread(&z2,1,4,f); fread(&attr,1,2,f); Node[nn++].Set(x0,y0,z0); Node[nn++].Set(x1,y1,z1); Node[nn++].Set(x2,y2,z2); SetElem(en++,n,n+1,n+2); n+=3; fclose(f); for(i=0;i<nodenum;i++) Color[i].Set(1,1,1); Centering(); CalculateNormal(); 27 데이터불러오기 - ASCII 타입 OBJ 의경우 : Homework #### # # OBJ File Generated by Meshlab # #### # Object 10-F-3D0053E.obj # # Vertices: 61719 # Faces: 123497 # #### Number of points and faces vn -0.385640-2.046920 0.375572 v -761.990601 13945.023438 301.880402... # 61719 vertices, 0 vertices normals Header Information Vertex normal x, y, z Vertex coordinate x, y, z f 1//1 3//3 61568//61568... # 123497 faces, 0 coords texture Face point0//normal0 point1//normal1 point2//normal2 # End of File 28
데이터저장하기 TFileStream 을상속한 TNewFilestream 을만들어서 binary 로저장하기를구현 #include <vcl.h> class TNewFileStream : public TFileStream public: ; TNewFileStream(const void void void WInt(int); WFloat(float); WString(AnsiString); AnsiString,Word); TNewFileStream::TNewFileStream(AnsiString File,Word Mode) : TFileStream(File,Mode) void TNewFileStream::WInt(int n) WriteBuffer((BYTE*)&n,sizeof(int)); void TNewFileStream::WFloat(float f) WriteBuffer((BYTE*)&f,sizeof(float)); void TNewFileStream::WString(AnsiString N) int n=n.length(); WInt(n); WriteBuffer(N.c_str(),n); 29 데이터저장하기 void ::SaveToFileStream(TNewFileStream *S) int i; S->WInt(1); // date of version S->WInt(NodeNum); for(i=0;i<nodenum;i++) S->WFloat(Node[i].x); S->WFloat(Node[i].y); S->WFloat(Node[i].z); S->WFloat(Color[i].x); TNewFileStream *S=new TNewFileStream("file.mdl",fmCreate); S->WFloat(Color[i].y); Model->SaveToFileStream(S); S->WFloat(Color[i].z); delete S; S->WFloat(Normal[i].x); S->WFloat(Normal[i].y); S->WFloat(Normal[i].z); S->WInt(ElemNum); for(i=0;i<elemnum*3;i++) S->WInt(Elem[i]); 30
데이터불러오기 void void AnsiString RInt(int*); RFloat(float*); RString(); void TNewFileStream::RInt(int *n) ReadBuffer((BYTE*)n,sizeof(int)); void TNewFileStream::RFloat(float *f) ReadBuffer((BYTE*)f,sizeof(float)); AnsiString TNewFileStream::RString() int n; RInt(&n); char *b=new char[n+1]; ReadBuffer(b,n); b[n]=0; AnsiString R=AnsiString(b); delete []b; return R; 31 데이터불러오기 void ::LoadFromFileStream(TNewFileStream *S) int version,i; S->RInt(&version); S->RInt(&NodeNum); AssignNode(NodeNum); for(i=0;i<nodenum;i++) S->RFloat(&Node[i].x); S->RFloat(&Node[i].y); S->RFloat(&Node[i].z); S->RFloat(&Color[i].x); TNewFileStream *S=new TNewFileStream("file.mdl",fmOpenRead); S->RFloat(&Color[i].y); Model->LoadFromFileStream(S); S->RFloat(&Color[i].z); delete S; S->RFloat(&Normal[i].x); S->RFloat(&Normal[i].y); S->RFloat(&Normal[i].z); S->RInt(&ElemNum); AssignElem(ElemNum); for(i=0;i<elemnum*3;i++) S->RInt(&Elem[i]); 32