[HN Gopher] Recreating Real-World Terrain with React, Three.js a...
___________________________________________________________________
Recreating Real-World Terrain with React, Three.js and WebGL
Shaders
Author : ObiWanFrijoles
Score : 122 points
Date : 2021-02-23 16:32 UTC (6 hours ago)
(HTM) web link (techblog.geekyants.com)
(TXT) w3m dump (techblog.geekyants.com)
| ObiWanFrijoles wrote:
| A guide to rendering photo-real terrain with React + Three.js
| gw wrote:
| That looks neat but why would you need a react-style reconciler
| to render a webgl scene? It's immediate mode...every frame is
| rendered according to the latest state available. What is even
| being reconciled?
| crypt0x wrote:
| Agreed. Haven't checked out the code but it might because of
| the text labels in the first example?
|
| Last time I checked rendering text into a webgl context was
| basically reinventing harfbuzz or using a proper game engine
| like unity.
|
| Edit: So a reactive way to lay over HTML which properly hooks
| into the 3d context doesn't sound beyond crazy, at least for
| web tech standards.
| andy_ppp wrote:
| Unity?
| crypt0x wrote:
| Yup thanks, typo.
| brundolf wrote:
| Three.js has an imperative/stateful API for constructing and
| updating objects, not dissimilar to the DOM. So if your state
| lives in a separate place, then just like the DOM, you'd have
| to imperatively patch the view state to keep it in sync. Adding
| a layer that does this syncing automatically makes a lot of
| sense to me.
|
| Doing it _through_ React seems a little bit odd... but I haven
| 't looked closely enough to understand why/whether this
| coupling is actually necessary
| gw wrote:
| That makes sense, but it seems like a case of building an
| abstraction to solve a problem caused by another abstraction.
| If a scene graph creates a new chore for me that necessitates
| yet another dependency, i think it'd be simpler to not fuss
| with these layers at all. That's a choice i don't have with
| the DOM.
| brundolf wrote:
| You don't really have the choice with graphics either. The
| GPU keeps mesh and texture data in memory between frames,
| and I would imagine something similar happens for lighting,
| etc at some layer in the pipeline. Reconstructing the
| entire scene every time would not be feasible.
| gw wrote:
| You can still hold on to references to textures and
| meshes you uploaded to the GPU without using a full-blown
| scene graph. Some state is necessary no doubt, but this
| seems more like unnecessary state that could be replaced
| by something more direct. But i don't know, i'm not
| familiar with three.js; the click handlers seem useful.
| brundolf wrote:
| Regardless: the reason for having a base API be
| imperative is usually because it's maximally flexible and
| performant. By your own admission, any reactive API for
| 3D rendering will at least have to hold on to references
| to GPU objects in-between iterations, which means it
| could never be a truly stateless API; it would always be
| an abstraction over something stateful.
|
| So given that constraint, I think it's better for the
| base API not to hide that statefulness behind an
| abstraction, and to leave the abstracting to a higher-
| level API
| westoncb wrote:
| > i think it'd be simpler to not fuss with these layers at
| all
|
| You should check out some example code for react-three-
| fiber (e.g. https://codesandbox.io/embed/r3f-bones-3i7iu).
| If you have any experience with writing raw webgl, it will
| become abundantly clear that something is gained by going
| through three.js before returning to React's more
| declarative style.
|
| Most of the savings in the example are coming from three.js
| itself (not r3f), which is maybe the key point: three.js
| offers much more than a scenegraph, which is why it's
| worthwhile (check out the official examples to get an idea:
| https://threejs.org/examples/). Webgl as an API doesn't
| even really talk about 3d objects for the most part; the
| language it provides is primarily about moving data around
| in buffers. The difference in possible time savings in
| three.js vs webgl is on the level of writing in C vs an
| assembly language.
|
| And once you're building an application with a non-trivial
| amount of state mutation (on which the view
| depends)--you're faced with the same dilemma as traditional
| web dev and the DOM, hence the desirability of react-three-
| fiber.
|
| That said, I think it would be super interesting to see a
| three.js alternative that was 'natively'
| reactive/declarative, because I'll readily admit the tower
| of abstractions involved in writing a react-three-fiber app
| has its downsides. (Then again, I consider three.js to be a
| rare gem, know of nothing comparable in terms of
| simplicity/quality for building 3d apps, and would be
| [pleasantly] surprised to see anything like the above
| anywhere in the near future.)
|
| EDIT: if you want to see an example app that really
| benefits from react-three-fiber (over plain three.js),
| check this out: https://www.youtube.com/watch?v=1qBOXfzHybU
|
| Repo: https://github.com/westoncb/extrude-client
|
| Here's the line that renders the Player components:
| {Object.values(state.players).map(player => <Player
| key={player.id} t={t} player={player}
| isLocalPlayer={player.id === localPlayer.id} />)}
| tppiotrowski wrote:
| I believe React developers think in terms of Components now as
| we used to think of Object/modules in the past. I personally
| find it easier to encapsulate logic into a Component because it
| seems more tangible than a plain JS file/module. You can also
| nest React components to compose logic, for example: composing
| multiple shaders.
| moron4hire wrote:
| Yes, but they are using Three.js, which provides a scene graph
| structure, basically wrapping WebGL in a retained mode.
| mdoms wrote:
| Looks very cool and there's a ton of good info here. But the
| final product is unusably laggy on my Dell XPS 13 i7 - not
| something I'd be happy to put into production.
|
| Edit - thank you for all the replies, we have now established
| that different hardware renders at different speeds, quite the
| discovery.
| gdubs wrote:
| FWIW it's zippy as hell on my iPhone 11 Pro.
| tppiotrowski wrote:
| The iPhone/iPad GPU's are actually faster than the Intel
| MacBooks in my experience. I haven't tried an M1 yet, but
| hopefully it eliminates this performance gap.
| astrea wrote:
| Ran perfectly fine on my Dell Precision with an i7-9850H.
| PTOB wrote:
| Same here. Probably the turbo encabulator on that XPS.
| mdoms wrote:
| Yes I understand that different hardware renders things at
| different speeds, thanks for your input? I'm saying that if
| something runs like shit on my $3,000 laptop I wouldn't be
| comfortable putting it into production for a user base that
| likely has, on average, far less.
| nmg wrote:
| Runs silky smooth on my 2015 MBP - it's possibly a system
| specific issue
| [deleted]
| brundolf wrote:
| It probably lacks a discrete graphics card. Not much to be done
| about that for a fundamentally graphics-concerned project; the
| only thing I can think of for production would be to disable
| the 3D content when the client lacks discrete graphics (which,
| I'm not actually sure whether that can be detected)
|
| Edit: Here's something. You could probably hack something up
| that would check if the vendor name includes AMD or NVIDIA, or
| something. Might be fragile though
| https://developer.mozilla.org/en-US/docs/Web/API/WebGLRender...
| esrauch wrote:
| The demo in the article would still run full speed on several
| year old integrated graphics. Probably chrome blacklisted his
| gpu driver and it's doing pure cpu rendering (or else his
| driver itself is bugged in a way that is killing the
| performance).
| brundolf wrote:
| Ah, yeah, it's running smooth on my MBP without switching
| to discrete
| onion2k wrote:
| react-three-fiber is a _really_ nice library to make web 3D
| things with. Three.js is brilliant, but there 's a metric ton of
| boilerplate to get complicated things up and running. react-
| three-fiber just shuffles that away so you can concentrate on
| building a graph out of components. I've been getting up to speed
| with it for a little while and I've been chucking things I've
| learned in to a Github Pages site -
| https://onion2k.github.io/r3f-by-example/ Each example can be
| spun up on Codesandbox with the click of a link eg
| https://onion2k.github.io/r3f-by-example/examples/geometry/i...
| (Click the "Fork on Codesandbox" link)
|
| There are _tons_ of good examples of how to use react-three-fiber
| on Codesandbox - https://codesandbox.io/search?query=react-three-
| fiber&page=1
| chrisweekly wrote:
| Thanks for the helpful repo and linking to it! Been looking fwd
| to playing w react-three-fiber...
| codetrotter wrote:
| When I went to your site, the "screenshot coming soon" for each
| of them caught all of my attention so I didn't notice the fork
| on codesandbox link.
|
| But why not just have the live WebGL thing on each page itself?
| onion2k wrote:
| I'm writing something to generate screenshots at the moment.
| They'll be there fairly soon.
|
| I could embed the live WebGL, or a codesandbox embed. I might
| do that eventually.
| pheelicks wrote:
| Nice writeup, I always like it when the shaders are highlighted
| like this. I got started in a similar way 7 years ago and have
| been making 3D terrains with THREE.js & WebGL since.
|
| The real fun begins when you need to implement some sort of
| Level-of-Detail system and streaming in data to give the illusion
| of high detail everywhere without sacrificing performance.
|
| Last year I released an open-source framework
| (https://github.com/felixpalmer/procedural-gl-js) for creating 3D
| terrains for web applications, you can see Uluru here:
| https://www.procedural.eu/map/?longitude=131.036&latitude=-2...
| (unfortunately the aerial imagery from our default provider isn't
| as high resolution as other places in Europe)
| tppiotrowski wrote:
| Excellent write up. I've been using elevation models for the past
| few months to create real time shadows overlaid on slippy maps
| using WebGL. [1]
|
| One thing I learned is that if you really want to recreate "real-
| world" terrain you have to account for the curvature of the
| earth. Uluru is over 3km wide and I estimate your image is around
| 5km. Across this distance the earth will curve 2 meters so you
| could modify the elevation model to drop off a meter gradually
| from the center to the edges.
|
| [1] https://shademap.app
| onion2k wrote:
| That's ace when it loads, but modifying the time on the bar at
| the bottom of the screen makes the shadow disappear. I get a
| NaN in the URL which is presumably related (eg
| https://shademap.app/#47.62769,24.44286,4z,NaNt). Chrome
| 88.0.4324.182, OSX, no plugins to speak of. There's a bunch of
| 404s from Mapbox (eg https://api.mapbox.com/v4/mapbox.terrain-
| rgb/3/3/6.pngraw?ac...) but no other console errors.
| tppiotrowski wrote:
| The 404s from Mapbox are for elevation map tiles over the
| ocean where elevation is assumed to be 0.
|
| As you pan, zoom and change the time, the url updates so you
| can share a permalink with others and they see exactly what
| you do. It looks like somehow you got an invalid timestamp
| (NaNt should be a timestamp: 1614115393106t). Will dig more
| into this. Thanks.
| vagrantJin wrote:
| It's confirmed that I'm an idiot who happens to just be into
| WebGl and threejs these last few months. But I must ask about the
| choice to use React. Is there an actual benefit to using React or
| is it popular enough to justify its use?
| tppiotrowski wrote:
| I think React's main role here is just to provide structure to
| the code base: React component as the basic unit of logic
| encapsulation and then composing logic by combining React
| components.
| vagrantJin wrote:
| Got it.
| matthoiland wrote:
| Very cool demo! And also nice to know my laptop fans still work.
| (2019 MBP 16", Chrome v84)
___________________________________________________________________
(page generated 2021-02-23 23:00 UTC)