feat(stage-ui): VRM model setting page: FOV and Rotation#307
feat(stage-ui): VRM model setting page: FOV and Rotation#307nekomeowww merged 19 commits intomoeru-ai:mainfrom
Conversation
✅ Deploy Preview for airi-vtuber ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
✅ Deploy Preview for airi-docs ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
There was a problem hiding this comment.
Summary of Changes
Hello @Lilia-Chen, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!
This pull request significantly enhances the VRM model setting page by introducing new user controls for camera Field of View (FOV) and model Y-axis rotation. It refines the interactive experience by implementing a custom OrbitControls that restricts camera movement to rotation and zooming, aligning with the technical limitations and desired user interaction. Furthermore, the changes include improvements to model loading logic, dynamic adjustment of positioning controls, and persistence of user settings, all contributing to a more flexible and user-friendly VRM model customization experience.
Highlights
- VRM Model Customization: Introduced new UI controls for adjusting the camera's Field of View (FOV) and the VRM model's rotation around the Y-axis, enhancing user control over model presentation.
- Improved Camera Interaction: Implemented a custom
OrbitControlscomponent that explicitly disables camera panning, ensuring that users can only rotate and 'zoom' (dolly) the VRM model, aligning with the stated design constraints. - Dynamic Model Positioning: Refined the X, Y, and Z offset sliders to dynamically adjust their ranges based on the loaded VRM model's dimensions, providing more intuitive and relevant controls.
- Enhanced Model Loading & Persistence: Updated the model loading mechanism to prevent redundant reloads and introduced
localStoragepersistence for camera FOV, initial camera position, and model Y-rotation settings. - Structural Improvements: Encapsulated the VRM model within a new
VRMGroupobject, simplifying model manipulation (like rotation) and enabling a more robust initial camera positioning calculation based on model size.
Using Gemini Code Assist
The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.
Invoking Gemini
You can request assistance from Gemini at any point in your pull request via creating an issue comment (i.e. comment on the pull request page) using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands.
| Feature | Command | Description |
|---|---|---|
| Code Review | /gemini review |
Performs a code review for the current pull request in its current state. |
| Pull Request Summary | /gemini summary |
Provides a summary of the current pull request in its current state. |
| Comment | @gemini-code-assist | Responds in comments when explicitly tagged, both in issue comments and review comments. |
| Help | /gemini help |
Displays a list of available commands. |
Customization
To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.
Limitations & Feedback
Gemini Code Assist is currently in preview and may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments to provide feedback.
You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.
Footnotes
-
Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution. ↩
There was a problem hiding this comment.
Code Review
This pull request introduces new features for the VRM model settings page, including camera Field of View (FOV) adjustment and model rotation. It also includes a refactoring of the VRM scene setup. I've identified a critical bug in the scene graph manipulation that would break model rotation, and a high-severity issue where the camera's aspect ratio doesn't update on resize, causing visual distortion.
| // watch([width, height], () => { | ||
| // if (camera.value) { | ||
| // camera.value.aspect = width.value / height.value | ||
| // camera.value.updateProjectionMatrix() | ||
| // } | ||
| // }) |
There was a problem hiding this comment.
The commented-out watcher for width and height is necessary for keeping the camera's aspect ratio in sync with the component's dimensions. Without it, the rendered scene will appear stretched or squashed if the component or window is resized. Enable this to prevent visual distortions.
watch([width, height], () => {
if (camera.value) {
camera.value.aspect = width.value / height.value
camera.value.updateProjectionMatrix()
}
})
There was a problem hiding this comment.
Tbh I'm not sure if this is necessary or ideal. Although this can let the camera's aspect ratio be in sync with the component's dimensions... due to the render of the animation, the image will be stretched... which is ugly tbf.
| function urlUploadClick() { | ||
| modelUrl.value = localModelUrl.value | ||
| // same URL will let the loader be lazy and forgot to reset loading state | ||
| // If the loading state is still true, then the URL input will be locked | ||
| if (modelUrl.value === selectedModel.value) { | ||
| console.warn('Model URL is the same as the selected model, no need to reload.') | ||
| return | ||
| } | ||
| // Can't let the default model URL be reentered into the loader, otherwise it will still be too lazy to reset the loading state | ||
| if (!modelUrl.value && selectedModel.value === defaultModelUrl.value) { | ||
| localModelUrl.value = defaultModelUrl.value | ||
| return | ||
| } | ||
| // Only when real different URL is entered, then the loader will be triggered | ||
| loadSource.value = 'url' | ||
| loadingModel.value = true | ||
| localModelUrl.value = selectedModel.value | ||
| } |
There was a problem hiding this comment.
The line localModelUrl.value = selectedModel.value at the end of urlUploadClick function will reset the URL input field to the previously loaded model's URL right after the user clicks the load button. This can be confusing for the user, as the URL they just entered will be replaced. Removing this line preserves the user's input in the text field.
function urlUploadClick() {
modelUrl.value = localModelUrl.value
// same URL will let the loader be lazy and forgot to reset loading state
// If the loading state is still true, then the URL input will be locked
if (modelUrl.value === selectedModel.value) {
console.warn('Model URL is the same as the selected model, no need to reload.')
return
}
// Can't let the default model URL be reentered into the loader, otherwise it will still be too lazy to reset the loading state
if (!modelUrl.value && selectedModel.value === defaultModelUrl.value) {
localModelUrl.value = defaultModelUrl.value
return
}
// Only when real different URL is entered, then the loader will be triggered
loadSource.value = 'url'
loadingModel.value = true
}
There was a problem hiding this comment.
This may not be the most elegant way to do things, but I just want to consider the following situation:
- In common, we hope the input area retains what the user has input
- If the user inputs nothing and clicks the import form URL button, then we just load the default model
- The default model still has a URL, so I think maybe it's better to put it in the input area as a reminder that there is a URL for the model
@nekomeowww What's your opinion on this? Just want to seek some advice on the front-end design~
Co-authored-by: Neko <neko@ayaka.moe>
… model into the vrmGroup
Co-authored-by: Neko <neko@ayaka.moe>
|
|
||
| // Compute the initial camera position (once per loaded model) | ||
| // In order to see the up-2/3 part fo the model, z = (y/3) / tan(fov/2) | ||
| const fov = 40 // default fov = 40 degrees |
nekomeowww
left a comment
There was a problem hiding this comment.
Much appreciated! 🎉 You made a lot progress for our 3D scenes for VRM models. Really thanks. One of the best contributors in field of 3D.
--------- Co-authored-by: Neko <neko@ayaka.moe>
--------- Co-authored-by: Neko <neko@ayaka.moe>
Description
New features for the VRM model setting page:
Linked Issues
Trackers for some VRM model future ideas
Additional context
Due to the functionality limits of Tres.js and Three.js, there is no way to use them to implement a similar camera movement trace as it is in Blender. The focusing target is also the rotation centre of the camera movement.
Therefore, I just banned the pan function in the OrbitControls. Currently, users can only rotate and "scale" (actually changing the distance between the target and the camera) in the interactive TresCanvas.