-
Notifications
You must be signed in to change notification settings - Fork 822
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
AR autogenerate USDZ #2374
AR autogenerate USDZ #2374
Conversation
Thanks, I notice you reference my own PR on this topic; can you give a bit of detail of how yours is different or what it adds? |
Hello, yes. I checked your implementation, the key differences in mine are:
|
@@ -327,7 +331,12 @@ configuration or device capabilities'); | |||
* Takes a URL to a USDZ file and sets the appropriate fields so that Safari | |||
* iOS can intent to their AR Quick Look. | |||
*/ | |||
[$openIOSARQuickLook]() { | |||
async[$openIOSARQuickLook]() { | |||
if (this.arAutogenerateUsdz && !this.iosSrc) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Generate USDZ on the fly only if autogenerate property is set and there is not ios-src.
Also disable temporally the AR button so the user cannot press it multiple times during the export.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Take a look at the documentation updates in my PR and let me know what you think of my alternative solution to this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, the export of USDZ has a tons of limitations, I'm very aware of them and I had a really hard time creating dozens of workarounds about them. That was actually one of the main reasons why I wanted to leave a possibility to disable the on the fly generation, sometimes you still want your static prepared ahead USDZ file or set it manually from a pool of static variants or something like this, in any case we need a mechanism to turn it on/off
Fantastic! 2-6 are great; I simply hadn't gotten around to those yet. I think I prefer my method of keeping this from being a breaking change without introducing a new attribute. Do you agree? If so, I think merging our PRs would be ideal. Would you like to pull mine into yours and I can review? |
@@ -72,6 +73,8 @@ export const ARMixin = <T extends Constructor<ModelViewerElementBase>>( | |||
ModelViewerElement: T): Constructor<ARInterface>&T => { | |||
class ARModelViewerElement extends ModelViewerElement { | |||
@property({type: Boolean, attribute: 'ar'}) ar: boolean = false; | |||
@property({type: Boolean, attribute: 'ar-autogenerate-usdz'}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Set this property to true if you want to enable on the fly USDZ generation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did you see my comment about doing this without introducing a new attribute? If you look at my PR, I changed the logic a bit so that the presence of ios-src
automatically enables Quick Look, while explicitly adding the quick-look
ar-mode
opts in to USDZ generation. I think I prefer that approach; what do you think? Would you mind merging in that part of my PR here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, quick-look presence can be enough. I also added blob clean up before creating a new one (see the commit)
@@ -340,9 +349,50 @@ configuration or device capabilities'); | |||
const img = document.createElement('img'); | |||
anchor.appendChild(img); | |||
anchor.setAttribute('href', modelUrl.toString()); | |||
if (this.arAutogenerateUsdz) { | |||
anchor.setAttribute('download', 'model.usdz'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this tricks Safari to open the Quick Look. the file name has been chosen the same as it is in USDZExporter.js, although it could be anything.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In my testing it wasn't necessary on my iPhone SE. But it also probably doesn't hurt anything.
@@ -340,9 +349,50 @@ configuration or device capabilities'); | |||
const img = document.createElement('img'); | |||
anchor.appendChild(img); | |||
anchor.setAttribute('href', modelUrl.toString()); | |||
if (this.arAutogenerateUsdz) { | |||
anchor.setAttribute('download', 'model.usdz'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What does this do? Is it necessary?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When I prepare the Blob, I use simply "application/octet-stream"for the type. So Safari need a "hint" to treat the link as a valid source to open Quick Look, that's why there is a download attribute. As a side effect you can also test the export in desktop browser as it will download the usdz file for you.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, interesting. I think it worked for me because I used a more specific mime type; you can see in my PR. The button still doesn't appear on desktop Safari though, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, you have to manually override IS_AR_QUICKLOOK_CANDIDATE constant :)
type: 'application/octet-stream', | ||
}); | ||
|
||
this.iosSrc = URL.createObjectURL(blob); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure I like this internal detail being publicly visible; maybe better to create a new private symbol instead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You mean showing the loading bar? I was initially thinking about showing some custom poster but then decided to just show some simulated (0.2) progress. On latest iPhone it is quite immediate to export a simple scene, but on older devices or when the scene is quite complex, it might require more time.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, the loading bar is great. It's just that this.iosSrc
is part of our public API. If someone replaced it without revoking it, bad things would happen. I just mean we should store our blob as a private member instead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, ok. Infact, ios-src continue to store only the url string not the actual blob. I need to check if when we call URL.revoke... if it actually dispose the blob and to not create a memory leak here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Or the Blob is garbage collected after URL.revokeObjectURL is called?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it is probably still a good thing to store blob url in separate member. Let me make those changes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added more details using comments in code
You may want to try with the |
@mrdoob Honestly it already feels faster than downloading the separate USDZ, even on my old SE. I'd rather stick to released versions :). We'll update soon enough anyway. |
const modelUrl = new URL(this.iosSrc!, self.location.toString()); | ||
const modelUrl = this.arAutogenerateUsdz ? | ||
new URL(this[$generatedIosUrl]!, self.location.toString()) : | ||
new URL(this.iosSrc!, self.location.toString()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can put the ternary op inside of the new URL()
to simplify this a bit.
@@ -72,6 +73,8 @@ export const ARMixin = <T extends Constructor<ModelViewerElementBase>>( | |||
ModelViewerElement: T): Constructor<ARInterface>&T => { | |||
class ARModelViewerElement extends ModelViewerElement { | |||
@property({type: Boolean, attribute: 'ar'}) ar: boolean = false; | |||
@property({type: Boolean, attribute: 'ar-autogenerate-usdz'}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did you see my comment about doing this without introducing a new attribute? If you look at my PR, I changed the logic a bit so that the presence of ios-src
automatically enables Quick Look, while explicitly adding the quick-look
ar-mode
opts in to USDZ generation. I think I prefer that approach; what do you think? Would you mind merging in that part of my PR here?
[$openIOSARQuickLook]() { | ||
const modelUrl = new URL(this.iosSrc!, self.location.toString()); | ||
async[$openIOSARQuickLook]() { | ||
if (this.arAutogenerateUsdz && !this[$generatedIosUrl]) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, I just noticed a problematic aspect of your feature 2: if the file changes due to the scene-graph API (switched variant, swapped texture/color etc) and you jump into Quick Look again, you won't see the changes due to caching the USDZ. We could either skip the cache entirely (I don't think the perf change is a huge deal, especially since going into Quick Look twice with the same model is probably pretty rare), or else we'd have to add some kind of isDirty
for the scene-graph functions that would tell us to regenerate the USDZ. I think simpler is better, especially for the first version.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
From the scene-graph I can see that this is used when changing something:
[$needsRender]() {
this[$scene].isDirty = true;
}
We can override this method in AR mixin to revoke our URL
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, but the chance of breaking things is high. Again, I don't think the perf gain here is enough to justify the complexity. Let's just skip the USDZ caching and call it a win on memory footprint. 😁
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
alright, for now, let's make those bionic chips do their job :). I really hope they will finally let us use WebXR on iOS directly so we can avoid using USDZ for good :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here here! Someday...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is looking just about ready to merge, thanks for the quick turn around! I'll remove the code changes from my PR and merge it afterwards just for the docs/examples updates. Can you please pull master and resolve whatever small conflict has arisen?
@@ -53,6 +54,7 @@ const $arMode = Symbol('arMode'); | |||
const $arModes = Symbol('arModes'); | |||
const $arAnchor = Symbol('arAnchor'); | |||
const $preload = Symbol('preload'); | |||
const $generatedIosUrl = Symbol('generatedIosUrl'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is vestigial now.
} else if ( | ||
value === 'quick-look' && !!this.iosSrc && | ||
IS_AR_QUICKLOOK_CANDIDATE) { | ||
} else if (value === 'quick-look' && IS_AR_QUICKLOOK_CANDIDATE) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's an extra logic block we'll need below this from my PR. You can either pull it in, or I can add it in mine with the docs update.
if (this.arScale === 'fixed') { | ||
if (modelUrl.hash) { | ||
modelUrl.hash += '&'; | ||
} | ||
modelUrl.hash += 'allowsContentScaling=0'; | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I read somewhere that Safari doesn't like hashes on blob URLs. Have you tried arScale="fixed"
to see if it actually works in QuickLook? I'm not very concerned if it doesn't, so long as it doesn't crash, but I'd be pretty stoked if I'm wrong.
Ok, I'll try now |
I have merged your usdz branch and (hopefully) resolved all conflicts correctly :) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you! This is a really important feature.
A question @elalish since this has been merged already: how would one now set the URL parameters on the USDZ file for configuring checkoutTitle etc.? There's similar URL parameters for Quick Look as for Scene Viewer, and we're using those a lot. One idea here would be: could the ios-src still be set but contain a "magic" string for "insert autogenerated USDZ here"? This way the URL parameters would "just work". |
Actually, could you give that a test for me first? I read that Safari doesn't handle query params on blob URLs, so I figured this wasn't going to work. If it does, I'll be happy to find a way to enable it. |
You mean parameter after a hashtag (docs), hmm, I never used them. Do they really work? One can set ios-src with a string starting with "#", then we can check that this is a "hashtag part" only and not a valid URL therefore generate the USDZ on the fly and add the "hashtag part" to the link. There is also a problem with the link being destroyed immediately after the click event, so your listener for "message" would not work... but I think we can delay destroying the link to the point when user turns back to the web page. |
Ah. Maybe this is the cause of #2405 ? |
Reference Issue #2373
Adding USDZ generation on the fly as an alternative to static ios-src (maintain both ways)