Commit Graph

58 Commits

Author SHA1 Message Date
Danny McGee e0cf0efc7a Fix studio-web build issues (#17)
* Add plugins for `wasm` and `top-level-await` to Vite config
* Avoid bundling dependencies
* Add external dependencies to project-level `package.json` manifests
2023-12-27 17:45:07 -05:00
Danny McGee 0a0acacfdb Single-canvas juggling (#15)
This PR adds a `CanvasProviderElement` to `@storyteller/studio-web` to manage
the complexity of maintaining a single concrete `HTMLCanvasElement` for
`@storyteller/studio`, while still being able to treat components like the
`ViewerElement` as self-contained "views" that behave as expected with regards
to CSS styling, DOM placement, etc.

Consuming applications should wrap the new `<sts-canvas-provider />` element
around some common ancestor of all views into the `@storyteller/studio` app,
similar to a React context provider.

The `react-frontend` application has been updated to take advantage of the new
`CanvasProviderElement` by demonstrating a more realistic use case for the
`ViewerElement`. The new demo presents a grid of "thumbnails," one for each
object in our hard-coded "object library." Clicking on one of these thumbnails
will render a `ViewerElement` for that object in a modal dialog.
2023-12-19 16:11:25 -05:00
Danny McGee cba70a62ae Single-object viewer POC (#14)
This commit implements a Sketchfab-style single-object viewer as a minimal
proof-of-concept.

### `@storyteller/studio-web`
This is a new package to house web components for interfacing with the
`@storyteller/studio` WASM library. It currently includes a single component,
`<sts-viewer />`, which is exported from `@storyteller/studio-web/viewer`.

### `react-frontend`
This is a new application intended as a proof-of-concept and testbed for React
interop with `@storyteller/studio-web`.

Web components are currently a little bit fiddly to use in a React application.
`react-frontend/src/app/studio-viewer.tsx` demonstrates how a React-idiomatic
component can be written as a thin wrapper around a web component, and
`react-frontend/src/app/app.tsx` demonstrates that wrapper component in use.
2023-12-07 15:46:32 -05:00
Danny McGee 155272a5ba Upgrade to Bevy v0.12 (#12)
* Migrate `System::pipe(...)` calls to `System::map(...)`
* Migrate `EventReader::iter()` and `EventReader::into_iter()` calls to
  `EventReader::read()`
* Migrate asset handling
* Generate `*.meta` files for assets
* Migrate a shader import
* Fix emissive materials double-applying their emissive strength
* Fix non-normalized bone weights resulting in incorrect vertex positions
* Set shadow filtering to `Hardware2x2` to mitigate increase in shader
  compilation times
2023-11-22 23:05:42 -05:00
Danny McGee 8bf4abc3a4 Scene Inspector (#11)
This PR adds the bones of a user-facing scene inspector.

### Work Done

To facilitate this work, the Bevy/frontend interface has been expanded to
accommodate two-way communications:

- The Bevy app can now dispatch JavaScript `CustomEvent`s via
  `wasm::dispatch_to_js(...)`
- The frontend application can receive those events by listening for the given
  event type on the `window` object

In its current state, the inspection system works by attaching the `Inspectable`
marker component to any entities which should be exposed to the user. A Bevy
system runs on `Update` to check for newly spawned or despawned entities with
that component, and emits events to notify the frontend. The frontend listens
for those events and updates its model of the scene accordingly, which is then
displayed with a simple tree view.

### Future Enhancements

There are many improvements that must be made to make this system actually
useful, but this PR is being expedited to focus on migrating to Bevy 0.12. A
shortlist of planned updates:

- Identify and expose the "type" of entity (e.g. lights, cameras, meshes,
  skeletons, etc.) via a field on the `Inspectable` component
- Highlight the currently selected entity in the frontend hierarchy
- Ask the Bevy app to update the selection when the user selects an entry in the
  hierarchy
- Add a separate UI panel to inspect and modify the selected entity's components
  via the frontend
2023-11-10 21:07:39 -05:00
Danny McGee 5fed2b6f59 Transform gizmos (#10)
This PR adds functional transform gizmos, along with some new frontend UI to
configure their state.

## Work Done
- [x] Global / Local space toggling
- [x] Gizmo type toggling
- [x] Translation gizmo
  - [x] Axis-constrained translation
  - [x] Plane-constrained translation
  - [x] Screen-space translation
- [x] Rotation gizmo
  - [x] Axis-constrained rotation
  - [x] Screen-space rotation
  - [x] "Trackball" rotation
- [ ] Scale gizmo
  - [ ] Single-axis non-uniform scaling
  - [ ] Two-axis non-uniform scaling
  - [ ] Uniform scaling
- [ ] Combination gizmos
  - [x] Translation + Rotation
  - [ ] Translation + Scale
  - [ ] Rotation + Scale
  - [ ] Translation + Rotation + Scale

## Future Enhancements

### Better visual feedback during transformations

Most DCCs update the visual representation of the transform gizmo while it's in
the process of being actively manipulated. (For example, Blender draws lines in
world-space to indicate that the transformation is constrained to a particular
axis or plane, hides widgets that aren't participating in the current
transformation, and illustrates the angle of difference between the original and
updated rotation.) At a minimum, we should indicate the current widget being
manipulated with a color change (like we already do when the widget is being
hovered). This requires a bit of additional state management effort but
shouldn't be overly difficult to add in a future PR.

### Better visual representation for rotation widgets

Currently, each axis of rotation is represented on the gizmo with a full-circle,
unlit "ring" shape. This can make it difficult to tell which half of the ring is
closer to the viewer, and thus to get an accurate understanding of how the
transform is currently oriented, without moving the camera around. A [previous
version of this work](#4) bisected the rings along a view-oriented plane and
rendered the "back-side" ring halves with reduced opacity. This PR uses static
meshes instead of an immediate-mode drawing API to render the gizmos, so a
custom shader would be the ideal way to reproduce that effect. That effort
should be deferred until after upgrading to Bevy 0.12, as it brings some changes
which would likely require some updates to that code.

### Better visual representation for translation arrows

A [previous version of this work](#4) faded the opacity of the translation
arrows when they were very close to parallel with the view direction — an idea
that was borrowed from Blender. It's a nice UX enhancement because translating
along an axis that's very close to parallel with the view direction can be janky
and error-prone, so it makes sense to disallow it and instead provide an
unobstructed view of the screen-space translation widget. This would also
require a custom shader, in addition to some extra state management logic (to
disable the widgets when their opacity is zeroed out). Given that it's only a
"nice-to-have," I think it makes sense to backlog this for the time being.

## Known Issues

### Picking

There's currently a bug in `bevy_mod_picking` that affects the hit-testing of
the gizmo widgets. The gizmos are currently _rendering_ on top of everything
else (via a second camera and render-layer configurations), but the picking
behavior doesn't take the rendering order into account. This means that portions
of the gizmo widgets which are occluded by geometry in the world cannot be
interacted with (because the occluding geometry interrupts the picking raycast).

> Update: This is fixed in the new release of `bevy_mod_picking` for Bevy 0.12.

### Delay on first-render

The first time a new widget shape is spawned, there's a noticeable delay (of 1
to several seconds) before the widget is rendered, during which the UI becomes
unresponsive. This is likely the same issue that triggers a much longer delay
when the glTF scene is being spawned. I'd like to see if Bevy 0.12 resolves or
mitigates this issue before addressing it on our end, but if it doesn't, I think
we can simply spawn an instance of each of the gizmo widgets off-screen on
application startup to prevent lag spikes from happening while a user is
interacting with the scene.

### Non-deterministic hover states

The widget colors are currently being updated by, e.g., multiplying on
mouser-over and dividing on mouse-out. Occasionally those events happen in quick
enough succession that our mouse-out listener is not invoked, so a widget gets
"stuck" in its hovered state. The fix for this is trivial but fairly annoying,
so I haven't gotten around to it yet. 🙂

> Update: This issue mostly occurs when in world-space mode. The gizmo is torn
> down and re-built from scratch once a drag event completes, which can despawn
> the gizmo while an element is still hovered. The solution will likely involve
> completely separate materials for default and hover states, similar to how
> `bevy_mod_picking`'s highlight plugin works.

### Object Selection

There's still some jank happening with object selection and camera orbiting, as
mentioned in #8. I don't anticipate this being overly difficult to resolve, but
I'm deferring that work until more of the core functionality is built out since
it's not a blocker for now.

### Skinned Mesh Selection

There's also still the issue of the skinned mesh being unselectable — which, it
turns out, is [technically not actually the
case](https://github.com/bevyengine/bevy/issues/4971). Rather, the picking
raycast "sees" the mesh as if it were still in its original rest pose, because
the mesh deformations are processed on the GPU and not reflected back to the
CPU-side representation.

I think the ideal workaround for this will be to attach capsule-shaped Rapier
colliders to the skeleton (similar to Unreal Engine's auto-generated "physics
assets" for skeletal meshes) and use those for picking instead. This would
automatically enable skeletal pose manipulation (by transforming the individual
joints), which is already a long term goal. It also makes more sense from a
practical standpoint, as the mesh itself cannot be independently transformed
while it's bound to the skeleton, so there's little point in directly selecting
it.
2023-11-10 15:51:17 -05:00
Danny McGee edbc1fa30f Debug toggling (#9)
#8 introduced some additional debug information to the view, which was already
rendering some information and visualizations which were not necessary relevant
to the end-user experience. This PR adds an input action (bound to Ctrl + `) to
toggle the display of those visualizations, and disables them by default.
2023-11-02 15:25:14 -04:00
Danny McGee 06751e54f6 Object picking (#8)
This PR implements basic object selection, with help from `bevy_mod_picking` and
`bevy_mod_outline`.

### Work Done
 * Click to select objects in the world
 * Selected objects become visually highlighted
 * The selected entity is available globally on the `Res<Selection>` resource
 * Selected entities can also be queried via the `Selected` marker component
 * Pressing `F` will "focus" the camera on the selected entity
 * Pressing `Esc` will clear the active selection

### Known Issues
 * We're currently using `bevy_mod_picking`'s "Selection" feature, which isn't 
   aware of our own input events. As a consequence, it will select the object
   under the cursor when releasing `LMB` after orbiting the camera, which is not
   what we want. This should be pretty easily fixable by dropping
   `bevy_mod_picking`'s selection feature and reading the object under the
   cursor in our own click listener that only runs if the LMB event is
   unhandled.
 * The skinned mesh is not currently selectable. This is likely fixable by
   adjusting the logic in `scene::mark_scene_objects`... somehow. The `Gltf`
   data structure is kind of a nightmare to work with, so this will take some
   investigation.

### Future Enhancements
 * For parity with other DCC apps, the "Focus" action should also adjust the
   camera zoom level to "frame" the selected object in the view. Punting on that
   for now because I'm not super confident about the math involved.
 * Group selection with Shift/Ctrl and/or marquee selection would be really nice
   to have, but probably not critical for now.
2023-11-02 13:32:58 -04:00
Danny McGee ce6db7fc3c Refactoring, reorganization and cleanup (#7)
### New `math` module
 * Traits for error-tolerant floating-point comparisons
 * Traits for interpolation and easing
 * Bevy plugin to manage 3D interpolations with ECS components

### `skybox` module refactor
 * ECS resource to enable external skybox selection/updates
 * System run conditions for more idiomatic/ECS-friendly control flow

### Camera controller refactor
 * Renamed from `orbit_cam` to `camera_controller`
 * Now delegates to the new interpolation plugin for WASD motion smoothing
 * Simple API for attaching the `CameraController` component to the camera from
   another module -- this resolves an awkward separation-of-concerns situation
	where we had to configure a bunch of render-quality settings in the camera
	controller module

### Scene module refactor
 * Renamed from `test_scene` to `scene`
 * This module is now responsible for configuring the skybox
 * This module is now responsible for spawning the camera and configuring the
   render settings
2023-10-31 16:39:10 -04:00
Danny McGee 4b9ea61495 New test scene, better render quality (#6)
* Updated test scene
* Adjusted lighting, tonemapping
* Replaced skybox
* Added bloom and FXAA
* [meta] Added assets folder to build dependencies
2023-10-25 17:45:24 -04:00
Danny McGee c84fd31387 UI infrastructure and simple "Help" dialog (#3)
Sets up some WIP infrastructure for building out the UI, and adds a simple popup
to show the navigation controls for the app.
2023-10-09 22:19:58 -04:00
Danny McGee 57d64f08f0 Touchpad-friendly controls (#2)
Adds `Shift` as an alternate modifier for FPS-style camera rotation, and binds
wheel events to camera zoom/dolly.

An attempt was made to translate 2D scroll events on a touchpad to camera
panning (this is what Blender does, and it's smooth as butter), but Bevy and/or
`winit` and/or the browser is doing some weird preprocessing of those events
before we're able to read them, which makes that unfeasible for now. That issue
has been documented with a `FIXME` comment.
2023-10-06 16:36:38 -04:00
Danny McGee 699c1baa4b Add WASD camera controls (#1)
This PR adds FPS-style controls to the camera in addition to the existing DCC-style pan/orbit/dolly controls. Additionally, some architectural changes have been made to facilitate this and pave the way toward making all of the app controls configurable in the future. Namely, a new `input` module has been added, loosely inspired by Unreal Engine's "Enhanced Input" system (and as I understand it, conceptually similar to Unity's "new" input system as well).

The basic idea is that raw device inputs (coming from `bevy::input`) are mapped to named, app-specific "input actions" before being consumed by other parts of the application. For example, in the camera motion system, instead of checking for mouse motion while the middle mouse button is pressed, we now check for a `CameraMotion::Pan` input action event.

Input actions carry information about their lifecycle phase (`Start`, `Ongoing`, and `Stop` — a stand-in for Bevy's `just_pressed`, `pressed`, and `just_released` methods) and some type of magnitude (`f32`, `Vec2`, or `Vec3` depending on the action).

At present, we've simply moved the hard-coded device input checks from the `orbit_cam` module to the new `input` module, but theoretically, this could eventually be refactored to read the mappings between device inputs and input actions from some kind of user configuration.
2023-10-05 22:29:01 -04:00
Danny McGee 05644b55bd Update page title 2023-10-04 19:24:48 -04:00
Danny McGee 37b24d489c Adjust Netlify build pipeline 2023-10-04 17:57:37 -04:00
Brandon Thomas 07fd600e4d mark executable 2023-10-04 17:45:55 -04:00
Danny McGee 28f034c670 Add Netlify build script 2023-10-04 17:38:10 -04:00
Danny McGee 5d8d9fe620 Split UI module 2023-10-04 16:05:34 -04:00
Danny McGee 90e504501d Load test model from glTF 2023-10-03 18:07:42 -04:00
Danny McGee 82157bd54a Document skybox generation process 2023-10-03 17:08:21 -04:00
Danny McGee ccf4d5945e Fix studio-frontend:preview configuration 2023-10-02 22:08:05 -04:00
Danny McGee bc0e81e2a0 Switch default skybox 2023-10-02 21:52:07 -04:00
Danny McGee 2273514fa6 Fix skybox for web 2023-10-02 21:51:45 -04:00
Danny McGee e97c14c5da Upgrade bevy to 0.11.3; Switch to WebGL backend 2023-10-02 21:51:05 -04:00
Danny McGee d396a45509 HDRI Skyboxes / Image-Based Lighting 2023-10-02 20:07:16 -04:00
Danny McGee 64133de881 Workflow fixes 2023-10-02 20:05:42 -04:00
Danny McGee 82e3d791bc Update @nxrs/cargo 2023-10-02 20:04:17 -04:00
Danny McGee f152706c29 Basic README 2023-09-30 00:17:20 -04:00
Danny McGee b11155c649 UX tuning + mini-refactor 2023-09-29 23:58:36 -04:00
Danny McGee 2e3979b336 Sync Bevy canvas size with browser viewport size 2023-09-29 22:15:18 -04:00
Danny McGee c1f92cc2d6 Spawn Bevy canvas at full viewport size 2023-09-29 20:36:23 -04:00
Danny McGee bed97cff47 Rename projects 2023-09-29 18:33:00 -04:00
Danny McGee 32057039b0 Fix cargo warning (duplicate target names) 2023-09-29 18:20:15 -04:00
Danny McGee ab380bc3da Restore procedural grid shader 2023-09-29 18:19:38 -04:00
Danny McGee fc66d2e1b3 Share assets between Bevy app and web frontend 2023-09-29 18:19:22 -04:00
Danny McGee 7cc20fa500 Fix issues with procedural grid shader 2023-09-29 18:15:53 -04:00
Danny McGee c05f341770 Add hello-world:build:web dependency to hello-web targets 2023-09-28 23:42:53 -04:00
Danny McGee bc8994a780 Get wasm build running in browser 2023-09-28 23:33:08 -04:00
Danny McGee 842f985c23 Document grid_lines function 2023-09-28 17:46:22 -04:00
Danny McGee 6030127f19 Add additional grid-lines layer 2023-09-28 17:46:07 -04:00
Danny McGee dd3b6b1346 Use Bevy's FrameTimeDiagnostics for FPS counter 2023-09-28 17:45:19 -04:00
Danny McGee a4dee10487 Move framerate counter to UI layer 2023-09-28 15:48:50 -04:00
Danny McGee 775c8e43f9 Tweak world-grid plane shader 2023-09-28 15:07:06 -04:00
Danny McGee 5414f9c944 Allow complex types 2023-09-28 15:06:23 -04:00
Danny McGee d70671aaac Only update plane location when camera has moved 2023-09-28 15:05:45 -04:00
Danny McGee 78303cd0b0 Make world-grid plane double-sided 2023-09-28 15:04:26 -04:00
Danny McGee bf6993a412 Monitor framerate 2023-09-28 15:02:05 -04:00
Danny McGee 9e3ce970e3 Remove tutorial stuff 2023-09-27 23:46:36 -04:00
Danny McGee 3dba0ee868 Perf improvement 2023-09-27 23:41:50 -04:00
Danny McGee a60d86f2d2 Camera controller, basic test scene 2023-09-27 23:15:19 -04:00