OpenXR для FPC

Обсуждаются как существующие проекты (перевод документации, информационная система и т.п.), так и создание новых.

Модератор: Модераторы

OpenXR для FPC

Сообщение dedm0zaj » 04.01.2023 03:15:36

Только начинаю данное дело. Результатами буду делиться, если будут положительные.

На данный момент нужна помощь.
Конвертирую сишный заголовочный в pas при помощи h2pas. Внутри pas есть ошибки.
Много такого типа:
Код: Выделить всё
(* error
typedef uint32_t XrBool32;
in declarator_list *)

ещё есть такое:
Код: Выделить всё
(* error
typedef struct XR_MAY_ALIAS XrBaseInStructure {
in member_list *)

и такое, как понял, можно просто игнорировать:
Код: Выделить всё
(* Const before type ignored *)
(* Const before declarator ignored *)


Вопрос простой: что это значит?
страница https://wiki.freepascal.org/Common_prob ... ader_files не сильно помогла. Или я сонный не увидел
dedm0zaj
постоялец
 
Сообщения: 108
Зарегистрирован: 05.10.2012 19:55:20

Re: OpenXR для FPC

Сообщение Alex2013 » 04.01.2023 12:33:39

h2pas помогает далеко не всегда он выдает, то что можно назвать "полуфабрикат".
Что-бы сказать что-то более полезное нужно посмотреть исходник на Си
PS
Это они ?
https://github.com/KhronosGroup/OpenXR-SDK
Alex2013
долгожитель
 
Сообщения: 2922
Зарегистрирован: 03.04.2013 11:59:44

Re: OpenXR для FPC

Сообщение dedm0zaj » 04.01.2023 17:16:17

ага. но брал не оттуда.
по твоей ссылке вот
https://github.com/KhronosGroup/OpenXR- ... ude/openxr

п.с. вчера заглянул в dglOpenGL.pas - 20к строк. вручную это же всю жизнь делать :shock:
dedm0zaj
постоялец
 
Сообщения: 108
Зарегистрирован: 05.10.2012 19:55:20

Re: OpenXR для FPC

Сообщение Alex2013 » 04.01.2023 18:23:47

dedm0zaj писал(а):ага. но брал не оттуда.
по твоей ссылке вот
https://github.com/KhronosGroup/OpenXR- ... ude/openxr

п.с. вчера заглянул в dglOpenGL.pas - 20к строк. вручную это же всю жизнь делать :shock:

Основная проблема использования современных блиотек на С++ в том что они экспортирую не функции, а классы, а паскаль без "диких танцев с бубном" ничего подобного нормально импортировать не умеет . Поэтому иногда имеет смысл делать свои DLL-"обертки" на С++ и уже их использовать в паскале. (это все равно проще чем переписывать библиотеки вручную )
Последний раз редактировалось Alex2013 04.01.2023 18:29:57, всего редактировалось 1 раз.
Alex2013
долгожитель
 
Сообщения: 2922
Зарегистрирован: 03.04.2013 11:59:44

Re: OpenXR для FPC

Сообщение dedm0zaj » 04.01.2023 18:29:24

как здесь например?
Код: Выделить всё
#if !defined(XR_DEFINE_HANDLE)
#if (XR_PTR_SIZE == 8)
    #define XR_DEFINE_HANDLE(object) typedef struct object##_T* object;
#else
    #define XR_DEFINE_HANDLE(object) typedef uint64_t object;
#endif
#endif
dedm0zaj
постоялец
 
Сообщения: 108
Зарегистрирован: 05.10.2012 19:55:20

Re: OpenXR для FPC

Сообщение Alex2013 » 04.01.2023 18:42:21

dedm0zaj писал(а):как здесь например?
Код: Выделить всё
#if !defined(XR_DEFINE_HANDLE)
#if (XR_PTR_SIZE == 8)
    #define XR_DEFINE_HANDLE(object) typedef struct object##_T* object;
#else
    #define XR_DEFINE_HANDLE(object) typedef uint64_t object;
#endif
#endif

Обычно делают как-то примерно так
http://source.oriolussoftware.de/openvr.html
Или так ...
https://github.com/Kagamma/OpenVR-Pasca ... vr_api.pas
(Там довольно сильно извратились получая openvr.pas из openvr.h )

Однако, ИМХО проще сделать чисто процедурную "обертку" .

Добавлено спустя 28 минут 1 секунду:
Вообще интереснее всего сделать OpenXR приложение для Окулус Квест ( причем в автономном режиме то бишь на тамошний андроид )
Сборку демок на Андроид ОС в Лазарусе я освоил ...
Изображение
и даже запустил несколько полученных APK на Окулус Квест 2...
Изображение
Но дальше пока не продвинулся ...
Alex2013
долгожитель
 
Сообщения: 2922
Зарегистрирован: 03.04.2013 11:59:44

Re: OpenXR для FPC

Сообщение dedm0zaj » 04.01.2023 19:58:15

как же всё просто в движках (Godot, Unity), пара кликов и приложения хоть где. на андроиде, на пк, на пквр, автономно на квесте.
при этом код не меняется

Добавлено спустя 24 минуты 49 секунд:
во фрипаскалевском дефайне есть замена с параметрами?
как тут (в скобках object)
Код: Выделить всё
#define XR_DEFINE_HANDLE(object) uint64_t object


upd: нету
dedm0zaj
постоялец
 
Сообщения: 108
Зарегистрирован: 05.10.2012 19:55:20

Re: OpenXR для FPC

Сообщение Alex2013 » 05.01.2023 01:55:46

dedm0zaj писал(а):как же всё просто в движках (Godot, Unity), пара кликов и приложения хоть где. на андроиде, на пк, на пквр, автономно на квесте.
при этом код не меняется

Разумеется ! В Unity "все просто " но это иллюзия ( там все "просто" пока находишься в рамках профильных задач но у меня задачи заметно ближе к "системном программированию" чем к обычным для Unity и там на движках подобных Unity начинается полный "АД и адик" ) + если пишешь что-то вроде небольшой утилиты то тащить в проект огромный движок просто жуть как не хочется.

во фрипаскалевском дефайне есть замена с параметрами?
как тут (в скобках object)

Точно такого как в Си точно нет .
https://www.freepascal.org/docs-html/prog/progsu11.html
{$define <идентификатор>} - определение имени, используемого в директивах $ifdef, $ifndef.
Макросы FPC: они могут быть определены, например, кодом вроде такого: {$define MYFPCMACRO:=42}.
https://www.freepascal.org/docs-html/prog/progse5.html
Alex2013
долгожитель
 
Сообщения: 2922
Зарегистрирован: 03.04.2013 11:59:44

Re: OpenXR для FPC

Сообщение dedm0zaj » 20.03.2023 00:08:56

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

Добавлено спустя 4 минуты 40 секунд:
как уменьшить изображение в img?
dedm0zaj
постоялец
 
Сообщения: 108
Зарегистрирован: 05.10.2012 19:55:20

Re: OpenXR для FPC

Сообщение Alex2013 » 20.03.2023 09:15:20

почти получилось. матрица репроекции шалит. но изображение выводится

Замечательно ! Поздравляю! (Если я верно понял о чем речь то с Матрицей репроекции все довольно просто )
Код: Выделить всё
procedure VV_XYZR; //Расчет общей настройки координат
begin
VV_X:=(CameraX+30)/10;;
VV_Y:=(TankY-1)/50-0.5;
VV_Z:=(CameraTargetY-10)/10-3.5;

VVR_X:=0;   VVR_Y:=0;   VVR_Z:=0;

If WorldX_on=1 then VVR_X:=WorldA;
If WorldY_on=1 then VVR_Y:=WorldA;
If WorldZ_on=1 then VVR_Z:=WorldA;
VVR_X:=WorldX+DuloA;
end;

procedure LoopRenderer(const View, Proj: TMatrix4f; M3D: Boolean );
// View, Proj: TMatrix4f; этот что приходит от шлема
//( для каждого глаза отдельно а еще есть подобные данные от контролеров    ) 
var
  T, R, M: TMatrix4f;
  I, J, K: Integer;
  //
const  TS:TStringList=nil;
        TS2:TStringList=nil;
        AX : Single=0;
   var

        PF:^TTrFunc;

        gWorldLocation:GLuint;
        M2 :array [0..16] of GLdouble;
        tx_,ty_,tz:GLdouble ;

Const
  CL:TM_RGB=(R:1;G:0;B:1);
  CR:TM_RGB=(R:0;G:1;B:0);
  CL1:TM_RGB=(R:0.7;G:0.8;B:0.1);
  CR1:TM_RGB=(R:0.2;G:0.7;B:0.1);

Function TR(CC:XYZ):XYZ; far;
Var
   V:TVector3f;

begin
Result.x:=CC.x;
Result.Y:=CC.Y;
Result.Z:=CC.Z;
end;
begin

  glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
  glEnable(GL_DEPTH_TEST);


VR_View:=View;
VR_Proj:=Proj;
   glPushMatrix();                     // save current modelview matrix
   glLoadIdentity();                   // reset modelview matrix
   glMatrixMode(GL_PROJECTION);        // switch to projection matrix
   glLoadIdentity();
//----------------
   T:=Proj;  glLoadMatrixf(@T); Собственно вот  она 
   glMatrixMode(GL_MODELVIEW);
  T:=View;
  glLoadMatrixf(@T);
//===========================

if not VR_Run then VR_Run:=True;

If not  VR_MK_Ctrl  then
MyRender( BaseA ,gl_render,m3d)
else begin
   glPushMatrix();

  VV_XYZR;

  glTranslatef(VV_X,VV_Y,VV_Z);

  glRotatef(VVR_X,1,0,0);
  glRotatef(VVR_Y,0,1,0);
  glRotatef(VVR_Z,0,0,1);

    MyRender(BaseA,GL_RENDER,m3d); Мой основной рендер

  glPopMatrix();
end;


glPopMatrix();

end;


Кадр у меня посчитается аж три раза ( на шлем для каждого глаза и в окно, но зато рендер один )
Но в принципе я просто до стадии оптимизации так и не добрался до "заморозки" этого проекта .
Добавлено спустя 9 минут 22 секунды:
Alex2013 писал(а):как уменьшить изображение в img?

Просто масштабировать его самостоятельно ( до загрузки ) .
Последний раз редактировалось Alex2013 23.03.2023 12:28:39, всего редактировалось 1 раз.
Alex2013
долгожитель
 
Сообщения: 2922
Зарегистрирован: 03.04.2013 11:59:44

Re: OpenXR для FPC

Сообщение Seenkao » 20.03.2023 16:09:20

dedm0zaj писал(а):вчера заглянул в dglOpenGL.pas - 20к строк. вручную это же всю жизнь делать

Почему всю жизнь? Две недели (максимум) на переводы и две недели на состыковки несоответствий.
Понятно дело, что я подглядывал некоторые вещи, но и часть функций/процедур реализованы по разному.

https://youtu.be/_NLk5ZP6aM4 - здесь делал видео, по тому как помогал h2pas переводить заголовки. Может поможет.
Seenkao
энтузиаст
 
Сообщения: 502
Зарегистрирован: 01.04.2020 03:37:12

Re: OpenXR для FPC

Сообщение Alex2013 » 23.03.2023 12:25:02

Ну как продвигается ?
Зы
Интересно насколько модуль OpenXR.pas будет отличаться от OpenVR.pas ?
(То есть нельзя ли "срезать угол" и просто дополнить OpenVR.pas до OpenXR.pas )
Alex2013
долгожитель
 
Сообщения: 2922
Зарегистрирован: 03.04.2013 11:59:44

Re: OpenXR для FPC

Сообщение dedm0zaj » 23.03.2023 15:25:32

Alex2013 писал(а):Ну как продвигается ?

только по выходным. после работы голова не варит

Alex2013 писал(а):Интересно насколько модуль OpenXR.pas будет отличаться от OpenVR.pas ?

ничего сложного там не встретил. никаких классов. всё на структурах и функциях. есть конечно задачки, как в 5-ом сообщении данного топика. так и не понял, как структуру делать пустой. возможно никак. оставил просто uint64_t.

Alex2013 писал(а):То есть нельзя ли "срезать угол" и просто дополнить OpenVR.pas до OpenXR.pas

в OpenVR подробно не заглядывал. не скажу.

про OpenXR, если кратко, работает так:
1. делаем всякую инициализацию
2. OpenXR дает параметры для рендера картинки (позицию, поворот, углы для матрицы репроекции, индекс текстуры в которую рендерить)
3. в Loop'е OpenXR рендерим для двух глаз
dedm0zaj
постоялец
 
Сообщения: 108
Зарегистрирован: 05.10.2012 19:55:20

Re: OpenXR для FPC

Сообщение Alex2013 » 23.03.2023 22:17:26

dedm0zaj писал(а):про OpenXR, если кратко, работает так:
1. делаем всякую инициализацию
2. OpenXR дает параметры для рендера картинки (позицию, поворот, углы для матрицы репроекции, индекс текстуры в которую рендерить)
3. в Loop'е OpenXR рендерим для двух глаз
dedm0zaj
постоялец
 
Сообщения: 103
Зарегистрирован: 05.10.2012 17:55:20
Вернуться к началу

Если описывать кратко от OpenVR вообще не отличается
За спряжение с openvr_api отвечает крохотный модуль vr.pas
(openvr_api.pas- это просто хедер openvr_api.dll }
Где всего три процедуры ...
procedure InitVR;
procedure LoopVR( M3D: Boolean);
procedure FreeVR;
Код: Выделить всё
unit vr;

interface

uses
  SysUtils, GL, GLExt, openvr_api, Math3D;

const
  WIDTH = 1366;
  HEIGHT = 768;
  EyeVerticles: array[0..31] of GLfloat = (
    -0.9, -0.9, 0.0, 0.0,
    -0.05, -0.9, 1.0, 0.0,
    -0.05, 0.9, 1.0, 1.0,
    -0.9, 0.9, 0.0, 1.0,
    // Right eye
    0.05, -0.9, 0.0, 0.0,
    0.9, -0.9, 1.0, 0.0,
    0.9, 0.9, 1.0, 1.0,
    0.05, 0.9, 0.0, 1.0
  );
  EyeIndices: array[0..11] of GLushort = (
    0, 1, 2, 0, 2, 3, 4, 5, 6, 4, 6, 7
  );

type
  TOVRDeviceName = array[0..1023] of Char;

  TOVRMesh = record
    VertexArray,
    VertexBuffer,
    ArrayBuffer,
    Texture,
    VertexCount: GLuint;
  end;

  TController = record
    Side: Integer; // 0 = left, 1 = right
    DeviceID: Integer;
    DeviceName: TOVRDeviceName;
    Mesh: TOVRMesh;
    Pose: TMatrix4f;
    ActionPose: VRActionHandle_t;
  end;

  TFrameBuffer = record
    DepthID,
    RenderFramebufferID,
    RenderTextureID,
    ResolveFramebufferID,
    ResolveTextureID: GLuint;
  end;

procedure InitVR;
procedure FreeVR;
procedure LoopVR( M3D: Boolean);

var
  IVRSystem: PIVRSystem;
  IVRCompositor: PIVRCompositor;
  IVRRenderModels: PIVRRenderModels;
  IVRInput: PIVRInput;
  EyeLeftProj,
  EyeRightProj,
  EyeLeftPose,
  EyeRightPose: TMatrix4f;
  EyeLeftFB,
  EyeRightFB: TFrameBuffer;
  Controllers: array[0..1] of TController;
  TrackedDevicePoses: array[0..7] of TrackedDevicePose_t;
  Poses: array[0..7] of TMatrix4f;
  HmdPose: TMatrix4f;
  RenderWidth,
  RenderHeight: LongWord;
  EyeVAO,
  EyeEAB,
  EyeVBO: GLuint;

implementation

uses
  Renderer,my_Renderer;

function ConvertVR34ToMatrix(const M: HmdMatrix34_t): TMatrix4f;
begin
  Result[0,0] := M.m[0,0]; Result[0,1] := M.m[1,0]; Result[0,2] := M.m[2,0]; Result[0,3] := 0;
  Result[1,0] := M.m[0,1]; Result[1,1] := M.m[1,1]; Result[1,2] := M.m[2,1]; Result[1,3] := 0;
  Result[2,0] := M.m[0,2]; Result[2,1] := M.m[1,2]; Result[2,2] := M.m[2,2]; Result[2,3] := 0;
  Result[3,0] := M.m[0,3]; Result[3,1] := M.m[1,3]; Result[3,2] := M.m[2,3]; Result[3,3] := 1;
end;

procedure FindHmdEye(const Eye: EVREye; out Pose, Proj: TMatrix4f);
const
  FNear: Single = 0.1;
  FFar: Single = 100;
begin
  Pose := Inverse(ConvertVR34ToMatrix(IVRSystem^.GetEyeToHeadTransform(Eye)));
  Proj := Transpose(TMatrix4f(IVRSystem^.GetProjectionMatrix(Eye, FNear, FFar)));
//IVRSystem^.
end;

function CreateFrameBuffer(const Width, Height: Integer): TFrameBuffer;
var
  Status: GLenum;
begin
glGenFramebuffers(1, @Result.RenderFramebufferID);
glBindFramebuffer(GL_FRAMEBUFFER, Result.RenderFramebufferID);

  glGenRenderbuffers(1, @Result.DepthID);
  glBindRenderbuffer(GL_RENDERBUFFER, Result.DepthID);
  glRenderbufferStorageMultisample(GL_RENDERBUFFER, 4, GL_DEPTH_COMPONENT, Width, Height);
  glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER,   Result.DepthID);

  glGenTextures(1, @Result.RenderTextureID);
  glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, Result.RenderTextureID);
  glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 4, GL_RGBA8, Width, Height, GL_TRUE);
  glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE,   Result.RenderTextureID, 0);

  Status := glCheckFramebufferStatus(GL_FRAMEBUFFER);
  if Status <> GL_FRAMEBUFFER_COMPLETE then
  begin
    Writeln('Failed to create framebuffer 1');
    Halt;
  end;
  glGenFramebuffers(1, @Result.ResolveFramebufferID);
  glBindFramebuffer(GL_FRAMEBUFFER, Result.ResolveFramebufferID);

  glGenTextures(1, @Result.ResolveTextureID);
  glBindTexture(GL_TEXTURE_2D, Result.ResolveTextureID);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, Width, Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nil);
  glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,   Result.ResolveTextureID, 0);

  Status := glCheckFramebufferStatus(GL_FRAMEBUFFER);
  if Status <> GL_FRAMEBUFFER_COMPLETE then
  begin
    Writeln('Failed to create framebuffer 2');
    Halt;
  end;
  glBindFramebuffer(GL_FRAMEBUFFER, 0);
