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