irregularities with procedurally generated sphere

I have created a procedurally generated sphere; but it has a strange crease, a ‘pinch point’ at the poles, and the lighting is off at the seam.

How can I correct this so the lighting is uniform? And if possible remove the ‘point’ at the poles? (although this is not so detrimental as it is masked when the deform is applied).

[2968-sphere_seam.png*|2968]

Here’s the full script :

#pragma strict

@script RequireComponent(MeshFilter)
@script RequireComponent(MeshRenderer)

public var radius : float = 1.0;
public var segments : int = 5;
public var perlinRange : float = 0.25;

private var calcAngle : float;
private var posX : float[];
private var posY : float[];
private var posX2 : float[];
private var posY2 : float[];

private var myMesh : Mesh;
private var verts : Vector3[];
private var uv : Vector2[];
private var tris : int[];


function Start() 
{
	CreateSphere();
}

function Update() 
{
	if (Input.GetMouseButtonUp(1))
	{
		CreateSphere();
	}
}


function CreateSphere() 
{
	var i : int = 0;
	// ----
	
	calcAngle = 0;
	posX = new float[segments + 1];
	posY = new float[segments + 1];
	
	// Calculate Circle on X-Y
	for (i = 0; i < segments + 1; i ++)
	{
		posX _= Mathf.Sin( calcAngle * Mathf.Deg2Rad );_

posY = Mathf.Cos( calcAngle * Mathf.Deg2Rad );

* calcAngle += 180.0 / parseFloat(segments);*
* }*

* // ----*

* calcAngle = 0;*
_ posX2 = new float[ (segments * 2) + 1 ];
posY2 = new float[ (segments * 2) + 1 ];_

* // Calculate Circle on X-Z*
_ for (i = 0; i < (segments * 2) + 1; i ++)_
* {*
posX2 = Mathf.Sin( calcAngle * Mathf.Deg2Rad );
posY2 = Mathf.Cos( calcAngle * Mathf.Deg2Rad );

* calcAngle += 180.0 / parseFloat(segments);*
* }*

* // ----*

* // Vertices - Add Perlin Noise*
_ verts = new Vector3[ ( segments + 1 ) * ( (segments * 2) + 1 )];_

* var p : int = 0;*
* for (i = 0; i < (segments + 1); i ++)*
* {*
_ for (p = 0; p < (segments * 2) + 1; p ++)
* {
if ( i == 0 || i == segments ) // align top and bottom verts to same vert*

* {*_

verts[ p + (i * ( (segments * 2) + 1 )) ] = new Vector3( posX2[p] * posX, posY, posY2[p] * posX ) * radius * ( Random.Range(1.0 - perlinRange, 1.0) );

* if (p != 0) // leave first in row randomly generated (no need to make equal to self)*
* {*
_ verts[ p + (i * ( (segments * 2) + 1 )) ] = verts[ 0 + (i * ( (segments * 2) + 1 )) ];
* }
}
else if ( p == (segments * 2) ) // at end of row_

_ {
verts[ p + (i * ( (segments * 2) + 1 )) ] = verts[ 0 + (i * ( (segments * 2) + 1 )) ];
}
else*

* {
verts[ p + (i * ( (segments * 2) + 1 )) ] = new Vector3( posX2[p] * posX, posY, posY2[p] * posX ) * radius * ( Random.Range(1.0 - perlinRange, 1.0) );
}
}
}*_

* // ----*

* // UVs*

* uv = new Vector2[verts.length];*

_ //var calcUVchunk : Vector2 = Vector2( 1.0 / ( (segments * 2) + 1 ), 1.0 / (segments + 1) );
var calcUVchunk : Vector2 = Vector2( 1.0 / (segments * 2), 1.0 / (segments) );_

* for (i = 0; i < (segments + 1); i ++)*
* {*
_ for (p = 0; p < (segments * 2) + 1; p ++)
* {*
uv[ p + (i * ( (segments * 2) + 1 )) ] = new Vector2( 1.0 - (calcUVchunk.x * p), 1.0 - (calcUVchunk.y * i) );_

_ //Debug.Log( " " + uv[ p + (i * ( (segments * 2) + 1 )) ] + " : " + Vector2( calcUVchunk.x * p, 1.0 - (calcUVchunk.y * i) ) );
* }
}*_

* // ----*

* // Triangles*

_ tris = new int[ ( segments * segments * 4 * 3 ) ];_

* var t : int = 0;*

* for (i = 0; i < segments; i ++)*
* {*
_ for (p = 0; p < (segments * 2); p ++)
* {*
tris[ t + 0 ] = ( (i + 0) * ( (segments * 2) + 1 ) ) + p + 0;
tris[ t + 1 ] = ( (i + 1) * ( (segments * 2) + 1 ) ) + p + 0;
tris[ t + 2 ] = ( (i + 1) * ( (segments * 2) + 1 ) ) + p + 1;_

_ tris[ t + 3 ] = ( (i + 0) * ( (segments * 2) + 1 ) ) + p + 1;
tris[ t + 4 ] = ( (i + 0) * ( (segments * 2) + 1 ) ) + p + 0;
tris[ t + 5 ] = ( (i + 1) * ( (segments * 2) + 1 ) ) + p + 1;_

* t += 6;*
* }*
* }*

* // ----*

* // Show Mesh*

* var theMeshFilter : MeshFilter = this.gameObject.GetComponent(MeshFilter) as MeshFilter;*

* theMeshFilter.mesh.vertices = new Vector3[verts.length];*
* theMeshFilter.mesh.uv = new Vector2[uv.length];*
* theMeshFilter.mesh.triangles = new int[tris.length];*

* theMeshFilter.mesh.vertices = verts;*
* theMeshFilter.mesh.uv = uv;*
* theMeshFilter.mesh.triangles = tris;*

* theMeshFilter.mesh.RecalculateBounds();*
* theMeshFilter.mesh.RecalculateNormals();*

* // Calculate Tangents*
* TangentSolver(theMeshFilter.mesh);*

* // assign default material if there is none *
* if (!theMeshFilter.renderer.material)*
* {*
* theMeshFilter.renderer.material.color = Color.white;*
* }*
}
note : yes, I do reference Perlin Noise but don’t use it. The original line was
verts[ p + (i * ( (segments * 2) + 1 )) ] = new Vector3( posX2[p] * posX, posY, posY2[p] * posX ) * radius * ( Mathf.PerlinNoise(1.0 - perlinRange, 1.0) );
but all this did was scale the whole object. I have alot to learn yet …
*