end;

function LoadOVRMesh(DI: TrackedDeviceIndex_t): TController;
var
  TPError: ETrackedPropertyError;
  RMError: EVRRenderModelError;
  POVRRenderModel: ^RenderModel_t = nil;
  POVRRenderTexture: ^RenderModel_TextureMap_t = nil;
  Side: Integer = -1;
  Role: LongInt;
  I: Integer;
  IsLoaded: Boolean = True;
begin
  Result.Side := -1;
  Result.DeviceID := DI;
  // We only want to load controller mesh
  if IVRSystem^.GetTrackedDeviceClass(DI) <> TrackedDeviceClass_Controller then
    Exit;
  FillChar(Result.DeviceName, 1024, 0);
  IVRSystem^.GetStringTrackedDeviceProperty(DI, Prop_RenderModelName_String, @Result.DeviceName, 1024, @TPError);
  Role := IVRSystem^.GetInt32TrackedDeviceProperty(DI, Prop_ControllerRoleHint_Int32, @TPError);
  case ETrackedControllerRole(Role) of
    TrackedControllerRole_LeftHand:
      Side := 0;
    TrackedControllerRole_RightHand:
      Side := 1;
  end;
  if Side < 0 then
    Exit;
  for I := 0 to 1023 do
  begin
    if Controllers[Side].DeviceName[I] <> Result.DeviceName[I] then
    begin
      IsLoaded := False;
      break;
    end;
  end;
  if IsLoaded then Exit;
  Result.Side := Side;
  Writeln('Device name: ', PChar(@Result.DeviceName));
  repeat
    RMError := IVRRenderModels^.LoadRenderModel_Async(@Result.DeviceName, @POVRRenderModel);
    Sleep(1);
  until RMError <> VRRenderModelError_Loading;
  if RMError <> VRRenderModelError_None then
  begin
    Writeln('LoadRenderModel_Async(', PChar(@Result.DeviceName), '): ', IVRRenderModels^.GetRenderModelErrorNameFromEnum(RMError));
  end;
  repeat
    RMError := IVRRenderModels^.LoadTexture_Async(POVRRenderModel^.diffuseTextureId, @POVRRenderTexture);
    Sleep(1);
  until RMError <> VRRenderModelError_Loading;
  if RMError <> VRRenderModelError_None then
  begin
    Writeln('LoadTexture_Async(', PChar(@Result.DeviceName), '): ', IVRRenderModels^.GetRenderModelErrorNameFromEnum(RMError));
  end;

  // create and bind a VAO to hold state for this model
  glGenVertexArrays(1, @Result.Mesh.VertexArray);
  glBindVertexArray(Result.Mesh.VertexArray);

  // Populate a vertex buffer
  glGenBuffers(1, @Result.Mesh.VertexBuffer);
  glBindBuffer(GL_ARRAY_BUFFER, Result.Mesh.VertexBuffer);
  glBufferData(GL_ARRAY_BUFFER, SizeOf(RenderModel_Vertex_t) * POVRRenderModel^.unVertexCount, POVRRenderModel^.rVertexData, GL_STATIC_DRAW);

  // Identify the components in the vertex buffer
  glEnableVertexAttribArray(0);
  glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 32, Pointer(0));
  glEnableVertexAttribArray(1);
  glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 32, Pointer(12));
  glEnableVertexAttribArray(2);
  glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 32, Pointer(24));

  // Create and populate the index buffer
  glGenBuffers(1, @Result.Mesh.ArrayBuffer);
  glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, Result.Mesh.ArrayBuffer);
  glBufferData(GL_ELEMENT_ARRAY_BUFFER, SizeOf(Word) * POVRRenderModel^.unTriangleCount * 3, POVRRenderModel^.rIndexData, GL_STATIC_DRAW);

  glBindVertexArray(0);

  // create and populate the texture
  glGenTextures(1, @Result.Mesh.Texture);
  glBindTexture(GL_TEXTURE_2D, Result.Mesh.Texture);

  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, POVRRenderTexture^.unWidth, POVRRenderTexture^.unHeight,
    0, GL_RGBA, GL_UNSIGNED_BYTE, POVRRenderTexture^.rubTextureMapData);

  // If this renders black ask McJohn what's wrong.
  glGenerateMipmap(GL_TEXTURE_2D);

  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
  glBindTexture(GL_TEXTURE_2D, 0);
  glBindVertexArray(0);

  Result.Mesh.VertexCount := POVRRenderModel^.unTriangleCount * 3;
