git.s-ol.nu openxPriments / e08d451
wip s-ol 1 year, 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
(No changes)
(No changes)
(No changes)
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());