pmndrs / react-three-fiber

🇨🇭 A React renderer for Three.js
https://docs.pmnd.rs/react-three-fiber
MIT License
27.32k stars 1.56k forks source link

Multiple canvases display the same thing #26

Closed dbismut closed 5 years ago

dbismut commented 5 years ago

Hey again, so I'm still trying to replicate this example. From their code, a canvas is created for each couple of images.

Here is my attempt, also based on the sandbox you provided me in issue #23 (thanks again!) https://codesandbox.io/s/w5902o607

I'm not sure if it's updating to v1.3.7 that created this but now all canvases are showing the same image, and behave like one. I had it running properly at one point (under v1.3.6) but then I was running into THREE.WebGLRenderer: Context Lost issues.

Maybe this is not the right place to ask, but it really felt related to the version bump from v1.3.6 to v1.3.7

drcmda commented 5 years ago

there seems to be something wrong with codesandbox, too, look at this: https://codesandbox.io/s/40v634pk9

remove the first canvas and you still get images 1 and 2. probably bad cache?

dbismut commented 5 years ago

Not sure really, this is new behavior. Reloading the page also changes the images... Don't know what happens to be honest. I'll try to investigate later.

drcmda commented 5 years ago

maybe caching in the texture loader, something is really, really weird.

drcmda commented 5 years ago

Looks like TextureLoader > ImageLoader uses a global cache: https://github.com/mrdoob/three.js/blob/master/src/loaders/ImageLoader.js

dbismut commented 5 years ago

Isn’t it weird that all canvases also react to hover simultaneously?

drcmda commented 5 years ago

yes, that's most likely my fault. never tried it with multiple canvases - i'll focus this week on interaction.

drcmda commented 5 years ago

tried a little more, i don't understand what's causing it tbh. if you have time, here's how you can run stuff and debug directly in the root folder: https://github.com/drcmda/react-three-fiber/tree/master/examples

drcmda commented 5 years ago

Ran some more tests, the mouse events are fine, only one image component gets hit. (see the same box i posted above) To me it looks like they're all using the same shader, which gets compiled and then cached. So one image receive the hover, moves over, the others have their own state and meshes, but display the first shader.

dbismut commented 5 years ago

Hm makes sense. I'll try to revert to 1.3.6 and the previous code see if this changes anything.

drcmda commented 5 years ago

when i give it the same shader under two different names, at least they start interacting right again, weirdly image is still doubled. https://codesandbox.io/s/40v634pk9

drcmda commented 5 years ago

hm, i refreshed and now it works ... anyway, you need to figure out how to compile shaders without cache, this is probably all a three thing. i start to doubt any of this is related to this lib.

dbismut commented 5 years ago

Using the same shader but with the previous way you suggested structuring the code (plus some rookie mistakes I guess), I do get different images though...

https://codesandbox.io/s/w5902o607

With 1.3.7 the hover wasN'T working with progress interpolation, now on 1.3.6 it does work properly.

drcmda commented 5 years ago

it's "uniforms-dispFactor-value={progress}" ... but the other thing should work as well, i think need to tweak a little so that it accepts objects and atomics. next patch will be able to run both

dbismut commented 5 years ago

Yes I know, the idea was to replicate the previous code that ran on 1.3.6 see if there was the same "caching" issue, and the fact there isn't. Regardless of the hover and progress, and even regardless of the versions:

This:

 <anim.shaderMaterial
        name="material"
        args={[XFadeShader]}
        uniforms-texture-value={texture1}
        uniforms-texture2-value={texture2}
        uniforms-disp-value={dispTexture}
        uniforms-dispFactor-value={0}
      />

Doesn't do the same as:

      <anim.shaderMaterial name="material" args={[args]} />
// args include all the uniforms value in the props above

To prove this, here is the updated sandbox: https://codesandbox.io/s/w5902o607

The first row of images is done using the first code, the second row using the second one.

image
drcmda commented 5 years ago

interesting, looks like putting shader defs inside the args object stops three from caching it? so is this fixed? i pushed a patch as well for object piercing so both xxx-value={...} and xxx={{ ..., value: ... }} work again.

dbismut commented 5 years ago

Cool! Looks like it’s fixed indeed!

dbismut commented 5 years ago

Here is the complete sandbox similar to the Tympanus original example btw: https://codesandbox.io/s/n74213346l

drcmda commented 5 years ago

Great! The code has remained glanceable. If you want to tweet it, i'd love to retweet. It's a nice example for using shadermaterial.

dbismut commented 5 years ago