end;

procedure LoadEyeMesh;
begin
  glGenVertexArrays(1, @EyeVAO);
  glBindVertexArray(EyeVAO);

  glGenBuffers(1, @EyeVBO);
  glBindBuffer(GL_ARRAY_BUFFER, EyeVBO);
  glBufferData(GL_ARRAY_BUFFER, SizeOf(EyeVerticles), @EyeVerticles, GL_STATIC_DRAW);

  glGenBuffers(1, @EyeEAB );
  glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EyeEAB);
  glBufferData(GL_ELEMENT_ARRAY_BUFFER, SizeOf(EyeIndices), @EyeIndices, GL_STATIC_DRAW);

  glEnableVertexAttribArray(0);
  glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 16, Pointer(0));

  glEnableVertexAttribArray(1);
  glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 16, Pointer(8));

  glBindVertexArray(0);
  glBindBuffer(GL_ARRAY_BUFFER, 0);
  glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
end;

procedure InitVR;
var
  Error: EVRInitError;
  FnTableName: AnsiString;
begin
  if not OpenVR_Load() then
  begin
    Writeln('Cannot init OpenVR!');
    Halt;
  end;
      Writeln(' init OpenVR!');

  if not VR_IsHmdPresent() then
  begin
    Writeln('VR headset not found!');
    Halt;
  end;
    Writeln('VR headset  found!');

  if not VR_IsRuntimeInstalled() then
  begin
    Writeln('OpenVR runtime is not installed!');
    Halt;
  end;
  Writeln('OpenVR runtime is installed!');

  VR_InitInternal(@Error, VRApplication_Scene);
  if Error <> VRInitError_None then
  begin
    Writeln('VR_InitInternal: ', Error);
    Halt;
  end;
  Writeln('VR_InitInternal:Ok');

  FnTableName := 'FnTable:' + IVRSystem_Version + #0;
  IVRSystem := PIVRSystem(VR_GetGenericInterface(PChar(FnTableName), @Error));
  if Error <> VRInitError_None then
  begin
    Writeln('VR_GetGenericInterface(', IVRSystem_Version, '): ', Error);
    Halt;
  end;
     Writeln('VR_GetGenericInterface Ok' );
  FnTableName := 'FnTable:' + IVRCompositor_Version + #0;
  IVRCompositor := PIVRCompositor(VR_GetGenericInterface(PChar(FnTableName), @Error));
  if Error <> VRInitError_None then
  begin
    Writeln('VR_GetGenericInterface(', IVRCompositor_Version, '): ', Error);
    Halt;
  end;
    Writeln('VR_GetGenericInterface(', IVRCompositor_Version, ' Ok');
  FnTableName := 'FnTable:' + IVRRenderModels_Version + #0;
  IVRRenderModels := PIVRRenderModels(VR_GetGenericInterface(PChar(FnTableName), @Error));
  if Error <> VRInitError_None then
  begin
    Writeln('VR_GetGenericInterface(', IVRRenderModels_Version, '): ', Error);
    Halt;
  end;
  Writeln('VR_GetGenericInterface(', IVRRenderModels_Version, '): Ok');

  FnTableName := 'FnTable:' + IVRInput_Version + #0;
  IVRInput := PIVRInput(VR_GetGenericInterface(PChar(FnTableName), @Error));
  if Error <> VRInitError_None then
  begin
    Writeln('VR_GetGenericInterface(', IVRInput_Version, '): ', Error);
    Halt;
  end;
    Writeln('VR_GetGenericInterface(', IVRInput_Version, '): Ok');

  // Writeln(IVRInput^.SetActionManifestPath(PChar(StringReplace(GetCurrentDir, '\', '/', [rfReplaceAll]) + '/hellovr_actions.json')));
  // IVRInput^.GetActionHandle('/actions/demo/in/Hand_Left', @Controllers[0].ActionPose);
  // IVRInput^.GetActionHandle('/actions/demo/in/Hand_Right', @Controllers[1].ActionPose);

  IVRSystem^.GetRecommendedRenderTargetSize(@RenderWidth, @RenderHeight);
  Writeln('RenderTarget: ', RenderWidth, ' x ', RenderHeight);

  FindHmdEye(Eye_Left, EyeLeftPose, EyeLeftProj);
  FindHmdEye(Eye_Right, EyeRightPose, EyeRightProj);

  Controllers[0].Side := -1;
  Controllers[1].Side := -1;

