Jump to content
  • Advertisement
Sign in to follow this  
s3mt3x

OpenGL Can someone try this for me (cool camera code)

This topic is 4066 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi Guys, I'm porting an old applicatin over from OpenGl to managed directx, and i'm getting poor performance on my machine. I was wondering if some of you could try the following code on your machines to see if you get the same? I need to know whether this is just my crappy old PC or an issue with mdx. I'm repainting responding to mouse events (it's a modelling app, not a game before i get flamed!!). The code features a cool maya style camera for anyone who's interested. Any feedback would be great.
public partial class Form1 : Form
    {
        //our device
        Device device;

        //constant to convert degrees to radians
        const float RAD = 0.0174532925f;

        #region Camera Variables
        //integers to track our mouse position
        int mouseX;
        int mouseY;

        //our mouse button states
        private bool leftMouseDown = false;
        private bool middleMouseDown = false;
        private bool rightMouseDown = false;

        private Vector3 translation = new Vector3();
        //Up Vector
        Vector3 up = new Vector3(0, 1, 0);
        //Left Vector 
        Vector3 left = new Vector3(1, 0, 0);
        //forward Vector
        Vector3 forward = new Vector3(0, 0, 1);
        //vector to store our rotation
        Vector3 rotation = new Vector3();
        //our zoom value
        private float zoom = 100f;
        //the plane we drag our mouse on
        private Plane middleMouseDragPlane;
        //our view matricies
        Matrix projectionMatrix;
        Matrix viewMatrix;
        //our viewport
        Viewport viewPort;
        #endregion

        #region Grid Variables
        //the grid vertices
        CustomVertex.PositionColored[] gridGeometry;
        //the grid size
        int gridSize = 500;
        //the grid step
        int gridStep = 10;
        #endregion

        /// <summary>
        /// Returns the camera's position in world space
        /// </summary>
        public Vector3 CameraPosition
        {
            get
            {
                Matrix inverseView = Matrix.Multiply(this.viewMatrix, Matrix.Identity);
                inverseView.Invert();
                Vector4 temp = Vector3.Transform(new Vector3(), inverseView);
                return new Vector3(temp.X, temp.Y, temp.Z);
            }
        }

        public Form1()
        {
            this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
            this.SetStyle(ControlStyles.Opaque, true);
            this.SetStyle(ControlStyles.UserPaint, true);
            InitializeComponent();
            InitializeGraphics();

            //manually call our resize method to initialize our viewport
            this.OnResize(new System.EventArgs());
        }

        private void InitializeGraphics()
        {
            PresentParameters present = new PresentParameters();
            present = new PresentParameters();
            present.SwapEffect = SwapEffect.Discard;
            present.Windowed = true;
            present.EnableAutoDepthStencil = true;
            present.AutoDepthStencilFormat = DepthFormat.D16;

            this.device = new Device(0, DeviceType.Hardware, this, CreateFlags.SoftwareVertexProcessing, present);

            this.InitializeGrid();
        }

        private void Form1_Resize(object sender, EventArgs e)
        {
            this.viewPort = new Viewport();
            this.viewPort.X = 0;
            this.viewPort.Y = 0;
            this.viewPort.Width = this.ClientSize.Width;
            this.viewPort.Height = this.ClientSize.Height;

            this.viewPort.MinZ = 0.0f;
            this.viewPort.MaxZ = 1.0f;
        }

        public void SetupView(Device device)
        {
            device.Viewport = this.viewPort;

            this.projectionMatrix = Matrix.PerspectiveFovLH((float)Math.PI / 4, ((float)this.ClientSize.Width) / ((float)this.ClientSize.Height), 1f, 20000.0f);
            device.Transform.Projection = this.projectionMatrix;

            Matrix zoomMat = Matrix.LookAtLH(new Vector3(0, 0, this.zoom), new Vector3(), new Vector3(0, 1, 0));
            Matrix rotationXMat = Matrix.RotationX(this.rotation.X * RAD);
            Matrix rotationYMat = Matrix.RotationY(this.rotation.Y * RAD);
            Matrix translationMat = Matrix.Translation(this.translation.X, this.translation.Y, this.translation.Z);

            this.viewMatrix = translationMat * rotationYMat * rotationXMat * zoomMat;
            device.Transform.View = this.viewMatrix;

            Matrix negativeRotationX = Matrix.RotationX(-this.rotation.X * RAD);
            Matrix negativeRotationY = Matrix.RotationY(-this.rotation.Y * RAD);

            Matrix axisRotation = negativeRotationX * negativeRotationY;

            //transform static view vectors
            Vector4 tempUp = Vector3.Transform(new Vector3(0, 1, 0), axisRotation);
            Vector4 tempLeft = Vector3.Transform(new Vector3(1, 0, 0), axisRotation);
            Vector4 tempForward = Vector3.Transform(new Vector3(0, 0, 1), axisRotation);

            //set our view vectors to the result
            this.up = new Vector3(tempUp.X, tempUp.Y, tempUp.Z);
            this.left = new Vector3(tempLeft.X, tempLeft.Y, tempLeft.Z);
            this.forward = new Vector3(tempForward.X, tempForward.Y, tempForward.Z);
            //make sure we've normailised our view vectors
            this.up.Normalize();
            this.left.Normalize();
            this.up.Normalize();
        }

        public Microsoft.DirectX.Vector3 GenerateNormalizedPickRay(int x, int y)
        {
            Vector3 near = new Vector3(x, y, 0);
            Vector3 far = new Vector3(x, y, 1);
            Viewport viewPort = new Viewport();
            viewPort.Width = this.viewPort.Width;
            viewPort.Height = this.viewPort.Height;
            viewPort.MinZ = 0;
            viewPort.MaxZ = 1;
            near.Unproject(viewPort, this.projectionMatrix, this.viewMatrix, Matrix.Identity);
            far.Unproject(viewPort, this.projectionMatrix, this.viewMatrix, Matrix.Identity);

            Vector3 direction = Vector3.Subtract(far, near);

            return Vector3.Normalize(direction);
        }

        private void Form1_MouseDown(object sender, MouseEventArgs e)
        {
            int x = e.X;
            int y = e.Y;
            System.Windows.Forms.MouseButtons buttons = e.Button;
            switch (buttons)
            {
                case System.Windows.Forms.MouseButtons.Left:
                    this.leftMouseDown = true;
                    break;
                case System.Windows.Forms.MouseButtons.Middle:
                    Vector3 cameraPosition = this.CameraPosition;
                    Vector3 focalDirection = new Vector3(this.forward.X, this.forward.Y, this.forward.Z);
                    Vector3 focalPoint = new Vector3(cameraPosition.X - 
(focalDirection.X * this.zoom), cameraPosition.Y - (focalDirection.Y * this.zoom), cameraPosition.Z - (focalDirection.Z * this.zoom));
                    this.middleMouseDragPlane = Plane.FromPointNormal(focalPoint, this.forward);
                    this.middleMouseDown = true;
                    break;
                case System.Windows.Forms.MouseButtons.Right:
                    this.rightMouseDown = true;
                    break;
            }
            this.mouseX = x;
            this.mouseY = y;
        }

        private void Form1_MouseMove(object sender, MouseEventArgs e)
        {
            int x = e.X;
            int y = e.Y;
            System.Windows.Forms.MouseButtons buttons = e.Button;
            if (this.leftMouseDown)
            {
                this.rotation.Y += this.mouseX - x;
                this.rotation.X -= this.mouseY - y;

                if (this.rotation.X > 90)
                {
                    this.rotation.X = 90;
                }

                if (this.rotation.X < -90)
                {
                    this.rotation.X = -90;
                }

                if (this.rotation.Y > 360)
                {
                    this.rotation.Y = this.rotation.Y % 360.0f;
                }

                if (this.rotation.Y < 0)
                {
                    this.rotation.Y = 360.0f - this.rotation.Y;
                }
            }
            else if (this.middleMouseDown)
            {
                Vector3 cameraPosition = this.CameraPosition;

                Vector3 newPosition = Plane.IntersectLine(this.middleMouseDragPlane, cameraPosition, this.CameraPosition + (this.GenerateNormalizedPickRay(x, y) * this.zoom));
                Vector3 currentPosition = Plane.IntersectLine
(this.middleMouseDragPlane, cameraPosition, this.CameraPosition + 
(this.GenerateNormalizedPickRay(this.mouseX, this.mouseY) * this.zoom));
                Vector3 difference = newPosition - currentPosition;
                this.translation.X += difference.X;
                this.translation.Y += difference.Y;
                this.translation.Z += difference.Z;
            }
            else if (this.rightMouseDown)
            {
                int deltaY = y - this.mouseY;
                this.zoom -= ((float)deltaY) * (this.zoom / 1000.0f);
            }

            this.mouseX = x;
            this.mouseY = y;

            if (this.leftMouseDown | this.middleMouseDown | this.rightMouseDown)
            {
                this.Invalidate();
            }
        }

        private void Form1_MouseUp(object sender, MouseEventArgs e)
        {
            int x = e.X;
            int y = e.Y;
            System.Windows.Forms.MouseButtons buttons = e.Button;
            switch (buttons)
            {
                case System.Windows.Forms.MouseButtons.Left:
                    this.leftMouseDown = false;
                    break;
                case System.Windows.Forms.MouseButtons.Middle:
                    this.middleMouseDown = false;
                    break;
                case System.Windows.Forms.MouseButtons.Right:
                    this.rightMouseDown = false;
                    break;
            }
            this.mouseX = x;
            this.mouseY = y;

            this.Invalidate();
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            device.RenderState.Lighting = false;

            device.Clear(ClearFlags.Target | ClearFlags.ZBuffer, Color.FromArgb(161, 161, 161), 1.0f, 0);

            this.SetupView(device);

            device.BeginScene();

            //draw our grid
            device.VertexFormat = CustomVertex.PositionColored.Format;
            device.DrawUserPrimitives(PrimitiveType.LineList, this.gridGeometry.Length / 2, this.gridGeometry);

            device.EndScene();

            device.Present();
            
            base.OnPaint(e);
        }


        private void InitializeGrid()
        {
            int numLines = this.gridSize / this.gridStep;

            this.gridGeometry = new CustomVertex.PositionColored[((numLines * 2) * 2) + 4];
            int gridIndex = 0;
            for (int x = 0 - this.gridSize / 2; x <= this.gridSize / 2; x += this.gridStep)
            {
                this.gridGeometry[gridIndex].X = x;
                this.gridGeometry[gridIndex].Y = 0;
                this.gridGeometry[gridIndex].Z = 0 - this.gridSize / 2;
                if (x != 0)
                {
                    this.gridGeometry[gridIndex].Color = System.Drawing.Color.FromArgb(128, 128, 128).ToArgb();
                }
                else
                {
                    this.gridGeometry[gridIndex].Color = System.Drawing.Color.Black.ToArgb();
                }



                this.gridGeometry[gridIndex + 1].X = x;
                this.gridGeometry[gridIndex + 1].Y = 0;
                this.gridGeometry[gridIndex + 1].Z = this.gridSize / 2;
                if (x != 0)
                {
                    this.gridGeometry[gridIndex + 1].Color = System.Drawing.Color.FromArgb(128, 128, 128).ToArgb();
                }
                else
                {
                    this.gridGeometry[gridIndex + 1].Color = System.Drawing.Color.Black.ToArgb();
                }

                gridIndex += 2;
            }

            for (int z = 0 - this.gridSize / 2; z <= this.gridSize / 2; z += this.gridStep)
            {
                this.gridGeometry[gridIndex].X = 0 - this.gridSize / 2;
                this.gridGeometry[gridIndex].Y = 0;
                this.gridGeometry[gridIndex].Z = z;
                if (z != 0)
                {
                    this.gridGeometry[gridIndex].Color = System.Drawing.Color.FromArgb(128, 128, 128).ToArgb();
                }
                else
                {
                    this.gridGeometry[gridIndex].Color = System.Drawing.Color.Black.ToArgb();
                }


                this.gridGeometry[gridIndex + 1].X = this.gridSize / 2;
                this.gridGeometry[gridIndex + 1].Y = 0;
                this.gridGeometry[gridIndex + 1].Z = z;
                if (z != 0)
                {
                    this.gridGeometry[gridIndex + 1].Color = System.Drawing.Color.FromArgb(128, 128, 128).ToArgb();
                }
                else
                {
                    this.gridGeometry[gridIndex + 1].Color = System.Drawing.Color.Black.ToArgb();
                }

                gridIndex += 2;
            }
        }
    }


