Basic LWJGL/GLFW/OpenVR Example

Started by MKutschin, April 19, 2018, 12:19:58

Previous topic - Next topic

MKutschin

Can someone give me a super basic example of how to render some images to a HTC Vive using LWJGL, GLFW and OpenVR?

I get the VRCompositor to show me the default-grid with the controllers and basestations, but i'm not able to add anything to it.

I found an example, where the GLFW window is rendered to the Vive. He used
GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices();
to identify the HTC Vive as a monitor.
In a comment he wrote, that LWJGL3 doesn't support this anymore :-[. So i tried to identify the Vive with the GLFW method
glfwGetMonitors();

The result is an array of size 1 though (so he only finds the Default Monitor attached to the computer).  :'(


In a C++ OpenVR example i found this:
vr::Texture_t leftEyeTexture = {(void*)leftEyeTex, vr::API_OpenGL, colorSpace};
vr::Texture_t rightEyeTexture = {(void*)rightEyeTex, vr::API_OpenGL, colorSpace};
		
vr::VRCompositor()->Submit(vr::Eye_Left, &leftEyeTexture);
vr::VRCompositor()->Submit(vr::Eye_Right, &rightEyeTexture);

leftEyeTex and rightEyeTex where created using openGL.
So i tried to do this in Java:
Texture texture = Texture.create();
texture.set(modelTexture.getID(), ETextureType_TextureType_OpenGL, EColorSpace_ColorSpace_Auto);

VRCompositor.VRCompositor_Submit(EVREye_Eye_Left, texture, null, VR.EVRSubmitFlags_Submit_GlRenderBuffer);
VRCompositor.VRCompositor_Submit(EVREye_Eye_Right, texture, null, VR.EVRSubmitFlags_Submit_GlRenderBuffer);

texture is an OpenVR Texture, modelTexture was created with OpenGL.
This didnt work either  :'(

Thanks in advance!

spasi

You don't need to discover the HMD as a monitor afaik.

I can't help you much without seeing more code, but here are a couple of samples that you may find useful:

Minimal OpenVR + GLFW
OpenGL sample (from the OpenVR repository, uses SDL which is similar to GLFW)

MKutschin

Thanks for the quick answer!

I already looked through the "Minimal OpenVr + GLFW" example. Actually the C++ code i posted was from there ;)

What part of my code would you need?

spasi

As much of it as possible I guess. There are no hints to what may be wrong in what you posted above.

Before you post though, make sure there are no issues that are trivially discovered with the available tools:

- Run your application with -Dorg.lwjgl.util.Debug=true
- Create a debug OpenGL context and register a debug callback (glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GLFW_TRUE) and GLUtil.setupDebugMessageCallback())
- Try LWJGLX/debug

MKutschin

Debugging:
-Dorg.lwjgl.util.Debug=true:
unusual things:
[LWJGL] 	opengl32.dll not found in org.lwjgl.librarypath
[LWJGL] 	Loaded from system paths


and:
[LWJGL] [GL] GL_ARB_shader_subroutine was reported as available but an entry point is missing.


the other dll's were loaded normally.


the OpenGL debug context gave me lot of:
[LWJGL] OpenGL debug message
	ID: 0x20071
	Source: API
	Type: OTHER
	Severity: NOTIFICATION
	Message: Buffer detailed info: Buffer object 104 (bound to GL_ELEMENT_ARRAY_BUFFER_ARB, usage hint is GL_STATIC_DRAW) will use VIDEO memory as the source for buffer object operations.


and a few of:
[LWJGL] OpenGL debug message
	ID: 0x502
	Source: API
	Type: ERROR
	Severity: HIGH
	Message: GL_INVALID_OPERATION error generated. No active program.


I dont think these messages are generated by my code, because there's a game running, which was implemented by other students.


I removed all the try-blocks from the code.

Setting up VR:
System.out.println("VR_IsRuntimeInstalled() = " + VR_IsRuntimeInstalled());
System.out.println("VR_RuntimePath() = " + VR.VR_RuntimePath());
System.out.println("VR_IsHmdPresent() = " + VR_IsHmdPresent());

IntBuffer peError = stack.mallocInt(1);
int token = VR_InitInternal(peError, VR.EVRApplicationType_VRApplication_Scene);
if (peError.get(0) == 0) {
	OpenVR.create(token);

	System.out.println("Model Number : " + VRSystem_GetStringTrackedDeviceProperty(
		k_unTrackedDeviceIndex_Hmd, ETrackedDeviceProperty_Prop_ModelNumber_String, peError));
	System.out.println("Serial Number: " + VRSystem_GetStringTrackedDeviceProperty(
		k_unTrackedDeviceIndex_Hmd, ETrackedDeviceProperty_Prop_SerialNumber_String, peError));

	IntBuffer w = stack.mallocInt(1);
	IntBuffer h = stack.mallocInt(1);
	VRSystem_GetRecommendedRenderTargetSize(w, h);
	System.out.println("Recommended width : " + w.get(0));
	System.out.println("Recommended height: " + h.get(0));

} else {
	System.out.println("INIT ERROR SYMBOL: " + VR_GetVRInitErrorAsSymbol(peError.get(0)));
	System.out.println("INIT ERROR  DESCR: " + VR_GetVRInitErrorAsEnglishDescription(peError.get(0)));
	System.exit(-1);
}


i tried to follow the implementation of Minimal OpenVR + GLFW Example as strictly as possible, so the comments in the code mark the methods of the example.
// the following comments reference: https://gist.github.com/VirtuosoChris/272f803966e62796b83dce2a597adcc7#file-helloopenvr_glfw-cpp-L284
// main:
int tex = GL11.glGenTextures();
GL11.glBindTexture(GL11.GL_TEXTURE_2D, tex);
GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0,GL11.GL_RGBA, 1024, 768, 0,GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, 0);