EyeLeftFB := CreateFrameBuffer(RenderWidth, RenderHeight);
EyeRightFB := CreateFrameBuffer(RenderWidth, RenderHeight);
LoadEyeMesh;
end;

procedure FreeVR;
begin
  VR_ShutdownInternal();
end;

procedure RenderVRControllers(const Pose, Proj: TMatrix4f);
var
  I: Integer;
begin
{  glUseProgram(TextureShader.ProgramID);
  glUniformMatrix4fv(TextureShader.Loc[1], 1, GL_FALSE, @Pose);
  glUniformMatrix4fv(TextureShader.Loc[2], 1, GL_FALSE, @Proj);
  for I := 0 to 1 do
  begin
    if Controllers[I].Side < 0 then
      continue;
    glUniformMatrix4fv(TextureShader.Loc[0], 1, GL_FALSE, @Controllers[I].Pose);
    glBindVertexArray(Controllers[I].Mesh.VertexArray);
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, Controllers[I].Mesh.Texture);
    glDrawElements(GL_TRIANGLES, Controllers[I].Mesh.VertexCount, GL_UNSIGNED_SHORT, Pointer(0));
    glBindVertexArray(0);
    glBindTexture(GL_TEXTURE_2D, 0);
  end;
  glUseProgram(0);
  }
  end;

