Start a new topic

Texture Mapping

Original Post by: Tharak Fri May 3 08:45:08 2013


Hi Support,


Your support really helpful for me. I facing some problems in texture mapping. Let me explain my requirement here.


I am having one TIN file with x,y,z values. This TIN is having more number of triangles with x,y,z coordinates. Now i am applying this triangles to presagis library and I am generating FLT file.Upto here is fine. But my requirement here it is I wanted to assign texture to that triangles . I am having sigle TIF or JPG image. How to assign this single JPG texture to those triangles(complete triangles). How to map this texture to that triangles.


Please help me on this one. I am having one urgent requirement. If you can give small sample also very helpful for me.


Thanks.


Original Post by: SteveThompson Mon May 6 18:25:28 2013


In your related post, we talked about how to apply texture to polygons (using fltPolyTexture attribute of fltPolygon) and how to set UV values on vertices (using fltVU and fltVV attributes of fltVertex) using mgSetAttList.


For this new problem, your main challenge is how to calculate the UV values for each vertex of the TIN. Once you know the UV values for each vertex, you would simply use mgSetAttList to set the UV values on the vertex.


So how do you calculate the UV values at each vertex of the TIN? This is really just the classic "3 Point Put" texture problem. If you are familiar with Creator (or other comparable 3D modeling tools), when you use the "3 Point Put Texture" tool you specify 3 points in the model and 3 points in the texture and the tool "maps" the texture from the 3 points in the texture to the 3 points in the model. Under the hood, it is actually mapping 4 points of the texture to 4 points in the model but assuming a linear mapping the "4th" point in each can be easily calculated from the 3 points you specify (the 4th point is simply the last corner of the parallelogram formed by the other 3 points).


You can approach your problem in a similar fashion. You are simply mapping 4 points of your texture to 4 points in your TIN. This is called "quad to quad" mapping. If you can come up with these 8 coordinates, there are functions in the OpenFlight API to help you with the matrix math. If your TIN is a nice rectangular area, the 4 points you choose in your database can simply be the "extents" of the rectangular area (the 4 corners). For the texture (presuming you want to map the texture to fit exactly on the TIN) you can simply choose the 4 corners of the texture (in UV space). In the attached diagram you can see the 8 coordinates you'll need to do "quad to quad" mapping.


Once you have these coordinates (4 coordinates in your database and 4 coordinates in texture space), you can build a 4x4 matrix that can be used to transform any XYZ coordinate in database space to Texture UV space. The OpenFlight API provides a convenient function to build this "quad to quad" matrix, called mgMatrixFormQuadToQuad.


The following OpenFlight script shows you how to build and use this"quad to quad" matrix. This should get you started on mapping the texture to your TIN. Note that if you're using the C language API, you might have to tweak the code here a bit to translate from Python to C. If you have further questions, let us know.



# this class is a simple structure to contain two member

# variables:

# matrix - the quad to quad matrix to compute UV values

# for each vertex of the polygons we map texture to.

# textureIndex - the index of the texture in the db

# palette to apply to the polygon.

class textureinfo:

def __init__(self, i_matrix, i_textureIndex):

self.matrix = i_matrix

self.textureIndex = i_textureIndex


# This is the "mgWalk" callback that will be called for each

# node in our database when we "mgWalk" it (see below).

# For each fltPolygon node found by this function, the polygon

# will be mapped to a texture and its vertices will get proper

# UV values that we pass in the parameter tInfo (an object of

# type textureinfo (see class definition above).


def ApplyTextureToFace (rec, tInfo):

# node is a polygon...

# first apply the texture to the polygon by assigning

# the texture index.

mgSetAttList (rec, fltPolyTexture, tInfo.textureIndex)


# then visit each of the vertices of the polygon

vtx = mgGetChild(rec);

while (vtx):

# get the XYX of the vertex

b, x,y,z = mgGetVtxCoord (vtx)

c = mgMakeCoord3d (x,y,z)

# use the "quad to quad" matrix we built to compute

# the UV values of this vertex based on its XYZ

# coordinate position.

uv = mgCoord3dTransform (tInfo.matrix, c)

# at this point uv.x is the U value and uv.Y is the V

# value. since we're doing orthographic mapping

# we can ignore the Z coordinate

numAttr = mgSetAttList (vtx, fltVU, uv.x, fltVV, uv.y)

vtx = mgGetNext(vtx)


def ApplyTextureToFaceCB (db, parent, rec, tInfo):

code = mgGetCode(rec)

# ignore all nodes except polygons

if (code == fltPolygon):

ApplyTextureToFace(rec, tInfo)

return MG_TRUE


# Using mgMatrixFormQuadToQuad...

# Make a matrix that maps from XYZ values to UV values.

# This matrix simply maps from one quad (defined by 4 points)

# to another quad (another 4 points).

# In this specific case the 1st quad is the extents of the

# geometry we want to map texture to and the 2nd quad is the

# of the texture we want to map onto the geometry


# The first quad ("from" points) is the extents of the geometry.

# In this example, the extents we're using is 0,0 to 100,100.

# Since we're mapping a standard "3 point put" onto the geometry

