Портирование с OpenGL на MetalKit - матрица проекций (?) - PullRequest
0 голосов
/ 26 октября 2019

Вопрос

Я работаю над портированием с OpenGL (OGL) на MetalKit (MTK) на iOS. Мне не удается получить идентичный дисплей в версии приложения MetalKit. Я изменил матрицу проекции, чтобы учесть различия в нормализованных координатах устройства между двумя структурами, но не знаю, что еще нужно изменить, чтобы получить идентичный дисплей. Есть идеи, что еще нужно изменить для переноса из OpenGL в MetalKit?

Изменения матрицы проекции до сих пор ...

Я понимаю, что нормализованные координаты устройства (NDC) отличаются в OGL по сравнению сMTK:

  • OGL NDC: -1 < z < 1
  • MTK NDC: 0 < z < 1

Я изменил матрицу проекции для устранения разницы NDC, так какуказано здесь . К сожалению, это изменение матрицы проецирования не приводит к тому же отображению, что и старый код OGL.

Я изо всех сил пытаюсь узнать, что еще можно попробовать.

Фон

Для справки вот некоторая разная справочная информация:

  • Матрица вида очень проста (единичная матрица);т.е. камера находится на (0, 0, 0) и смотрит в сторону (0, 0, -1)
  • В устаревшем коде OpenGL я использовал GLKMatrix4MakeFrustum для получения матрицы проекции, используя границы экрана для left, right, top, bottom и near=1, far=1000

Я сократил сцену до голой кости во время отладки и ниже приведены 2 изображения: первое из унаследованного кода OGL и второе изMTK, который показывает только «заземленную» плоскость с текстурой отладки и черным фоном.

Любые идеи о том, что еще нужно изменить, чтобы получить идентичный дисплей в MetalKit, будут очень благодарны.

Снимки экрана

OpenGL (прежняя версия)

OpenGL Scene

MetalKit

MetalKit Scene

Редактировать 1

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

float aspectRatio = 1.777; // iPhone 8 device
float top = 1;
float bottom = -1;
float left = -aspectRatio;
float right = aspectRatio;
float RmL = right - left;
float TmB = top - bottom;
float nearZ = 1;
float farZ = 1000;

GLKMatrix4 projMatrix = {   2 * nearZ / RmL,     0,                      0,                               0,
                            0,                   2 * nearZ / TmB,        0,                               0,
                            0,                   0,                      -farZ / (farZ - nearZ),          -1,
                            0,                   0,                      -farZ * nearZ / (farZ - nearZ),  0 };

GLKMatrix4 viewMatrix = ...; // Identity matrix: camera at origin, looking at (0, 0, -1), yUp=(0, 1, 0);
GLKMatrix4 modelMatrix = ...; // Different for various models, but even when this is the identity matrix in old/new code the visual output is different
GLKMatrix4 mvpMatrix = GLKMatrix4Multiply(projMatrix, GLKMatrix4Multiply(viewMatrix, modelMatrix));

...

GLKMatrix4 x = mvpMatrix; // rename for brevity below
float mvpMatrixArray[16] = {x.m00, x.m01, x.m02, x.m03, x.m10, x.m11, x.m12, x.m13, x.m20, x.m21, x.m22, x.m23, x.m30, x.m31, x.m32, x.m33};

// making MVP matrix available to vertex shader
[renderCommandEncoder setVertexBytes:&mvpMatrixArray
                              length:16 * sizeof(float)
                             atIndex:1]; // vertex data is at "0"

[renderCommandEncoder setVertexBuffer:vertexBuffer
                               offset:0
                              atIndex:0];

...

[renderCommandEncoder drawPrimitives:MTLPrimitiveTypeTriangleStrip
                         vertexStart:0
                         vertexCount:4];

Ответы [ 2 ]

0 голосов
/ 06 ноября 2019

К сожалению, эта проблема в конечном итоге возникла из-за ошибки в вершинном шейдере, которая выдвигала всю геометрию +1 на оси Z, что приводило к визуальным различиям.

Для любых будущих портеров OpenGL-to-Metal: изменения матрицы проекции, приведенные выше, с учетом различий в нормированных координатах устройства, достаточно.

0 голосов
/ 27 октября 2019

Не видя код, трудно сказать, в чем проблема. Одной из наиболее распространенных проблем может быть неправильно настроенный видовой экран:

// Set the region of the drawable to draw into.
[renderEncoder setViewport:(MTLViewport){0.0, 0.0, _viewportSize.x, _viewportSize.y, 0.0, 1.0 }];

Значения по умолчанию для видового экрана:

originX = 0.0
originY = 0.0
width = w
height = h
znear = 0.0
zfar = 1.0

enter image description here

* Металл: znear = minZ, zfar = maxZ.

MinZ и MaxZ указывают диапазоны глубины, на которые будет визуализироваться сцена, и являютсяне используется для отсечения. Большинство приложений устанавливают эти элементы в 0.0 и 1.0, чтобы система могла отображать весь диапазон значений глубины в буфере глубины. В некоторых случаях вы можете добиться специальных эффектов, используя другие диапазоны глубины. Например, для рендеринга дисплея в игре, вы можете установить оба значения равными 0,0, чтобы заставить систему отображать объекты в сцене на переднем плане, или вы можете установить оба значения на 1,0, чтобы рендерить объект, который должен всегданаходиться в фоновом режиме.

Приложения обычно устанавливают MinZ и MaxZ равными 0,0 и 1,0 соответственно, чтобы система отображала весь диапазон глубины. Тем не менее, вы можете использовать другие значения для достижения определенных эффектов. Например, вы можете установить оба значения на 0.0, чтобы заставить все объекты на передний план, или установить оба на 1.0, чтобы отобразить все объекты на заднем плане.

...