3
\$\begingroup\$

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.

\$\endgroup\$
2
  • \$\begingroup\$ Hi Jonas! Since you've solved your problem, you should just answer your own question, and accept it (instead of editing the question itself) - nothing prohibits you from answering your own questions, it's even encouraged, and it helps keeping the site Q&A structure. \$\endgroup\$ Aug 3, 2012 at 23:05
  • \$\begingroup\$ Ok. ill fix that. \$\endgroup\$ Aug 4, 2012 at 14:23

1 Answer 1

0
\$\begingroup\$

Solved. Typical... :) Been struggling with this for a while now. and now that I posted for any tips i finally found the solution.

I had theese Rasterizer settings for rendering.

        RasterizerState rs = new RasterizerState();
    rs.CullMode = CullMode.None;
    rs.FillMode = FillMode.Solid;
    Engine.GraphicsDevice.RasterizerState = rs;          

If i removed them and only ran

Engine.GraphicsDevice.RasterizerState = RasterizerState.CullCounterClockwise;

It worked as it should. Well if anyone else should have problem with overlapped drawing I hope this helps to check out how the Rastarizer is set.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .