Skip to content

Commit

Permalink
Merge pull request #70 from yushiang-demo/dev
Browse files Browse the repository at this point in the history
v2.0.0
  • Loading branch information
tsengyushiang authored Dec 16, 2023
2 parents 85bf454 + 2c28de2 commit ebc87fd
Show file tree
Hide file tree
Showing 19 changed files with 385 additions and 62 deletions.
17 changes: 16 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,20 @@ The format is based on [Keep a Changelog](https://github.com/olivierlacan/keep-a

### Removed

## [2.0.0] - 2023-12-16

### Added

- Add camera animation for viewer with `animejs`. (https://github.com/yushiang-demo/pano-to-mesh/pull/68)

### Changed

- Change README.md demo links and snapshots. (https://github.com/yushiang-demo/pano-to-mesh/pull/50)

### Fixed

### Removed

## [1.4.1] - 2023-11-14

### Added
Expand Down Expand Up @@ -171,7 +185,8 @@ Codes without pull requests won't be recorded.

### Removed

[unreleased]: https://github.com/yushiang-demo/PanoToMesh/compare/v1.4.1...HEAD
[unreleased]: https://github.com/yushiang-demo/PanoToMesh/compare/v2.0.0...HEAD
[2.0.0]: https://github.com/yushiang-demo/PanoToMesh/compare/v1.4.1...v2.0.0
[1.4.1]: https://github.com/yushiang-demo/PanoToMesh/compare/v1.4.0...v1.4.1
[1.4.0]: https://github.com/yushiang-demo/PanoToMesh/compare/v1.3.0...v1.4.0
[1.3.0]: https://github.com/yushiang-demo/PanoToMesh/compare/v1.2.0...v1.3.0
Expand Down
Binary file removed Demo.png
Binary file not shown.
48 changes: 24 additions & 24 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,50 +1,50 @@
# Quick start
# Pano-to-mesh

## Development with Yarn
Our tool simplifies 3D panorama creation. You can annotate layouts, preview 3D meshes, export them with textures, arrange your media, share a viewer link for collaboration, and also experience immersive interaction through a first-person view.

## Quick start

### Development

```
yarn
yarn dev
```

## Production with Docker
### Production

### From Dockerfile
- From Dockerfile

```
docker build . -t pano-to-mesh --no-cache
docker run -p 3000:3000 pano-to-mesh
```

### From Github Docker Registry
- From Github Docker Registry

```
docker run -p 3000:3000 ghcr.io/yushiang-demo/pano-to-mesh
```

# Introduction

## Demo

### Editor

- [Panorama to mesh](https://pano-to-mesh.vercel.app/editors/layout2d#eNpdkE9rwzAMxb-Lz8aWHP-Rcyyjt7WHwqCUENKsSTMyJ6TutjL23ecUtrDp8EPiPZ6EPlnTD8O0ZzlwVp-6vgttGlgmtGac9dVtuEb1wPLDAQTav5VxEIZcBriw4MmoQQM6Mg61mmlmo7fGAukf3o1Wg1WzmhqFuPCueufsvxQLhhTgL4uCs7EKw1S9Vunsc4zjJZeyuqBoYv0cRDhF-abky9hKQEleAklHEgGgXJdIHsgRuXK7mvqsQXT7rh693q3O6_fH28dTe9yYTVMfRUpgy67t1LVdSG8BjmJ-RPH1DUTpVnM)
- [Mesh preview and download](https://pano-to-mesh.vercel.app/editors/layout3d#eNpdkE9rwzAMxb-Lz8aWHP-Rcyyjt7WHwqCUENKsSTMyJ6TutjL23ecUtrDp8EPiPZ6EPlnTD8O0ZzlwVp-6vgttGlgmtGac9dVtuEb1wPLDAQTav5VxEIZcBriw4MmoQQM6Mg61mmlmo7fGAukf3o1Wg1WzmhqFuPCueufsvxQLhhTgL4uCs7EKw1S9Vunsc4zjJZeyuqBoYv0cRDhF-abky9hKQEleAklHEgGgXJdIHsgRuXK7mvqsQXT7rh693q3O6_fH28dTe9yYTVMfRUpgy67t1LVdSG8BjmJ-RPH1DUTpVnM)
- [Decoration with media](https://pano-to-mesh.vercel.app/editors/decoration#eNpdkE9rwzAMxb-Lz8aWHP-Rcyyjt7WHwqCUENKsSTMyJ6TutjL23ecUtrDp8EPiPZ6EPlnTD8O0ZzlwVp-6vgttGlgmtGac9dVtuEb1wPLDAQTav5VxEIZcBriw4MmoQQM6Mg61mmlmo7fGAukf3o1Wg1WzmhqFuPCueufsvxQLhhTgL4uCs7EKw1S9Vunsc4zjJZeyuqBoYv0cRDhF-abky9hKQEleAklHEgGgXJdIHsgRuXK7mvqsQXT7rh693q3O6_fH28dTe9yYTVMfRUpgy67t1LVdSG8BjmJ-RPH1DUTpVnM)
## Features

![image](./Demo.png)
- Annotate panorama layouts and preview 3D meshes.
- Export meshes and textures.
- Arrange media, including 3D meshes and HTML elements.
- Experience a first-person view and interact in the viewer.

### Viewer
| [Panorama to mesh] | [Mesh preview and download] |
| :----------------------: | :-------------------------: |
| ![2d.png](./docs/2d.png) | ![3d.png](./docs/3d.png) |

- [Viewer](https://pano-to-mesh.vercel.app#eNpdkE9rwzAMxb-Lz8aWHP-Rcyyjt7WHwqCUENKsSTMyJ6TutjL23ecUtrDp8EPiPZ6EPlnTD8O0ZzlwVp-6vgttGlgmtGac9dVtuEb1wPLDAQTav5VxEIZcBriw4MmoQQM6Mg61mmlmo7fGAukf3o1Wg1WzmhqFuPCueufsvxQLhhTgL4uCs7EKw1S9Vunsc4zjJZeyuqBoYv0cRDhF-abky9hKQEleAklHEgGgXJdIHsgRuXK7mvqsQXT7rh693q3O6_fH28dTe9yYTVMfRUpgy67t1LVdSG8BjmJ-RPH1DUTpVnM)
| [Decoration with media] | [Viewer] |
| :----------------------------: | :-----------------------------: |
| ![media.png](./docs/media.png) | ![view.png](./docs//viewer.png) |

> Demo image is provided by:
> https://as1.ftcdn.net/v2/jpg/01/89/08/78/1000_F_189087887_OBrl3f117Yicp94SBhFwMyxVgbN5Nfcb.jpg
## Features

- Load panorama from url.
- Annotate layout from a panorama and preview 3D Mesh.
- Save 3D mesh and texture to local.
- Share result of viewer and editor with data embedded in URL.
- Editor of arranging media for viewer.
[Panorama to mesh]: https://pano-to-mesh.vercel.app/editors/layout2d#eNrNl19vGzcQxL9Kcc-XM_8suaSf89KHokVSFC1co7jYZ1mtpFMlGagR-Lv3t1ITSJGdKIkLRBBki-LdcYczO8O3zbJfjKt-3jfnzdlqWI93q6thffZutPtzOWna95N-XE0n00VzfuFa36XWXbbNzWwcV781565trobpbLqY8KWJXYxcN-vvx7tNeMkVF67LMfoiKcTiqn22NuRC9c6l3We8bJkXa06q72a5GpmYqob913aiz6FKllCSej7zdmLRyvD793Zi1SIhZF-dKJ_2YJel-PfvdEkp8-F6Cg4Xb5vNql-sb8bVvN9MR-p92yzH9XT3_8UL37lSJGsNKhrE81zfFe9zjb5ahTGqtKFLOWjiq69KmUV4xPqqnw3cI3bOB599VldEVEtkvovBxSjM9S5w__Z4Frf4-67fDKvFbi2OUooLPCnzp7joom_dFq-csjKQxIG7XD60zeZ-ybObX6bXw8jmrIb-elzM7pvzm362Htrmut_0Vut6dXXIhi0w3XwpzcND-yl0qENYcpJaYmRZBXAkaSilGjo1ssb2BTvAN6pLxUnVHMsBOjGoyz55cdV5DTtwqnPFx1qSz7k9mvMc0Ly-7a-H1XdfgxAyGGfjqjln11Sp79OQUYpLmjOrrDH5IEq9vgSrqgT4rD4BmQELg6nZJ0215kM-MQAdIaYmJJNAHT4ml0SQhkguvj2edQzadmdAOEUH7QIbFraocQ3Q80sqNedU9lD7ft5Phi-Aa7mYnEAo6RxKK67kADIoxFpPVHQMvFFThGoMOYlVAjpJVdjgcAgOmpRATUg27aCBPIhTUWzNYnQ6nPMswPxHp6_B5wvoZLT3KpVqTIBarOBEj0SQjKM1FegUO2st1rZiSpn-eYCYZtopjbjkLHAow8iybZlwr9Lg6N4RWQNWTakgSAilj0nQR5_o47TxYMJLW8xq9cgxhZxrcjGHfTLdYDQnoHW72SzX52dnm_WwmNzfrW-n_WLSTaab27s33XQ8W4wbgDylYWE4ScU5oekG6kMooQsZr8p0L6mMBlNfxapctvaOVHM6gCvRwLxxoJZcIQYMg2ASksPBog-xGkVj0Wx3K-qpuzwHXD8P_2w-BtbGfj9vXg7z8ffFq3Gcn4IIbuZEos-IyUWhFVlDqhRWIjjhtIyw1iJmawVZ0r2C30PE2bqfoyP_NOuvhttxZjoiRzxd6UllVfHBGmhE--rj1qPFFeyVFMGgU9toUSlAr1GwX9RySl2fu2_PW1dBhSZVnkfgcBY-tFJqwCxrjUFYEIXhBoZxNhQ8qv72C9vuFDGuKFmLnEBhtZCQotHFw9KtMjG6gkk6lUxrTulbr8t1YiEmZUyLeFh2jq-0eCKrVxKS7loOQouKYSdhUb5-43WhL-eNdmJbVWiS1gfxZ6qg7zkXyTPYRsLIqdr6aMBK9qoSnD1hUuR04jqR0WAJ2QxXwYWWmtqjOY9adS2cDOjFmUhVS9lZtSdEizpvtshy_P_UaIKddCqHFJIIIcULj0Zv-y_xtuMQFlrTETFhQat7SHAPnCJTBquF7SKWeGEI8ZCaSG-ixyNHULASOh2wKZ5D3PGGjaVN5aQBRcgEduunBj-8eg-vH4b17WdlmtdgOx1W3WT2xlLNbLrk91d3i-aURCPwF2aH7YHQU4YhauRgvZhRxmA5PtZ4gKBgt4kYnZNdvUWc7BaZD0eLxbb2eNKHEIIC51IsAyAKO0X4cbahoAInYZJy0nGaHx86vvRrIPz1zbg5xG-9GPq__gAqS0yb6dxua3KvzSlyxSCUUwcLTLZWDgd7L-9qSweGwqTaoGonD866ewjTntV7zmRwkBRA-kXv5EMykp31yEIkqvZ41iMQE5oQOZkoVYuoamJlq4LpnIxanBb_xNiHlz6h6fhxTV8-_Avsc5U2
[Mesh preview and download]: https://pano-to-mesh.vercel.app/editors/layout3d#eNrNl19vGzcQxL9Kcc-XM_8suaSf89KHokVSFC1co7jYZ1mtpFMlGagR-Lv3t1ITSJGdKIkLRBBki-LdcYczO8O3zbJfjKt-3jfnzdlqWI93q6thffZutPtzOWna95N-XE0n00VzfuFa36XWXbbNzWwcV781565trobpbLqY8KWJXYxcN-vvx7tNeMkVF67LMfoiKcTiqn22NuRC9c6l3We8bJkXa06q72a5GpmYqob913aiz6FKllCSej7zdmLRyvD793Zi1SIhZF-dKJ_2YJel-PfvdEkp8-F6Cg4Xb5vNql-sb8bVvN9MR-p92yzH9XT3_8UL37lSJGsNKhrE81zfFe9zjb5ahTGqtKFLOWjiq69KmUV4xPqqnw3cI3bOB599VldEVEtkvovBxSjM9S5w__Z4Frf4-67fDKvFbi2OUooLPCnzp7joom_dFq-csjKQxIG7XD60zeZ-ybObX6bXw8jmrIb-elzM7pvzm362Htrmut_0Vut6dXXIhi0w3XwpzcND-yl0qENYcpJaYmRZBXAkaSilGjo1ssb2BTvAN6pLxUnVHMsBOjGoyz55cdV5DTtwqnPFx1qSz7k9mvMc0Ly-7a-H1XdfgxAyGGfjqjln11Sp79OQUYpLmjOrrDH5IEq9vgSrqgT4rD4BmQELg6nZJ0215kM-MQAdIaYmJJNAHT4ml0SQhkguvj2edQzadmdAOEUH7QIbFraocQ3Q80sqNedU9lD7ft5Phi-Aa7mYnEAo6RxKK67kADIoxFpPVHQMvFFThGoMOYlVAjpJVdjgcAgOmpRATUg27aCBPIhTUWzNYnQ6nPMswPxHp6_B5wvoZLT3KpVqTIBarOBEj0SQjKM1FegUO2st1rZiSpn-eYCYZtopjbjkLHAow8iybZlwr9Lg6N4RWQNWTakgSAilj0nQR5_o47TxYMJLW8xq9cgxhZxrcjGHfTLdYDQnoHW72SzX52dnm_WwmNzfrW-n_WLSTaab27s33XQ8W4wbgDylYWE4ScU5oekG6kMooQsZr8p0L6mMBlNfxapctvaOVHM6gCvRwLxxoJZcIQYMg2ASksPBog-xGkVj0Wx3K-qpuzwHXD8P_2w-BtbGfj9vXg7z8ffFq3Gcn4IIbuZEos-IyUWhFVlDqhRWIjjhtIyw1iJmawVZ0r2C30PE2bqfoyP_NOuvhttxZjoiRzxd6UllVfHBGmhE--rj1qPFFeyVFMGgU9toUSlAr1GwX9RySl2fu2_PW1dBhSZVnkfgcBY-tFJqwCxrjUFYEIXhBoZxNhQ8qv72C9vuFDGuKFmLnEBhtZCQotHFw9KtMjG6gkk6lUxrTulbr8t1YiEmZUyLeFh2jq-0eCKrVxKS7loOQouKYSdhUb5-43WhL-eNdmJbVWiS1gfxZ6qg7zkXyTPYRsLIqdr6aMBK9qoSnD1hUuR04jqR0WAJ2QxXwYWWmtqjOY9adS2cDOjFmUhVS9lZtSdEizpvtshy_P_UaIKddCqHFJIIIcULj0Zv-y_xtuMQFlrTETFhQat7SHAPnCJTBquF7SKWeGEI8ZCaSG-ixyNHULASOh2wKZ5D3PGGjaVN5aQBRcgEduunBj-8eg-vH4b17WdlmtdgOx1W3WT2xlLNbLrk91d3i-aURCPwF2aH7YHQU4YhauRgvZhRxmA5PtZ4gKBgt4kYnZNdvUWc7BaZD0eLxbb2eNKHEIIC51IsAyAKO0X4cbahoAInYZJy0nGaHx86vvRrIPz1zbg5xG-9GPq__gAqS0yb6dxua3KvzSlyxSCUUwcLTLZWDgd7L-9qSweGwqTaoGonD866ewjTntV7zmRwkBRA-kXv5EMykp31yEIkqvZ41iMQE5oQOZkoVYuoamJlq4LpnIxanBb_xNiHlz6h6fhxTV8-_Avsc5U2
[Decoration with media]: https://pano-to-mesh.vercel.app/editors/decoration#eNrNl19vGzcQxL9Kcc-XM_8suaSf89KHokVSFC1co7jYZ1mtpFMlGagR-Lv3t1ITSJGdKIkLRBBki-LdcYczO8O3zbJfjKt-3jfnzdlqWI93q6thffZutPtzOWna95N-XE0n00VzfuFa36XWXbbNzWwcV781565trobpbLqY8KWJXYxcN-vvx7tNeMkVF67LMfoiKcTiqn22NuRC9c6l3We8bJkXa06q72a5GpmYqob913aiz6FKllCSej7zdmLRyvD793Zi1SIhZF-dKJ_2YJel-PfvdEkp8-F6Cg4Xb5vNql-sb8bVvN9MR-p92yzH9XT3_8UL37lSJGsNKhrE81zfFe9zjb5ahTGqtKFLOWjiq69KmUV4xPqqnw3cI3bOB599VldEVEtkvovBxSjM9S5w__Z4Frf4-67fDKvFbi2OUooLPCnzp7joom_dFq-csjKQxIG7XD60zeZ-ybObX6bXw8jmrIb-elzM7pvzm362Htrmut_0Vut6dXXIhi0w3XwpzcND-yl0qENYcpJaYmRZBXAkaSilGjo1ssb2BTvAN6pLxUnVHMsBOjGoyz55cdV5DTtwqnPFx1qSz7k9mvMc0Ly-7a-H1XdfgxAyGGfjqjln11Sp79OQUYpLmjOrrDH5IEq9vgSrqgT4rD4BmQELg6nZJ0215kM-MQAdIaYmJJNAHT4ml0SQhkguvj2edQzadmdAOEUH7QIbFraocQ3Q80sqNedU9lD7ft5Phi-Aa7mYnEAo6RxKK67kADIoxFpPVHQMvFFThGoMOYlVAjpJVdjgcAgOmpRATUg27aCBPIhTUWzNYnQ6nPMswPxHp6_B5wvoZLT3KpVqTIBarOBEj0SQjKM1FegUO2st1rZiSpn-eYCYZtopjbjkLHAow8iybZlwr9Lg6N4RWQNWTakgSAilj0nQR5_o47TxYMJLW8xq9cgxhZxrcjGHfTLdYDQnoHW72SzX52dnm_WwmNzfrW-n_WLSTaab27s33XQ8W4wbgDylYWE4ScU5oekG6kMooQsZr8p0L6mMBlNfxapctvaOVHM6gCvRwLxxoJZcIQYMg2ASksPBog-xGkVj0Wx3K-qpuzwHXD8P_2w-BtbGfj9vXg7z8ffFq3Gcn4IIbuZEos-IyUWhFVlDqhRWIjjhtIyw1iJmawVZ0r2C30PE2bqfoyP_NOuvhttxZjoiRzxd6UllVfHBGmhE--rj1qPFFeyVFMGgU9toUSlAr1GwX9RySl2fu2_PW1dBhSZVnkfgcBY-tFJqwCxrjUFYEIXhBoZxNhQ8qv72C9vuFDGuKFmLnEBhtZCQotHFw9KtMjG6gkk6lUxrTulbr8t1YiEmZUyLeFh2jq-0eCKrVxKS7loOQouKYSdhUb5-43WhL-eNdmJbVWiS1gfxZ6qg7zkXyTPYRsLIqdr6aMBK9qoSnD1hUuR04jqR0WAJ2QxXwYWWmtqjOY9adS2cDOjFmUhVS9lZtSdEizpvtshy_P_UaIKddCqHFJIIIcULj0Zv-y_xtuMQFlrTETFhQat7SHAPnCJTBquF7SKWeGEI8ZCaSG-ixyNHULASOh2wKZ5D3PGGjaVN5aQBRcgEduunBj-8eg-vH4b17WdlmtdgOx1W3WT2xlLNbLrk91d3i-aURCPwF2aH7YHQU4YhauRgvZhRxmA5PtZ4gKBgt4kYnZNdvUWc7BaZD0eLxbb2eNKHEIIC51IsAyAKO0X4cbahoAInYZJy0nGaHx86vvRrIPz1zbg5xG-9GPq__gAqS0yb6dxua3KvzSlyxSCUUwcLTLZWDgd7L-9qSweGwqTaoGonD866ewjTntV7zmRwkBRA-kXv5EMykp31yEIkqvZ41iMQE5oQOZkoVYuoamJlq4LpnIxanBb_xNiHlz6h6fhxTV8-_Avsc5U2
[Viewer]: https://pano-to-mesh.vercel.app/#eNrNl19vGzcQxL9Kcc-XM_8suaSf89KHokVSFC1co7jYZ1mtpFMlGagR-Lv3t1ITSJGdKIkLRBBki-LdcYczO8O3zbJfjKt-3jfnzdlqWI93q6thffZutPtzOWna95N-XE0n00VzfuFa36XWXbbNzWwcV781565trobpbLqY8KWJXYxcN-vvx7tNeMkVF67LMfoiKcTiqn22NuRC9c6l3We8bJkXa06q72a5GpmYqob913aiz6FKllCSej7zdmLRyvD793Zi1SIhZF-dKJ_2YJel-PfvdEkp8-F6Cg4Xb5vNql-sb8bVvN9MR-p92yzH9XT3_8UL37lSJGsNKhrE81zfFe9zjb5ahTGqtKFLOWjiq69KmUV4xPqqnw3cI3bOB599VldEVEtkvovBxSjM9S5w__Z4Frf4-67fDKvFbi2OUooLPCnzp7joom_dFq-csjKQxIG7XD60zeZ-ybObX6bXw8jmrIb-elzM7pvzm362Htrmut_0Vut6dXXIhi0w3XwpzcND-yl0qENYcpJaYmRZBXAkaSilGjo1ssb2BTvAN6pLxUnVHMsBOjGoyz55cdV5DTtwqnPFx1qSz7k9mvMc0Ly-7a-H1XdfgxAyGGfjqjln11Sp79OQUYpLmjOrrDH5IEq9vgSrqgT4rD4BmQELg6nZJ0215kM-MQAdIaYmJJNAHT4ml0SQhkguvj2edQzadmdAOEUH7QIbFraocQ3Q80sqNedU9lD7ft5Phi-Aa7mYnEAo6RxKK67kADIoxFpPVHQMvFFThGoMOYlVAjpJVdjgcAgOmpRATUg27aCBPIhTUWzNYnQ6nPMswPxHp6_B5wvoZLT3KpVqTIBarOBEj0SQjKM1FegUO2st1rZiSpn-eYCYZtopjbjkLHAow8iybZlwr9Lg6N4RWQNWTakgSAilj0nQR5_o47TxYMJLW8xq9cgxhZxrcjGHfTLdYDQnoHW72SzX52dnm_WwmNzfrW-n_WLSTaab27s33XQ8W4wbgDylYWE4ScU5oekG6kMooQsZr8p0L6mMBlNfxapctvaOVHM6gCvRwLxxoJZcIQYMg2ASksPBog-xGkVj0Wx3K-qpuzwHXD8P_2w-BtbGfj9vXg7z8ffFq3Gcn4IIbuZEos-IyUWhFVlDqhRWIjjhtIyw1iJmawVZ0r2C30PE2bqfoyP_NOuvhttxZjoiRzxd6UllVfHBGmhE--rj1qPFFeyVFMGgU9toUSlAr1GwX9RySl2fu2_PW1dBhSZVnkfgcBY-tFJqwCxrjUFYEIXhBoZxNhQ8qv72C9vuFDGuKFmLnEBhtZCQotHFw9KtMjG6gkk6lUxrTulbr8t1YiEmZUyLeFh2jq-0eCKrVxKS7loOQouKYSdhUb5-43WhL-eNdmJbVWiS1gfxZ6qg7zkXyTPYRsLIqdr6aMBK9qoSnD1hUuR04jqR0WAJ2QxXwYWWmtqjOY9adS2cDOjFmUhVS9lZtSdEizpvtshy_P_UaIKddCqHFJIIIcULj0Zv-y_xtuMQFlrTETFhQat7SHAPnCJTBquF7SKWeGEI8ZCaSG-ixyNHULASOh2wKZ5D3PGGjaVN5aQBRcgEduunBj-8eg-vH4b17WdlmtdgOx1W3WT2xlLNbLrk91d3i-aURCPwF2aH7YHQU4YhauRgvZhRxmA5PtZ4gKBgt4kYnZNdvUWc7BaZD0eLxbb2eNKHEIIC51IsAyAKO0X4cbahoAInYZJy0nGaHx86vvRrIPz1zbg5xG-9GPq__gAqS0yb6dxua3KvzSlyxSCUUwcLTLZWDgd7L-9qSweGwqTaoGonD866ewjTntV7zmRwkBRA-kXv5EMykp31yEIkqvZ41iMQE5oQOZkoVYuoamJlq4LpnIxanBb_xNiHlz6h6fhxTV8-_Avsc5U2
104 changes: 93 additions & 11 deletions apps/viewer.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React, { useRef, useMemo } from "react";

import React, { useRef, useMemo, useState, useCallback } from "react";
import Animator from "@pano-to-mesh/anime";
import {
Core,
Loaders,
ThreeCanvas,
PanoramaProjectionMesh,
Expand All @@ -10,11 +11,17 @@ import {
import useClick2AddWalls from "../hooks/useClick2AddWalls";
import MediaManager from "../components/MediaManager";
import { MEDIA_2D, MEDIA_3D } from "../components/MediaManager/types";
import useMouseSkipDrag from "../hooks/useMouseSkipDrag";
import ToolbarRnd from "../components/ToolbarRnd";
import Toolbar from "../components/Toolbar";
import Icons from "../components/Icon";

const dev = process.env.NODE_ENV === "development";
const Viewer = ({ data }) => {
const threeRef = useRef(null);

const [isTopView, setIsTopView] = useState(true);
const [isCameraMoving, setIsCameraMoving] = useState(false);
const [baseMesh, setBaseMesh] = useState(null);
const geometryInfo = useMemo(
() => ({
floorY: data.floorY,
Expand All @@ -35,22 +42,97 @@ const Viewer = ({ data }) => {
panorama: Loaders.useTexture({ src: data.panorama }),
};

const onLoad = (mesh) => {
const onLoad = useCallback((mesh) => {
threeRef.current.cameraControls.focus(mesh);
};
setBaseMesh(mesh);
}, []);

const media = (data.media || []).filter(
(data) =>
![MEDIA_3D.PLACEHOLDER_3D, MEDIA_2D.PLACEHOLDER_2D].includes(data.type)
);

const runAnimation = (clips, onfinish) => {
if (isCameraMoving) return;

const timeline = Animator.createTimeline();
clips.forEach(timeline.addClip);
timeline.play();
timeline.finished.then(() => {
setIsCameraMoving(false);
if (onfinish) onfinish();
});
setIsCameraMoving(true);
};

const goTop = () => {
if (isCameraMoving) return;

const { cameraControls } = threeRef.current;
const { animations } = cameraControls;
const clip = animations.moveToTop(baseMesh);

runAnimation(clip, () => setIsTopView(true));
};

const goDown = () => {
if (isCameraMoving) return;

const { cameraControls } = threeRef.current;
const { animations } = cameraControls;
const clip = animations.moveFromTop(data.panoramaOrigin);

runAnimation(clip, () => setIsTopView(false));
};

const eventsHandlers = useMouseSkipDrag(({ normalizedX, normalizedY }) => {
const { cameraControls } = threeRef.current;
const { animations } = cameraControls;

const intersections = Core.raycastMeshFromScreen(
[normalizedX, normalizedY],
cameraControls.getCamera(),
baseMesh
);

const firstIntersections = intersections[0];

if (!firstIntersections) return;

const { faceNormal, point } = firstIntersections;
const cameraHeight = data.panoramaOrigin[1];
const target = [
point[0] + faceNormal[0] * cameraHeight,
cameraHeight,
point[2] + faceNormal[2] * cameraHeight,
];

runAnimation(
(isTopView ? animations.moveFromTop : animations.moveTo)(target),
() => setIsTopView(false)
);
});

return (
<ThreeCanvas dev={dev} ref={threeRef}>
<BackgroundPanel />
<Light />
<PanoramaProjectionMesh {...textureMeshProps} onLoad={onLoad} />
<MediaManager data={media} />
</ThreeCanvas>
<>
<ThreeCanvas dev={dev} ref={threeRef} {...eventsHandlers}>
<BackgroundPanel />
<Light />
<PanoramaProjectionMesh {...textureMeshProps} onLoad={onLoad} />
<MediaManager data={media} />
</ThreeCanvas>
{!isCameraMoving && (
<ToolbarRnd>
<Toolbar>
{isTopView ? (
<Icons.arrowToDown onClick={goDown} />
) : (
<Icons.arrowToTop onClick={goTop} />
)}
</Toolbar>
</ToolbarRnd>
)}
</>
);
};

Expand Down
2 changes: 2 additions & 0 deletions components/Icon/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ const Icon = ({ src, onClick, ...props }) => {
// all svg resources is download from https://www.svgrepo.com/vectors/cursor/
const IconFolder = `/icons`;
const files = {
arrowToDown: `${IconFolder}/arrowToDown.svg`,
arrowToTop: `${IconFolder}/arrowToTop.svg`,
download: `${IconFolder}/download.svg`,
panorama: `${IconFolder}/panorama.svg`,
camera: `${IconFolder}/camera.svg`,
Expand Down
Binary file added docs/2d.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/3d.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/media.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/viewer.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
36 changes: 36 additions & 0 deletions hooks/useMouseSkipDrag.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { useState } from "react";

const MOUSE_UP_THRESHOLD = 5;

const useMouseSkipDrag = (handleMouseUp) => {
const [cursorPosition, setCursorPosition] = useState(null);
const [cumulativeDelta, setCumulativeDelta] = useState(0);

const onMouseDown = ({ offsetX, offsetY }) => {
setCursorPosition({ offsetX, offsetY });
setCumulativeDelta(0);
};
const onMouseMove = ({ offsetX, offsetY }) => {
if (!cursorPosition) return;
setCumulativeDelta(
(prev) =>
prev +
Math.abs(offsetX - cursorPosition.offsetX) +
Math.abs(offsetY - cursorPosition.offsetY)
);
setCursorPosition({ offsetX, offsetY });
};
const onMouseUp = (data) => {
setCursorPosition(null);
if (MOUSE_UP_THRESHOLD < cumulativeDelta) return;
handleMouseUp(data);
};

return {
onMouseDown,
onMouseMove,
onMouseUp,
};
};

export default useMouseSkipDrag;
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"lint": "next lint"
},
"dependencies": {
"@pano-to-mesh/anime": "1.0.0",
"@pano-to-mesh/three": "1.0.0",
"@pano-to-mesh/base64": "1.0.0",
"next": "13.2.4",
Expand Down
47 changes: 47 additions & 0 deletions packages/anime/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import anime from "animejs";

const Animator = (() => {
const createTimeline = () => {
const animation = anime.timeline({
autoplay: false,
});

const addClip = ({
begin,
update,
complete,
duration,
easing,
timeOffset,
}) => {
animation.add(
{
duration: duration || 1e3,
easing: easing || "linear",
update: (anim) => {
update(anim.progress / 1e2);
},
begin: begin,
complete: complete,
},
timeOffset
);
};

const play = () => {
animation.play();
};

return {
finished: animation.finished,
addClip,
play,
};
};

return {
createTimeline,
};
})();

export default Animator;
7 changes: 7 additions & 0 deletions packages/anime/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"version": "1.0.0",
"name": "@pano-to-mesh/anime",
"dependencies": {
"animejs": "^3.2.2"
}
}
1 change: 1 addition & 0 deletions packages/three/components/ThreeCanvas/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ const ThreeCanvas = (
setThree(publicProps);

const cancelResizeListener = addBeforeRenderEvent(() => {
if (!WrapperRef.current) return;
const { clientWidth: width, clientHeight: height } = WrapperRef.current;
setCanvasSize(width, height);
css3DControls.setSize(width, height);
Expand Down
Loading

1 comment on commit ebc87fd

@vercel
Copy link

@vercel vercel bot commented on ebc87fd Dec 16, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

pano-to-mesh – ./

pano-to-mesh.vercel.app
pano-to-mesh-git-main-yushiang.vercel.app
pano-to-mesh-yushiang.vercel.app

Please sign in to comment.