procedure LoopVR( M3D: Boolean);
var
  VRE: VREvent_t;
  I: Integer;
  IError: EVRInputError;
  State: VRControllerState_t;
  PoseData: InputPoseActionData_t;
  Controller: TController;
  Left, Right: TMatrix4f;
  CError: EVRCompositorError;
  LeftTexture,
  RightTexture: Texture_t;
begin
  // Process OpenVR events
  while IVRSystem^.PollNextEvent(@VRE, SizeOf(VRE)) do
  begin
    case EVREventType(VRE.eventType) of
      VREvent_TrackedDeviceActivated:
        Writeln('Device activated: ', vre.trackedDeviceIndex, '(', IVRSystem^.GetTrackedDeviceClass(vre.trackedDeviceIndex), ')');
      VREvent_TrackedDeviceDeactivated:
        begin
          Writeln('Device deactivated: ', vre.trackedDeviceIndex);
          if VRE.trackedDeviceIndex = Controllers[0].DeviceID then
            Controllers[0].Side := -1
          else
          if VRE.trackedDeviceIndex = Controllers[1].DeviceID then
            Controllers[1].Side := -1;
        end;
    end;
  end;
  // Process HMD position
  IVRCompositor^.WaitGetPoses(@TrackedDevicePoses, 8, nil, 0);
  for I := 0 to 7 do
  begin
    case IVRSystem^.GetTrackedDeviceClass(I) of
      TrackedDeviceClass_Controller:
        begin
          Poses[I] := ConvertVR34ToMatrix(TrackedDevicePoses[I].mDeviceToAbsoluteTracking);
          Controller := LoadOVRMesh(I);
          if Controller.Side = 0 then
            Controllers[0] := Controller
          else
          if Controller.Side = 1 then
            Controllers[1] := Controller;
        end;
      TrackedDeviceClass_HMD:
        begin
          Poses[I] := ConvertVR34ToMatrix(TrackedDevicePoses[I].mDeviceToAbsoluteTracking);
        end;
    end;
  end;
  if TrackedDevicePoses[k_unTrackedDeviceIndex_Hmd].bPoseIsValid then
  begin
    HmdPose := Inverse(Poses[k_unTrackedDeviceIndex_Hmd]);
  end;
  Left := EyeLeftPose * HmdPose;
  Right := EyeRightPose * HmdPose;
  if (Controllers[0].Side = 0) and (Controllers[0].DeviceID < k_unMaxTrackedDeviceCount) then
    Controllers[0].Pose := Poses[Controllers[0].DeviceID];
  if (Controllers[1].Side = 1) and (Controllers[1].DeviceID < k_unMaxTrackedDeviceCount) then
    Controllers[1].Pose := Poses[Controllers[1].DeviceID];
  // Render
  // Left eye

  glEnable(GL_MULTISAMPLE);
  glBindFramebuffer(GL_FRAMEBUFFER, EyeLeftFB.RenderFramebufferID);
  glViewport(0, 0, RenderWidth, RenderHeight);
  FRender:=FR_L;

  LoopRenderer(Left, EyeLeftProj, M3D);//для левого глаза

   FRender:=FR_W;

