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

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

## 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.diffuse = D3DCOLOR_COLORVALUE( 1.0, 1.0, 1.0, 1.0 ); theta = asin(pVertices.y/R);//-PI/2~PI/2 y1 = theta; theta2 = atan2(pVertices.z,pVertices.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.tu= (float)x1; pVertices.tv= 1.0f-(float)y1; } } pTempVertexBuffer->Unlock(); pTempVertexBuffer->Release(); } pTempEarthMesh->Release();

##### 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

• ### What is your GameDev Story?

In 2019 we are celebrating 20 years of GameDev.net! Share your GameDev Story with us.

• 13
• 9
• 15
• 14
• 46
• ### Forum Statistics

• Total Topics
634060
• Total Posts
3015300
×