“This is the 31st day of my participation in the First Challenge 2022. For details: First Challenge 2022”

The sample code USES three. Js – r73 version: cdnjs.cloudflare.com/ajax/libs/t…

Sometimes we ask the question, can WebGL implement large presentation scenarios? Our WebGL project has no problem in the browser, but it freezes in the mobile terminal. These are all webGL performance-related issues, so let’s take a look.

Render 1.6 million triangles

  • How do you render 1.6 million triangles and still keep it over 35 frames
    • Convention: Limit the size of triangles, which are all in a cube
  • Let’s take a look at the effect and then start our drawing

Initialization Scenario

  • We added a fog effect to the scene
function initScene() {
    scene = new THREE.Scene();
    scene.fog = new THREE.Fog(0x050505.2000.3500);
}
Copy the code

Initializing the camera

  • Add the camera to the scene
const near = 1;
const far = 3500;

function initCamera() {
    camera = new THREE.PerspectiveCamera(27, width / height, near, far);
    camera.position.z = 2750;
    scene.add(camera);
}
Copy the code

Initialize light

  • Create one ambient light, two parallel lights
function initLight() {
    scene.add(new THREE.AmbientLight(0x444444));
    light = new THREE.DirectionalLight(0xffffff.0.5);
    light.position.set(1.1.1);
    scene.add(light);

    var light2 = new THREE.DirectionalLight(0xffffff.1.5);
    light2.position.set(0, -1.0);
    scene.add(light2);
}
Copy the code

Create 1.6 million triangles

Example Initialize storage space

var triangles = 1600000; // The number of triangles

var geometry = new THREE.BufferGeometry();
// The storage space required to generate 1.6 million triangles with three vertices and one vertex with three variables xyz
var positions = new Float32Array(triangles * 3 * 3);
// There is one normal for each vertex, or one normal for each face
var normals = new Float32Array(triangles * 3 * 3);
// One color per vertex
var colors = new Float32Array(triangles * 3 * 3);

var color = new THREE.Color();
Copy the code

Javascript allocates contiguous space

  • Here we touch on the concept of storage space
  • Uint16Array, Float32Array and other objects in javascript can allocate a specified number of integers or floating-point arrays. Arrays allocated by them are linear, contiguous units, so CPU access is extremely fast.
  • Documents: Uint16Array
  • We have three vertices in a triangle, and each vertex has three variables xyz, so the amount of storage required for vertices istriangles * 3 * 3The normals and vertices are the same color

Initializes vectors and limits the range of triangles

var n = 800, n2 = n / 2; // In a cube, n2 represents half of the diameter
var d = 12, d2 = d / 2; // Set the size of the triangle to 12, with d2 representing half the length of each side (if there is a radius)

var pA = new THREE.Vector3();
var pB = new THREE.Vector3();
var pC = new THREE.Vector3();

var cb = new THREE.Vector3();
var ab = new THREE.Vector3();
Copy the code
  • We limit the range of triangles to -400,400, and the size of the triangle to 12

Vector addition and subtraction

  • We’re going to do vector addition and subtraction, and we’re going to use that.
  • Triangle rule:
    • Triangle rule to solve the method of vector addition: each vector in turn end to end, the result is that the starting point of the first vector points to the end of the last vector
  • Plane quadrilateral rule:
    • Parallelogram rule to solve vector addition method: translation of two vectors to the common starting point, with two sides of the vector as parallelogram, the result is the diagonal of the common starting point.
    • Parallelogram rule to solve the method of vector subtraction: translation of two vectors to the common starting point, the two sides of the vector as parallelogram, the result from the end point of the subtraction vector to the end point of the subtraction vector

Iterate over the length of points, randomly generate vertices, normal vectors, vertex colors

  • Generate a vertex at random
for (var i = 0; i < positions.length; i += 9) {
    // Generate the location of the point by random number

    // Generate a vertex in the range [-400,400]
    var x = Math.random() * n - n2;
    var y = Math.random() * n - n2;
    var z = Math.random() * n - n2;
}
Copy the code
  • From the randomly generated vertices, three points are randomly generated to form a triangle
