Sphere custom UV mapping

I generate procedurally ([algorithm][1]) UV-Sphere and I have to do UV mapping. I use this code based on formulas in [Wikipedia][2]

for (const auto Vertex : SphereVertices)
{
	const auto NormalVertex = Vertex.GetSafeNormal();
	auto NewUv = FVector2D(0.5f + FMath::Atan2(NormalVertex.X, NormalVertex.Z) / (2 * PI), 0.5f - FMath::Asin(NormalVertex.Y) / PI);
	SphereUVs.Add(NewUv);
}

But my texture has defects marked in red in the screenshot

As I understand it, this happens due to the fact that uv is generated from 0 to 1, and when the last section is generated, then 1-0 = 1 and the full texture is drawn there. How to avoid this problem?

I also used other formulas but the result remains the same.

Hello! When calculating for end of round you cant simply use FMath::Asin(NormalVertex.Y). It will give you just 0, same as it gives for start of round. It should give you 2*PI for end of round… So, because your layout has a break, you should use piecewise function of two pieces - for NormalVertex.X > 0 and for NormalVertex.X <=0…

Hello. I am very grateful to you for the answer, but I still do not understand how to implement this in code. Can you give me some hints or a piece of pseudocode?

Hello. You set a wrong UV coordinates attribute to Your vertices. Your attributes by X is red, right is green. You set X attribute like X = i/N, where N - all edges count, i - current edge number. But You need X = i/(1+N)

Sorry, I had drawn a wrong dir, but it doesn’t matter

347047-download.png

Oh, just apply you method two times )) You can try this for UV Y-axis value:

(
	NormalVertex.Z < 0
	? 
    (PI/2 - FMath::Asin(NormalVertex.Y))
	:
    (3 * PI/2 + FMath::Asin(NormalVertex.Y))
)/2/PI

Thank you very much but now it’s gotten worse :frowning:

for (const auto Vertex : SphereVertices)
	{
		const auto NormalVertex = Vertex.GetSafeNormal();
		auto NewUv = FVector2D(0.5f + FMath::Atan2(NormalVertex.X, NormalVertex.Z) / (2 * PI), (
			                       NormalVertex.Z < 0
				                       ? (PI / 2 - FMath::Asin(NormalVertex.Y))
				                       : (3 * PI / 2 + FMath::Asin(NormalVertex.Y))
		                       ) / 2 / PI);
		SphereUVs.Add(NewUv);
	}

Can you provide a texture and model? I want to give it a practical try. One more thing - if you generate mesh by your self, then why are you operating with normal rather then with index? For any mesh that is generated by you, everything is known and there is no any difficulties to map faces with index. And normal is your case, if mesh is generated by third party and you cant map faces with index…

This is clear project (UE 4.26) with my sphere and texture (you can use no texture and the result will be the same) GitHub - grouptout/ProcSphere Problem is in function void GenerateUVs(const TArray<FVector>& SphereVertices, TArray<FVector2D>& SphereUVs);

I am building a sphere directly in ue in function void BuildUVSphere(const int Slices, const int Stacks, const float Radius, TArray<FVector>& SphereVertices, TArray<int32>& SphereTriangles);

For any mesh that is generated by you, everything is known and there is no any difficulties to map faces with index
I don’t know how to do this. I took most of the information from the Internet and there were only such methods.

This project contains C++ Actor sphere with the functions described above and his child class in BP. Functions are called in bp Construction script

Hello! Just get it on with this code

void AProceduralSphere::GenerateUVs(const int Slices, const int Stacks, const TArray<FVector>& SphereVertices, TArray<FVector2D>& SphereUVs)
{
	const auto textureCellsCount = 16;	
	const auto uvXStep = 1.f / Slices;
	const auto uvYStep = 1.f / Stacks;

	auto uvX = 0.f;
	auto uvY = 0.f;

	// add top vertex
	SphereUVs.Add(FVector2D(0, 0.5f));

	// generate vertices per stack / slice
	for (int32 i = 0; i < Stacks - 1; i++) {
		uvX = 0;
		uvY += uvYStep;
		
		for (int32 j = 0; j < Slices; j++) {
			uvX += uvXStep;
			SphereUVs.Add(FVector2D(uvX, uvY));
		}
	}

	// add bottom vertex
	SphereUVs.Add(FVector2D(1, 0.5f));
}

One important thing - if you want to solve artifact on top and bottom caps, then you need to have one cap vertice for each slice. This is needed because one vertice just cant have more than one UV coords, while here wee need them. By the way, for that reason, every UV seam vertices are stored with more than one instance when render works