// constructor of BasicRenderTarget
int fbo = GL30.glGenFramebuffers();
int rbo = GL30.glGenRenderbuffers();
GL30.glRenderbufferStorage(rbo, GL11.GL_RGBA, 1024, 768);
GL30.glBindRenderbuffer(GL30.GL_DEPTH_ATTACHMENT, fbo);
GL11.glViewport(0, 0, 1024, 768);
	
// BasicRenderTarget.prime
GL30.glBindFramebuffer(GL30.GL_FRAMEBUFFER, fbo);
GL30.glFramebufferTexture2D(GL30.GL_FRAMEBUFFER, GL30.GL_COLOR_ATTACHMENT0, GL11.GL_TEXTURE_2D, tex, 0);
GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT);
		
// main
GL11.glClearColor(1f, 0f, 0f, 1f);
GL30.glBindFramebuffer(GL30.GL_FRAMEBUFFER, fbo);
GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT);


VREvent vrEvent = new VREvent(bb);

// Process SteamVR events
while (VRSystem_PollNextEvent(vrEvent)) {
	processVREvent(vrEvent);
}

TrackedDevicePose.Buffer tdpb = TrackedDevicePose.create(k_unMaxTrackedDeviceCount);
TrackedDevicePose.Buffer tdpb2 = TrackedDevicePose.create(k_unMaxTrackedDeviceCount);

VRCompositor.VRCompositor_WaitGetPoses(tdpb, tdpb2);

			
Texture texture = Texture.create();
texture.set(tex, ETextureType_TextureType_OpenGL, EColorSpace_ColorSpace_Auto);
			
VRCompositor.VRCompositor_Submit(EVREye_Eye_Left, texture, null, VR.EVRSubmitFlags_Submit_GlRenderBuffer);
VRCompositor.VRCompositor_Submit(EVREye_Eye_Right, texture, null, VR.EVRSubmitFlags_Submit_GlRenderBuffer);

GL11.glFlush();
VRCompositor.VRCompositor_PostPresentHandoff();


i am completely new to OpenGL so pls be gentle  ;)

spasi

You may ignore OpenGL notifications, but errors must be eliminated. One thing you could do is enable synchronous error reporting (see GL43.GL_DEBUG_OUTPUT_SYNCHRONOUS) and register a custom debug callback that throws a Java exception (or use a breakpoint while debugging). This will let you know exactly which OpenGL call causes the error.

KaiHH

As @Spasi already pointed out, you could/should use LWJGLX/debug. It will either print the cause of the error (if it can validate it itself) or it will display a callstack in the installed synchronous OpenGL debug callback with the first stack trace element being _exactly_ the erroneous OpenGL call.
You can obtain the jar of LWJGLX/debug on https://www.lwjgl.org/customize under "Addons".
Start the JVM with `-javaagent:/path/to/lwjglx-debug-1.0.0.jar`

MKutschin

Sorry for my slow responses, but I have limited access to the HMD  :-\

I debuged the code using LWJGLX/debug, located and solved a lot of errors. some errors i cant solve are:
[error][1] OpenGL debug message
  ID: 0x502
  Source: API
  Type: ERROR
  Severity: HIGH
  Message: GL_INVALID_OPERATION error generated. Unknown buffer name.

[error][1] OpenGL debug message
  ID: 0x502
  Source: API
  Type: ERROR
  Severity: HIGH
  Message: GL_INVALID_OPERATION error generated. Invalid render buffer.

[error][1] OpenGL debug message
  ID: 0x506
  Source: API
  Type: ERROR
  Severity: HIGH
  Message: GL_INVALID_FRAMEBUFFER_OPERATION error generated. Framebuffer bindings are not framebuffer complete.


if i call
GL30.glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT);

I get "36053" as a result.
Acording to this post it means "GL_FRAMEBUFFER_COMPLETE".

I changed the creation of the texture, following this wiki (lines 119-137).

This is my code atm:
int tex = GL11.glGenTextures();
GL11.glBindTexture(GL11.GL_TEXTURE_2D, tex);
GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0,GL11.GL_RGBA8, 1024, 768, 0,GL11.GL_RGBA, GL11.GL_INT, (java.nio.ByteBuffer) null);
GL11.glTexParameterf(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR);
		
int fbo = glGenFramebuffersEXT();
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL11.GL_TEXTURE_2D, tex, 0);
		
int rbo = glGenRenderbuffersEXT();
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, rbo);
glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL14.GL_DEPTH_COMPONENT24, 1024, 768);
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, rbo);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
		
GL11.glViewport(0, 0, 1024, 768);
GL11.glBindTexture(GL11.GL_TEXTURE_2D, 0);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);
GL11.glClearColor(1f, 0f, 0f, 1f);
GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT);

glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
GL11.glClearColor(0f, 1f, 0f, 1f);
GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT);
GL11.glBindTexture(GL11.GL_TEXTURE_2D, tex);
GL11.glViewport(0, 0, 1024, 768);
		
int result = GL30.glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT);

// Handling VREvents and VRCompositors waitGetPoses 

Texture texture = Texture.create();
texture.set(tex, ETextureType_TextureType_OpenGL, EColorSpace_ColorSpace_Auto);

VRCompositor.VRCompositor_Submit(EVREye_Eye_Left, texture, null, VR.EVRSubmitFlags_Submit_GlRenderBuffer); // this line throws the exceptions


if i dont call
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);


i get the same result from the checkStatus call