跪拜 Guibai
← All articles
Frontend

A Three.js Tribute to Viral Zero-Budget Film 'Niu Lai'

By 李剑一 ·
Read original on juejin.cn ↗ Google Translate ↗ Alt translation

The demo is a compact, self-contained example of several real-time 3D techniques that trip up web developers: instanced rendering for large object counts, frame-rate-independent camera smoothing, procedural texture generation on a canvas, and proper GPU resource disposal. The full source code is provided, making it a practical reference for anyone building a third-person browser experience with Three.js.

Summary

A developer built a browser-based 3D tribute to the viral Chinese film *Niu Lai*, a movie made by a two-person crew that went from a 342-yuan opening day to a trending topic and 168 nationwide screenings. The demo loads a custom 3D character model into a Three.js scene with a procedural dirt ground texture and instanced grass that spawns dynamically as the player moves. A third-person camera follows the character with a frame-rate-independent smoothing coefficient, while keyboard input drives movement, jumping with gravity integration, and a crouch mechanic that scales the character model around its feet. The entire interaction loop is encapsulated in a `GameWorld` class that manages the renderer, scene, input state, and cleanup to prevent memory leaks.

Takeaways
An `InstancedMesh` renders thousands of grass blades as a single draw call by merging three crossed `PlaneGeometry` planes into one geometry per blade.
The camera follow uses a coefficient `a = 1 - 0.0015^dt` so the smoothing feels consistent regardless of frame rate fluctuations.
A procedural ground texture is generated on a 512×512 canvas with 2,600 semi-transparent dirt patches and 400 grass dots, then tiled 40×40 times across the ground plane.
Jump physics apply gravity as a uniform acceleration integral, resetting vertical velocity and position when `jumpY` reaches or crosses zero.
Crouching scales the character pivot's Y-axis to 0.55 with a lerp toward the target, keeping the feet planted by placing the pivot origin at ground level.
Grass spawns dynamically: accumulated movement distance triggers a new blade placement near the character, up to a maximum instance count.
The `GameWorld` class disposes the renderer, removes event listeners, and clears the scene on unmount to avoid GPU memory leaks.
Conclusions

Using `frustumCulled = false` on the grass `InstancedMesh` is a necessary hack; otherwise the entire grass field can vanish when its bounding sphere leaves the camera frustum, even if individual blades are still visible.

The pixel ratio is capped at 2 to prevent high-DPI devices from tanking performance, a small detail that many WebGL tutorials omit but which matters on modern 4K and mobile screens.

Generating the ground texture procedurally on a canvas avoids an external image dependency and keeps the demo self-contained, but the 2,600-iteration loop per texture creation is a one-time cost that could be cached in a real application.

Concepts & terms
InstancedMesh
A Three.js class that renders many copies of the same geometry with different transformations in a single GPU draw call, drastically reducing CPU overhead for repeated objects like grass or trees.
PCFSoftShadowMap
A shadow map type in Three.js that applies Percentage-Closer Filtering to produce soft-edged shadows, avoiding the hard, aliased edges of basic shadow maps.
Anisotropic filtering
A texture sampling technique that improves clarity when a surface is viewed at a steep angle, such as looking across a ground plane; it prevents the texture from blurring in the distance.
Frustum culling
An optimization where objects outside the camera's view are skipped during rendering. It can backfire on large instanced meshes, which is why it's sometimes disabled for objects like grass fields.
sRGB color space
A standard color space that matches typical monitor gamma. Three.js requires setting `outputColorSpace` to `SRGBColorSpace` so textures and lighting appear with correct brightness rather than looking washed out.
From the discussion

The conversation splits between appreciation for the Three.js tribute and a desire for more authentic, rough-hewn detail. One thread pushes for a bipedal walking animation, while another argues the model is too polished and lacks the original character's pockmarked texture. A separate promotional comment for a visualization collection draws attention, and a spam link gets called out.

Adding a bipedal walking animation requires building the skeleton and gait into the model during the initial modeling phase.
The current model is too refined; the original character's appeal comes from a rough, pockmarked surface texture that is missing here.
A front-end visualization collection app (visualization-collection) is recommended as a relevant resource, containing hundreds of CSS, Canvas, and Three.js examples.
A spam link was posted and immediately challenged.
Featured comments
用户24171602916

Can you make it walk on two legs? I really need this

用户9233975482866

You need to build the walking animation into the model when you create it

李剑一

That has to be done during modeling — the skeleton, the walking animation

家里有蜘蛛 2 likes

Still too polished, missing that pockmarked charm [mischievous grin]

李剑一

My modeling skills are limited, a veteran artist is still a veteran artist [thumbs up]

River_何 2 likes

Really not bad, thumbs up. Recommending a popular tool used by many front-end devs: visualization-collection, an app focused on front-end visual effects. It contains hundreds of cases including rich CSS animations, Canvas animations, Three.js 3D, and more — open-source and free. App URL (desktop): https://hepengwei.cn Source code: https://github.com/hepengwei/visualization-collection

See top comments, translated →
Source: juejin.cn ↗ Google Translate ↗ Backup ↗