Sign in to follow this  

[Please, HELP!!] Texture mapping on a Sphere(Direct 3D 9.0)

This topic is 4489 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Below is my code to texture on a sphere. There is one problem. tu value must be mapped 0.0 ~ 1.0. but, according to below code, tu value mapped 0.0X~ 0.9X. so one part of sphere have invalid texture. Is there any other way to texture on sphere? or Do you know what is wrong with my code and solution? ---------------------------------------------------------------------- D3DXCreateSphere(g_pd3dDevice, 1.0f, 10, 10, &pTempEarthMesh, NULL); LPDIRECT3DVERTEXBUFFER9 pTempVertexBuffer; pTempEarthMesh->CloneMeshFVF( 0, D3DFVF_MY_VERTEX, g_pd3dDevice, &g_pEarthMesh ); if( SUCCEEDED( g_pEarthMesh ->GetVertexBuffer( &pTempVertexBuffer ) ) ) { int nNumVerts = g_pSunMesh->GetNumVertices(); Vertex *pVertices = NULL; pTempVertexBuffer->Lock( 0, 0, (void**)&pVertices, 0 ); { double R = 1.0; double theta,theta2, r; double x1, y1; for( int i = 0; i < nNumVerts; ++i ){ pVertices[i].diffuse = D3DCOLOR_COLORVALUE( 1.0, 1.0, 1.0, 1.0 ); theta = asin(pVertices[i].y/R);//-PI/2~PI/2 y1 = theta; theta2 = atan2(pVertices[i].z,pVertices[i].x);//-PI~PI x1 = theta2; x1 = (x1/PI/2.0f)+0.5;//0.0~ 1.0 y1 = ((y1/PI*2.0f)+1.0f)/2.0f; pVertices[i].tu= (float)x1; pVertices[i].tv= 1.0f-(float)y1; } } pTempVertexBuffer->Unlock(); pTempVertexBuffer->Release(); } pTempEarthMesh->Release();

Share this post


Link to post
Share on other sites
Hi,

I had just the same problem sime time ago...
The cause of the problem is this:
one vertical segment of the sphere will have U coord 0, and 0.9 on its sides, dx will place almost the whole texture there, reversed. (as it shuold do it from 0.9 to 1.0).
Now, the vertices having 0.0 here should really have 1.0, but from the other side, the same vertices should have 0.0 (next to the 0.1), beacuse else, the same problem will appear on the other side.

This is why you should duplicate these vertices, and assign 0.0 to one, and 1.0 to the other.
(if you don;t understand what I mean, then just write a debug function that writes the U and V next to the vertices, it helps a lot!)

the other effect that you might not realized is: on the top and bottom of the sphere, the texture is "swirled". This is because the U of the upper point should increase as you go around the circle, but since it's th same point, it cannot have more that one U value. If you make multiple copies, you still don't get what you want, since the XYZ of the vertices is the same, thus the computation will give you the same U values. This can be solved by taking the average of the Us of the other two vertices in the triange, but only on the very top and the very bottom (this can be detected by V~=0.0 and V~=1.0)

Here is an old code of mine, that solved this problem. It assumes that no vertices are shared between any triangles. It will not work if the sphere is rotated in its local coordsystem.


void SphericalTexture::GenerateSphericalTextureCoords(void)
{
TexGenerator::Generate();
const BoundingBox3D&bbox = m_shell->GetBoundingBox();
GM::Vector3D center = bbox.Center();
double zlength = bbox.maxPoint.z - bbox.minPoint.z;
long nPolygons = m_shell->GetPolygonCount();

for (long i = 0; i < nPolygons; i++) {
Polygon3D* p3d = m_shell->GetPolygon(i);

double highX = 0.0, lowX = 1.0;
bool hasZeroY = false, hasOneY = false;

// compute u,v normally, but collect the highest and lowest u for this face
long nCont = p3d->GetContourCount();
for (long c = 0; c < nCont; c++) {
Contour3D* cont = p3d->GetContour(c);
long nEdge = cont->GetPEdgeCount();
for (long e = 0; e < nEdge; e++) {
GM::Vector3D pos = m_shell->GetVertex1Pos(cont->GetPEdge(e)) - center;
Vector2D uv;
uv.x = ((1 - atan2(pos.x, pos.y) + m_uvMappingRotateRad) / (M_PI * 2) - 0.5) * m_uvMappingScaleU;
uv.y = (( acos(-pos.z / (zlength / 2)) + m_uvMappingUpperRotateRad) / M_PI) * m_uvMappingScaleV;
cont->SetTexCoord(m_id, e, uv);
if (uv.x > highX)
highX = uv.x;
if (uv.x < lowX)
lowX = uv.x;
if (::IsNearZero(uv.y))
hasZeroY = true;
if (::IsNearZero(1 - uv.y))
hasOneY = true;
}

// correct vertical segments
if (highX - lowX > 0.7) {
for (long e = 0; e < nEdge; e++) {
GM::Vector3D pos = m_shell->GetVertex1Pos(cont->GetPEdge(e));
Vector2D uv;
uv = cont->GetTexCoord(m_id, e);
if (uv.x < ((highX + lowX) / 2)) {
uv.x += 1.0;
}
cont->SetTexCoord(m_id, e, uv);
}
}

// upper vertices of upper triangles on the top will be computed from taking the average of the other two (to correct the upper swirl)
if (hasZeroY) {
Vector2D uv;
double others = 0.0;
long zeroIndex = 0;
long nEdge = cont->GetPEdgeCount();
for (long e = 0; e < nEdge; e++) {
Vector2D uv;
uv = cont->GetTexCoord(m_id, e);
if (!::IsNearZero(uv.y))
others += uv.x;
else
zeroIndex = e;
}
uv.y = 0.0;
uv.x = others / 2;
cont->SetTexCoord(m_id, zeroIndex, uv);
}

// same for bottom
if (hasOneY) {
Vector2D uv;
double others = 0.0;
long oneIndex = 0;
long nEdge = cont->GetPEdgeCount();
for (long e = 0; e < nEdge; e++) {
Vector2D uv;
uv = cont->GetTexCoord(m_id, e);
if (!::IsNearZero(1 - uv.y))
others += uv.x;
else
oneIndex = e;
}
uv.y = 1.0;
uv.x = others / 2;
cont->SetTexCoord(m_id, oneIndex, uv);
}
}
}
}



Since this solution is a HAAAACK, I don't recommend you to use it, but this is how I have managed to solve it long ago.. since then, we have another solution for geometry generation, which automatically solves this.

kp

Share this post


Link to post
Share on other sites

This topic is 4489 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this