Search code examples
silverlight3dxnasilverlight-5.0

Moving the camera around objects


I'm trying to set the camera to move around the rendered object and I'm following this guide:

MSDN Guide on Rotating and Moving The Camera

here's the code I got:

public partial class MainPage : UserControl
{
    float _cameraRotationRadians = 0.0f;
    Vector3 _cameraPosition = new Vector3(5.0f, 5.0f, 5.0f);
    List<TexturedMesh> _meshes;
    BasicEffect _effect;

public MainPage()
{
    InitializeComponent();
}

private void DrawingSurface_Loaded(object sender, RoutedEventArgs e)
{
    GraphicsDevice device = GraphicsDeviceManager.Current.GraphicsDevice;
    RenderModeReason reason = GraphicsDeviceManager.Current.RenderModeReason;

    _meshes = StreamHelper.ToMesh(device, "capsule.obj");

    _effect = new BasicEffect(GraphicsDeviceManager.Current.GraphicsDevice);
    _effect.TextureEnabled = false;
    _effect.World = Matrix.Identity;
    _effect.View = Matrix.CreateLookAt(_cameraPosition, new Vector3(0.0f, 0.0f, 0.0f), Vector3.Up);
    _effect.Projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4, 1.667f, 1.0f, 100.0f);
}

private void DrawingSurface_Draw(object sender, DrawEventArgs e)
{
    GraphicsDevice device = GraphicsDeviceManager.Current.GraphicsDevice;

    device.Clear(ClearOptions.Target | ClearOptions.DepthBuffer, new Microsoft.Xna.Framework.Color(0, 0, 0, 0), 10.0f, 0);
    device.RasterizerState = new RasterizerState()
    {
        CullMode = CullMode.None
    };

    foreach (TexturedMesh mesh in _meshes)
    {
        // Load current vertex buffer
        device.SetVertexBuffer(mesh.VertexBuffer);

        // Apply texture
        if (mesh.Texture != null)
        {
            _effect.Texture = mesh.Texture;
            _effect.TextureEnabled = true;
        }
        else
            _effect.TextureEnabled = false;

        // Draw the mesh
        foreach (EffectPass pass in _effect.CurrentTechnique.Passes)
        {
            pass.Apply();
            device.SamplerStates[0] = SamplerState.LinearClamp;
            device.DrawPrimitives(PrimitiveType.TriangleList, 0, mesh.VertexBuffer.VertexCount / 3);
        }

        // updates camera position
        UpdateCameraPosition();
    }

    e.InvalidateSurface();
}

private void UpdateCameraPosition()
{
    float nearClip = 1.0f;
    float farClip = 2000.0f;

    // set object origin
    Vector3 objectPosition = new Vector3(0, 0, 0);

    // set angle to rotate to
    float cameraDegree = _cameraRotationRadians;
    Matrix rotationMatrix = Matrix.CreateRotationX(MathHelper.ToRadians(cameraDegree));

    // set where camera is looking at
    Vector3 transformedReference = Vector3.Transform(objectPosition, rotationMatrix);
    Vector3 cameraLookAt = _cameraPosition + transformedReference;

    // set view matrix and projection matrix
    _effect.View = Matrix.CreateLookAt(_cameraPosition, objectPosition, Vector3.Up);
    _effect.Projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4, 1.667f, nearClip, farClip);
}

private void slider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
    // slider.Value;
    _cameraRotationRadians += (float)slider.Value;
}
}

I have a slider control that gives the radians value. When the slider value changes, I then set a new angle for the camera. The UpdateCameraPosition() is called every time the DrawingSurface refreshes after the objects are loaded.

Now when I try to move the slider, the position of the camera never changes. Can someone help and tell me what to fix to make it revolve around the whole group of objects?


Solution

  • That guide is how to rotate the camera in place, but it sounds like you are trying to have your camera orbit your object. In that case, both transformedReference and cameraLookAt are not needed.

    Simply remove those two lines and rotate the _cameraPosition around the objectPosition to have the camera orbit the object.

    //add this line in place of those two lines:
    _cameraPosition = Vector3.Transform(_cameraPosition, rotationMatrix);
    
    //now when you plug _cameraPosition into Matrix.CreateLookAt(), it will offer it a new camera position
    

    Technically my snippet causes _cameraPosition to orbit the world origin 0,0,0. It works because your objectPosition happens to be at the world origin so the camera is orbiting objectPosition too.

    But if objectPosition ever wanders away from the origin, you can still cause the camera to orbit the object by translating the camera/object system to the origin, perform the rotation, the translate them back. it is easier that it sounds:

    _cameraPosition = Vector3.Transform(_cameraPosition - objectPosition, rotationMatrix) + objectPosition;
    //now the camera will orbit the object no matter where in the world the object is.