2
\$\begingroup\$

I'm sure there is a simple explanation for this behavior that makes mathematical good sense, but I need a way to look at my model along the up vector. I have tested it with the three unit vectors to confirm it is viewing along the up vector that causes my model to disappear, at least in the current configuration.

tldr; Model disappears when camera is along up vector, how do I fix it?

Edit: Also forgot to mention besides changing the up vector to confirm, I also confirmed this was the problem by looking off the up factor by a small amount like so, which works fine I could potentially use this fact, but on principle I would like to know why I can't view along the up vector and possibly correct it in a way that makes mathematical sense:

if (Keyboard.GetState().IsKeyDown(Keys.D3))
    _cameraPosition = new Vector3(0f, 1f, 0.000001f);

One Solution, as suggested by DMGregory. You can change the up vector when switching to the top view like so and that works, better than using float epsilon I suppose. Code below, but I am still not sure that this is the best way to accomplish this effect:

        if (Keyboard.GetState().IsKeyDown(Keys.D1))
        {
            _cameraUp = Vector3.UnitY;
            _cameraPosition = Vector3.UnitX;
        }

        if (Keyboard.GetState().IsKeyDown(Keys.D2))
        {
            _cameraUp = Vector3.UnitY;
            _cameraPosition = Vector3.UnitZ;
        }

        if (Keyboard.GetState().IsKeyDown(Keys.D3))
        {
            _cameraUp = -Vector3.UnitZ;
            _cameraPosition = Vector3.UnitY;
        }

Code to follow, monkey from blender is the idol:

public class MyGame : Game
{
    private GraphicsDeviceManager _graphics;

    private Model _idol;
    private Matrix _idolWorld;
    private Vector3 _idolPosition;

    private Vector3 _cameraPosition;
    private Vector3 _cameraUp;

    private float _width;
    private float _height;
    private float _near;
    private float _far;

    private Matrix _view;
    private Matrix _projection;

    public MyGame()
    {
        _graphics = new GraphicsDeviceManager(this);
        _graphics.PreferredBackBufferWidth = 1920;
        _graphics.PreferredBackBufferHeight = 1080;
        _graphics.ApplyChanges();
        Content.RootDirectory = "Content";
    }

    protected override void Initialize()
    {
        // TODO: Add your initialization logic here
        _width = (float)(_graphics.PreferredBackBufferWidth >> 1);
        _height = (float)(_graphics.PreferredBackBufferHeight >> 1);
        _near = -MathHelper.Max(_width, _height) - 1f;
        _far = -_near;

        _idolPosition = Vector3.Zero;
        _idolWorld = Matrix.Identity;

        _cameraPosition = new Vector3(0f, 0f, 1f);
        _cameraUp = Vector3.UnitY;

        _view = Matrix.CreateLookAt(_idolPosition + _cameraPosition, _idolPosition, _cameraUp);
        _projection = Matrix.CreateOrthographicOffCenter(-_width, _width, -_height, _height, _near, _far);

        base.Initialize();
    }

    protected override void LoadContent()
    {
        // TODO: use this.Content to load your game content here
        _idol = Content.Load<Model>("Idol");
    }

    protected override void UnloadContent()
    {
        // TODO: Unload any non ContentManager content here
    }

    protected override void Update(GameTime gameTime)
    {
        if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || Keyboard.GetState().IsKeyDown(Keys.Escape))
            Exit();

        // TODO: Add your update logic here
        if (Keyboard.GetState().IsKeyDown(Keys.D1))
            _cameraPosition = new Vector3(1f, 0f, 0f);

        if (Keyboard.GetState().IsKeyDown(Keys.D2))
            _cameraPosition = new Vector3(0f, 0f, 1f);

        if (Keyboard.GetState().IsKeyDown(Keys.D3))
            _cameraPosition = new Vector3(0f, 1f, 0f);

        _view = Matrix.CreateLookAt(_idolPosition + _cameraPosition, _idolPosition, _cameraUp);

        base.Update(gameTime);
    }

    protected override void Draw(GameTime gameTime)
    {
        GraphicsDevice.Clear(Color.CornflowerBlue);

        // TODO: Add your drawing code here
        foreach (ModelMesh mesh in _idol.Meshes)
        {
            foreach (BasicEffect effect in mesh.Effects)
            {
                effect.EnableDefaultLighting();
                effect.World = _idolWorld;
                effect.View = _view;
                effect.Projection = _projection;
            }
            mesh.Draw();
        }

        base.Draw(gameTime);
    }
}

Edit for clabe45 (the model, near and far seem fine): Without Metric Large Near Far Volumes

\$\endgroup\$
10
  • \$\begingroup\$ What are the general coordinates of each mesh? \$\endgroup\$
    – clabe45
    Jul 30, 2017 at 16:00
  • \$\begingroup\$ @clabe45 It is a single mesh with the center about the origin. It was imported from blender as an FBX. Metric was turned on before this with a 0.01 unit size. The monkey model itself is 1 meter. \$\endgroup\$
    – bitmouse
    Jul 30, 2017 at 16:08
  • \$\begingroup\$ I'm not familiar with using real-world dimensions. How large is it in 3d units? Compare the "radius" of the mesh with _near, and you might find it's too close to the camera to see. \$\endgroup\$
    – clabe45
    Jul 30, 2017 at 16:10
  • 1
    \$\begingroup\$ I notice you're setting _cameraUp to Vector3.UnitY. So when you look straight up, you might be giving the camera a contradictory instruction like "point your nose this way AND point the top of your head in that same direction" — depending on how your system deals with these contradictions, you could get either an invalid view matrix or one oriented a different way than you'd intended. \$\endgroup\$
    – DMGregory
    Jul 30, 2017 at 18:14
  • 1
    \$\begingroup\$ ...they do it by setting the camera's up direction so it's not parallel to its forward. There's no rule saying you have to use the same up direction for every choice of forward. \$\endgroup\$
    – DMGregory
    Jul 30, 2017 at 19:44

1 Answer 1

0
\$\begingroup\$

DMGregory suggested this answer. Thanks!

What he suggested seemed reasonable: https://en.wikipedia.org/wiki/Hairy_ball_theorem

To put this to the test, I created a bottom view perspective. The model did disappear as in accordance with the theorem, I should have at least two cow licks in this case.

Changing the up vector to accommodate the two unique cow licks turned out to be the answer:

    // side
    if (Keyboard.GetState().IsKeyDown(Keys.D1))
    {
        _cameraUp = Vector3.UnitY;
        _cameraPosition = Vector3.UnitX;
    }
    // front
    if (Keyboard.GetState().IsKeyDown(Keys.D2))
    {
        _cameraUp = Vector3.UnitY;
        _cameraPosition = Vector3.UnitZ;
    }
    // top
    if (Keyboard.GetState().IsKeyDown(Keys.D3))
    {
        _cameraUp = -Vector3.UnitZ;
        _cameraPosition = Vector3.UnitY;
    }
    // bottom
    if (Keyboard.GetState().IsKeyDown(Keys.D4))
    {
        _cameraUp = Vector3.UnitZ;
        _cameraPosition = -Vector3.UnitY;
    }
\$\endgroup\$

You must log in to answer this question.

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