git.s-ol.nu openxPriments / e08d451
wip s-ol 3 months ago
10 changed file(s) with 491 addition(s) and 101 deletion(s). Raw diff Collapse all Expand all
Binary diff not shown
Binary diff not shown
Binary diff not shown
Binary diff not shown
00 const std = @import("std");
1 usingnamespace @import("xrvk.zig");
2 const dg = @import("diligent");
13 const mem = std.mem;
2 usingnamespace @import("xrvk.zig");
3 const Allocator = std.mem.Allocator;
4 const dg = @import("diligent");
5
6 fn quat2euler(q: xr.Quaternionf) xr.Vector3f {
7 const sinr_cosp = 2 * (q.w * q.x + q.y * q.z);
8 const siny_cosp = 2 * (q.w * q.z + q.x * q.y);
9 const cosr_cosp = 1 - 2 * (q.x * q.x + q.y * q.y);
10 const cosy_cosp = 1 - 2 * (q.y * q.y + q.z * q.z);
11 const sinp = 2 * (q.w * q.y - q.z * q.x);
12
13 return .{
14 .x = std.math.atan2(f32, sinr_cosp, cosr_cosp),
15 .y = if (std.math.fabs(sinp) >= 1) std.math.pi / 2.0 else std.math.asin(sinp),
16 .z = std.math.atan2(f32, siny_cosp, cosy_cosp),
17 };
18 }
4 const Allocator = mem.Allocator;
195
206 pub const Graphics = struct {
217 xri: xr.InstanceDispatch,
403389 // get images
404390 const image_count = try gfx.xri.enumerateSwapchainImages(swapchain, 0, null);
405391 const xr_images = try gfx.allocator.alloc(xr.SwapchainImageVulkan2KHR, image_count);
406 std.mem.set(xr.SwapchainImageVulkan2KHR, xr_images, xr.SwapchainImageVulkan2KHR.empty());
392 mem.set(xr.SwapchainImageVulkan2KHR, xr_images, xr.SwapchainImageVulkan2KHR.empty());
407393 defer gfx.allocator.free(xr_images);
408394
409395 _ = try gfx.xri.enumerateSwapchainImages(swapchain, image_count, @ptrCast(
11 const std = @import("std");
22 const glm = @import("glm");
33 const gfx = @import("graphics.zig");
4 const math = @import("math.zig");
45 const scene = @import("scene.zig");
56 const renderdoc = @import("renderdoc.zig");
6 const Allocator = std.mem.Allocator;
7 const mem = std.mem;
8 const Allocator = mem.Allocator;
79
810 pub fn main() !void {
911 try renderdoc.load_api();
1214 session.deinit();
1315 }
1416
15 const Paths = struct {
16 user_hand_right: xr.Path,
17 user_hand_left: xr.Path,
18 user_hand_head: xr.Path,
19
20 pub fn init(xri: xr.InstanceDispatch, inst: xr.Instance) !Paths {
21 var self: Paths = undefined;
22
23 inline for (@typeInfo(Paths).Struct.fields) |field| {
24 var buffer: [field.name.len + 2:0]u8 = undefined;
25 _ = std.mem.replace(u8, field.name, "_", "/", buffer[1..]);
26 buffer[0] = '/';
27 buffer[buffer.len - 1] = 0;
28 @field(self, field.name) = try xri.stringToPath(inst, buffer[0..]);
29 }
17 const HandState = struct {
18 subaction_path: xr.Path,
19 handedness: []const u8,
20 space: xr.Space,
21
22 active: bool,
23 grab: ?f32,
24 pose: ?glm.Mat4,
25 quit: ?bool,
26 vibrate: ?xr.HapticVibration,
27
28 pub fn init(path: xr.Path, handedness: []const u8, space: xr.Space) HandState {
29 return .{
30 .subaction_path = path,
31 .space = space,
32 .handedness = handedness,
33
34 .active = false,
35 .grab = null,
36 .pose = null,
37 .quit = null,
38 .vibrate = null,
39 };
40 }
41
42 pub fn sync(self: *HandState, actions: *const Actions) !void {
43 const xri = actions.xri;
44 const session = actions.session;
45
46 var grab = xr.ActionStateFloat.empty();
47 var pose = xr.ActionStatePose.empty();
48 var quit = xr.ActionStateBoolean.empty();
49
50 try xri.getActionStateFloat(session, .{
51 .action = actions.grab_object,
52 .subaction_path = self.subaction_path,
53 }, &grab);
54 self.grab = if (grab.is_active == xr.TRUE) grab.current_state else null;
55
56 try xri.getActionStatePose(session, .{
57 .action = actions.grip_pose,
58 .subaction_path = self.subaction_path,
59 }, &pose);
60 self.active = pose.is_active == xr.TRUE;
61
62 try xri.getActionStateBoolean(session, .{
63 .action = actions.quit_session,
64 .subaction_path = self.subaction_path,
65 }, &quit);
66 self.quit = if (quit.is_active == xr.TRUE) quit.current_state == xr.TRUE else null;
67 }
68
69 pub fn locate(
70 self: *HandState,
71 xri: xr.InstanceDispatch,
72 reference_space: xr.Space,
73 query_time: xr.Time,
74 ) !void {
75 if (!self.active) {
76 self.pose = null;
77 return;
78 }
79
80 var location = xr.SpaceLocation.empty();
81 try xri.locateSpace(self.space, reference_space, query_time, &location);
82
83 if (!location.location_flags.contains(.{
84 .position_valid_bit = true,
85 .orientation_valid_bit = true,
86 })) {
87 self.pose = null;
88 return;
89 }
90
91 self.pose = math.pose2mat(location.pose);
92 }
93
94 pub fn applyOutput(self: *const HandState, actions: *const Actions) !void {
95 if (self.vibrate) |vibration| {
96 try xri.applyHapticFeedback(
97 session,
98 .{
99 .action = self.actions.vibrate,
100 .subaction_path = self.subaction_path,
101 },
102 @ptrCast(*const xr.HapticBaseHeader, &vibration),
103 );
104 }
105 }
106 };
107
108 const Actions = struct {
109 xri: xr.InstanceDispatch,
110 session: xr.Session,
111
112 set: xr.ActionSet,
113 grab_object: xr.Action,
114 grip_pose: xr.Action,
115 quit_session: xr.Action,
116 vibrate: xr.Action,
117
118 hands: [2]HandState,
119
120 pub fn init(
121 xri: xr.InstanceDispatch,
122 instance: xr.Instance,
123 session: xr.Session,
124 ) !Actions {
125 var self: Actions = undefined;
126 self.xri = xri;
127 self.session = session;
128
129 const subaction_strs = [_][:0]const u8{ "/user/hand/right", "/user/hand/left" };
130 const handedness_strs = [_][:0]const u8{ "right", "left" };
131 var subaction_paths: [subaction_strs.len]xr.Path = undefined;
132 for (subaction_strs) |str, i| {
133 subaction_paths[i] = try xri.stringToPath(instance, str);
134 }
135
136 var set_ci = xr.ActionSetCreateInfo{
137 .action_set_name = undefined,
138 .localized_action_set_name = undefined,
139 .priority = 0,
140 };
141 mem.copy(u8, set_ci.action_set_name[0..], "gameplay\x00");
142 mem.copy(u8, set_ci.localized_action_set_name[0..], "Gameplay\x00");
143 self.set = try xri.createActionSet(instance, set_ci);
144
145 {
146 // create actions
147 var action_ci = xr.ActionCreateInfo{
148 .action_type = undefined,
149 .action_name = undefined,
150 .localized_action_name = undefined,
151 .count_subaction_paths = subaction_paths.len,
152 .subaction_paths = &subaction_paths,
153 };
154
155 action_ci.action_type = .float_input;
156 mem.copy(u8, action_ci.action_name[0..], "grab_object\x00");
157 mem.copy(u8, action_ci.localized_action_name[0..], "Grab Object\x00");
158 self.grab_object = try xri.createAction(self.set, action_ci);
159
160 action_ci.action_type = .pose_input;
161 mem.copy(u8, action_ci.action_name[0..], "grip_pose\x00");
162 mem.copy(u8, action_ci.localized_action_name[0..], "Grip Pose\x00");
163 self.grip_pose = try xri.createAction(self.set, action_ci);
164
165 action_ci.action_type = .boolean_input;
166 mem.copy(u8, action_ci.action_name[0..], "quit_session\x00");
167 mem.copy(u8, action_ci.localized_action_name[0..], "Quit Session\x00");
168 self.quit_session = try xri.createAction(self.set, action_ci);
169
170 action_ci.action_type = .vibration_output;
171 mem.copy(u8, action_ci.action_name[0..], "vibrate_hand\x00");
172 mem.copy(u8, action_ci.localized_action_name[0..], "Vibrate Hand\x00");
173 self.vibrate = try xri.createAction(self.set, action_ci);
174 }
175
176 {
177 // suggested bindings
178 const PathStruct = struct {
179 squeeze_force: xr.Path,
180 pose: xr.Path,
181 b_click: xr.Path,
182 haptic: xr.Path,
183 };
184
185 var paths: [subaction_strs.len]PathStruct = undefined;
186 for (subaction_strs) |subaction, i| {
187 var path_buffer = [_]u8{0} ** 2048;
188 var string: [:0]const u8 = undefined;
189
190 string = try std.fmt.bufPrintZ(path_buffer[0..], "{}/input/squeeze/force", .{subaction});
191 const squeeze_force = try xri.stringToPath(instance, string.ptr);
192
193 string = try std.fmt.bufPrintZ(path_buffer[0..], "{}/input/grip/pose", .{subaction});
194 const pose = try xri.stringToPath(instance, string.ptr);
195
196 string = try std.fmt.bufPrintZ(path_buffer[0..], "{}/input/b/click", .{subaction});
197 const b_click = try xri.stringToPath(instance, string.ptr);
198
199 string = try std.fmt.bufPrintZ(path_buffer[0..], "{}/output/haptic", .{subaction});
200 const haptic = try xri.stringToPath(instance, string.ptr);
201
202 paths[i] = .{
203 .squeeze_force = squeeze_force,
204 .pose = pose,
205 .b_click = b_click,
206 .haptic = haptic,
207 };
208 }
209
210 const index_profile = try xri.stringToPath(instance, "/interaction_profiles/valve/index_controller");
211 const bindings = [_]xr.ActionSuggestedBinding{
212 .{ .action = self.grab_object, .binding = paths[0].squeeze_force },
213 .{ .action = self.grab_object, .binding = paths[1].squeeze_force },
214 .{ .action = self.grip_pose, .binding = paths[0].pose },
215 .{ .action = self.grip_pose, .binding = paths[1].pose },
216 .{ .action = self.quit_session, .binding = paths[0].b_click },
217 .{ .action = self.quit_session, .binding = paths[1].b_click },
218 .{ .action = self.vibrate, .binding = paths[0].haptic },
219 .{ .action = self.vibrate, .binding = paths[1].haptic },
220 };
221 try xri.suggestInteractionProfileBindings(instance, .{
222 .interaction_profile = index_profile,
223 .count_suggested_bindings = bindings.len,
224 .suggested_bindings = &bindings,
225 });
226 }
227
228 for (subaction_paths) |path, i| {
229 const handedness = handedness_strs[i];
230 const space = try xri.createActionSpace(session, .{
231 .action = self.grip_pose,
232 .pose_in_action_space = .{
233 // "origin": [-0.005154, 0.013042, 0.107171],
234 // "rotate_xyz" : [93.782, 0.0, 0.0]
235 // .position = .{ .x = 0.005154, .y = -0.013042, .z = -0.107171 },
236 // .orientation = .{ .x = 0.7300549, .y = 0, .z = 0, .w = 0.6833885 },
237 },
238 .subaction_path = path,
239 });
240 self.hands[i] = HandState.init(path, handedness, space);
241 }
242
243 try xri.attachSessionActionSets(session, .{
244 .count_action_sets = 1,
245 .action_sets = @ptrCast([*]xr.ActionSet, &self.set),
246 });
30247
31248 return self;
249 }
250
251 pub fn sync(self: *Actions) !void {
252 const active_sets = [_]xr.ActiveActionSet{
253 .{ .action_set = self.set, .subaction_path = 0 },
254 };
255 _ = try self.xri.syncActions(self.session, .{
256 .count_active_action_sets = active_sets.len,
257 .active_action_sets = &active_sets,
258 });
259
260 for (self.hands) |*hand| {
261 try hand.sync(self);
262 }
32263 }
33264 };
34265
35266 const Session = struct {
36267 xrb: xr.BaseDispatch,
37268 xri: xr.InstanceDispatch,
269 xrcmi: ?xr.CMInstanceDispatch,
38270
39271 instance: xr.Instance,
40272 session: xr.Session,
42274
43275 allocator: *Allocator,
44276
277 actions: Actions,
45278 state: xr.SessionState,
46279 views: ?ViewInfo,
47 paths: Paths,
48280 graphics: gfx.Graphics,
49281 layers: []*const xr.CompositionLayerBaseHeader,
50282 scene_space: xr.Space,
51283
52 first_render: bool = true,
284 hand_models: [2]?*scene.Model,
53285
54286 const ViewInfo = struct {
55287 configurations: []xr.ViewConfigurationView,
58290
59291 pub fn init(allocator: *Allocator) !Session {
60292 var name: [128]u8 = undefined;
61 std.mem.copy(u8, name[0..], "openxr-zig-test" ++ [_]u8{0});
293 mem.copy(u8, name[0..], "openxr-zig-test" ++ [_]u8{0});
294
295 const xrb = try xr.BaseDispatch.load(xr.getProcAddr);
296
297 const have_controller_model_ext = blk: {
298 var extensions = [_]xr.ExtensionProperties{ xr.ExtensionProperties.empty() } ** 512;
299 const extension_count = try xrb.enumerateInstanceExtensionProperties(null, extensions.len, &extensions);
300 for (extensions[0..extension_count]) |ext| {
301 const ext_name = @ptrCast([*:0]const u8, ext.extension_name[0..]);
302 if (mem.eql(u8, mem.spanZ(ext_name), "XR_MSFT_controller_model")) {
303 std.debug.print("found XR_MSFT_controller_model extension version {}\n", .{ ext.extension_version },);
304 break :blk true;
305 }
306 }
307
308 break :blk false;
309 };
62310
63311 const zero = [_:0]u8{};
64312 const extensions = [_][*:0]const u8{
66314 "XR_MSFT_controller_model",
67315 };
68316
69 const xrb = try xr.BaseDispatch.load(xr.getProcAddr);
70317 const instance = try xrb.createInstance(.{
71318 .create_flags = .{},
72319 .application_info = .{
78325 },
79326 .enabled_api_layer_count = 0,
80327 .enabled_api_layer_names = @ptrCast([*]const [*:0]const u8, &zero),
81 .enabled_extension_count = extensions.len,
328 .enabled_extension_count = if (have_controller_model_ext) 2 else 1,
82329 .enabled_extension_names = &extensions,
83330 });
84331
85332 const xri = try xr.InstanceDispatch.load(instance, xr.getProcAddr);
86333 errdefer xri.destroyInstance(instance) catch unreachable;
87334
88 const paths = try Paths.init(xri, instance);
335 var xrcmi: ?xr.CMInstanceDispatch = null;
336 if (have_controller_model_ext) {
337 xrcmi = try xr.CMInstanceDispatch.load(instance, xr.getProcAddr);
338 }
89339
90340 const system = try xri.getSystem(instance, .{ .form_factor = .head_mounted_display });
91341
125375 });
126376 errdefer xri.destroySession(session) catch unreachable;
127377
378 const actions = try Actions.init(xri, instance, session);
379
128380 const scene_space = try xri.createReferenceSpace(session, .{
129381 .reference_space_type = .stage,
130382 .pose_in_reference_space = .{
135387 return Session{
136388 .xrb = xrb,
137389 .xri = xri,
390 .xrcmi = xrcmi,
138391
139392 .instance = instance,
140393 .session = session,
141394 .system = system,
142395 .allocator = allocator,
143396
397 .actions = actions,
144398 .state = .idle,
145399 .views = null,
146 .paths = paths,
147400 .graphics = graphics,
148401 .scene_space = scene_space,
149402 .layers = &[_]*const xr.CompositionLayerBaseHeader{},
403
404 .hand_models = [_]?*scene.Model{ null, null },
150405 };
151406 }
152407
224479 .projections = try self.allocator.alloc(xr.CompositionLayerProjectionView, view_count),
225480 };
226481
227 std.mem.set(
482 mem.set(
228483 xr.ViewConfigurationView,
229484 views.configurations,
230485 xr.ViewConfigurationView.empty(),
231486 );
232 std.mem.set(
487 mem.set(
233488 xr.CompositionLayerProjectionView,
234489 views.projections,
235490 xr.CompositionLayerProjectionView.empty(),
250505 try self.graphics.createSwapchain(self.session, views.configurations);
251506 var gfx_scene = try scene.Scene.init(&self.graphics);
252507
253 var helmet = scene.Model.initFile(&gfx_scene, "assets/DamagedHelmet.gltf");
508 var helmet = scene.Model.initFile(self.allocator, &gfx_scene, "assets/DamagedHelmet.gltf");
254509 helmet.setTransform(glm.translation(glm.Vec3.init([_]f32{ 0, 1.5, -2 })));
255510 try gfx_scene.models.append(helmet);
256511
257 for ([_]xr.Path{ self.paths.user_hand_left, self.paths.user_hand_right }) |path, i| {
258 var model_state = xr.ControllerModelKeyStateMSFT.empty();
259 try self.xri.getControllerModelKeyMSFT(self.session, path, &model_state);
260
261 if (model_state.model_key == 0)
262 continue;
263
264 const size = try self.xri.loadControllerModelMSFT(self.session, model_state.model_key, 0, null);
265 const buffer = try self.allocator.alloc(u8, size);
266 defer self.allocator.free(buffer);
267
268 _ = try self.xri.loadControllerModelMSFT(self.session, model_state.model_key, size, buffer.ptr);
269 var model = scene.Model.initMemory(&gfx_scene, buffer);
270
271 var transform = glm.Mat4.IDENTITY;
272 transform = transform.mul(glm.translation(glm.Vec3.init([_]f32{ 0.6 * (@intToFloat(f32, i) - 0.5), 1.5, -0.5 })));
273 transform = transform.mul(glm.rotation(0.9, glm.Vec3.init([_]f32{ 1, 0, 0 })));
274 model.setTransform(transform);
275 try gfx_scene.models.append(model);
276 }
512 helmet = scene.Model.initFile(self.allocator, &gfx_scene, "assets/controller_right.glb");
513 helmet.setTransform(
514 glm.translation(glm.Vec3.init([_]f32{ -0.07, 1.6, -0.2 }))
515 .mul(glm.rotation(0.8, glm.Vec3.init([_]f32{ 1, 0, 0 })))
516 );
517 try helmet.loadNodeTransform("r_button_b");
518 try helmet.loadNodeTransform("r_trackpad_touch");
519 try gfx_scene.models.append(helmet);
277520
278521 const composition_layer = try self.allocator.create(xr.CompositionLayerProjection);
279522 composition_layer.* = .{
290533 while (true) {
291534 try self.pollEvents();
292535 if (self.state == .stopping) break;
293
294 if (!try self.renderFrame(&gfx_scene)) {
536 try self.actions.sync();
537
538 const did_render = try self.renderFrame(&gfx_scene);
539 if (!did_render) {
540 // no frame submitted, so compositor won't throttle by waiting for GPU
541 // sleep to prevent busy-loop
295542 std.os.nanosleep(0, 250_000_000);
296543 }
297544 }
312559 transform = transform.mul(glm.rotation(predicted_seconds, glm.Vec3.init([_]f32{ 0, 1, 0 })));
313560 gfx_scene.models.items[0].setTransform(transform);
314561
562 {
563 const model = &gfx_scene.models.items[1];
564 var txm = &model.node_transforms.items[0];
565 // motion.type == translate:l
566 // apply translation axis * lerp(in, value_mapping)
567 txm.position = glm.Vec3.init([_]f32{0, -0.927, 0.0375}).mulScalar(
568 (std.math.sin(predicted_seconds * 3) / 2 + 0.5) * 0.002
569 );
570
571 var tp_mot_rot = glm.Mat4.IDENTITY;
572 // motion.type == trackpad: only apply negative component_local transform
573 // apply translation axis * lerp(in, value_mapping)
574 tp_mot_rot.mulAssign(glm.rotation(1.18682389, glm.Vec3.init([_]f32{ 1, 0, 0 })));
575 tp_mot_rot.mulAssign(math.quat2mat(xr.Quaternionf{ .x=-0.17349398, .y=-0.79472193, .z=0.32537197, .w=-0.48213067 }));
576 tp_mot_rot.mulAssign(glm.rotation(-1.18682389, glm.Vec3.init([_]f32{ 1, 0, 0 })));
577
578 txm = &model.node_transforms.items[1];
579 txm.position =
580 tp_mot_rot.apply(
581 glm.Vec4.init([_]f32{
582 std.math.clamp(std.math.sin(predicted_seconds * 3) * 2, -1, 1) * 0.009,
583 std.math.clamp(std.math.cos(predicted_seconds * 3) * 2, -1, 1) * 0.015,
584 0,
585 1
586 })
587 ).shrink(3);
588 // txm.rotation = glm.Vec4.init([_]f32{ -0.17349398, -0.79472193, 0.32537197, -0.48213067 });
589
590 model.flushTransforms();
591 std.debug.print("transform pos: {}\n", .{ model.node_transforms.items[0].position });
592 }
593
315594 var layer_count: u32 = 0;
316595
317596 if (frame_state.should_render > 0) {
328607
329608 if (!view_state.view_state_flags.contains(.{ .position_valid_bit = true, .orientation_valid_bit = true })) {
330609 return error.InvalidPositionOrOrientation;
610 }
611
612 for (self.actions.hands) |*hand, i| {
613 try hand.locate(self.xri, self.scene_space, frame_state.predicted_display_time);
614 if (hand.active and self.hand_models[i] == null) {
615 var model = if (self.xrcmi) |xri| model: {
616 var model_state = xr.ControllerModelKeyStateMSFT.empty();
617 try xri.getControllerModelKeyMSFT(self.session, hand.subaction_path, &model_state);
618
619 if (model_state.model_key == 0)
620 continue;
621
622 const size = try xri.loadControllerModelMSFT(self.session, model_state.model_key, 0, null);
623 const buffer = try self.allocator.alloc(u8, size);
624 defer self.allocator.free(buffer);
625
626 _ = try xri.loadControllerModelMSFT(self.session, model_state.model_key, size, buffer.ptr);
627 break :model scene.Model.initMemory(self.allocator, gfx_scene, buffer);
628 } else model: {
629 var path_buffer = [_]u8{0} ** 128;
630 const path = try std.fmt.bufPrintZ(path_buffer[0..], "assets/controller_{}.glb", .{hand.handedness});
631 break :model scene.Model.initFile(self.allocator, gfx_scene, path);
632 };
633
634 const ptr = try gfx_scene.models.addOne();
635 ptr.* = model;
636 self.hand_models[i] = ptr;
637 }
638
639 if (hand.pose) |pose| {
640 if (self.hand_models[i]) |model| {
641 model.setTransform(pose);
642 }
643 }
331644 }
332645
333646 const swapchain = self.graphics.swapchain;
0 usingnamespace @import("xrvk.zig");
1 const glm = @import("glm");
2 const math = @import("std").math;
3
4 pub fn vec2vec(v: xr.Vector3f) glm.Vec3 {
5 return glm.Vec3.init([_]f32{ v.x, v.y, v.z });
6 }
7
8 pub fn quat2mat(q: xr.Quaternionf) glm.Mat4 {
9 const x = -q.x;
10 const y = -q.y;
11 const z = -q.z;
12 const w = q.w;
13 const x2 = q.x * q.x;
14 const y2 = q.y * q.y;
15 const z2 = q.z * q.z;
16
17 // zig fmt: off
18 return glm.Mat4.init([_][4]f32{
19 [_]f32{ 1 - 2 * y2 - 2 * z2, 2 * x * y - 2 * z * w, 2 * x * z + 2 * y * w, 0 },
20 [_]f32{ 2 * x * y + 2 * z * w, 1 - 2 * x2 - 2 * z2, 2 * y * z - 2 * x * w, 0 },
21 [_]f32{ 2 * x * z - 2 * y * w, 2 * y * z + 2 * x * w, 1 - 2 * x2 - 2 * y2, 0 },
22 [_]f32{ 0, 0, 0, 1 },
23 });
24 // zig fmt: on
25 }
26
27 pub fn pose2mat(pose: xr.Posef) glm.Mat4 {
28 return glm.translation(vec2vec(pose.position)).mul(quat2mat(pose.orientation));
29 }
30
31 pub fn pose2matInverse(pose: xr.Posef) glm.Mat4 {
32 var inverse = pose;
33 inverse.orientation.x *= -1;
34 inverse.orientation.y *= -1;
35 inverse.orientation.z *= -1;
36 inverse.position.x *= -1;
37 inverse.position.y *= -1;
38 inverse.position.z *= -1;
39 return quat2mat(inverse.orientation).mul(glm.translation(vec2vec(inverse.position)));
40 }
41
42
43 pub fn projection(fov: xr.Fovf, near: f32, far: f32) glm.Mat4 {
44 const tanUp = math.tan(fov.angle_up);
45 const tanDown = math.tan(fov.angle_down);
46 const tanLeft = math.tan(fov.angle_left);
47 const tanRight = math.tan(fov.angle_right);
48 const tanW = tanRight - tanLeft;
49 const tanH = tanUp - tanDown ;
50
51 return glm.Mat4.init([_][4]f32{
52 [_]f32{ 2 / tanW, 0, 0, 0 },
53 [_]f32{ 0, 2 / tanH, 0, 0 },
54 [_]f32{ (tanRight + tanLeft) / tanW, (tanUp + tanDown) / tanH, -far / (far - near), -1 },
55 [_]f32{ 0, 0, -far * near / (far - near), 0 },
56 });
57 }
00 const std = @import("std");
1 const mem = std.mem;
2 const Allocator = mem.Allocator;
13 const dg = @import("diligent");
24 const glm = @import("glm");
35 const graphics = @import("graphics.zig");
46 usingnamespace @import("xrvk.zig");
7 const math = @import("math.zig");
58
69 const geometry_source =
710 \\layout(triangles, invocations = 2) in;
6568 .view = view,
6669 .proj = proj,
6770 .viewproj = viewproj,
68 .view_inv = view.transpose(),
69 .proj_inv = proj.transpose(),
70 .viewproj_inv = viewproj.transpose(),
71 .view_inv = view.invert() orelse unreachable,
72 .proj_inv = proj.invert() orelse unreachable,
73 .viewproj_inv = viewproj.invert() orelse unreachable,
7174 };
7275 }
7376
125128 shadow_attribs: ShadowMapAttribs = .{},
126129 };
127130
128 fn vec2vec(v: xr.Vector3f) glm.Vec3 {
129 return glm.Vec3.init([_]f32{ v.x, v.y, v.z });
130 }
131
132 fn quat2mat(q: xr.Quaternionf) glm.Mat4 {
133 const x = q.x;
134 const y = q.y;
135 const z = q.z;
136 const w = q.w;
137 const x2 = q.x * q.x;
138 const y2 = q.y * q.y;
139 const z2 = q.z * q.z;
140
141 // zig fmt: off
142 return glm.Mat4.init([_][4]f32{
143 [_]f32{ 1 - 2 * y2 - 2 * z2, 2 * x * y - 2 * z * w, 2 * x * z + 2 * y * w, 0 },
144 [_]f32{ 2 * x * y + 2 * z * w, 1 - 2 * x2 - 2 * z2, 2 * y * z - 2 * x * w, 0 },
145 [_]f32{ 2 * x * z - 2 * y * w, 2 * y * z + 2 * x * w, 1 - 2 * x2 - 2 * y2, 0 },
146 [_]f32{ 0, 0, 0, 1 },
147 });
148 // zig fmt: on
149 }
150
151131 const defaultSampler = dg.SamplerDesc{
152132 ._DeviceObjectAttribs = .{ .Name = "Default Sampler" },
153133 .MinFilter = dg.FILTER_TYPE_LINEAR,
172152 model: dg.IGLTFModel_Wrapper,
173153 bindings: dg.GLTF_ModelResourceBindings,
174154 params: dg.GLTF_RenderInfo,
155
156 node_indices: std.ArrayList(u32),
157 node_transforms: std.ArrayList(Transform),
175158
176159 const DEFAULT_PARAMS = dg.GLTF_RenderInfo{
177160 .ModelTransform = @bitCast([16]f32, glm.Mat4.IDENTITY),
185168 .WhitePoint = 3,
186169 };
187170
188 pub fn initMemory(scene: *const Scene, data: []const u8) Model {
171 pub const Transform = extern struct {
172 position: glm.Vec3,
173 scale: glm.Vec3,
174 rotation: glm.Vec4,
175 matrix: glm.Mat4,
176 };
177
178 pub fn initMemory(allocator: *Allocator, scene: *const Scene, data: []const u8) Model {
189179 const model = dg.Diligent_IGLTFModel_Create(
190180 @ptrCast(*dg.IRenderDevice, scene.dev.ptr),
191181 scene.ctx.ptr,
208198 scene.light_ubo.ptr,
209199 ),
210200 .params = DEFAULT_PARAMS,
201
202 .node_indices = std.ArrayList(u32).init(allocator),
203 .node_transforms = std.ArrayList(Transform).init(allocator),
211204 };
212205 }
213206
214 pub fn initFile(scene: *const Scene, path: [:0]const u8) Model {
207 pub fn initFile(allocator: *Allocator, scene: *const Scene, path: [:0]const u8) Model {
215208 const model = dg.Diligent_IGLTFModel_Create(
216209 @ptrCast(*dg.IRenderDevice, scene.dev.ptr),
217210 scene.ctx.ptr,
234227 scene.light_ubo.ptr,
235228 ),
236229 .params = DEFAULT_PARAMS,
230
231 .node_indices = std.ArrayList(u32).init(allocator),
232 .node_transforms = std.ArrayList(Transform).init(allocator),
237233 };
238234 }
239235
240236 pub fn deinit(self: *Model) void {
241237 self.bindings.Release();
242238 self.model.Release();
239 self.node_transforms.deinit();
240 self.node_indices.deinit();
243241 }
244242
245243 pub fn setTransform(self: *Model, mat: glm.Mat4) void {
255253 null,
256254 scene.resource_binding.ptr,
257255 );
256 }
257
258 pub fn loadNodeTransform(self: *Model, name: [:0]const u8) !void {
259 var index: u32 = undefined;
260 if (self.model.GetNodeIndex(name.ptr, &index)) {
261 try self.node_indices.append(index);
262 const transform = try self.node_transforms.addOne();
263 const ptr = @intToPtr(?*dg.GLTF_Transform, @ptrToInt(transform));
264 self.model.GetNodeTransform(index, ptr);
265 } else {
266 return error.NodeNotFound;
267 }
268 }
269
270 pub fn flushTransforms(self: *Model) void {
271 for (self.node_indices.items) |index, i| {
272 const ptr = @intToPtr(?*dg.GLTF_Transform, @ptrToInt(&self.node_transforms.items[i]));
273 self.model.SetNodeTransform(index, ptr);
274 }
275 self.model.UpdateTransforms();
258276 }
259277 };
260278
492510 for (self.views) |*view, i| {
493511 const fov = views[i].fov;
494512 const viewport = self.viewports[i];
495 const fovY = fov.angle_up - fov.angle_down;
496 const aspect = viewport.Width / viewport.Height;
497 view.projection = glm.perspective(fovY, aspect, 0.1, 100);
498
499 const pose = views[i].pose;
500 view.modelview = quat2mat(pose.orientation).mul(glm.translation(vec2vec(pose.position).mulScalar(-1)));
513 // const fovY = fov.angle_up - fov.angle_down;
514 // const fovX = fov.angle_right - fov.angle_left;
515 // const aspect = viewport.Width / viewport.Height;
516 // view.projection = glm.perspective(fovX, aspect, 0.1, 100);
517 view.projection = math.projection(fov, 0.1, 100);
518 view.modelview = math.pose2matInverse(views[i].pose);
501519 }
502520 try self.updateBufferSlice(ViewUBO, self.views_ubo, self.views);
503521
675693 var data: [*c]T = null;
676694 self.ctx.MapBuffer(buffer.ptr, dg.MAP_WRITE, dg.MAP_FLAG_DISCARD, @ptrCast([*c]?*c_void, &data));
677695 if (data) |ptr| {
678 std.mem.copy(T, data[0..values.len], values);
696 mem.copy(T, data[0..values.len], values);
679697 self.ctx.UnmapBuffer(buffer.ptr, dg.MAP_WRITE);
680698 } else {
681699 return error.MapFailed;
4343 usingnamespace rxr;
4444
4545 pub const BaseDispatch = struct {
46 xrEnumerateInstanceExtensionProperties: PfnEnumerateInstanceExtensionProperties,
4647 xrCreateInstance: PfnCreateInstance,
4748 usingnamespace BaseWrapper(@This());
4849 };
5253 xrGetSystem: PfnGetSystem,
5354 xrGetSystemProperties: PfnGetSystemProperties,
5455 xrStringToPath: PfnStringToPath,
56 xrCreateActionSet: PfnCreateActionSet,
57 xrCreateAction: PfnCreateAction,
58 xrCreateActionSpace: PfnCreateActionSpace,
59 xrSuggestInteractionProfileBindings: PfnSuggestInteractionProfileBindings,
60 xrSyncActions: PfnSyncActions,
61 xrAttachSessionActionSets: PfnAttachSessionActionSets,
62 xrGetActionStateFloat: PfnGetActionStateFloat,
63 xrGetActionStatePose: PfnGetActionStatePose,
64 xrGetActionStateBoolean: PfnGetActionStateBoolean,
5565 xrCreateSession: PfnCreateSession,
5666 xrDestroySession: PfnDestroySession,
5767 xrBeginSession: PfnBeginSession,
6171 xrEndFrame: PfnEndFrame,
6272 xrPollEvent: PfnPollEvent,
6373 xrLocateViews: PfnLocateViews,
74 xrLocateSpace: PfnLocateSpace,
6475 xrCreateReferenceSpace: PfnCreateReferenceSpace,
6576 xrCreateVulkanInstanceKHR: PfnCreateVulkanInstanceKHR,
6677 xrGetVulkanGraphicsDevice2KHR: PfnGetVulkanGraphicsDevice2KHR,
7384 xrAcquireSwapchainImage: PfnAcquireSwapchainImage,
7485 xrWaitSwapchainImage: PfnWaitSwapchainImage,
7586 xrReleaseSwapchainImage: PfnReleaseSwapchainImage,
87 usingnamespace InstanceWrapper(@This());
88 };
89
90 pub const CMInstanceDispatch = struct {
7691 xrGetControllerModelKeyMSFT: PfnGetControllerModelKeyMSFT,
7792 xrLoadControllerModelMSFT: PfnLoadControllerModelMSFT,
7893 usingnamespace InstanceWrapper(@This());