Roy Triesscheijn’s Weblog

My programming world

Codesnippet: VertexPositionColorNormal

Posted by Roy Triesscheijn on 13th April 2011

For some prototyping I needed a struct like VertexPositionColor, but I also needed a normal, after a minute of Googling I found out that nobody wrote a small (XNA4) compatible snippet) for this. So here I give you my own snippet. (Which also is a handy reference to see how the ‘new’ IVertexType interface in XNA4 works (yes I still think of XNA4 as new).

Anyway the source code:

    public struct VertexPositionColorNormal : IVertexType
    {
        public Vector3 Position;
        public Color Color;
        public Vector3 Normal;

        public VertexPositionColorNormal(Vector3 position, Color color, Vector3 normal)
        {
            this.Position = position;
            this.Color = color;
            this.Normal = normal;
        }

        public static readonly VertexElement[] VertexElements =
        {
            new VertexElement(0, VertexElementFormat.Vector3, VertexElementUsage.Position, 0),
            new VertexElement(sizeof(float)*3, VertexElementFormat.Color, VertexElementUsage.Color, 0),
            new VertexElement(sizeof(float)*4, VertexElementFormat.Vector3, VertexElementUsage.Normal, 0)
        };
        public static readonly VertexDeclaration vertexDeclaration = new VertexDeclaration(VertexElements);

        public VertexDeclaration VertexDeclaration
        {
           get { return vertexDeclaration; }
        }
    }

Tags: , , ,
Posted in Blog, XNA | No Comments »

Code snippet: EventLog wrapper

Posted by Roy Triesscheijn on 21st November 2010

This is a small code snippet that allows your application to write log message to the event log. It will also allow you to capture events of these log messages so that your GUI can show pop-ups or other information messages.

(Added a small update a few hours after this was posted for Vista/W7 when not running the application as admin)

Anyway here’s the code:

     public class Logger
    {
        private static Logger instance;
        public static Logger Instance
        {
            get { if (instance == null) { instance = new Logger(); } return instance; }
        }

        private Logger(){}

        private string eventSource = "MyApplicationName";   //TODO: change this into the name of your application

        public delegate void logMessage(string message);
        public event logMessage Logged = delegate(string message) { };
        public event logMessage LoggedCritical = delegate(string message) { };
        public event logMessage LoggedWarning = delegate(string message) { };
        public event logMessage LoggedInfo = delegate(string message) { };

        public void Log(string message, EventLogEntryType severity)
        {
            try
            {
                if (!EventLog.SourceExists(eventSource))
                {
                    EventLog.CreateEventSource(eventSource, "Application");
                }
                EventLog.WriteEntry(eventSource, message, severity);
            }
            catch (SecurityException noRightsException)
            {
                //User has no rights to write logs.
            }
            Logged(message);

            switch (severity)
            {
                case EventLogEntryType.Error:
                    LoggedCritical(message);
                    break;
                case EventLogEntryType.Information:
                    LoggedInfo(message);
                    break;
                case EventLogEntryType.Warning:
                    LoggedWarning(message);
                    break;
            }
        }
    }

Tags: , , ,
Posted in Blog, General Coding | No Comments »

Code snippet: XNA Simple ArcBallCamera (Updated)

Posted by Roy Triesscheijn on 21st February 2010

Update 23-2-2010: Today I’ve updated the source code of the arcball camera, I made some small changes and added two helper methods for moving the camera right and forward as seen from the camera’s perspective. I’ve also changed the Position prop to be read only and show the real position of the camera instead of the relative position. I’ve also added a zoom property which can now be used instead of setting position, making this a truer ArcBallCamera and fixing a few small glitches when having a lookAt not at Vector3.Zero. (The LookAt is now truly the center of attention, changing the lookAt will also change the position of the camera.) Enjoy!

Today I was struggling with all different sorts of ArcBall/Rotating/Quaternion cameras to create a camera that could simple rotate around an object. I found a sample on xnawiki, but that didn’t seem to work (I still dont know why). In the end I ended up creating my own class.

Note that you never need an Update method for a camera, with one or two booleans you can track if something changed and only then recalculate your matrices the next time they are accessed. This saves you a lot of cpu cycles, because instead of every frame (60x per second) you only recalculate these matrices when you move the camera or change another camera property. In a lot of games this will be a lot less then 60x per second.

Special thanks to Gorion for the winning tip, when I got a bit stuck (my rotation order was flawed), sony` for spotting that the Quaternion was unneeded, and X-Tatic for helping me with the MoveCameraRight method.

Anyway the code:

public class ArcBallCamera
    {

        public ArcBallCamera(float aspectRation, Vector3 lookAt)
            : this(aspectRation, MathHelper.PiOver4, lookAt, Vector3.Up, 0.1f, float.MaxValue) { }

        public ArcBallCamera(float aspectRatio, float fieldOfView, Vector3 lookAt, Vector3 up, float nearPlane, float farPlane)
        {
            this.aspectRatio = aspectRatio;
            this.fieldOfView = fieldOfView;
            this.lookAt = lookAt;
            this.nearPlane = nearPlane;
            this.farPlane = farPlane;
        }

        /// <summary>
        /// Recreates our view matrix, then signals that the view matrix
        /// is clean.
        /// </summary>
        private void ReCreateViewMatrix()
        {
            //Calculate the relative position of the camera
            position = Vector3.Transform(Vector3.Backward, Matrix.CreateFromYawPitchRoll(yaw, pitch, 0));
            //Convert the relative position to the absolute position
            position *= zoom;
            position += lookAt;

            //Calculate a new viewmatrix
            viewMatrix = Matrix.CreateLookAt(position, lookAt, Vector3.Up);
            viewMatrixDirty = false;
        }

        /// <summary>
        /// Recreates our projection matrix, then signals that the projection
        /// matrix is clean.
        /// </summary>
        private void ReCreateProjectionMatrix()
        {
            projectionMatrix = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4, AspectRatio, nearPlane , farPlane);
            projectionMatrixDirty = false;
        }

        #region HelperMethods

        /// <summary>
        /// Moves the camera and lookAt at to the right,
        /// as seen from the camera, while keeping the same height
        /// </summary>
        public void MoveCameraRight(float amount)
        {
            Vector3 right = Vector3.Normalize(LookAt - Position); //calculate forward
            right = Vector3.Cross(right, Vector3.Up); //calculate the real right
            right.Y = 0;
            right.Normalize();
            LookAt += right * amount;
        }

        /// <summary>
        /// Moves the camera and lookAt forward,
        /// as seen from the camera, while keeping the same height
        /// </summary>
        public void MoveCameraForward(float amount)
        {
            Vector3 forward = Vector3.Normalize(LookAt - Position);
            forward.Y = 0;
            forward.Normalize();
            LookAt += forward * amount;
        }

        #endregion

        #region FieldsAndProperties
        //We don't need an update method because the camera only needs updating
        //when we change one of it's parameters.
        //We keep track if one of our matrices is dirty
        //and reacalculate that matrix when it is accesed.
        private bool viewMatrixDirty = true;
        private bool projectionMatrixDirty = true;

        public float MinPitch = -MathHelper.PiOver2 + 0.3f;
        public float MaxPitch = MathHelper.PiOver2 - 0.3f;
        private float pitch;
        public float Pitch
        {
            get { return pitch; }
            set
            {
                viewMatrixDirty = true;
                pitch = MathHelper.Clamp(value, MinPitch, MaxPitch);
            }
        }

        private float yaw;
        public float Yaw
        {
            get { return yaw; }
            set
            {
                viewMatrixDirty = true;
                yaw = value;
            }
        }

        private float fieldOfView;
        public float FieldOfView
        {
            get { return fieldOfView; }
            set
            {
                projectionMatrixDirty = true;
                fieldOfView = value;
            }
        }

        private float aspectRatio;
        public float AspectRatio
        {
            get { return aspectRatio; }
            set
            {
                projectionMatrixDirty = true;
                aspectRatio = value;
            }
        }

        private float nearPlane;
        public float NearPlane
        {
            get { return nearPlane; }
            set
            {
                projectionMatrixDirty = true;
                nearPlane = value;
            }
        }

        private float farPlane;
        public float FarPlane
        {
            get { return farPlane; }
            set
            {
                projectionMatrixDirty = true;
                farPlane = value;
            }
        }

        public float MinZoom = 1;
        public float MaxZoom = float.MaxValue;
        private float zoom = 1;
        public float Zoom
        {
            get { return zoom; }
            set
            {
                viewMatrixDirty = true;
                zoom = MathHelper.Clamp(value, MinZoom, MaxZoom);
            }
        }

        private Vector3 position;
        public Vector3 Position
        {
            get
            {
                if (viewMatrixDirty)
                {
                    ReCreateViewMatrix();
                }
                return position;
            }
        }

        private Vector3 lookAt;
        public Vector3 LookAt
        {
            get { return lookAt; }
            set
            {
                viewMatrixDirty = true;
                lookAt = value;
            }
        }
        #endregion

        #region ICamera Members
        public Matrix ViewProjectionMatrix
        {
            get {return ViewMatrix * ProjectionMatrix; }
        }

        private Matrix viewMatrix;
        public Matrix ViewMatrix
        {
            get
            {
                if (viewMatrixDirty)
                {
                    ReCreateViewMatrix();
                }
                return viewMatrix;
            }
        }

        private Matrix projectionMatrix;
        public Matrix ProjectionMatrix
        {
            get
            {
                if (projectionMatrixDirty)
                {
                    ReCreateProjectionMatrix();
                }
                return projectionMatrix;
            }
        }
        #endregion
    }

Tags: , , , , , , , ,
Posted in Blog, General Gamedesign, XNA | 11 Comments »

Mouse position in 3D, snippet

Posted by Roy Triesscheijn on 13th January 2010

And another snippet for today. I wanted to test some more path finding code so I wanted to move a collidable object with the mouse. To do so you have to ‘unproject’ your mouse coordinates (x and y) to a position in 3D space (x,y,z). I first tried to use the unproject method directly. But after reading the msdn article I figured out that the z-values can be either 0 (near clip plane) or something else (far clip plane). So this didn’t give me good results if I just plugged in the z level I wanted.

After reading on about rays and intersect methods, user ConkerJo on #XNA pointed out that intersect returns a point of intersection instead of true or false. So with that knowledge, and a little help from him and msdn, I quickly produced the following code.

This code will convert your mouse position to a point laying on the ground plane.

Remember that the definition of your ground plane is a normal. So if you want the x-z space to be the floor (eg. y is up), assign it like this:

private Plane GroundPlane = new Plane(0, 1, 0, 0);  //creates a plane on the x-z axises.

And if you use another common approach, where z is up and the ground is on x-y use this:

private Plane GroundPlane = new Plane(0, 0, 1, 0); //creates a plane on the x-y axises.

And now here’s the actual snippet:

/// <summary>
        /// Calculates where the mouse would be if it would float around at the level of the ground plane.
        /// Based on http://msdn.microsoft.com/en-us/library/bb203905.aspx and user conkerjo who
        /// pointed out that Ray.Intereset returns a vector3 and not a boolean (true/false) *DOH*.
        /// </summary>
        /// <returns></returns>
        private Vector3 CalculateMouse3DPosition()
        {
            int mouseX = Mouse.GetState().X;
            int mouseY = Mouse.GetState().Y;

            Vector3 nearsource = new Vector3((float)mouseX, (float)mouseY, 0f);
            Vector3 farsource = new Vector3((float)mouseX, (float)mouseY, 1f);

            Matrix world = Matrix.CreateTranslation(0, 0, 0);

            Vector3 nearPoint = device.Viewport.Unproject(nearsource,
                camera.ProjectionMatrix, camera.ViewMatrix , Matrix.Identity);

            Vector3 farPoint = device.Viewport.Unproject(farsource,
                camera.ProjectionMatrix, camera.ViewMatrix, Matrix.Identity);

            Vector3 direction = farPoint - nearPoint;
            direction.Normalize();
            Ray pickRay = new Ray(nearPoint, direction);
            float? position = pickRay.Intersects(GroundPlane);

            if (position.HasValue)
            {
                return pickRay.Position + pickRay.Direction * position.Value;
            }
            else
            {
                return target.Position;
            }
        }

Tags: , , , , , , , ,
Posted in Blog, General Gamedesign, XNA | 1 Comment »