# we can ignore the Z component of the geometry extents. This

# will give us a "nice" orthographic mapping.

# You have to determine the actual extents of your terrain and

# put those values here instead.

fromLL = mgMakeCoord3d(0,0,0)

fromLR = mgMakeCoord3d(100,0,0)

fromUR = mgMakeCoord3d(100,100,0)

fromUL = mgMakeCoord3d(0,100,0)


# The second quad ("to" points) is the extents of the texture

# mapping. Since we want to map the entire texture exactly one

# time over the terrain, the extents here are 0,0 to 1,1

toLL = mgMakeCoord3d(0,0,0)

toLR = mgMakeCoord3d(1,0,0)

toUR = mgMakeCoord3d(1,1,0)

toUL = mgMakeCoord3d(0,1,0)


# Now, just make the matrix. Once we have the matrix we can use

# it to transform any XYZ coordinate in the terrain to a UV value.

b, mat = mgMatrixFormQuadToQuad (

fromLL, fromLR, fromUR, fromUL,

toLL, toLR, toUR, toUL)


db = mgGetCurrentDb ()

b, textureIndex = mgGetCurrentTexture (db)


# We have a class that simply contains the matrix and the texture

# index to apply to all the polygons.

tInfo = textureinfo(mat, textureIndex)


# Now just visit all the polygons in the database and apply this

# texture index to each and use this matrix to calculate UV values

# for each vertex of the polygons we map.

mgWalk (db, ApplyTextureToFaceCB, None, tInfo, MWALK_ON)

Original Post by: Tharak Thu May 9 08:45:11 2013


Hi Support,


Thanks a lot for your support. Now i got How to apply UV values and texture mapping concepts. I want little bit help from the source code.. We are familiar with C language. There is some little bit confusion was there in python script. Kindly can you give that program in C language. It is my kind request from my side.


And one more thing is you mentioned there is two functions like ApplyTextureToFace and ApplyTextureToFaceCB . These two functions are in single program or two different way of program for applying UV values? And also mention in program which function i have to call first?


I understood total program the way of applying UV values. But kindly give me this program in C language. Then quickly i will finish my job as soon as possible.

Original Post by: SteveThompson Thu May 9 20:31:51 2013


And one more thing is you mentioned there is two functions like ApplyTextureToFace and ApplyTextureToFaceCB . These two functions are in single program or two different way of program for applying UV values? And also mention in program which function i have to call first?


ApplyTextureToFaceCB is the mgWalk preAction callback (a callback you provide to mgWalk). ApplyTextureToFace is called by ApplyTextureToFaceCB to actually do the work. If you are using mgWalk you must provide a very precisely formatted walk callback function (it must have the exact signature of ApplyTextureToFaceCB). In this situation, ApplyTextureToFaceCB is called by mgWalk for each node it visits - and then ApplyTextureToFaceCB simply calls ApplyTextureToFace when it finds a face node. You don’t need both functions, you could put the code of ApplyTextureToFace directly inside ApplyTextureToFaceCB . This is just a style thing that makes ApplyTextureToFace more easily reusable.


And also mention in program which function i have to call first?

Your program does not call either. Your program calls mgWalk. mgWalk calls ApplyTextureToFaceCB. ApplyTextureToFaceCB calls ApplyTextureToFace.

Original Post by: SteveThompson Thu May 9 20:54:21 2013


Sorry if the Python code was a bit foreign to you. Here is the C-language equivalent. Note, however, that this is not a complete program. You still have to customize it for your environment. These snippets should be enough for you to complete your task.

struct textureinfo

{

// this structure contain two member variables:

// matrix - the quad to quad matrix to compute UV values

// for each vertex of the polygons we map texture to.

// textureIndex - the index of the texture in the db

// palette to apply to the polygon.

mgmatrix matrix;

int textureIndex;

};


static void ApplyTextureToFace (mgrec* rec, textureinfo* tInfo)

{

// rec is a polygon...

// first apply the texture to the polygon by assigning

// the texture index.

mgSetAttList (rec, fltPolyTexture, tInfo->textureIndex, MG_NULL);


// then visit each of the vertices of the polygon

mgrec* vtx = mgGetChild(rec);

while (vtx)

{

// get the XYX of the vertex

mgcoord3d c;

mgbool b = mgGetVtxCoord (vtx, &(c.x), &(c.y), &(c.z));


// use the "quad to quad" matrix we built to compute

// the UV values of this vertex based on its XYZ

// coordinate position.

mgcoord3d uv = mgCoord3dTransform (tInfo->matrix, &(c));


// at this point uv.x is the U value and uv.Y is the V

// value. since we're doing orthographic mapping

// we can ignore the Z coordinate

int numAttr = mgSetAttList (vtx, fltVU, uv.x, fltVV, uv.y, MG_NULL);

vtx = mgGetNext(vtx);

}

}


// This is the "mgWalk" callback that will be called for each

// node in our database when we "mgWalk" it (see below).

// For each fltPolygon node found by this function, the polygon

// will be mapped to a texture and its vertices will get proper

// UV values that we pass in the parameter tInfo (an object of