Thanks, Chris [Edited by - s3mt3x on May 6, 2007 6:08:24 AM]

Share this post


Link to post
Share on other sites
Advertisement
Chris,

Yea that works super. I have an exact one of those that I use for level editing. Setup on the form a bit different but still operates the same. I like that style, it gives you good control over the environment.

-Devin

[edit] Oops, should have addressed the pefromance issue. You should be using a render loop instead of the OnPaint event of the Form if you want better performance. Look at the following thread:

Render Loop Thread

Share this post


Link to post
Share on other sites
Hi Devin,

Thanks for trying it out - with regard to the rendering loop, like i said, i'm repainting based on mouse movements - there's no need to repaint using a render loop - the only time the display needs to be updated is in response to input in some shape or form.

Did the camera motion go "scratchy"? On my pc once i start the application it drops in performance when the mouse is moved - however, sometimes it's smooth as expected.


Thanks again,


Chris

Share this post


Link to post
Share on other sites
Oh, OK, I see. If that is the case then I'm unsure what performance you are talking about. Is it rotating slow for you? It seems fine on my machine. I'll look at the code again just to verify everything's tops.

-Devin

Share this post


Link to post
Share on other sites
Just going thru your code to point a couple of things out. The following code is reduntant because any matrix multiplied by the identity is the matrix. Multiplying a matrix by the identity does nothing. If you're trying to get a new matrix then simply assigning it would be suffice (ie: Matrix inverseView = this.viewMatrix;). The reason for this is that Matrix is a struct and duplicates itself on assignment rather than assigning a reference of itself like an object would do.

[source lang = "c#"]
Matrix inverseView = Matrix.Multiply(this.viewMatrix, Matrix.Identity);



You might try Hardware Vertex Processing as well in the Device constructor. Just perhaps it might speed things up?:

[source lang = "c#"]
this.device = new Device(0, DeviceType.Hardware, this, CreateFlags.SoftwareVertexProcessing, present);



Again, it works super.

If you really need more efficiency in your code there are more efficient approaches to doing that. I think if you tweak at it and study the matrices and vector math more you will eventually get your code more and more efficient as time goes on. For now perhaps it's just super :).

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!