A preliminary studyTHREE.JSIn the coloring equipment and implement aThe circular pointsThe effect

· Create the world is committed to creating the first “cloud CAD” collaborative design platform integrating viewing, modeling, assembly and rendering in China.

At the request of readers, we hope to set up a professional WEBGL and Threejs industry QQ communication group for front-end developers in Chengdu-Chongqing area to facilitate discussion. There are webGL and Threejs in the group, welcome to join! — Click the link to join the group chat [three.js/ webGL Chongqing Union Group] : jq.qq.com/?_wv=1027&k…

The authors introduce

Li Chun, r&d engineer of large front end of Cloud map, is responsible for the development of 3d front end of cloud map.

The body of the

From the title can be seen in a preliminary discussion, this article is not to take you into depth understanding of THREE. This article is to introduce the coloring equipment in Three. JS and modify the material in three. JS to achieve the effect of rendering a circular point. The end result is an initial understanding of custom materials and the ability to achieve special effects through custom materials and WebGL technology.

The pre-basics used in this article

  • THREE. JS links
  • TypeScript link
  • WebGL foundation links

Custom material types in three.js

There are two types of custom material types in three.js: RawShaderMaterial and ShaderMaterial.

ShaderMaterial

A material rendered with custom shaders. A shader is a small program written in GLSL that runs on the GPU

RawShaderMaterial

This class works just like ShaderMaterial, except that definitions of built-in uniforms and attributes are not automatically prepended to the GLSL shader code.

ShaderMaterial

The vertex shader unit of the GPU is used to process vertex data such as vertex position, vertex color, vertex normal vector, and the slice shader unit is used to process slice metadata such as texture. A WebGL program object contains a vertex shader object and a slice shader object. They run on the GPU’s vertex shader unit and chip shader unit, respectively.

About ShaderMaterial, it can be seen from the source that ShaderMaterial is similar to other Material object classes. It inherits from Material and is an extension of the function of Material Material object. There are three main attributes to be concerned with here, and with these attributes, along with your familiarity with WebGL, you can achieve some pretty cool effects

  • uniforms
  • vertexShader
  • fragmentShader

VertexShader and fragmentShader are both strings, one passing in the vertex color unit and one passing in the slice shader unit. An imaginative is a uniform variable used to be passed into the vertex shader and pixel shader. The attribute variable in the vertex shader needs to be passed in via attributes of Geometry. In fact, there are some automatic processing of three. JS in ShaderMaterial (you can read the source code of webglProgram.js for details), so I won’t go into details here, but I will use a simple example to introduce the process of writing ShaderMaterial.

// Initialize the geometry object
const geometry = new THREE.BufferGeometry();
// Set vertex data
const pos = new Float32Array([0.0.0]);
// Set position attribute
geometry.setAttribute('position'.new THREE.BufferAttribute(pos, 3));
​
// Initializes the custom material object
const material = new THREE.ShaderMaterial();
// Vertex shader code
material.vertexShader = 'void main() {// Set point size to 50 pixels gl_PointSize = 50.0; Gl_Position = vec4(position, 1.0); } `;
// Chip shader code
material.fragmentShader = Void main() {// gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); } `;
// Use THREE.Points vertex drawing mode
const point = new THREE.Points(geometry, material);
scene.add(point);
Copy the code

The effect is shown below:

I want a circular point

As you might have noticed, this dot is a little bit different from what you expected. It is a square instead of a circle, so how to turn this square dot into a circle is very simple, just add a line of code to the fragment shader. The fragment shader code looks like this:

FragmentShader = 'void main() {if (distance(gl_PointCoord, vec2(0.5, 0.5)) > 0.5) discard; // gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); } `;Copy the code

The effect is shown below:

If (distance(gl_PointCoord, vec2(0.5, 0.5)) > 0.5) discard; If the distance between the current pixel position and vec2(0.5, 0.5) is greater than 0.5, the pixel is discarded without rendering. We can imagine a graphic shape with a distance of 0.5 from the origin, which is exactly a circle.

This is the end of the introduction of ShaderMaterial. Interested partners can read the source code of ShaderMaterial and the classic case on the official website.

A class that encapsulates a circular point

The above implementation of a circular point is relatively simple, and there are quite a lot of problems (interested partners can communicate with me in private), just to clarify the implementation of ideas; Next, a CPoint class is encapsulated to represent this generic circular point.

import * as THREE from 'three';
​
exportinterface CPointParams { color? : number; size? : number; }export class CPoint extends THREE.Points {
    constructor(params? : CPointParams) {
        super(a);// create geometry
        const geo = new THREE.BufferGeometry();
        const positionAttr = new THREE.BufferAttribute(
            new Float32Array([0.0.0]),
            3
        );
        geo.setAttribute('position', positionAttr);
​
        constcolor = params? .color ||0xffcc00;
        constsize = params? .size ||20;
​
        //material
        const material = new THREE.PointsMaterial({
            color: color,
            size: size,
            transparent: true.depthTest: false.sizeAttenuation: false}); material.onBeforeCompile =(shader) = > {
            shader.fragmentShader = shader.fragmentShader.replace(
                'vec4 diffuseColor = vec4( diffuse, opacity ); '.If (distance(gl_PointCoord, vec2(0.5, 0.5)) > 0.5) discard; vec4 diffuseColor = vec4( diffuse, opacity ); `
            );
        };
​
        this.geometry = geo;
        this.material = material;
        this.renderOrder = 1;
        this.matrixAutoUpdate = false;
    }
​
    get pointMaterial() :THREE.PointsMaterial {
        return this.material asTHREE.PointsMaterial; }}Copy the code

Test it out

/ / debug UI
const gui = new dat.GUI();
const parameters = {
    color: 0xffcc00.size: 15};/ / the xyz axis
const axes = new THREE.AxesHelper();
scene.add(axes);
// Initialize cpoint
const point = new CPoint({
    color: parameters.color,
    size: parameters.size,
});
scene.add(point);
// debug ui
gui.addColor(parameters, 'color').onChange(() = > {
    point.pointMaterial.color.set(parameters.color);
});
gui.add(point.pointMaterial, 'size').min(1).max(100);
Copy the code

conclusion

THREE.JS is an excellent 3d rendering library, and its encapsulation of the underlying WebGL API is worth studying. If you are interested, you can take a closer look at the code encapsulated in the shader part (SRC/Renderers folder).