I am participating in the Mid-Autumn Festival Creative Submission contest, please see: Mid-Autumn Festival Creative Submission Contest for details

The online preview

As the TYrannosaurus rex model is relatively large (20M+), it takes a while to wait.

1. The introduction

In ancient times, Hou Yi shot at the sun. After his descendants became heroes, god rewarded the elixir of immortality, which was then stolen by Chang ‘e. Inherent “Chang e should regret stealing elixir, blue sea qingtian heart every night” poem.

Today, Xiaoming follow the footsteps of idol descendants, prepared a three-level fire machine gun, under the pressure of tyrannosaurus Rex, brave shot on, chat solution chang e lonely.

2. Make a sketch

Open up the drawing software and imagine what it looks like

3. Elemental analysis

  1. Two characters
  2. Two spheres
  3. A dinosaur
  4. The trajectory of the bullet

The rendering engine uses three.js, and to make it easier to write, uses the simply-scene-react library (which was introduced in # three.js based trisomy).

Use maps for spheres and sprites for characters for simplicity.

Xiao Ming

The goddess of the moon

For tyrannosaurus rex, I found the.glB file in the model library,

Attack trajectories use the Fly-line (a simple fly-line effect that encapsulates the author).

4. Fly – line is introduced

Just like simple-scene-react, fly-line effects are used a lot, so we sent a NPM package.

The sample3D scene application 2D scene Application Applications in maps Xiao Ming has shooting practice See/example code

5. Class construction

5.1. Object classes

class Star { name: string; image: any; highImage: any; raduis: number; position: number[]; cita: number; mesh: any constructor( name: string, image: any, highImage: any, raduis: number, position: number[], cita: number, ) { this.name = name; this.image = image; this.highImage = highImage; this.raduis = raduis; this.position = position; this.cita = cita; }}Copy the code
attribute instructions
name Name of the object
image Map image
highImage Displacement map
raduis Radius of celestial bodies
position Object position
cita Orbital Angle

5.2. The Human kind

class Human { name: string; image: any; position: number[]; mesh: any constructor( name: string, image: any, position: number[], ) { this.name = name; this.image = image; this.position = position; }}Copy the code
attribute instructions
name The name
image The elves figure
position coordinates

Tyrannosaurus rex is independent and doesn’t bother to write classes.

6. Apply colours to a drawing

6.1. Celestial rendering

Definition:

const stars = [ new Star( 'Earth', require('./texture/earth.jpg'), require('./texture/earth-high.jpg'), 300, [0, -300, 600], 0 ), new Star( 'Moon', require('./texture/moon.jpg'), require('./texture/moon-high.jpg'), 150, [600, 400, -1000], 0)];Copy the code

For a better display, displacement maps were used. In my article# Echarts 3 d Earth “the tip of the iceberg” reveal | creator camp phase iiComparison of theDisplacement map, bump map, normal mapThe advantages and disadvantages.

const addStars = async (scene: THREE.Scene) => { for (let i = 0; i < stars.length; i++) { let star = stars[i]; let sphereGeo = new THREE.SphereGeometry(star.raduis, 50, 50); // create a sphere geometry object let img = await imageloader.load (star.image); let texture = new THREE.Texture(img); texture.needsUpdate = true; let imgH = await ImageLoader.load(star.highImage); let highTexture = new THREE.Texture(imgH); let material = new THREE.MeshStandardMaterial({ map: texture, displacementMap: HighTexture, // displacementScale: I === 0? 40 : 5, displacementBias: 10, }); (material.displacementMap as any).needsUpdate = true; let sphereMesh = new THREE.Mesh(sphereGeo, material); Set (star.position[0], star.position[1], star.position[2]); sphereMesh.name = star.name; star.mesh = sphereMesh; if (i === 0) { sphereMesh.rotation.z = Math.PI / 6; sphereMesh.rotation.y = (3 * Math.PI) / 2; } scene.add(sphereMesh); }};Copy the code

This can make the surface of the sphere concavity.

6.2. Character rendering

const addHumans = async (scene: THREE.Scene) => { for (let i = 0; i < humans.length; i++) { let human = humans[i]; let img = await ImageLoader.load(human.image); let texture = new THREE.Texture(img); texture.needsUpdate = true; let spriteMaterial = new THREE.SpriteMaterial({ rotation: i === 0 ? Math.PI / 6 : 2 * Math.PI, map: texture, }); let mesh = new THREE.Sprite(spriteMaterial); mesh.position.set(human.position[0], human.position[1], human.position[2]); // Mesh. Name = human. Name; human.mesh = mesh; mesh.scale.set(100, 100, 1); scene.add(mesh); }};Copy the code

A Sprite is a plane that always faces the camera. See Three. Js e-book for reference. The effect is as follows:

Sorry, this Angle only exposes Xiao Ming’s head, there is no way, he has to avoid the attack of tyrannosaurus Rex.

6.3. T-rex rendering

A GLTFLoader is preferred.

import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
const GLBLoader = new GLTFLoader();
Copy the code

And then load

const addRampaging = async (scene: THREE.Scene) => { GLBLoader.load(rampaging, gltf => { let modal = gltf.scene; modal.scale.set(50, 50, 50); mixer = new THREE.AnimationMixer(modal); // Mixer for global variables animations = gltf.animations; Mixer.clipaction (animations[1]).play(); // By default, modal.rotation. Y = math.pi / 2; modal.position.set(-80, 0, 600); scene.add(modal); }); };Copy the code

Note that the GLB model comes with animations, which I saved in the global variable animations, and use the second animation fragment by default. See the comments. For the rest of the actions I put the entry in the second line in the upper left corner.

{['run', 'bit', 'roar', 'tail', 'idke'].map((item, index) => (
  <button
    key={item}
    onClick={() => {
      if (mixer) {
        mixer.stopAllAction();
        mixer.clipAction(animations[index]).play();
      }
    }}
  >
    {item}
  </button>
))}
Copy the code

You can visitThe online previewTry it.

The animation is executed using mixer = new three.animationMixer (modal) objects, after clipAction().play(), mixer.update(delta) in the animate function.

6.4. Ballistic attack rendering

If only the straight line rendering, Xiao Ming will feel very monotonous, according to xiao Ming’s idea, he wants to give Chang ‘e a surprise like fireworks.

If using bezier curves to realize this curve, so the key lies in the calculation of control points, namely THREE. QuadraticBezierCurve3 the second parameter.

So Xiao Ming took out a pen and paper.

  1. Known starting pointAWith the endB;
  2. You can calculateAwithBThe midpoint ofC
    ( x c . y c . z c ) (x_c,y_c,z_c)
    ;
  3. passCThe point is perpendicular to the vectorABThe plane;
  4. This time can get the equation of A plane A (x – xc) + B (y – yc) + C (z – zc) = 0 (x – x_c) + B (y – y_c) + C (z – z_c) = 0 A (x – xc) + B (y – yc) + C (z – zc) = 0;
  5. The problem is equivalent to having a planeP, and planePThe points on theCLet’s make a radius of zerorTo find the parametric equation of the circle.

Xiao Ming calculated a few pieces of paper and found it was not easy to calculate, so he changed his mind.

1. Construct a XY plane circle. 2. Shift it to C; 3. Then do an axis rotation to get the answer.

So you apply a translation transformation matrix, and then you apply a rotation matrix.

However, Ming did not know what the non-X,Y and Z axis rotation matrix looked like. Ming was immersed in meditation.

Later he found THREE. Mesh APIsetRotationFromAxisAngle pivoting

So he wrote the following code to debug his machine gun.

Let arc = new THREE.ArcCurve(0, 0, 200, 0, 2 * math.pi, true); Arc.getpoints (50); arc.getpoints (50); // Let geometry = new THREE.BufferGeometry().setfrompoints (points); / / let the vertex data updated geometry. The attributes. The position. The needsUpdate = true; // Let Material = new THREE.LineBasicMaterial({color: 0x00ff00}); // Mesh object let circle = new THREE.Line(Geometry, material); // translateX to point C circle.translatex (C.x); circle.translateY(C.y); circle.translateZ(C.z); Let p = a.lone ().sub(B); Vector3(0, 0,1); // Let _p = new three.vector3 (0, 0,1); // The rotation axis should be perpendicular to the plane formed by p _p. Let axis = p.lone ().cross(_p).normalize();  / / standardized again / / rotating circle. SetRotationFromAxisAngle (axis, the cita)Copy the code

willcircleAdded to thesceneAfter that, it successfully renders in the specified location.

We’re just one step away from getting the vertex data out of the Mesh.

Tried a variety of measures, such as geometry. The attributes. The position. The needsUpdate = true, analytic circle. Geometry. The getAttribute (‘ position ‘). An array to get points, And then failed to find that it was not the latest value.

So Ming made a turn. Why did he need to operate Mesh? If he operated Vector directly, there would be no middlemen to earn the price difference. Vector also has the method applyAxisAngle that rotates around the axis.

/** ** @param axis Specifies the coordinate axis * @param Angle Specifies the rotation Angle * @param offset Specifies the translation vector * @param r radius * @param num Number of points * @returns points */ const generatePoints = ( axis: THREE.Vector3, angle: number, offset: THREE.Vector3, r: number, num: number ) => { let arr: THREE.Vector3[] = []; for (let i = 0; i <= num; i++) { let cita = (2 * Math.PI * i) / num; let p = new THREE.Vector3(r * Math.cos(cita), r * Math.sin(cita), 0); p.applyAxisAngle(axis, angle); p.add(offset); arr.push(p); } return arr; };Copy the code

Xiao Ming succeeded, he installed his machine gun with three levels of firepower, one is better than the other, and finally fiercely shot at the moon.

7. The animation

Animate is a simple code, with line_1, LINe_2, and LINe_3 representing three levels of firepower.

const animate = (target: any, clock: THREE.Clock) => { let delta = clock.getDelta(); if (mixer) { mixer.update(delta); } lines_1.forEach(flyLine => { flyLine.animate(); }); lines_2.forEach(flyLine => { flyLine.animate(); }); lines_3.forEach(flyLine => { flyLine.animate(); }); ForEach (star => {if (star.mesh) {star.mesh. }}); };Copy the code

Detailed code

8. Conclusion

Switch perspective, cover to chang ‘e sister’s point of view, Xiao Ming is fighting with tyrannosaurus Rex wonderful?

Links to online

Welcome to play, welcome to use the fly-line.