First, what is a shader

Shader: The highly programmable phases of the GPU pipeline are the code that runs on the GPU.

What are the categories of shader

  1. VertexShader: Defines the position and size of vertices. Each vertex is executed once.
  2. FragmentShader: Defines the material (color, reflectance, etc.) of the drawn object. Each pixel slice executes the code once.

Shader built-in functions used

  1. texture2D(sampler2D, coord): texture lookup
  2. Fract (x): Retrieves the fractional part

Four, the realization of ideas

Requirement – Implement a fence shaped arrow animation.

Generate bufferGeometry based on the trajectory.

(Instead of using some built-in geometry of THREE, we set the position of bufferGeometry and UV relation values by ourselves, which may seem a little difficult for students without relevant experience.)

How many vertices does WebGL need to draw a square plane? ** Since the smallest unit webGL draws is triangles, a square requires two triangles so 6 vertices are required (in case of no indices defined, only 4 vertices are required if defined) **Copy the code

Suppose we draw a rectangular enclosed fence. The path array at the bottom should be a set of three-dimensional points with a consistent length of 5.

let positions = []
let uvs = []
for (let i = 0, j = positions.length, t = uvs.length; i < points.length - 1; i++) {
 let vUvyMax = 1
 let left = points[i]
 letright = points[i + 1] positions[j++] = left.x positions[j++] = left.y positions[j++] = 0 uvs[t++] = 0 uvs[t++] = 0 positions[j++] = right.x positions[j++] = right.y positions[j++] = 0 uvs[t++] = 1 uvs[t++] = 0 positions[j++] = left.x positions[j++] = left.y positions[j++] = height uvs[t++] = 0 uvs[t++] = vUvyMax positions[j++] = left.x positions[j++] =  left.y positions[j++] = height uvs[t++] = 0 uvs[t++] = vUvyMax positions[j++] = right.x positions[j++] = right.y positions[j++] = 0 uvs[t++] = 1 uvs[t++] = 0 positions[j++] = right.x positions[j++] = right.y positions[j++] = height uvs[t++] = 1 uvs[t++] = vUvyMax }let geometry = new THREE.BufferGeometry()
geometry.addAttribute('position', new THREE.BufferAttribute(new Float32Array(positions), 3))
geometry.addAttribute('uv', new THREE.BufferAttribute(new Float32Array(uvs), 2))
Copy the code

This gives us a buffer custom fence geometry that contains all the vertices in the UV interval from 0 to 1.

Define the material

  • Define an IMAGINATIVE first

    1. The time parameter required by the animation.
    2. RepeatX parameter calculated to prevent texture distortion.Length/(aspect * height) // length: bottom path length, aspect: arrow map aspect ratio (can be preloaded to obtain the image), height: fence height
    3. Arrow map parameternew THREE.TextureLoader().load('arrow_url').
    4. The speed parameter of the animation.
  • Define vertex shaders

    varying vec2 vUv;
    ${THREE.ShaderChunk['fog_pars_vertex']}
    void main() {
      vUv = uv;
      vec4 mvPosition = modelViewMatrix * vec4(position, 1.0);
      gl_Position = projectionMatrix * mvPosition;
      ${THREE.ShaderChunk['fog_vertex']}
    }
Copy the code

No special handling required, just save the UV, pass it to fragmentShader, convert position, and add an additional support for atomization

  • Defines the normal mapping for the slice shader.
 vec4 fragColor = texture2D(map, vUv);
Copy the code

However, we need to keep the width to height ratio repeatedly

Let’s take the center point of the map as an example. The center point of the map corresponds to the coordinates of the whole map, which are described in percentage terms as (0.5, 0.5). The system will draw the pixel at uv value of (0.5, 0.5). So following the above line of code will put a textured stretch on the object.

So we give THE UV. x * repeatX. In this way, the UV range of x direction was changed to 0-REPEATx

 vec4 fragColor = texture2D(map, vec2(vUv.x * repeatX, vUv.y));
Copy the code

Here we drew a map without deformation on the geometry, but the range of Vuv. x was 2-REPEATx was blank, because there were no pixels in this range on the map.

And then there’s the darkest piece of technology. We only take the decimal part of the new UV, which is equivalent to mod uv.x to 1.

 vec4 fragColor = texture2D(map, vec2(fract(vUv.x * repeatX), vUv.y));
 vec4 fragColor = texture2D(map, vec2(mod(vUv.x * repeatX, 1.), vUv.y));
Copy the code

The above two lines of code actually do the same thing, so we get a tile with arrows. And the last step, we need to animate this arrow, remember our time parameter.

vec4 fragColor = texture2D(map, vec2(fract(vUv.x * repeatX + time), vUv.y));
Copy the code

We just increment time every frame to make our arrow move. On second thought, it seems that the animation controls are not free enough. We just give this time* the speed of the last animation.

vec4 fragColor = texture2D(map, vec2(fract(vUv.x * repeatX + time*speed), vUv.y));
Copy the code

Want to move fast move fast, want to rebel in turn move on the contrary move, what natural and unrestrained

Create geometry

let wall = new THREE.Mesh(geometry, material)
Copy the code

How simple, a high performance arrow wall animation is done, the texture can be customized, change to what you want to change to what

Personal a word a word hard code out, hope to reprint please indicate the source, thank you!