Commit 88022c87 authored by Lubosz Sarnecki's avatar Lubosz Sarnecki

scene: Implement pointer tip lighting.

Implement a pointer tip light source based on attenuation.
The light will be only received on buttons.
parent d80c0a9f
......@@ -7,21 +7,87 @@
#version 460
#extension GL_ARB_separate_shader_objects : enable
#extension GL_EXT_scalar_block_layout : enable
layout (location = 0) in vec2 uv;
const float shininess = 16.0f;
const float ambient = 0.5f;
layout (location = 0) in vec4 world_position;
layout (location = 1) in vec4 view_position;
layout (location = 2) in vec2 uv;
layout (binding = 0) uniform Transformation {
mat4 mvp;
mat4 mv;
mat4 m;
bool receive_light;
} transformation;
layout (binding = 1) uniform sampler2D image;
layout (binding = 2) uniform Shading {
layout (binding = 2) uniform Window {
vec4 color;
bool flip_y;
} ubo;
} window;
struct Light {
vec4 position;
vec4 color;
float radius;
float unused[3];
};
layout (std430, binding = 3) uniform Lights
{
Light lights[2];
int active_lights;
} lights;
layout (location = 0) out vec4 out_color;
const float intensity = 2.0f;
const vec3 light_color_max = vec3(1.0f, 1.0f, 1.0f);
// "Lighten only" blending
vec3 lighten (vec3 a, vec3 b)
{
vec3 c;
c.r = max (a.r, b.r);
c.g = max (a.g, b.g);
c.b = max (a.b, b.b);
return c;
}
void main ()
{
vec2 uv_b = ubo.flip_y ? vec2(uv.x, 1.0f - uv.y) : uv;
out_color = texture (image, uv_b) * ubo.color;
vec2 uv_b = window.flip_y ? vec2 (uv.x, 1.0f - uv.y) : uv;
vec4 texture_color = texture (image, uv_b);
if (!transformation.receive_light)
{
out_color = texture_color * window.color;
return;
}
vec4 diffuse = mix (texture_color * window.color, texture_color, 0.5f);
vec3 lit = vec3 (0);
float view_distance = length (view_position.xyz);
for (int i = 0; i < lights.active_lights; i++)
{
vec3 L = lights.lights[i].position.xyz - world_position.xyz;
float d = length (L);
float radius = lights.lights[i].radius * view_distance;
float atten = intensity / ((d / radius) + 1.0);
vec3 light_gradient = mix (lights.lights[i].color.xyz,
light_color_max,
atten * 0.5f);
lit += light_gradient * diffuse.rgb * atten;
}
out_color = vec4 (lighten (lit, diffuse.rgb), 1.0f);
}
......@@ -10,19 +10,31 @@
layout (binding = 0) uniform Transformation {
mat4 mvp;
} ubo;
mat4 mv;
mat4 m;
bool receive_light;
} transformation;
layout (location = 0) in vec3 position;
layout (location = 1) in vec2 uv;
layout (location = 0) out vec2 out_uv;
layout (location = 0) out vec4 out_world_position;
layout (location = 1) out vec4 out_view_position;
layout (location = 2) out vec2 out_uv;
out gl_PerVertex {
vec4 gl_Position;
};
void main() {
gl_Position = ubo.mvp * vec4 (position, 1.0);
gl_Position = transformation.mvp * vec4 (position, 1.0f);
gl_Position.y = -gl_Position.y;
out_uv = uv;
if (!transformation.receive_light)
return;
out_world_position = transformation.m * vec4 (position, 1.0f);
out_view_position = transformation.mv * vec4 (position, 1.0f);
}
......@@ -57,6 +57,9 @@ graphene_matrix_t _get_hmd_pose_matrix (EVREye eye);
graphene_matrix_t _get_view_projection_matrix (XrdSceneClient *self,
EVREye eye);
graphene_matrix_t
_get_view_matrix (XrdSceneClient *self, EVREye eye);
void _update_matrices (XrdSceneClient *self);
void _update_device_poses (XrdSceneClient *self);
void _render_stereo (XrdSceneClient *self, VkCommandBuffer cmd_buffer);
......@@ -172,6 +175,24 @@ _render_pointers (XrdSceneClient *self,
g_list_free (controllers);
}
/*
* Since we are using world space positons for the lights, this only needs
* to be run once for both eyes
*/
static void
_update_lights_cb (gpointer _self)
{
XrdSceneClient *self = XRD_SCENE_CLIENT (_self);
GList *controllers =
g_hash_table_get_values (xrd_client_get_controllers (XRD_CLIENT (self)));
XrdSceneRenderer *renderer = xrd_scene_renderer_get_instance ();
xrd_scene_renderer_update_lights (renderer, controllers);
g_list_free (controllers);
}
static void
_render_eye_cb (uint32_t eye,
VkCommandBuffer cmd_buffer,
......@@ -182,6 +203,7 @@ _render_eye_cb (uint32_t eye,
XrdSceneClient *self = XRD_SCENE_CLIENT (_self);
graphene_matrix_t vp = _get_view_projection_matrix (self, eye);
graphene_matrix_t view = _get_view_matrix (self, eye);
XrdWindowManager *manager = xrd_client_get_manager (XRD_CLIENT (self));
......@@ -201,10 +223,11 @@ _render_eye_cb (uint32_t eye,
for (GSList *l = xrd_window_manager_get_buttons (manager);
l != NULL; l = l->next)
{
xrd_scene_window_draw (XRD_SCENE_WINDOW (l->data), eye,
xrd_scene_window_draw_shaded (XRD_SCENE_WINDOW (l->data), eye,
pipelines[PIPELINE_WINDOWS],
pipeline_layout,
cmd_buffer, &vp);
cmd_buffer, &view,
&self->mat_projection[eye]);
}
_render_pointers (self, eye, cmd_buffer, pipelines, pipeline_layout, &vp);
......@@ -277,6 +300,7 @@ _init_vulkan (XrdSceneClient *self)
vkQueueWaitIdle (gulkan_device_get_queue_handle (device));
xrd_scene_renderer_set_render_cb (renderer, _render_eye_cb, self);
xrd_scene_renderer_set_update_lights_cb (renderer, _update_lights_cb, self);
return true;
}
......@@ -392,6 +416,15 @@ _get_view_projection_matrix (XrdSceneClient *self, EVREye eye)
return mat;
}
graphene_matrix_t
_get_view_matrix (XrdSceneClient *self, EVREye eye)
{
graphene_matrix_t mat;
graphene_matrix_init_from_matrix (&mat, &self->mat_head_pose);
graphene_matrix_multiply (&mat, &self->mat_eye_pos[eye], &mat);
return mat;
}
static GulkanClient *
_get_uploader (XrdClient *client)
{
......
......@@ -11,10 +11,18 @@
#include "xrd-scene-renderer.h"
#include "graphene-ext.h"
typedef struct {
float mvp[16];
float mv[16];
float m[16];
bool receive_light;
} XrdSceneObjectTransformation;
typedef struct _XrdSceneObjectPrivate
{
GObject parent;
XrdSceneObjectTransformation transformation[2];
GulkanUniformBuffer *uniform_buffers[2];
VkDescriptorPool descriptor_pool;
......@@ -99,9 +107,48 @@ xrd_scene_object_update_mvp_matrix (XrdSceneObject *self,
graphene_matrix_t mvp;
graphene_matrix_multiply (&priv->model_matrix, vp, &mvp);
graphene_matrix_to_float (&mvp, priv->transformation[eye].mvp);
priv->transformation[eye].receive_light = false;
/* Update matrix in uniform buffer */
gulkan_uniform_buffer_update_matrix (priv->uniform_buffers[eye], &mvp);
gulkan_uniform_buffer_update_struct (priv->uniform_buffers[eye],
(gpointer) &priv->transformation[eye]);
}
void
xrd_scene_object_update_transformation_buffer (XrdSceneObject *self,
EVREye eye,
graphene_matrix_t *view,
graphene_matrix_t *projection)
{
XrdSceneObjectPrivate *priv = xrd_scene_object_get_instance_private (self);
graphene_matrix_t vp;
graphene_matrix_multiply (view, projection, &vp);
graphene_matrix_to_float (&priv->model_matrix, priv->transformation[eye].m);
graphene_matrix_t mv;
graphene_matrix_multiply (&priv->model_matrix, view, &mv);
graphene_matrix_to_float (&mv, priv->transformation[eye].mv);
graphene_matrix_t mvp;
graphene_matrix_multiply (&priv->model_matrix, &vp, &mvp);
graphene_matrix_to_float (&mvp, priv->transformation[eye].mvp);
priv->transformation[eye].receive_light = true;
gulkan_uniform_buffer_update_struct (priv->uniform_buffers[eye],
(gpointer) &priv->transformation[eye]);
}
void
xrd_scene_object_get_model_matrix (XrdSceneObject *self,
graphene_matrix_t *model_matrix)
{
XrdSceneObjectPrivate *priv = xrd_scene_object_get_instance_private (self);
graphene_matrix_init_from_matrix (model_matrix, &priv->model_matrix);
}
void
......@@ -133,6 +180,14 @@ xrd_scene_object_set_position (XrdSceneObject *self,
_update_model_matrix (self);
}
void
xrd_scene_object_get_position (XrdSceneObject *self,
graphene_point3d_t *position)
{
XrdSceneObjectPrivate *priv = xrd_scene_object_get_instance_private (self);
graphene_point3d_init_from_point (position, &priv->position);
}
void
xrd_scene_object_set_rotation_euler (XrdSceneObject *self,
graphene_euler_t *euler)
......@@ -153,7 +208,7 @@ xrd_scene_object_initialize (XrdSceneObject *self,
/* Create uniform buffer to hold a matrix per eye */
for (uint32_t eye = 0; eye < 2; eye++)
if (!gulkan_uniform_buffer_allocate_and_map (priv->uniform_buffers[eye],
device, sizeof (float) * 16))
device, sizeof (XrdSceneObjectTransformation)))
return FALSE;
uint32_t set_count = 2;
......@@ -167,6 +222,10 @@ xrd_scene_object_initialize (XrdSceneObject *self,
.descriptorCount = set_count,
.type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER
},
{
.descriptorCount = set_count,
.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER
},
{
.descriptorCount = set_count,
.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER
......
......@@ -44,6 +44,10 @@ void
xrd_scene_object_set_position (XrdSceneObject *self,
graphene_point3d_t *position);
void
xrd_scene_object_get_position (XrdSceneObject *self,
graphene_point3d_t *position);
void
xrd_scene_object_set_rotation_euler (XrdSceneObject *self,
graphene_euler_t *euler);
......@@ -53,6 +57,16 @@ xrd_scene_object_update_mvp_matrix (XrdSceneObject *self,
EVREye eye,
graphene_matrix_t *vp);
void
xrd_scene_object_update_transformation_buffer (XrdSceneObject *self,
EVREye eye,
graphene_matrix_t *view,
graphene_matrix_t *projection);
void
xrd_scene_object_get_model_matrix (XrdSceneObject *self,
graphene_matrix_t *model_matrix);
void
xrd_scene_object_bind (XrdSceneObject *self,
EVREye eye,
......
......@@ -12,11 +12,29 @@
#include <gulkan.h>
#include <openvr-glib.h>
#include "xrd-controller.h"
#include "xrd-scene-pointer.h"
#include "xrd-scene-pointer-tip.h"
#include "graphene-ext.h"
typedef struct {
graphene_point3d_t position;
graphene_point_t uv;
} XrdSceneVertex;
typedef struct {
float position[4];
float color[4];
float radius;
float unused[3];
} XrdSceneLight;
typedef struct {
XrdSceneLight lights[2];
int active_lights;
} XrdSceneLights;
struct _XrdSceneRenderer
{
GulkanClient parent;
......@@ -35,7 +53,10 @@ struct _XrdSceneRenderer
uint32_t render_width;
uint32_t render_height;
gpointer render_cb_data;
gpointer scene_client;
XrdSceneLights lights;
GulkanUniformBuffer *lights_buffer;
void
(*render_eye) (uint32_t eye,
......@@ -43,6 +64,8 @@ struct _XrdSceneRenderer
VkPipelineLayout pipeline_layout,
VkPipeline *pipelines,
gpointer data);
void (*update_lights) (gpointer data);
};
G_DEFINE_TYPE (XrdSceneRenderer, xrd_scene_renderer, GULKAN_TYPE_CLIENT)
......@@ -63,7 +86,22 @@ xrd_scene_renderer_init (XrdSceneRenderer *self)
self->msaa_sample_count = VK_SAMPLE_COUNT_4_BIT;
self->super_sample_scale = 1.0f;
self->render_eye = NULL;
self->render_cb_data = NULL;
self->scene_client = NULL;
self->lights_buffer = gulkan_uniform_buffer_new ();
self->lights.active_lights = 0;
graphene_vec4_t position;
graphene_vec4_init (&position, 0, 0, 0, 1);
graphene_vec4_t color;
graphene_vec4_init (&color,.078f, .471f, .675f, 1);
for (uint32_t i = 0; i < 2; i++)
{
graphene_vec4_to_float (&position, self->lights.lights[i].position);
graphene_vec4_to_float (&color, self->lights.lights[i].color);
self->lights.lights[i].radius = 0.1f;
}
self->descriptor_set_layout = VK_NULL_HANDLE;
self->pipeline_layout = VK_NULL_HANDLE;
......@@ -84,6 +122,8 @@ xrd_scene_renderer_finalize (GObject *gobject)
if (device != VK_NULL_HANDLE)
{
g_object_unref (self->lights_buffer);
for (uint32_t eye = 0; eye < 2; eye++)
g_object_unref (self->framebuffer[eye]);
......@@ -177,26 +217,36 @@ _init_descriptor_layout (XrdSceneRenderer *self)
{
VkDescriptorSetLayoutCreateInfo info = {
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
.bindingCount = 3,
.bindingCount = 4,
.pBindings = (VkDescriptorSetLayoutBinding[]) {
// mvp buffer
{
.binding = 0,
.descriptorCount = 1,
.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
.stageFlags = VK_SHADER_STAGE_VERTEX_BIT
.stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT
},
// Window and device texture
{
.binding = 1,
.descriptorCount = 1,
.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT
},
// Window buffer
{
.binding = 2,
.descriptorCount = 1,
.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT
},
// Lights buffer
{
.binding = 3,
.descriptorCount = 1,
.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT
},
}
};
......@@ -525,6 +575,11 @@ _init_vulkan (XrdSceneRenderer *self)
if (!_init_shaders (self))
return false;
GulkanDevice *device = gulkan_client_get_device (GULKAN_CLIENT (self));
if (!gulkan_uniform_buffer_allocate_and_map (self->lights_buffer,
device, sizeof (XrdSceneLights)))
return false;
if (!_init_descriptor_layout (self))
return false;
if (!_init_pipeline_layout (self))
......@@ -587,18 +642,51 @@ _render_stereo (XrdSceneRenderer *self, VkCommandBuffer cmd_buffer)
if (self->render_eye)
self->render_eye (eye, cmd_buffer, self->pipeline_layout,
self->pipelines, self->render_cb_data);
self->pipelines, self->scene_client);
vkCmdEndRenderPass (cmd_buffer);
}
}
void
xrd_scene_renderer_update_lights (XrdSceneRenderer *self,
GList *controllers)
{
self->lights.active_lights = (int) g_list_length (controllers);
if (self->lights.active_lights > 2)
{
g_warning ("Update lights received more than 2 controllers.\n");
self->lights.active_lights = 2;
}
for (int i = 0; i < self->lights.active_lights; i++)
{
GList *l = g_list_nth (controllers, (guint) i);
XrdController *controller = XRD_CONTROLLER (l->data);
XrdScenePointerTip *scene_tip =
XRD_SCENE_POINTER_TIP (xrd_controller_get_pointer_tip (controller));
graphene_point3d_t tip_position;
xrd_scene_object_get_position (XRD_SCENE_OBJECT (scene_tip), &tip_position);
self->lights.lights[i].position[0] = tip_position.x;
self->lights.lights[i].position[1] = tip_position.y;
self->lights.lights[i].position[2] = tip_position.z;
}
gulkan_uniform_buffer_update_struct (self->lights_buffer,
(gpointer) &self->lights);
}
static void
_draw (XrdSceneRenderer *self)
{
GulkanCommandBuffer cmd_buffer;
gulkan_client_begin_cmd_buffer (GULKAN_CLIENT (self), &cmd_buffer);
self->update_lights (self->scene_client);
_render_stereo (self, cmd_buffer.handle);
vkEndCommandBuffer (cmd_buffer.handle);
......@@ -654,10 +742,19 @@ xrd_scene_renderer_set_render_cb (XrdSceneRenderer *self,
VkPipelineLayout pipeline_layout,
VkPipeline *pipelines,
gpointer data),
gpointer data)
gpointer scene_client)
{
self->render_eye = render_eye;
self->render_cb_data = data;
self->scene_client = scene_client;
}
void
xrd_scene_renderer_set_update_lights_cb (XrdSceneRenderer *self,
void (*update_lights) (gpointer data),
gpointer scene_client)
{
self->update_lights = update_lights;
self->scene_client = scene_client;
}
GulkanDevice*
......@@ -666,3 +763,9 @@ xrd_scene_renderer_get_device ()
XrdSceneRenderer *self = xrd_scene_renderer_get_instance ();
return gulkan_client_get_device (GULKAN_CLIENT (self));
}
VkBuffer
xrd_scene_renderer_get_lights_buffer_handle (XrdSceneRenderer *self)
{
return gulkan_uniform_buffer_get_handle (self->lights_buffer);
}
......@@ -59,7 +59,19 @@ xrd_scene_renderer_set_render_cb (XrdSceneRenderer *self,
VkPipelineLayout pipeline_layout,
VkPipeline *pipelines,
gpointer data),
gpointer data);
gpointer scene_client);
void
xrd_scene_renderer_set_update_lights_cb (XrdSceneRenderer *self,
void (*update_lights) (gpointer data),
gpointer scene_client);
VkBuffer
xrd_scene_renderer_get_lights_buffer_handle (XrdSceneRenderer *self);
void
xrd_scene_renderer_update_lights (XrdSceneRenderer *self,
GList *controllers);
G_END_DECLS
......
......@@ -336,6 +336,35 @@ xrd_scene_window_draw (XrdSceneWindow *self,
vkCmdBindPipeline (cmd_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
xrd_scene_object_update_mvp_matrix (obj, eye, vp);
xrd_scene_object_bind (obj, eye, cmd_buffer, pipeline_layout);
gulkan_vertex_buffer_draw (priv->vertex_buffer, cmd_buffer);
}
void
xrd_scene_window_draw_shaded (XrdSceneWindow *self,
EVREye eye,
VkPipeline pipeline,
VkPipelineLayout pipeline_layout,
VkCommandBuffer cmd_buffer,
graphene_matrix_t *view,
graphene_matrix_t *projection)
{
XrdSceneWindowPrivate *priv = xrd_scene_window_get_instance_private (self);
if (!priv->window_data->texture)
{
/* g_warning ("Trying to draw window with no texture.\n"); */
return;
}
XrdSceneObject *obj = XRD_SCENE_OBJECT (self);
if (!xrd_scene_object_is_visible (obj))
return;
vkCmdBindPipeline (cmd_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
xrd_scene_object_update_transformation_buffer (obj, eye, view, projection);
xrd_scene_object_bind (obj, eye, cmd_buffer, pipeline_layout);
gulkan_vertex_buffer_draw (priv->vertex_buffer, cmd_buffer);
}
......@@ -362,6 +391,7 @@ xrd_scene_window_update_descriptors (XrdSceneWindow *self)
XrdSceneRenderer *renderer = xrd_scene_renderer_get_instance ();
VkDevice device = gulkan_client_get_device_handle (GULKAN_CLIENT (renderer));
XrdSceneWindowPrivate *priv = xrd_scene_window_get_instance_private (self);
VkBuffer lights = xrd_scene_renderer_get_lights_buffer_handle (renderer);
for (uint32_t eye = 0; eye < 2; eye++)
{
......@@ -412,10 +442,23 @@ xrd_scene_window_update_descriptors (XrdSceneWindow *self)
.range = VK_WHOLE_SIZE
},
.pTexelBufferView = NULL
},
{
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
.dstSet = descriptor_set,
.dstBinding = 3,
.descriptorCount = 1,
.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
.pBufferInfo = &(VkDescriptorBufferInfo) {
.buffer = lights,
.offset = 0,
.range = VK_WHOLE_SIZE
},
.pTexelBufferView = NULL
}
};
vkUpdateDescriptorSets (device, 3, write_descriptor_sets, 0, NULL);
vkUpdateDescriptorSets (device, 4, write_descriptor_sets, 0, NULL);
}
}
......
......@@ -74,6 +74,15 @@ xrd_scene_window_draw (XrdSceneWindow *self,
VkCommandBuffer cmd_buffer,
graphene_matrix_t *vp);
void
xrd_scene_window_draw_shaded (XrdSceneWindow *self,
EVREye eye,
VkPipeline pipeline,
VkPipelineLayout pipeline_layout,
VkCommandBuffer cmd_buffer,
graphene_matrix_t *view,
graphene_matrix_t *projection);
void
xrd_scene_window_set_width_meters (XrdSceneWindow *self,
float width_meters);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment