Iv started up doing some programming in XNA as Iv been doing C# for several years and would like to start do some 3D work with C# and XNA framework.
Right now Im trying to build a sphere by code. It renders fine, but as soon as I apply some light it looks like it it is drawn twise with and without normals for shading. It gets very flickery, between light-shaded and unshaded.
basicEffect.EnableDefaultLighting();
basicEffect.DirectionalLight0.Direction = new Vector3(1, -1, 1);
basicEffect.DirectionalLight0.Enabled = true;
The code for generating the shpere data looks like this.
public class Sphere : Component, I3DComponent
{
float spehereRes = 10.0f;
// I3DComponent values
Vector3 position = Vector3.Zero;
Matrix rotation = Matrix.Identity;
Vector3 scale = new Vector3(1, 1, -1);
BoundingBox boundingBox = new BoundingBox(new Vector3(-1), new Vector3(1));
public Vector3 Position { get { return position; } set { position = value; } }
public Vector3 EulerRotation
{
get { return MathUtil.MatrixToVector3(Rotation); }
set { this.Rotation = MathUtil.Vector3ToMatrix(value); }
}
public Matrix Rotation { get { return rotation; } set { rotation = value; } }
public Vector3 Scale { get { return scale; } set { scale = value; } }
public BoundingBox BoundingBox { get { return boundingBox; } }
// Effect
BasicEffect basicEffect;
//Sphere variables
short[] indices;
int nvertices, nindices;
VertexPositionColorNormal[] vertices;
VertexBuffer vbuffer;
IndexBuffer ibuffer;
public Sphere(float radius)
: base()
{
basicEffect = new BasicEffect(Engine.GraphicsDevice);
SetupEffect();
Setup(radius);
}
public Sphere(float radius, GameScreen Parent)
: base(Parent)
{
basicEffect = new BasicEffect(Engine.GraphicsDevice);
SetupEffect();
}
private void Setup(float radius)
{
nvertices =Convert.ToInt32( spehereRes) * Convert.ToInt32(spehereRes); // nr of vertices in a circle, nr of circles in a sphere
nindices = Convert.ToInt32(spehereRes) * Convert.ToInt32(spehereRes) * 6;
vbuffer = new VertexBuffer(Engine.GraphicsDevice, typeof(VertexPositionNormalTexture), nvertices, BufferUsage.WriteOnly);
ibuffer = new IndexBuffer(Engine.GraphicsDevice, IndexElementSize.SixteenBits, nindices, BufferUsage.WriteOnly);
CreateIndices();
CreateSphereVertices(radius);
CalculateNormals();
vbuffer.SetData<VertexPositionColorNormal>(vertices);
ibuffer.SetData<short>(indices);
}
#region// Setup BasicEffect
/// <summary>
/// Setsup basic effect parameters
/// </summary>
private void SetupEffect()
{
//basicEffect.VertexColorEnabled = true;
//basicEffect.TextureEnabled = true;
basicEffect.EnableDefaultLighting();
basicEffect.DirectionalLight0.Direction = new Vector3(1, -1, 1);
basicEffect.DirectionalLight0.Enabled = true;
//basicEffect.AmbientLightColor = new Vector3(0.3f, 0.3f, 0.3f);
//basicEffect.DirectionalLight1.Enabled = false;
//basicEffect.DirectionalLight2.Enabled = false;
//basicEffect.SpecularColor = new Vector3(0, 0, 0);
}
#endregion
public override void Draw()
{
// Look for a camera in the service container
Camera camera = Engine.Services.GetService<Camera>();
// Throw an exception if one isn't present
if (camera == null)
{
throw new Exception("Camera not found in engine's"
+ "service container, cannot draw");
}
// Set effect values
basicEffect.World = MathUtil.CreateWorldMatrix(position, rotation, scale);
basicEffect.View = camera.View;
basicEffect.Projection = camera.Projection;
// For each pass..
foreach (EffectPass pass in basicEffect.CurrentTechnique.Passes)
{
pass.Apply();
// Draw the terrain vertices and indices
Engine.GraphicsDevice.SetVertexBuffer(vbuffer);
Engine.GraphicsDevice.Indices = ibuffer;
Engine.GraphicsDevice.DrawUserIndexedPrimitives(PrimitiveType.TriangleList, vertices, 0, nvertices, indices, 0, indices.Length / 3, VertexPositionColorNormal.VertexDeclaration);
}
}
#region //CreateIndices()
/// <summary>
/// Creates Sphere Indices
/// </summary>
private void CreateIndices()
{
indices = new short[nindices];
int i = 0;
for (int x = 0; x < spehereRes; x++)
{
for (int y = 0; y < spehereRes; y++)
{
int s1 = x == spehereRes-1 ? 0 : x + 1;
int s2 = y ==spehereRes-1 ? 0 : y + 1;
short upperLeft = (short)(x * spehereRes + y);
short upperRight = (short)(s1 * spehereRes + y);
short lowerLeft = (short)(x * spehereRes + s2);
short lowerRight = (short)(s1 * spehereRes + s2);
indices[i++] = upperLeft;
indices[i++] = upperRight;
indices[i++] = lowerLeft;
indices[i++] = lowerLeft;
indices[i++] = upperRight;
indices[i++] = lowerRight;
}
}
}
#endregion
#region //CreateSphereVertices(float radius)
/// <summary>
/// Setup Sphere object
/// </summary>
/// <param name="radius"></param>
void CreateSphereVertices(float radius)
{
vertices = new VertexPositionColorNormal[nvertices];
Vector3 center = new Vector3(0, 0, 0);
Vector3 rad = new Vector3((float)Math.Abs(radius), 0, 0);
for (int x = 0; x < spehereRes; x++) //nr of circles, difference between each is 4 degrees
{
float difx = 360.0f / spehereRes;
for (int y = 0; y < spehereRes; y++) //nr of veritces, difference between each is 4 degrees
{
float dify = 360.0f / spehereRes;
Matrix zrot = Matrix.CreateRotationZ(MathHelper.ToRadians(y * dify)); //rotate vertex around z
Matrix yrot = Matrix.CreateRotationY(MathHelper.ToRadians(x * difx)); //rotate circle around y
Vector3 point = Vector3.Transform(Vector3.Transform(rad, zrot), yrot);//transformation
vertices[x + y * Convert.ToInt32(spehereRes)].Position = point;
vertices[x + y * Convert.ToInt32(spehereRes)].Color = Color.Black;
}
}
}
#endregion
#region //CalculateNormals()
/// <summary>
/// Calculates Noramals for vertices
/// </summary>
private void CalculateNormals()
{
for (int i = 0; i < vertices.Length; i++)
vertices[i].Normal = new Vector3(0, 0, 0);
for (int i = 0; i < indices.Length / 3; i++)
{
int index1 = indices[i * 3];
int index2 = indices[i * 3 + 1];
int index3 = indices[i * 3 + 2];
Vector3 side1 = vertices[index1].Position - vertices[index3].Position;
Vector3 side2 = vertices[index1].Position - vertices[index2].Position;
Vector3 normal = Vector3.Cross(side1, side2);
vertices[index1].Normal += normal;
vertices[index2].Normal += normal;
vertices[index3].Normal += normal;
}
for (int i = 0; i < vertices.Length; i++)
vertices[i].Normal.Normalize();
}
#endregion
}
Any ideas about this would be appreciated. I lowered the spheres "resolution" to 10 to try find an answer while doing the drawing but looks kind of tricky.