libGDX - перспективная камера и поле зрения

У меня проблемы с пониманием поля зрения перспективной камеры в libGDX (а может мои расчеты неверны).

Я хочу нарисовать коробку (например, 800 пикселей в ширину, 480 пикселей в высоту и 20 пикселей в глубину). Блок помещается между осями x и y (другими словами: ширина по оси x и высота по оси y). Теперь я хочу стоять за коробкой на оси X (положение камеры) и смотреть в направлении таким образом, чтобы видеть коробку с правой стороны экрана. Я сделал несколько набросков:

рисование коробки

камера по оси x, смотрит на коробку

поле должно появиться справа

На последнем наброске коробка находится в правой части поля зрения.

При этом высота коробки должна точно соответствовать размеру экрана. Другими словами: верхний край окна должен быть в верхней части моего экрана, а нижний край окна должен быть в нижней части моего экрана. Вот некоторый код и расчеты для достижения этого:

public class Box implements ApplicationListener {

public PerspectiveCamera camera;
public float SCREEN_WIDTH;   
public float SCREEN_HEIGHT; 

@Override
public void create() {
    SCREEN_WIDTH = Gdx.graphics.getWidth(); // 800px
    SCREEN_HEIGHT = Gdx.graphics.getHeight(); // 480px

    // Create camera (90°) and set position
    camera = new PerspectiveCamera(90f, SCREEN_WIDTH, SCREEN_HEIGHT);
    camera.position.set(SCREEN_WIDTH + SCREEN_HEIGHT/2, SCREEN_HEIGHT/2, 0f);
    camera.lookAt(0f, SCREEN_HEIGHT/2, 0f);
    camera.near = 1;
    camera.far = 2 * SCREEN_WIDTH;
    camera.update();
}

@Override
public void render() {
    Gdx.gl.glClearColor(Color.WHITE.r, Color.WHITE.g, Color.WHITE.b, Color.WHITE.a);
    Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT); 

    // Build the box - width is screenwidth and height is screenheight - one corner in origin
    ModelBuilder modelBuilder = new ModelBuilder(); 
    modelBuilder.begin();
    MeshPartBuilder mpb = modelBuilder.part("ID", GL20.GL_TRIANGLES, Usage.Position | Usage.Normal,
            new Material(ColorAttribute.createDiffuse(Color.GREEN)));
    // bottom left corner of the box should be in (0,0,0)
    mpb.box(SCREEN_WIDTH/2, SCREEN_HEIGHT/2, -10f, SCREEN_WIDTH, SCREEN_HEIGHT, 20f);
    Model model = modelBuilder.end();
    ModelInstance instance = new ModelInstance(model);

    // Build some light
    Environment environment = new Environment();
    environment.set(new ColorAttribute(ColorAttribute.AmbientLight, 0.4f, 0.4f, 0.4f, 1f));
    environment.add(new DirectionalLight().set(0.8f, 0.8f, 0.8f, -1f, -0.8f, -0.2f));

    // Draw the box
    ModelBatch modelBatch = new ModelBatch();
    modelBatch.begin(camera);
    modelBatch.render(instance, environment);
    modelBatch.end();
}
}

Чтобы вписать высоту блока в экран, я должен отступить на SCREEN_HEIGHT/2, потому что x = SCREEN_HEIGHT/2 / tan(45°) = SCREEN_HEIGHT/2 / 1 = SCREEN_HEIGHT/2, поэтому я добавил эту длину в x-компоненту в настройке положения.

Код представляет скетч 2 и дайте мне правильный снимок экрана:

скриншот эскиза 2

Чтобы получить набросок 3, я должен повернуть поле зрения примерно на 45° влево. Но в связи с этим я должен немного отступить, потому что стороны поля зрения длиннее осевой линии. Я сделал два наброска от руки:

поворот поля зрения

Где h = SCREEN_HEIGHT. Прежде всего, мне нужно вычислить х. x = h/2/sin(45°) = h/sqrt(2). Теперь я должен отступить на длину x и посмотреть в новом направлении (45° влево от прямоугольника). Чтобы вычислить точку, на которую я буду смотреть, я вычисляю длину y на этом эскизе:

расчет

y = sin(45°) * h/2 = h * sqrt(2)/4. Итак, точка, например, (SCREEN_WIDTH + (x-y), SCREEN_HEIGHT/2, y). Теперь я меняю позицию и точку поиска в своем коде:

public void create() {
    SCREEN_WIDTH = Gdx.graphics.getWidth(); // 800px
    SCREEN_HEIGHT = Gdx.graphics.getHeight(); // 480px

    // Create camera (90°) and set position
    camera = new PerspectiveCamera(90f, SCREEN_WIDTH, SCREEN_HEIGHT);
    float x = (float) (SCREEN_HEIGHT / Math.sqrt(2));
    float y = (float) (SCREEN_HEIGHT * Math.sqrt(2)/4f);
    camera.position.set(SCREEN_WIDTH + x, SCREEN_HEIGHT/2, 0f);
    camera.lookAt(SCREEN_WIDTH + x - y, SCREEN_HEIGHT/2, y);
    camera.near = 1;
    camera.far = 2 * SCREEN_WIDTH;
    camera.update();
}

И я получаю этот экран:

скриншот, который должен представлять эскиз 3

Но коробка не с правой стороны :(

Итак, теперь вопрос: что не так? Я неправильно думаю о поле зрения или мои расчеты?

С наилучшими пожеланиями!


person Namenlos    schedule 13.04.2014    source источник


Ответы (1)


Ваше понимание PerspectiveCamera немного отличается, в частности, что он делает со вторым (viewportWidth) и третьим (viewportHeight) аргументом.

Единственное, что делает с ними PerspectiveCamera, — это получает соотношение сторон и использует его для установки projectionMatrix. Конкретный код, который он использует, см. в разделе эта строка, которая вычисляет соотношение сторон и этот метод, который устанавливает projectionMatrix.

Теперь все это хорошо, за исключением того, что вы также выполняете математику, чтобы иметь дело с соотношением сторон, и выполнение этого дважды заставляет камеру снова растягиваться. Решение довольно простое, либо переделайте свою математику, чтобы не корректировать соотношение сторон, либо замените

camera = new PerspectiveCamera(90f, SCREEN_WIDTH, SCREEN_HEIGHT);

с

camera = new PerspectiveCamera(90f, 1, 1);

чтобы соотношение сторон, которое вычисляет libgdx, было 1.

Я не очень хорошо разбираюсь в синусе и косинусе, поэтому не могу дать решения для первого варианта, но, похоже, у вас нет проблем со сложной математикой.

person Mim-nim    schedule 23.12.2014