From 435d7a9cf86aae9ab8e7e0404053933a51288392 Mon Sep 17 00:00:00 2001 From: bjorn Date: Mon, 26 Sep 2016 23:48:09 -0700 Subject: [PATCH] Projection matrices; --- src/graphics/graphics.c | 64 ++++++++++++++++++++++------------------- src/graphics/graphics.h | 11 ++++++- src/headset/headset.c | 20 +++++++++---- src/headset/headset.h | 4 +++ src/headset/vive.c | 64 ++++++++++++++++++++++------------------- src/headset/vive.h | 2 ++ src/lovr/graphics.c | 13 +++++++-- src/lovr/graphics.h | 1 + src/lovr/headset.c | 24 ++++++++++++++-- src/lovr/headset.h | 8 ++++-- src/matrix.c | 44 ++++++++++++++++++++++++++++ src/matrix.h | 3 ++ 12 files changed, 183 insertions(+), 75 deletions(-) diff --git a/src/graphics/graphics.c b/src/graphics/graphics.c index 4647cbed..15ed65be 100644 --- a/src/graphics/graphics.c +++ b/src/graphics/graphics.c @@ -10,24 +10,21 @@ #include #include "../headset/headset.h" -typedef struct { - Shader* activeShader; - vec_mat4_t transforms; - mat4 lastTransform; - mat4 projection; - mat4 lastProjection; -} GraphicsState; - -static GraphicsState graphicsState; +static GraphicsState state; void lovrGraphicsInit() { - vec_init(&graphicsState.transforms); - vec_push(&graphicsState.transforms, mat4_init()); - graphicsState.lastTransform = mat4_init(); - memset(graphicsState.lastTransform, 0, 16); - graphicsState.projection = mat4_init(); - graphicsState.lastProjection = mat4_init(); - memset(graphicsState.lastProjection, 0, 16); + vec_init(&state.transforms); + vec_push(&state.transforms, mat4_init()); + + state.projection = mat4_init(); + state.lastTransform = mat4_init(); + state.lastProjection = mat4_init(); + + memset(state.lastTransform, 0, 16); + memset(state.lastProjection, 0, 16); + + // TODO customize via lovr.conf + lovrGraphicsSetProjection(.1f, 100.f, 67 * M_PI / 180); } void lovrGraphicsClear(int color, int depth) { @@ -55,8 +52,8 @@ void lovrGraphicsPrepare() { return; } - mat4 transform = vec_last(&graphicsState.transforms); - mat4 lastTransform = graphicsState.lastTransform; + mat4 transform = vec_last(&state.transforms); + mat4 lastTransform = state.lastTransform; if (memcmp(transform, lastTransform, 16 * sizeof(float))) { int uniformId = lovrShaderGetUniformId(shader, "lovrTransform"); @@ -64,8 +61,8 @@ void lovrGraphicsPrepare() { memcpy(lastTransform, transform, 16 * sizeof(float)); } - mat4 projection = graphicsState.projection; - mat4 lastProjection = graphicsState.lastProjection; + mat4 projection = state.projection; + mat4 lastProjection = state.lastProjection; if (memcmp(projection, lastProjection, 16 * sizeof(float))) { int uniformId = lovrShaderGetUniformId(shader, "lovrProjection"); @@ -88,48 +85,55 @@ void lovrGraphicsSetClearColor(float r, float g, float b, float a) { } Shader* lovrGraphicsGetShader() { - return graphicsState.activeShader; + return state.activeShader; } // TODO default shader void lovrGraphicsSetShader(Shader* shader) { - graphicsState.activeShader = shader; + state.activeShader = shader; glUseProgram(shader->id); } -void lovrGraphicsSetProjection(float near, float far, float fov, float aspect) { - mat4_setProjection(graphicsState.projection, near, far, fov, aspect); +void lovrGraphicsGetProjection(float* near, float* far, float* fov) { + float aspect; + mat4_getProjection(state.projection, near, far, fov, &aspect); +} + +void lovrGraphicsSetProjection(float near, float far, float fov) { + int width, height; + glfwGetWindowSize(window, &width, &height); + mat4_setProjection(state.projection, near, far, fov, (float) width / height); } int lovrGraphicsPush() { - vec_mat4_t* transforms = &graphicsState.transforms; + vec_mat4_t* transforms = &state.transforms; if (transforms->length >= 64) { return 1; } vec_push(transforms, mat4_copy(vec_last(transforms))); return 0; } int lovrGraphicsPop() { - vec_mat4_t* transforms = &graphicsState.transforms; + vec_mat4_t* transforms = &state.transforms; if (transforms->length <= 1) { return 1; } mat4_deinit(vec_pop(transforms)); return 0; } void lovrGraphicsOrigin() { - vec_mat4_t* transforms = &graphicsState.transforms; + vec_mat4_t* transforms = &state.transforms; mat4_setIdentity(vec_last(transforms)); } void lovrGraphicsTranslate(float x, float y, float z) { - mat4_translate(vec_last(&graphicsState.transforms), x, y, z); + mat4_translate(vec_last(&state.transforms), x, y, z); } void lovrGraphicsRotate(float w, float x, float y, float z) { - mat4_rotate(vec_last(&graphicsState.transforms), w, x, y, z); + mat4_rotate(vec_last(&state.transforms), w, x, y, z); } void lovrGraphicsScale(float x, float y, float z) { - mat4_scale(vec_last(&graphicsState.transforms), x, y, z); + mat4_scale(vec_last(&state.transforms), x, y, z); } Buffer* lovrGraphicsNewBuffer(int size, BufferDrawMode drawMode, BufferUsage usage) { diff --git a/src/graphics/graphics.h b/src/graphics/graphics.h index baad5ca0..8c20d53d 100644 --- a/src/graphics/graphics.h +++ b/src/graphics/graphics.h @@ -6,6 +6,14 @@ #ifndef LOVR_GRAPHICS_TYPES #define LOVR_GRAPHICS_TYPES typedef vec_t(mat4) vec_mat4_t; + +typedef struct { + Shader* activeShader; + vec_mat4_t transforms; + mat4 lastTransform; + mat4 projection; + mat4 lastProjection; +} GraphicsState; #endif void lovrGraphicsInit(); @@ -16,7 +24,8 @@ void lovrGraphicsGetClearColor(float* r, float* g, float* b, float* a); void lovrGraphicsSetClearColor(float r, float g, float b, float a); Shader* lovrGraphicsGetShader(); void lovrGraphicsSetShader(Shader* shader); -void lovrGraphicsSetProjection(float near, float far, float fov, float aspect); +void lovrGraphicsGetProjection(float* near, float* far, float* fov); +void lovrGraphicsSetProjection(float near, float far, float fov); int lovrGraphicsPush(); int lovrGraphicsPop(); void lovrGraphicsOrigin(); diff --git a/src/headset/headset.c b/src/headset/headset.c index 3a669e5c..a4760e42 100644 --- a/src/headset/headset.c +++ b/src/headset/headset.c @@ -7,20 +7,24 @@ void lovrHeadsetInit() { headset = viveInit(); } -void lovrHeadsetGetPosition(float* x, float* y, float* z) { - headset->interface->getPosition(headset, x, y, z); +void lovrHeadsetGetAngularVelocity(float* x, float* y, float* z) { + headset->interface->getAngularVelocity(headset, x, y, z); +} + +void lovrHeadsetGetClipDistance(float* near, float* far) { + headset->interface->getClipDistance(headset, near, far); } void lovrHeadsetGetOrientation(float* x, float* y, float* z, float* w) { headset->interface->getOrientation(headset, x, y, z, w); } -void lovrHeadsetGetVelocity(float* x, float* y, float* z) { - headset->interface->getVelocity(headset, x, y, z); +void lovrHeadsetGetPosition(float* x, float* y, float* z) { + headset->interface->getPosition(headset, x, y, z); } -void lovrHeadsetGetAngularVelocity(float* x, float* y, float* z) { - headset->interface->getAngularVelocity(headset, x, y, z); +void lovrHeadsetGetVelocity(float* x, float* y, float* z) { + headset->interface->getVelocity(headset, x, y, z); } int lovrHeadsetIsPresent() { @@ -30,3 +34,7 @@ int lovrHeadsetIsPresent() { void lovrHeadsetRenderTo(headsetRenderCallback callback, void* userdata) { headset->interface->renderTo(headset, callback, userdata); } + +void lovrHeadsetSetClipDistance(float near, float far) { + headset->interface->setClipDistance(headset, near, far); +} diff --git a/src/headset/headset.h b/src/headset/headset.h index a94ef47b..f61ed4e8 100644 --- a/src/headset/headset.h +++ b/src/headset/headset.h @@ -4,12 +4,14 @@ typedef void (*headsetRenderCallback)(int eyeIndex, void* userdata); typedef struct { void (*getAngularVelocity)(void* headset, float* x, float* y, float* z); + void (*getClipDistance)(void* headset, float* near, float* far); void (*getOrientation)(void* headset, float* x, float* y, float* z, float* w); void (*getPosition)(void* headset, float* x, float* y, float* z); const char* (*getType)(void* headset); void (*getVelocity)(void* headset, float* x, float* y, float* z); int (*isPresent)(void* headset); void (*renderTo)(void* headset, headsetRenderCallback callback, void* userdata); + void (*setClipDistance)(void* headset, float near, float far); } HeadsetInterface; typedef struct { @@ -20,9 +22,11 @@ typedef struct { void lovrHeadsetInit(); void lovrHeadsetGetAngularVelocity(float* x, float* y, float* z); +void lovrHeadsetGetClipDistance(float* near, float* far); void lovrHeadsetGetOrientation(float* x, float* y, float* z, float* w); void lovrHeadsetGetPosition(float* x, float* y, float* z); const char* lovrHeadsetGetType(); void lovrHeadsetGetVelocity(float* x, float* y, float* z); int lovrHeadsetIsPresent(); void lovrHeadsetRenderTo(headsetRenderCallback callback, void* userdata); +void lovrHeadsetSetClipDistance(float near, float far); diff --git a/src/headset/vive.c b/src/headset/vive.c index 63e975f8..b2090c57 100644 --- a/src/headset/vive.c +++ b/src/headset/vive.c @@ -10,6 +10,9 @@ typedef struct { unsigned int deviceIndex; + float clipNear; + float clipFar; + uint32_t renderWidth; uint32_t renderHeight; @@ -44,7 +47,7 @@ Headset* viveInit() { } EVRInitError vrError; - uint32_t vrHandle = VR_InitInternal(&vrError, EVRApplicationType_VRApplication_Scene); + VR_InitInternal(&vrError, EVRApplicationType_VRApplication_Scene); if (vrError != EVRInitError_VRInitError_None) { error("Problem initializing OpenVR"); @@ -127,6 +130,13 @@ void viveGetAngularVelocity(void* headset, float* x, float* y, float* z) { *z = pose.vAngularVelocity.v[2]; } +void viveGetClipDistance(void* headset, float* near, float* far) { + Headset* this = (Headset*) headset; + ViveState* state = this->state; + *near = state->clipNear; + *far = state->clipFar; +} + // TODO convert matrix to quaternion! void viveGetOrientation(void* headset, float* x, float* y, float *z, float* w) { *x = *y = *z = *w = 0.f; @@ -184,46 +194,32 @@ int viveIsPresent(void* headset) { void viveRenderTo(void* headset, headsetRenderCallback callback, void* userdata) { Headset* this = headset; ViveState* state = this->state; - + float headMatrix[16], eyeMatrix[16], projectionMatrix[16]; + float (*matrix)[4]; + EGraphicsAPIConvention graphicsConvention = EGraphicsAPIConvention_API_OpenGL; TrackedDevicePose_t pose; + state->vrCompositor->WaitGetPoses(&pose, 1, NULL, 0); - - float (*m)[4]; - m = pose.mDeviceToAbsoluteTracking.m; - float headMatrix[16] = { - m[0][0], m[1][0], m[2][0], 0.0, - m[0][1], m[1][1], m[2][1], 0.0, - m[0][2], m[1][2], m[2][2], 0.0, - m[0][3], m[1][3], m[2][3], 1.0 - }; - - mat4_invert(headMatrix); + matrix = pose.mDeviceToAbsoluteTracking.m; + mat4_invert(mat4_fromMat34(headMatrix, matrix)); for (int i = 0; i < 2; i++) { EVREye eye = (i == 0) ? EVREye_Eye_Left : EVREye_Eye_Right; - m = state->vrSystem->GetEyeToHeadTransform(eye).m; - float eyeMatrix[16] = { - m[0][0], m[1][0], m[2][0], 0.0, - m[0][1], m[1][1], m[2][1], 0.0, - m[0][2], m[1][2], m[2][2], 0.0, - m[0][3], m[1][3], m[2][3], 1.0 - }; + matrix = state->vrSystem->GetEyeToHeadTransform(eye).m; + mat4_invert(mat4_fromMat34(eyeMatrix, matrix)); - m = state->vrSystem->GetProjectionMatrix(eye, 0.1f, 30.0f, EGraphicsAPIConvention_API_OpenGL).m; - float projectionMatrix[16] = { - m[0][0], m[1][0], m[2][0], m[3][0], - m[0][1], m[1][1], m[2][1], m[3][1], - m[0][2], m[1][2], m[2][2], m[3][2], - m[0][3], m[1][3], m[2][3], m[3][3] - }; + float near = state->clipNear; + float far = state->clipFar; + matrix = state->vrSystem->GetProjectionMatrix(eye, near, far, graphicsConvention).m; + mat4_fromMat44(projectionMatrix, matrix); Shader* shader = lovrGraphicsGetShader(); if (shader) { int lovrTransformId = lovrShaderGetUniformId(shader, "lovrTransform"); int lovrProjectionId = lovrShaderGetUniformId(shader, "lovrProjection"); - mat4 m = mat4_multiply(mat4_multiply(projectionMatrix, mat4_invert(eyeMatrix)), headMatrix); - lovrShaderSendFloatMat4(shader, lovrTransformId, m); + mat4 transformMatrix = mat4_multiply(eyeMatrix, headMatrix); + lovrShaderSendFloatMat4(shader, lovrTransformId, transformMatrix); lovrShaderSendFloatMat4(shader, lovrProjectionId, projectionMatrix); } @@ -243,8 +239,16 @@ void viveRenderTo(void* headset, headsetRenderCallback callback, void* userdata) glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); - Texture_t eyeTexture = { (void*) state->resolveTexture, EGraphicsAPIConvention_API_OpenGL, EColorSpace_ColorSpace_Gamma }; + Texture_t eyeTexture = { (void*) state->resolveTexture, graphicsConvention, EColorSpace_ColorSpace_Gamma }; EVRSubmitFlags flags = EVRSubmitFlags_Submit_Default; state->vrCompositor->Submit(eye, &eyeTexture, NULL, flags); } } + +void viveSetClipDistance(void* headset, float near, float far) { + Headset* this = (Headset*) headset; + ViveState* state = this->state; + state->clipNear = near; + state->clipFar = far; + // TODO recompute matrix (only if we're rendering?) +} diff --git a/src/headset/vive.h b/src/headset/vive.h index 555c5b17..0ec29b3a 100644 --- a/src/headset/vive.h +++ b/src/headset/vive.h @@ -4,9 +4,11 @@ typedef char bool; Headset* viveInit(); void viveGetAngularVelocity(void* headset, float* x, float* y, float* z); +void viveGetClipDistance(void* headset, float* near, float* far); void viveGetOrientation(void* headset, float* x, float* y, float* z, float* w); void viveGetPosition(void* headset, float* x, float* y, float* z); const char* viveGetType(void* headset); void viveGetVelocity(void* headset, float* x, float* y, float* z); int viveIsPresent(void* headset); void viveRenderTo(void* headset, headsetRenderCallback callback, void* userdata); +void viveSetClipDistance(void* headset, float near, float far); diff --git a/src/lovr/graphics.c b/src/lovr/graphics.c index ccf8aa25..55f37090 100644 --- a/src/lovr/graphics.c +++ b/src/lovr/graphics.c @@ -11,6 +11,7 @@ const luaL_Reg lovrGraphics[] = { { "getClearColor", l_lovrGraphicsGetClearColor }, { "setClearColor", l_lovrGraphicsSetClearColor }, { "setShader", l_lovrGraphicsSetShader }, + { "getProjection", l_lovrGraphicsGetProjection }, { "setProjection", l_lovrGraphicsSetProjection }, { "push", l_lovrGraphicsPush }, { "pop", l_lovrGraphicsPop }, @@ -91,12 +92,20 @@ int l_lovrGraphicsSetShader(lua_State* L) { return 0; } +int l_lovrGraphicsGetProjection(lua_State* L) { + float near, far, fov; + lovrGraphicsGetProjection(&near, &far, &fov); + lua_pushnumber(L, near); + lua_pushnumber(L, far); + lua_pushnumber(L, fov); + return 3; +} + int l_lovrGraphicsSetProjection(lua_State* L) { float near = luaL_checknumber(L, 1); float far = luaL_checknumber(L, 2); float fov = luaL_checknumber(L, 3); - float aspect = luaL_checknumber(L, 4); - lovrGraphicsSetProjection(near, far, fov, aspect); + lovrGraphicsSetProjection(near, far, fov); return 0; } diff --git a/src/lovr/graphics.h b/src/lovr/graphics.h index 730cbd60..d5576ea0 100644 --- a/src/lovr/graphics.h +++ b/src/lovr/graphics.h @@ -14,6 +14,7 @@ int l_lovrGraphicsGetClearColor(lua_State* L); int l_lovrGraphicsSetClearColor(lua_State* L); int l_lovrGraphicsGetShader(lua_State* L); int l_lovrGraphicsSetShader(lua_State* L); +int l_lovrGraphicsGetProjection(lua_State* L); int l_lovrGraphicsSetProjection(lua_State* L); int l_lovrGraphicsPush(lua_State* L); int l_lovrGraphicsPop(lua_State* L); diff --git a/src/lovr/headset.c b/src/lovr/headset.c index 9b1441b1..69827e2a 100644 --- a/src/lovr/headset.c +++ b/src/lovr/headset.c @@ -10,12 +10,14 @@ void renderHelper(int eyeIndex, void* userdata) { } const luaL_Reg lovrHeadset[] = { - { "getPosition", l_lovrHeadsetGetPosition }, - { "getOrientation", l_lovrHeadsetGetPosition }, - { "getVelocity", l_lovrHeadsetGetVelocity }, { "getAngularVelocity", l_lovrHeadsetGetAngularVelocity }, + { "getClipDistance", l_lovrHeadsetGetClipDistance }, + { "getOrientation", l_lovrHeadsetGetPosition }, + { "getPosition", l_lovrHeadsetGetPosition }, + { "getVelocity", l_lovrHeadsetGetVelocity }, { "isPresent", l_lovrHeadsetIsPresent }, { "renderTo", l_lovrHeadsetRenderTo }, + { "setClipDistance", l_lovrHeadsetSetClipDistance }, { NULL, NULL } }; @@ -35,6 +37,14 @@ int l_lovrHeadsetGetAngularVelocity(lua_State* L) { return 3; } +int l_lovrHeadsetGetClipDistance(lua_State* L) { + float near, far; + lovrHeadsetGetClipDistance(&near, &far); + lua_pushnumber(L, near); + lua_pushnumber(L, far); + return 2; +} + int l_lovrHeadsetGetOrientation(lua_State* L) { float x, y, z, w; lovrHeadsetGetOrientation(&x, &y, &z, &w); @@ -73,3 +83,11 @@ int l_lovrHeadsetRenderTo(lua_State* L) { lovrHeadsetRenderTo(renderHelper, L); return 0; } + +int l_lovrHeadsetSetClipDistance(lua_State* L) { + float near = luaL_checknumber(L, 1); + float far = luaL_checknumber(L, 2); + lovrHeadsetSetClipDistance(near, far); + return 0; +} + diff --git a/src/lovr/headset.h b/src/lovr/headset.h index a911d2da..12f28174 100644 --- a/src/lovr/headset.h +++ b/src/lovr/headset.h @@ -4,9 +4,11 @@ extern const luaL_Reg lovrHeadset[]; int l_lovrHeadsetInit(lua_State* L); -int l_lovrHeadsetGetPosition(lua_State* L); -int l_lovrHeadsetGetOrientation(lua_State* L); -int l_lovrHeadsetGetVelocity(lua_State* L); int l_lovrHeadsetGetAngularVelocity(lua_State* L); +int l_lovrHeadsetGetClipDistance(lua_State* L); +int l_lovrHeadsetGetOrientation(lua_State* L); +int l_lovrHeadsetGetPosition(lua_State* L); +int l_lovrHeadsetGetVelocity(lua_State* L); int l_lovrHeadsetIsPresent(lua_State* L); int l_lovrHeadsetRenderTo(lua_State* L); +int l_lovrHeadsetSetClipDistance(lua_State* L); diff --git a/src/matrix.c b/src/matrix.c index 2296d0ca..ae2e3b4e 100644 --- a/src/matrix.c +++ b/src/matrix.c @@ -21,6 +21,46 @@ mat4 mat4_copy(mat4 source) { return matrix; } +mat4 mat4_fromMat34(mat4 matrix, float (*source)[4]) { + matrix[0] = source[0][0]; + matrix[1] = source[1][0]; + matrix[2] = source[2][0]; + matrix[3] = 0.f; + matrix[4] = source[0][1]; + matrix[5] = source[1][1]; + matrix[6] = source[2][1]; + matrix[7] = 0.f; + matrix[8] = source[0][2]; + matrix[9] = source[1][2]; + matrix[10] = source[2][2]; + matrix[11] = 0.f; + matrix[12] = source[0][3]; + matrix[13] = source[1][3]; + matrix[14] = source[2][3]; + matrix[15] = 1.f; + return matrix; +} + +mat4 mat4_fromMat44(mat4 matrix, float (*source)[4]) { + matrix[0] = source[0][0]; + matrix[1] = source[1][0]; + matrix[2] = source[2][0]; + matrix[3] = source[3][0]; + matrix[4] = source[0][1]; + matrix[5] = source[1][1]; + matrix[6] = source[2][1]; + matrix[7] = source[3][1]; + matrix[8] = source[0][2]; + matrix[9] = source[1][2]; + matrix[10] = source[2][2]; + matrix[11] = source[3][2]; + matrix[12] = source[0][3]; + matrix[13] = source[1][3]; + matrix[14] = source[2][3]; + matrix[15] = source[3][3]; + return matrix; +} + void mat4_deinit(mat4 matrix) { free(matrix); } @@ -77,6 +117,10 @@ mat4 mat4_setProjection(mat4 matrix, float near, float far, float fov, float asp return matrix; } +void mat4_getProjection(mat4 matrix, float* near, float* far, float* fov, float* aspect) { + *near = *far = *fov = *aspect = 0.f; +} + mat4 mat4_translate(mat4 matrix, float x, float y, float z) { float translation[16]; mat4_setTranslation(translation, x, y, z); diff --git a/src/matrix.h b/src/matrix.h index 99ee611c..fd3723a3 100644 --- a/src/matrix.h +++ b/src/matrix.h @@ -3,11 +3,14 @@ typedef float* mat4; mat4 mat4_init(); void mat4_deinit(mat4 matrix); mat4 mat4_copy(mat4 source); +mat4 mat4_fromMat34(mat4 matrix, float (*source)[4]); +mat4 mat4_fromMat44(mat4 matrix, float (*source)[4]); mat4 mat4_setIdentity(mat4 matrix); mat4 mat4_setTranslation(mat4 matrix, float x, float y, float z); mat4 mat4_setRotation(mat4 matrix, float w, float x, float y, float z); mat4 mat4_setScale(mat4 matrix, float x, float y, float z); mat4 mat4_setProjection(mat4 matrix, float near, float far, float fov, float aspect); +void mat4_getProjection(mat4 matrix, float* near, float* far, float* fov, float* aspect); mat4 mat4_translate(mat4 matrix, float x, float y, float z); mat4 mat4_rotate(mat4 matrix, float w, float x, float y, float z); mat4 mat4_scale(mat4 matrix, float x, float y, float z);