Ah you are just letting unity calculate the normals is that correct?

very likely you’ll have to figure out and enter the normals MANUALLY … that’s probably your only issue here.

I’d say that when you write code to make mesh, it’s usually more conceptually difficult and takes more lines of code to do the normals than the triangles themselves.

Fortunately … it’s very easy to do this on a sphere as all the normals just point outwards!!! Heh! (Well that’s how you’d normally have the normals on a sphere!)

So it shouldn’t give you too much trouble in this project.


Suggest … If you take a moment to write a utility routine that simply shows you all the normals, you’d quickly see the problem w/ the normals Unity generated for you.

I was gonna say … this age-old post may have much useful information for you,

it occurs to me, in fact the sundry downloadable full projects in that question/answer, in fact include various code to display normals, I believe.

i find when you are writing code to build mesh, it’s basically essential during development to have something that shows you all your normals… (use gizmos, debug or whatever) Otherwise it’s hard to have a clue what the hell is going on with your handiwork you know! Heh!


#Note on deforming the sphere
.

I think you mention you may want to deform the sphere. You then have some wonderful thinking to do, concerning the new normals after you deform the sphere! Now this is real programming, thinking! Good luck!

IF you can assume the verts are pretty evenly spaced all over the sphere (unlikely at the poles?) you can more or less just take a right angle from the verts nearby. That’s a good cheap solution for many situations. Video games are all about fast cheap solutions, so that could help.

(Indeed don’t forget that very often you have to CREATE AROUND a good chep solution. IE, for this very reason, you may have to in fact limit yourself to only using sphere models that involve reasonably evenly-spaced verts everywhere.)

In any event, deforming a sphere, the hard work is all about the normals.

It’s trivial enough to deform a sphere. Hey you got the last page of my rigging pad! That’s good luck!