// RenderVRControllers(Left, EyeLeftProj);

  glDisable(GL_MULTISAMPLE);
  glBindFramebuffer(GL_READ_FRAMEBUFFER, EyeLeftFB.RenderFramebufferID);
  glBindFramebuffer(GL_DRAW_FRAMEBUFFER, EyeLeftFB.ResolveFramebufferID);
  glBlitFramebuffer(0, 0, RenderWidth, RenderHeight, 0, 0, RenderWidth, RenderHeight, GL_COLOR_BUFFER_BIT, GL_LINEAR);
  glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
  glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);

  // Right eye
  glEnable(GL_MULTISAMPLE);
  glBindFramebuffer(GL_FRAMEBUFFER, EyeRightFB.RenderFramebufferID);
  glViewport(0, 0, RenderWidth, RenderHeight);
  FRender:=FR_R;

  LoopRenderer(Right, EyeRightProj, M3D);// для правого глаза

  FRender:=0;

  // RenderVRControllers(Right, EyeRightProj);

  glDisable(GL_MULTISAMPLE);
  glBindFramebuffer(GL_READ_FRAMEBUFFER, EyeRightFB.RenderFramebufferID);
  glBindFramebuffer(GL_DRAW_FRAMEBUFFER, EyeRightFB.ResolveFramebufferID);
  glBlitFramebuffer(0, 0, RenderWidth, RenderHeight, 0, 0, RenderWidth, RenderHeight, GL_COLOR_BUFFER_BIT, GL_LINEAR);
  glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
  glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);

