[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)