Hey everyone!
I’m trying to create a „Scrollytelling" effect for my project with three.js and gsap. The user is supposed to scroll through the page from top to bottom (and vice versa) with alternating 3D and 2D content. The camera movement is attached to the page scroll and works fine for the first canvas as you can see here:
What I’m struggling with is how to make the 2nd and 3rd canvas work. (The camera (or a different camera) is supposed to move on a different path) I obviously don’t want to create a renderer for each canvas due to performance issues. I found the three.js examples with multiple canvases but frankly don’t understand how renderer, canvas and camera work together since I’m still new to three.js.
How can I assign multiple canvases to the same renderer? Is this the right approach in my case since only one canvas is visible at a time anyway?
I’m happy for any advice.
If you have the time to have a deeper look into my code you can find it here:
You can use one very long canvas(of full body size) and render the scenes with multiple views like this example: three.js examples
Or you can have a full-screen canvas, that changes the camera depending on scroll position y. In this case you cannot show 2 scenes on the screen at one time. And the 2D sections would need to be larger than the screen/browser height
In both canvas will be fixed and behind all the 2D text which will scroll up.
Thank you so much repalash!
I really like the idea with the very high canvas and multiple views – I will definitely give it a try.
Just one question: Does a very large canvas have a negative effect on the overall performance?
Cheers,
Raymund
I think a beter solution would to use a single canvas plased on the background with position: fixed
And you don’t needs to update projectionMatrix, you can “move” the picture along the x and y axes by changing 8th and 9th elements of the matrix. This sets the translation in screen coordinates, t.i. matrix.elements[9]=1 sets the image shift up by half the height of the canvas.
Thank you @repalash and @trueshko. I understand that it is better to use one fullscreen canvas with position fixed instead of many. If I understand correct @trueshko suggests to manipulate the “8th and 9th elements of the (projection?)matrix” to move the 3D content of the canvas along x and y coordinates. (In my case I want to make the 3D content disappear at the top of the screen and appear again at the bottom.) Can you explain this a bit more in detail? Does this approach also include multiple viewports (in the same canvas)?
Thank you!
For multiple viewports you need to disable autoclear buffers in renderer and render each scene with their camera which has it’s own viewport. You can refresh viewports every frame using setViewOffset method - you can insert empty blocks into you page for each viewport and set the related camera’s viewOffset using block position geting from getBondingClientRect() every animation frame. For best sinchronisation with scrolling it would be good to place a page content into a fullscreen fixed block with overflow:hidden аnd set body:height to this block scrollHeight. And every animation frame set block.scrollTop = window.scrollY and body.style.height=block.scrollHeight+‘px’
I have taken this approach in this work - You can see the source code of the page scripts. Sorry for its poor legibility. And there I made it a little more difficult to give the scrolling some extra smoothness.
By the way, it also uses there a change in the elements of the projection matrix for vertical image translation.
This helps a lot. Thank you @trueshko for the explanation.
So what it basically means is, I was thinking too complicated. Instead of using multiple canvases or viewports I render all my 3D scroll animations one after another in one canvas (and viewport) and make this canvas appear and reappear along with the 2D content while scrolling.
So in the end this is more a html/css topic than three.js. So allow me one last question:
Why does the position of the canvas need to be fixed if I wanna move it along the Y-axis?
Thank you so much – I really appreciate your help!
Hey so, I meant one canvas with multiple viewports, and controlling the viewport coordinates according to the bounding client rect of the 2d elements. In this case canvas would be fixed and full screen, while 2d content scrolls on top.