// Render to monitor

{ glDisable(GL_DEPTH_TEST);
  glViewport(0, 0, WIDTH, HEIGHT);
  glBindVertexArray(EyeVAO);
  glUseProgram(EyeShader.ProgramID);
  glBindTexture(GL_TEXTURE_2D, EyeLeftFB.ResolveTextureID);
  glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, Pointer(0));
  glBindTexture(GL_TEXTURE_2D, EyeRightFB.ResolveTextureID);
  glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, Pointer(12));
  glBindTexture(GL_TEXTURE_2D, 0);
  glBindVertexArray(0);
  glUseProgram(0);}

  // Submit to HMD
  LeftTexture.handle := Pointer(EyeLeftFB.ResolveTextureID);
  LeftTexture.eType := TextureType_OpenGL;
  LeftTexture.eColorSpace := ColorSpace_Gamma;
  RightTexture.handle := Pointer(EyeRightFB.ResolveTextureID);
  RightTexture.eType := TextureType_OpenGL;
  RightTexture.eColorSpace := ColorSpace_Gamma;
  CError := IVRCompositor^.Submit(Eye_Left, @LeftTexture, nil, Submit_Default);
  if CError <> VRCompositorError_None then
    Writeln('Error(Submit_Left): ', CError);
  CError := IVRCompositor^.Submit(Eye_Right, @RightTexture, nil, Submit_Default);
  if CError <> VRCompositorError_None then
    Writeln('Error(Submit_Right): ', CError);
  // Force HMD vsync
  glFinish;
  glFlush;
  glFinish;
end;
end.

В исходной демке в этом же модуле и на монитор выводится но я считаю отдельно .
До контролеров я не добрался но код для сопряжения с ними есть.
Главная фишка в том что для шлема создается отдельный OpenGL контекс но в принципе все решается через фрейм буфер и по идее может обходится даже софт-рендером .
Alex2013
долгожитель
 
Сообщения: 2922
Зарегистрирован: 03.04.2013 11:59:44

Re: OpenXR для FPC

Сообщение dedm0zaj » 24.03.2023 04:55:09

Alex2013 писал(а):Главная фишка в том что для шлема создается отдельный OpenGL контекс но в принципе все решается через фрейм буфер и по идее может обходится даже софт-рендером

в OpenXR отдельный контекст OpenGL не создается. берется тот же, что создается для окна WinAPI
dedm0zaj
постоялец
 
Сообщения: 108
Зарегистрирован: 05.10.2012 19:55:20

След.

Вернуться в Разное

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 1

Рейтинг@Mail.ru