Sure. I’m just adding a few tweaks (is handling events from the dom rather than from THREE so that it can support touch, also at the moment unhover isn't triggered when the mouse leaves the window). I’m also testing performance against the Tympanus code, I’ll do a screen capture and post it here if anything interesting comes out.

dbismut commented 5 years ago

@drcmda arf, I'm actually running into a Safari specific issue, that happens also on your sandbox here: https://codesandbox.io/s/x37p4kk6p4

null is not an object (evaluating 'context.drawImage')

Maybe this should require an issue on its own?

drcmda commented 5 years ago

I get "Cannot find variable: ImageBitmap", but i think these are already known: https://github.com/mrdoob/three.js/issues/15885

drcmda commented 5 years ago

I think it's even related to the texture flip stuff, there was a regression in threejs.

dbismut commented 5 years ago

Oh, that might explain why I don't get the Safari error on the Tympanus example code, that ships with a minified version of three js that I guess compiled at the time.

drcmda commented 5 years ago

yep, going back to three version 100 fixes it: https://codesandbox.io/s/x37p4kk6p4

I think they have already fixed it in dev, but not released as a patch yet

dbismut commented 5 years ago

Ok so not that it proves anything about the performance of this lib, but I've captured a side-by-side comparison between the react version (left) and the vanilla version (right) from Tympanus with a 4x CPU slowdown, and for some reason the hover events are triggered with a significant delay on the react version, although the smoothness of the animation is equal on both.

perf

EDIT: forgot to mention that the react version is built, running a React in production.

drcmda commented 5 years ago

could it be its just the spring starting slower, or friction being higher than the curve in the original? i think visually you'll not be able to profile it in a meaningful way unless the configs match. you could use duration and the same easing. but using dev console profiling would be a way. then you see how much time is spent on a single frame, that will be a better indication.

drcmda commented 5 years ago

original

Screenshot 2019-03-14 at 12 46 35

three fiber (in codesandbox, which i believe runs development env (?))

Screenshot 2019-03-14 at 12 47 22

it looks like react is a tiny bit faster, insignificantly, though. But i could be better - right now react-spring and react-three-fiber use their own requestAnimationFrame loops. If they share one i can cut off a couple of ms still. That's one of the goals for 2.x.

dbismut commented 5 years ago

I’ll re-run some tests after lunch but I had inserted console.logs and there was a significant delay between when the dom got the event and when it was propagated to the props. I’ll investigate further in a few hours.

dbismut commented 5 years ago

Regarding your last comment did you try slowing down the CPU in the performance tab?

Codesandbox does run in dev mode btw!

drcmda commented 5 years ago

no i didn't, but running both on the same browser and system should give comparable results. dev mode should put react at a disadvantage, so im a little surprised it comes out on top, spend lots and lots of time optimizing react-spring though. and it's the part that's being profiled here because react otherwise isn't involved - it renders once and stays out, lets three just render. react-spring also functions 100% outside of react when it animates.

dbismut commented 5 years ago

Maybe it’s the way that Chrome emulates the CPU slowdown that creates the delay.

Final note regarding perf, initial scrolling on my iPhone X seems to stutter a bit on the react version.

drcmda commented 5 years ago

that as well could be how we're setting up textures. in the original they do it before the view is constructed. we're doing it right smack in the middle of UI built-up.

im not so concerned about perf otherwise, because react has no relation to three, it just renders once, then keeps out completely. In the frame readout you can set it - react is entirely missing, there's not so much as a single function of the react kernel being called.

but compiling textures and stuff is costly, and that has to be done carefully. we could also do that in global scope like in the codrops example, or perhaps using reacts new tools like scheduling. or using a splash until textures are done, like many webgl sites do. but these are userland considerations.

dbismut commented 5 years ago

You’re right, this is approximately what I thought but if I wait for a couple of seconds before scrolling then the shader should be built and useMemo should make sure it’s not recompiled for any reason? But yes I understand that this lib can’t have impact on perfs per se, I’m just curious on why this happens really ^^

drcmda commented 5 years ago

there's also gl.compile(scene, camera)

https://threejs.org/docs/index.html#api/en/renderers/WebGLRenderer.compile

which could maybe be utilized. It's finishing all shaders and textures in the scene. three otherwise will start doing it lazy, when they first appear or something like that. i guess memo isn't good enough for this kind of thing, textures need to be made before the component is ready to render.

here i'm not so knowledgable, this is the first time i'm using three for website related stuff.

dbismut commented 5 years ago

Ok thanks I’ll definitely have a look! I’ll close the issue since I think it’s resolved by now 😅