3
\$\begingroup\$

I'm making an Android game using LibGDX. I would like to render a cropped version of the camera's viewport.

Here's an original camera view (in 3ds max):

I can get the same view in LibGDX without any problems, with this code:

perspCam = new PerspectiveCamera(40, screenHeight, screenWidth * h / w);
perspCam.position.set(1, 6, 18f);
perspCam.lookAt(1, 3, -1f);
perspCam.update();

Now the tricky part: I actually want to see this view in-game:

It's basically just a crop of the camera viewport, keeping the original perspective and other camera properties.

Could someone explain the general concept? (No need for working code.)

\$\endgroup\$
2
  • \$\begingroup\$ Can't you just move the camera? or do you want to have only that portion of the screen being rendered? If you want to render the red rectangle in the whole screen, moving the camera is the way to go. \$\endgroup\$
    – Lestat
    Dec 12 '13 at 17:56
  • 1
    \$\begingroup\$ Moving the camera would change the perspective (the middle line wouldn't be parallel to left&right sides of the viewport) \$\endgroup\$
    – tom37
    Dec 18 '13 at 22:54
4
\$\begingroup\$

This is an old question, so I'm guessing that tom37 may have moved on by now, but I think I have an answer for anyone else with the same problem.

For reference, here is a view of a surface grid using a perspective camera.

Original perspective

Now let's say that we want to render a portion of this current view, but to the entire screen. Let's render the top-left quarter of the image, outlined in white.

Original perspective with intended new view

If we move the camera, then the perspective will change. We can use scissors to mask the rest of the image, but we want that portion to take up the entire screen. Let's try changing the viewport.

public class PerspectiveTest implements Screen {

    Viewport viewport;
    Camera camera;
    Sprite background = new Sprite(new Texture("grid.png");
    Stage ui;
    SpriteBatch batch = new SpriteBatch(250);

    public PerspectiveTest () {
        camera = new PerspectiveCamera(60f, 16, 9f);
        viewport = new FitViewport(8f, 4.5f, camera);
        ui = new Stage(viewport, batch);
        camera.rotate(60f, 1f, 0f, 0f);
        camera.translate(12f, -5f, 4f);
        camera.update();
        background.setSize(32f,32f);
    }

    @Override
    public void render (float delta) {
        Gdx.gl.glClearColor(0,0,0,1);
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
        int x = 0;
        int y = -Gdx.graphics.getHeight();
        int w = 2*Gdx.graphics.getWidth();
        int h = 2*Gdx.graphics.getWidth();
        Gdx.gl.glViewport(x, y, w, h);
        batch.setProjectionMatrix(camera.combined);
        batch.begin();
        background.draw(batch);
        batch.end();
    }

    // There are a bunch of empty overrides here that I have left out.
}

The important line is Gdx.gl.glViewport(x, y, w, h); The viewport usually starts at x = 0 and y = 0 and extends to the full width and height of the screen. If we want to see only a part of that original viewport, we need to change both the size and the starting position. Here, I have moved the viewport down by one screen height and stretched the viewport to be twice as large in both directions. Let's see what happens:

Same perspective, smaller view, full screen.

The camera hasn't moved, so the perspective is the same, but we're only looking at what was the top-left corner of the original view! This topic had been giving me trouble for a few hours. I read this solution to a similar problem, and I realized it could be applied here.

To focus on any different portion of the viewport, simply choose x, y, w, and h accordingly. If you're going to do any more rendering in the normal fashion, make sure to reset the viewport with the original x, y, w, and h values.

I believe that the other three quarters of the viewport are not visible but are still rendering. It would probably be wise to use scissors in conjunction with this method in order to save resources.

\$\endgroup\$
2
\$\begingroup\$

You want scissor regions. Documentation for this feature in libgdx is here.

Sample code provided on that page is:

Rectangle scissors = new Rectangle();
Rectangle clipBounds = new Rectangle(x,y,w,h);
ScissorStack.calculateScissors(camera, spriteBatch.getTransformMatrix(), clipBounds, scissors);
ScissorStack.pushScissors(scissors);
spriteBatch.draw(...);
spriteBatch.flush();
ScissorStack.popScissors();
\$\endgroup\$
3
  • \$\begingroup\$ I believe this works only with sprite batch, which I'm not using - I'm using model batch with perspective camera. Correct me if I'm wrong. \$\endgroup\$
    – tom37
    Dec 8 '13 at 11:29
  • \$\begingroup\$ Did you try it? According to the documentation, the ScissorStack class calls directly into OpenGL's glScissor() function, which works for any sort of drawing. (OpenGL can not distinguish between "sprites" and "models") \$\endgroup\$ Dec 9 '13 at 0:27
  • \$\begingroup\$ I kind of got it working: (i.imgur.com/YX2Oi5D.jpg) But I have no idea how to make it span the whole window \$\endgroup\$
    – tom37
    Dec 18 '13 at 20:54

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.