// type textureinfo (see class definition above).

static mgbool ApplyTextureToFaceCB (mgrec *db, mgrec *par, mgrec *rec, void *info)

{

textureinfo* tInfo = static_cast<textureinfo*>(info);

mgcode code = mgGetCode(rec);

// ignore all nodes except polygons

if (code == fltPolygon)

{

ApplyTextureToFace(rec, tInfo);

}

return MG_TRUE;

}


static void ApplyTextureToTIN (mgrec* db)

{

// Using mgMatrixFormQuadToQuad...

// Make a matrix that maps from XYZ values to UV values.

// This matrix simply maps from one quad (defined by 4 points)

// to another quad (another 4 points).

// In this specific case the 1st quad is the extents of the

// geometry we want to map texture to and the 2nd quad is the

// of the texture we want to map onto the geometry


// The first quad ("from" points) is the extents of the geometry.

// In this example, the extents we're using is 0,0 to 100,100.

// Since we're mapping a standard "3 point put" onto the geometry

// we can ignore the Z component of the geometry extents. This

// will give us a "nice" orthographic mapping.

// You have to determine the actual extents of your terrain and

// put those values here instead.

mgcoord3d fromLL = mgMakeCoord3d(0,0,0);

mgcoord3d fromLR = mgMakeCoord3d(100,0,0);

mgcoord3d fromUR = mgMakeCoord3d(100,100,0);

mgcoord3d fromUL = mgMakeCoord3d(0,100,0);


// The second quad ("to" points) is the extents of the texture

// mapping. Since we want to map the entire texture exactly one

// time over the terrain, the extents here are 0,0 to 1,1

mgcoord3d toLL = mgMakeCoord3d(0,0,0);

mgcoord3d toLR = mgMakeCoord3d(1,0,0);

mgcoord3d toUR = mgMakeCoord3d(1,1,0);

mgcoord3d toUL = mgMakeCoord3d(0,1,0);


// Now, just make the matrix. Once we have the matrix we can use

// it to transform any XYZ coordinate in the terrain to a UV value.

mgmatrix mat;

mgbool b;

int textureIndex;


b = mgMatrixFormQuadToQuad (&(mat),

&(fromLL), &(fromLR), &(fromUR), &(fromUL),

&(toLL), &(toLR), &(toUR), &(toUL));


b = mgGetCurrentTexture (db, &(textureIndex));


// We have a class that simply contains the matrix and the texture

// index to apply to all the polygons.

textureinfo tInfo;

mgMatrixCopy (&(tInfo.matrix), mat);

tInfo.textureIndex = textureIndex;


// Now just visit all the polygons in the database and apply this

// texture index to each and use this matrix to calculate UV values

// for each vertex of the polygons we map.

mgWalk (db, ApplyTextureToFaceCB, MG_NULL, &(tInfo), MWALK_ON);

}

Original Post by: Tharak Mon May 13 16:57:50 2013


Hi Support,

Really thanks for your support. I completed my job successfully. I have another question on this one. Let me explain my problem. I am having one building with 4 walls with roof. So 4 walls as 4 polygons and roof is another polygon. So totally 5 polygons with texture i created one FLT. Now i am getting small problem here. Like When I open that FLT the texture showing inside the walls not outside the walls and also i am not able to see all the walls at a time. At a time it is showing two walls and if I want to see the another two walls i have to rotate and see.


I attached sample FLT file. Please see this one and give me solution for this problem.

Original Post by: ChrisRogers Mon May 13 17:11:05 2013


Your box is simply inside-out. This is caused by using an incorrect winding order when creating your polygons. In OpenFlight, only one side of your polygon is visible. The visible side is determined by the winding order. Basically your vertices must be ordered in counter-clockwize order when viewed from the direction you want the polygon to be visible from.


To fix your model, just reverse the order of all your vertices.

Original Post by: Tharak Tue May 14 05:57:01 2013


Hi Support,


Thank you for your support. Now it is coming properly all the buildings with textures. Thank you Thank you very much.

Original Post by: Tharak Tue May 21 12:52:34 2013


Hi Support,


Thanks for your valuable reply for me. I finished my job maximum extent but again i am having some question here.


Is there any limitation of FLT size. Meaning i want export to more than 4km * 4km area. When i am exporting more than 4km*4km (I generated TIN then I applied texture for that one ) it is not showing the terrain texture. But if i exported below 4km*4km texture coming perfectly. Is there any limitation for the terrain texture.

Original Post by: SteveThompson Tue May 21 19:41:26 2013


There is no geographic size constraint on OpenFlight files. When you say the terrain texture is not showing, do you mean in Creator? If so, how large is the texture you are using (in texels that is, not kilometers)?

Original Post by: SteveThompson Mon Jun 3 17:35:42 2013


First ... a friendly tip on forum etiquette... When asking a "new" question as you have in your last post, it is better to start a new thread rather to pose the new question on the end of an existing, unrelated topic. This benefits others who might be browsing the forum and is just a good practice all around.


Second, I've taken the liberty of moving your last question to a new topic : support/discussions/topics/1659

Login to post a comment