// randomly generate a,b, and c
// The position of the point plus the size of the triangle
var ax = x + Math.random() * d - d2;
var ay = y + Math.random() * d - d2;
var az = z + Math.random() * d - d2;

var bx = x + Math.random() * d - d2;
var by = y + Math.random() * d - d2;
var bz = z + Math.random() * d - d2;

var cx = x + Math.random() * d - d2;
var cy = y + Math.random() * d - d2;
var cz = z + Math.random() * d - d2;
/ / a point
positions[i] = ax;
positions[i + 1] = ay;
positions[i + 2] = az;
/ / point b
positions[i + 3] = bx;
positions[i + 4] = by;
positions[i + 5] = bz;
/ / c point
positions[i + 6] = cx;
positions[i + 7] = cy;
positions[i + 8] = cz;
Copy the code

Compute the normal vector for each triangle

// Put points A, B, and c in vectors
pA.set(ax, ay, az);
pB.set(bx, by, bz);
pC.set(cx, cy, cz);
// Vector subtraction computes vectors in order to compute vectors perpendicular to triangles
cb.subVectors(pC, pB)
ab.subVectors(pA, pB)
cb.cross(ab) // Get orthogonal vectors that are perpendicular to the plane of the two vectors, the normal line
// Vector normalization
cb.normalize()

// Store normal coordinates
var nx = cb.x
var ny = cb.y
var nz = cb.z
// a vertex normals
normals[i] = nx
normals[i + 1] = ny
normals[i + 2] = nz
// b vertex normal
normals[i + 3] = nz
normals[i + 4] = nz
normals[i + 5] = nz
// c vertex normal
normals[i + 6] = nz
normals[i + 7] = nz
normals[i + 8] = nz
Copy the code

Vector calculation

// Vector subtraction computes vectors in order to compute vectors perpendicular to triangles
cb.subVectors(pC, pB)
ab.subVectors(pA, pB)
Copy the code
  • The two subtraction calculations above let me illustrate them by drawing a picture

The orthogonal vector cross

  • Our normal vector is perpendicular to the plane, so we need to compute the orthogonal vectors
  • If two or more vectors have a dot product of 0, they are called orthogonal vectors. In a two – or three-dimensional Euclidean space, two or three vectors are 22/90. At angles, they’re orthogonal to each other. The set of orthogonal vectors is called the set of orthogonal vectors.

  • Normalization of vectors: that is, scaling down to unit length in the same direction

Assign a color to each vertex

// Assign a color to each vertex
// x/n to get range [-0.5,0.5], add 0.5 to get [0,1]
var vx = (x / n) + 0.5
var vy = (y / n) + 0.5
var vz = (z / n) + 0.5

color.setRGB(vx, vy, vz)

colors[i] = color.r
colors[i + 1] = color.g
colors[i + 2] = color.b

colors[i + 3] = color.r
colors[i + 4] = color.g
colors[i + 5] = color.b

colors[i + 6] = color.r
colors[i + 7] = color.g
colors[i + 8] = color.b
Copy the code

Add attributes to geometry

geometry.addAttribute('position'.new THREE.BufferAttribute(positions, 3))
geometry.addAttribute('normal'.new THREE.BufferAttribute(normals, 3))
geometry.addAttribute('color'.new THREE.BufferAttribute(colors, 3))
// Compute the bounding box of the geometry
geometry.computeBoundingSphere();
Copy the code

Create a grid and add it to the scene

var material = new THREE.MeshPhongMaterial({
    color: 0xaaaaaa.specular: 0xffffff.shininess: 250.side: THREE.DoubleSide,
    vertexColors: THREE.VertexColors
})

mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
Copy the code

Add rotation animation

/* Data update */
function update() {
    var time = Date.now() * 0.001;
    mesh.rotation.x = time * 0.25
    mesh.rotation.y = time * 0.5
}
Copy the code

Relationships between positions, colors, and normals

  • What is the relationship between positions, colors, and normals after assigning values to the attributes of BufferGeometry?
  • You can see the relationship between them in the figure below

Codepen sample code