Disclaimer: This article is only used for personal study, research and appreciation, please do not modify, illegally spread, reprint, publish, commercial use, and other profit behavior.
background
In the example of Three.js Journey course, an example of 3D text suspension effect realized by built-in method of three. js is provided. In this paper, React + three. js technology stack is used to achieve a similar effect by referring to the example. The knowledge points involved in this paper mainly include: CSS grid background, MeshNormalMaterial normal material, FontLoader FontLoader, TextGeometry text buffer geometry, TorusBufferGeometry ring buffer geometry, ConeBufferGeometry Conical cushion geometry, OctahedronBufferGeometry eight surface geometry, Three late js rendering, GlitchPass channels, Element. RequestFullscreen, Document. ExitFullscreen And so on.
The effect
The realization effect is shown in ๐ banner. The main body of the page is composed of a text grid model in the center and torus, cone and octahedron around it. As ๐ฑ mouse moves or clicks over the page, the model moves with it. There are two buttons in the upper right corner of the page, which can switch the background color of the page and the post-effect of the fault style. Double-click the screen to enter or exit the full screen.
๐ online preview: 3D-dragonir.vercel. app/#/floating
๐ or dragonir. Making. IO / 3 d / # / floati…
Adaptation:
๐ป
PC
็ซฏ๐ฑ
The mobile terminal
implementation
Resources to introduce
The module resources required for development are introduced first, including FontLoader for loading font files, TextGeometry for creating 3D font grids, and EffectComposer, RenderPass and GlitchPass for post-effect rendering.
import * as THREE from "three";
import { FontLoader } from "three/examples/jsm/loaders/FontLoader";
import { TextGeometry } from 'three/examples/jsm/geometries/TextGeometry';
import { EffectComposer } from 'three/examples/jsm/postprocessing/EffectComposer.js';
import { RenderPass } from 'three/examples/jsm/postprocessing/RenderPass.js';
import { GlitchPass } from 'three/examples/jsm/postprocessing/GlitchPass.js';
Copy the code
DOM structure
The page DOM structure is very simple. The container #canvas is used for scene rendering,.color_pick is used to switch page background color, and.pass_button is used to switch fault style post-rendering.
<div className='floating_page' style={{ backgroundColor: this.state.backgroundColor}} >
<div id="canvas"></div>
<input className='color_pick' type="color" onChange={this.handleInputChange} value={this.state.backgroundColor} />
<button className='pass_button' onClick={this.handleRenderChange}>The special effects<span className='highlight'>{this.state.renderGlithPass ? 'on' : 'off '}</span></button>
</div>
Copy the code
Set the state of
BackgroundColor indicates the current page backgroundColor, and renderGlithPass indicates whether post status is enabled. Self-test found that in iOS Safari browser, failure style late rendering will lead to model wear problem ๐ฑ, so use this parameter to control the late effect on the mobile end by default, and on the PC end by default.
state = {
backgroundColor: '#164CCA'.renderGlithPass: !(window.navigator.userAgent.toLowerCase().indexOf('mobile') > 0)}Copy the code
The grid background
Use pure CSS property Linear-gradient to implement grid background to beautify the page ๐.
background-image: linear-gradient(rgba(3.192.60.3) 1px, transparent 1px), linear-gradient(90deg.rgba(3.192.60.3) 1px, transparent 1px);
background-size: 1em 1em;
Copy the code
Scene initialization
Initialize the render container, scene, and camera. The camera position can be adjusted according to its own needs. Render Turns on alpha and sets.setclearalpha (0) to set the background color to transparent.
canvas = document.getElementById('canvas');
renderer = new THREE.WebGLRenderer({ antialias: true.alpha: true });
renderer.setPixelRatio(Math.min(2.window.devicePixelRatio));
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setClearAlpha(0);
canvas.appendChild(renderer.domElement);
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(70.window.innerWidth / window.innerHeight, 1..10000);
camera.position.set(-2 * 10000.0.780);
Copy the code
Create the material
All of the mesh models in this article will use the same material, MeshNormalMaterial, which can be used to create color gradients for the mesh model. Global creation once, subsequent development does not need to repeat creation, conducive to page performance improvement.
const material = new THREE.MeshNormalMaterial();
Copy the code
๐ก
MeshNormalMaterial Normal material
Is a material that maps normal vectors to RGB colors. It can detect whether the model surface is smooth by observing whether the model surface gradient color is continuous.
Constructor:
MeshNormalMaterial(parameters : Object)
Copy the code
parameters
: Optional, an object used to define the appearance of a material, with one or more properties.
Special attributes:
.normalMap[Texture]
: used to create normal map textures,RGB
Values affect the surface normals of each pixel fragment and change the way colors are illuminated..normalMapType[Integer]
: Type of normal map, option isTHREE.TangentSpaceNormalMap
(Default) andTHREE.ObjectSpaceNormalMap
..normalScale[Vector2]
: How much the normal map affects the material. The range is0-1
, the default value isVector2
Set to(1, 1)
..flatShading[Boolean]
: defines whether the material is rendered using flat shaders. The default isfalse
..morphNormals[Boolean]
: Defines whether to usemorphNormals
. Set totrue
Can bemorphNormal
Properties fromgeometry
Passed to theshader
. The default value isfalse
..morphTargets[Boolean]
: Defines whether the material is usedmorphTargets
, the default value isfalse
.
Creating a text model
Load the fontface font JSON file using FontLoader and create the TextGeometry model using TextGeometry.
const loader = new FontLoader();
loader.load('./fonts/helvetiker_regular.typeface.json'.font= > {
textMesh.geometry = new TextGeometry('@dragonir\nfantastic\nthree.js\nart work', {
font: font,
size: 100.height: 40.curveSegments: 12.bevelEnabled: true.bevelThickness: 30.bevelSize: 8.bevelOffset: 1.bevelSegments: 12
});
textMesh.material = material;
scene.add(textMesh);
});
Copy the code
๐ก
FontLoader FontLoader
A class that uses JSON format to load fonts, returns Font, and the return value is an array of shapes representing the Font. FileLoader is used inside to load the file.
Constructor:
FontLoader(manager: LoadingManager)
Copy the code
manager
: used by the loaderloadingManager
, the default value isTHREE.DefaultLoadingManager
.
Methods:
.load
ไปURL
Is loaded and will be loadedtexture
Passed to theonLoad
..load(url: String, onLoad: Function, onProgress: Function, onError: Function): null
.url
: Indicates the URL or path of the fileData URI
.onLoad
: will be called when the load is complete. The callback argument is what will be loadedtexture
.onProgress
: will be called during loading. Parameters forXMLHttpRequest
Instance containingtotal
ๅloaded
Bytes.onError
: is called when loading errors occur.
.parse
ไปฅJSON
Format is parsed and one is returnedFont
..parse (json: Object ): Font
.json
: used for parsingJSON
Structure.
๐ก
TextGeometry is the TextGeometry
Class used to generate text into a single geometry, constructed from a given string of text with parameters made up of the loaded Font Font and Settings in the geometry’s ExtrudeGeometry parent class.
Constructor:
TextGeometry(text: String.parameters: Object)
Copy the code
text
: The text to be displayed.parameters
:font[Font]
:THREE.Font
Instance.size[Float]
: Font size. The default value is100
.height[Float]
: The thickness of the extruded text. The default value is50
.curveSegments[Integer]
: indicates the number of points on the curve of the text. The default value is12
.bevelEnabled[Boolean]
: Indicates whether to enable bevel. The default value isfalse
.bevelThickness[Float]
: The depth of the text bevel. The default value is20
.bevelSize[Float]
: The distance between the bevel and the original text contour. The default value is8
.bevelSegments[Integer]
: Number of bevel segments. The default value is3
.
๐ can convert the fonts supported by three.js online using faceType.js.
Create geometry models
Decorate the page with the other three built-in geometry models: circle, cone, and octahedron. The amount of decorative geometry is quite large. In order to effectively improve page performance, the following two points need to be paid attention to:
โญ
useTHREE.Group
Manage all geometry.โญ
Used when creating geometryBufferAttribute
, such as usingConeBufferGeometry is not ConeGeometry, which can more efficiently transfer data toGPU
.
// Create models in batches
generateRandomMesh = (geometry, material, count) = > {
for (let i = 0; i < count; i++) {
let mesh = new THREE.Mesh(geometry, material);
let dist = farDist / 3;
let distDouble = dist * 2;
// Set random position and rotation Angle
mesh.position.x = Math.random() * distDouble - dist;
mesh.position.y = Math.random() * distDouble - dist;
mesh.position.z = Math.random() * distDouble - dist;
mesh.rotation.x = Math.random() * 2 * Math.PI;
mesh.rotation.y = Math.random() * 2 * Math.PI;
mesh.rotation.z = Math.random() * 2 * Math.PI;
// Manually control when to recalculate the 3D transform for better performance
mesh.matrixAutoUpdate = false; mesh.updateMatrix(); group.add(mesh); }}// Create 100 octahedrons
const octahedronGeometry = new THREE.OctahedronBufferGeometry(80);
generateRandomMesh(octahedronGeometry, material, 100);
// Create 200 toris
const torusGeometry = new THREE.TorusBufferGeometry(40.25.16.40);
generateRandomMesh(torusGeometry, material, 200);
// Create 100 cones
const coneGeometry = new THREE.ConeBufferGeometry(40.80.80);
generateRandomMesh(coneGeometry, material, 100);
scene.add(group);
Copy the code
๐ก
TorusBufferGeometry indicates the TorusBufferGeometry
Class used to generate ring geometry.
Constructor:
TorusBufferGeometry(radius: Float, tube: Float, radialSegments: Integer, tubularSegments: Integer, arc: Float)
Copy the code
radius
: Radius of the ring from the center of the ring to the center of the pipe cross section. The default value is1
.tube
: Radius of the pipe. The default value is0.4
.radialSegments
: Indicates the number of segments of a ring. The default value is8
.tubularSegments
: The number of segments for a pipe. The default value is6
.arc
: Central Angle of a ring, in radians. The default value isMath.PI * 2
.
๐ก
ConeBufferGeometry is a cone of geometry
Class used to generate conic geometry.
Constructor:
ConeBufferGeometry(radius: Float, height: Float, radialSegments: Integer, heightSegments: Integer, openEnded: Boolean.thetaStart: Float, thetaLength: Float)
Copy the code
radius
: Radius at the bottom of the cone. The default value is1
.height
: Height of the cone, default value is1
.radialSegments
: The number of segments around the side of the cone. Default is8
.heightSegments
: The number of segments along the side of a cone along its height. Default is1
.openEnded
: Indicates whether the underside of the cone is open or capped. The default value isfalse
, that is, its underside is capped by default.thetaStart
: Specifies the starting Angle of the first segment0
.thetaLength
The central Angle of a circular sector, usually called the underside of a coneTheta.
. The default value is2*PI
, making it a complete cone.
๐ก
Octahedrongeometry is an octahedral buffer geometry
Class for creating octahedrons.
Constructor:
OctahedronBufferGeometry(radius: Float, detail: Integer)
Copy the code
radius
: Octahedron radius. The default value is1
.detail
: The default value is0
, set the value to a greater than0
Will add some vertices to it, making it no longer an octahedron.
Mouse event listening
Add listening methods for mouse movement and touch movement events by converting ๐ฑ mouse movement coordinates to and from model coordinates.
const mouseFX = {
windowHalfX: window.innerWidth / 2.windowHalfY: window.innerHeight / 2.coordinates: (coordX, coordY) = > {
mouseX = (coordX - mouseFX.windowHalfX) * 5;
mouseY = (coordY - mouseFX.windowHalfY) * 5;
},
onMouseMove: e= > { mouseFX.coordinates(e.clientX, e.clientY) },
onTouchMove: e= > { mouseFX.coordinates(e.changedTouches[0].clientX, e.changedTouches[0].clientY)}
};
document.addEventListener('mousemove', mouseFX.onMouseMove, false);
document.addEventListener('touchmove', mouseFX.onTouchMove, false);
Copy the code
Background color switch
Use an input[type=’color’] tag to switch the background color.
handleInputChange = e= > {
this.setState({ backgroundColor: e.target.value });
}
Copy the code
The late apply colours to a drawing
For a more impactful look ๐ฅ, I added a fault style post render and used a button switch โ to turn it on and off.
composer = new EffectComposer(renderer);
composer.addPass( new RenderPass(scene, camera));
glitchPass = new GlitchPass();
composer.addPass(glitchPass);
Copy the code
handleRenderChange = () = > {
this.setState({ renderGlithPass:!this.state.renderGlithPass });
}
Copy the code
๐ก
The late apply colours to a drawing
The post-rendering processing of Three.js is the process of achieving the expected visual effect by superimposing rendering channels. The implementation process is as follows:
- Create effect combinators: Effect combinators are portals to various processing channels, used
EffectComposer
Object creates an effect combinator. - Add channel: Add
RenderPass
Pass it will render a new scene based on the specified scene and camera. - Combinator update: In the animation loop, the effect combinator is called
render
Method, the channel generation effect will be output in the scene.
๐ก
GlitchPass Fault style channel
The GlitchPass channel produces a simulated fault style effect, which has only one optional configuration parameter:
goWild
This property receives a Boolean value that specifies whether the electromagnetic storm effect is sustained.
๐ three.js provides many post-processing channels that can be used directly. The ShaderPass channel is also provided, which supports the use of custom shaders to create advanced custom post-processing channels.
animation
Update the scene, camera, and post-render channels in the requestAnimationFrame.
function animate() {
requestAnimationFrame(animate);
camera.position.x += (mouseX - camera.position.x) * 0.05;
camera.position.y += (mouseY * -1 - camera.position.y) * 0.05;
camera.lookAt(scene.position);
// Add rotation animations to the cube mesh and font mesh in the scene
const t = Date.now() * 0.001;
const rx = Math.sin(t * 0.7) * 0.5;
const ry = Math.sin(t * 0.3) * 0.5;
const rz = Math.sin(t * 0.2) * 0.5;
group.rotation.x = rx;
group.rotation.y = ry;
group.rotation.z = rz;
textMesh.rotation.x = rx;
textMesh.rotation.y = ry;
textMesh.rotation.z = rx;
renderer.render(scene, camera);
// Update the post-render channel
composer.render();
}
Copy the code
Zoom adapter
The renderer and composer should be resized simultaneously.
window.addEventListener('resize'.() = > {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
composer.setSize( window.innerWidth, window.innerHeight );
}, false);
Copy the code
Double-click on the full screen
Listen to the page ๐ฑ double-click the dBLclick event to enter or exit the full-screen state by calling requestFullscreen and exitFullscreen.
window.addEventListener('dblclick'.() = > {
let fullscreenElement = document.fullscreenElement || document.webkitFullscreenElement;
if(! fullscreenElement) {if (canvas.requestFullscreen) {
canvas.requestFullscreen();
} else if (canvas.webkitRequestFullscreen) {
canvas.webkitRequestFullscreen();
}
console.log('Go full screen')}else {
if (document.exitFullscreen) {
document.exitFullscreen();
} else if (document.webkitExitFullscreen) {
document.webkitExitFullscreen();
}
console.log('Exit full screen')}})Copy the code
๐ก
Element.requestFullscreen
Element. RequestFullscreen method is used to send asynchronous requests make elements into full screen mode. Calling this API does not guarantee that an element will enter full-screen mode. If the element is allowed to enter full-screen mode, the returned Promise will resolve and the element will receive a Fullscreenchange event notifying it that it has entered full-screen mode. If the full-screen request is rejected, the returned promise becomes Rejected and the element receives a FullScreenError event. If the element has been separated from the original document, the document will receive these events.
Grammar:
var Promise = Element.requestFullscreen(options);
Copy the code
options
: Optional, oneFullscreenOptions
Object provides control options to switch to full-screen mode.
๐ this method can only be called during user interaction or device orientation changes, otherwise it will fail. The only option currently available for FullscreenOptions is navigationUI, which controls whether the navigation bar UI is displayed when the element is in full-screen mode. The default value is auto, indicating that it is up to the browser to decide whether to display the navigation bar.
๐ก
Document.exitFullscreen
The document. exitFullscreen method is used to exit the current Document from full-screen mode. Call this method will make a document on a call back to the Element. The requestFullscreen method before they enter full screen mode.
Grammar:
document.exitFullscreen();
Copy the code
At this point, all the functionality of the sample page is complete, and the full code can be viewed at ๐.
๐ Full code: github.com/dragonir/3d…
conclusion
This article mainly contains new knowledge:
CSS
The grid backgroundMeshNormalMaterial
The normal materialFontLoader
Font loaderTextGeometry
Text buffer geometryTorusBufferGeometry
Ring buffer geometryConeBufferGeometry
Conical buffer geometryOctahedronBufferGeometry
Octahedral buffer geometryThree.js
The late apply colours to a drawingGlitchPass
channelElement.requestFullscreen
Document.exitFullscreen
To learn more about scene initialization, lighting, shadows, base geometry, meshes, materials, and more about three.js, read my previous articles. Please indicate the original address and author. If you think the article is helpful to you, don’t forget a key three link oh ๐.
The appendix
- [1].three.js implementation makes 2d images have 3D effect
- [2].three.js to achieve the 2022 Winter Olympics theme 3D interesting page, Bing Dwen Dwen ๐ผ
- [3].three.js to create an exclusive 3D medal
- [4].three.js to achieve the Year of the Tiger Spring Festival 3D creative page
- [5].three.js to implement the 3D dynamic Logo of facebook metasomes
- [6].three.js to implement 3D panoramic detective game
- [7].three.js to achieve cool acid style 3D pages
- [8]. www.ilithya.rocks
- [9]. MDN requestFullScreen
- [10]. MDN exitFullscreen