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,RGBValues 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 isVector2Set to(1, 1).
  • .flatShading[Boolean]: defines whether the material is rendered using flat shaders. The default isfalse.
  • .morphNormals[Boolean]: Defines whether to usemorphNormals. Set totrueCan bemorphNormalProperties fromgeometryPassed 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 ไปŽ URLIs loaded and will be loadedtexturePassed 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 forXMLHttpRequestInstance containingtotal ๅ’Œ loadedBytes.
    • onError: is called when loading errors occur.
  • .parse ไปฅ JSONFormat is parsed and one is returnedFont.
    • .parse (json: Object ): Font.
    • json: used for parsingJSONStructure.

๐Ÿ’ก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.FontInstance.
    • 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.GroupManage 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.
  • thetaLengthThe 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 than0Will 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, usedEffectComposerObject creates an effect combinator.
  • Add channel: AddRenderPassPass it will render a new scene based on the specified scene and camera.
  • Combinator update: In the animation loop, the effect combinator is calledrenderMethod, 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:

  • goWildThis 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, oneFullscreenOptionsObject 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:

  • CSSThe grid background
  • MeshNormalMaterialThe normal material
  • FontLoaderFont loader
  • TextGeometryText buffer geometry
  • TorusBufferGeometryRing buffer geometry
  • ConeBufferGeometryConical buffer geometry
  • OctahedronBufferGeometryOctahedral buffer geometry
  • Three.jsThe late apply colours to a drawing
  • GlitchPasschannel
  • Element.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