How to draw a NFT “mushroom” with three.js

Author ح ferluht

Compiling Cui Wei

Planning ح Sun Shujuan, Liang Gu

First, introduction

In this article, I will try to briefly outline what is generating art, how to link it with NFT (Non-Fungible token, non-homogenated coins), and how to make a build product in the block chain. The mushroom design will use JavaScript and Three.js, this article will take this to you how to generate and publish art works in virtual world.


For interest, I often write some strange articles. During the New Year, the news about NFT once made me shocked, so I also want to try some creative things in this mode. I didn’t think it would have been uploading JPEG to the block chain, but the possibility of chain of art is expected to be expected.

In short, the idea behind this is to create some collection of generators. Every time you “cast”, you will give you a unique artwork (actually, it is the calling method in the block chain, you are It is necessary to spend money when it is executed, and it is also necessary to pay the artist’s money). Obviously, you may have a wonderful feeling that this transaction has generated some unique items and is stored in the block chain.

There is therefore some art platforms use this idea, the most famous is It is based on the Tanfront block chain, which is still using the Proof-Of-Work mode and the GAS (handling fee) is very high. So, I decided to try a more independent, cheaper, and more environmentally friendly platform – FXHASH.XYZ.

What is a generated NFT art?

All Generate NFT Arts (NFT, “Non-Fungible token, referring to non-homogenized coins, including JPG and video clip form, is the only encrypted currency token used to represent digital assets, can be traded.) Basic They are presented in web page and draw on the canvas using Vanilla JavaScript or some third party libraries. NFT art can be divided into three categories: abstract mathematical artwork, shape procedures, art and variable hand-painted artwork.

As shown in Figure 1.

The first category, abstract mathematical artwork, use some mathematical concepts to generate abstract images, may have some fractals (Fractals, a complex geometry), attracting (Attractors, a system has a tendency toward a steady development, This steady state is called the attractor), the cell automatic (Cellular Automata is a time, space, state discrete, spatial interaction, and time causal relationship as partial grid kinetic model, with simulated complex system time and space evolution The ability of the process.)

The second class, a formal procedure art product, attempting to use a parameterized manner to describe some specific things.

Third categories, variable hand-painted artworks are simple and randomized.

figure 1

In addition, there are some experimental and interactive works, and even artwork such as modular synthesizers and games, but it is relatively rare. This article will describe the creation process of a mushroom artwork, and randomly use trading hash. Coupled with some artistic vision, composition and stylization, we finally created this “generation NFT art”.

Second, painting mushrooms

Otinium Caseubbacula – One of the generated mushrooms

Introduce the theoretical knowledge, we entered the technical link. This project uses the Three.js library, which has a simple JavaScript library, which is easy to find online.

1, generate a bacteria

First, the spline of the bacteria (we call it a basic spline, the role of the spline is an auxiliary generating entity), and the contour of parameterization forming the shank for the sample line. In order to create a basic spline, I used the CATMullRomcurve3 class in Three.js. Then, the corresponding geometry is constructed by creating a closed shape along the movement of the basic spray line, and finally connects these graphics, as shown in FIG. Use the BufferGeometry component in Three.js for this purpose. code show as below:

STIPE_VSEGMENTS = 30; // Vertical Resolution

STIPE_RSEGMENTS = 20; // Angular Resolution

STIPE_POINTS = []; // Vertices

Stipe_indices = []; // Face INDES

STIPE_SHAPE = New Three.catmullromcurve3 (…, Closed = FALSE);

Function Stipe_Radius (A, T) {…}

For (VAR T = 0; T

Var curve = new three.catmullromcurve3 ([[[

New three.vector3 (0, 0, stipe_radius (0, t)),

New three.vector3 (stipe_radius (math.pi / 2, t), 0, 0),

New three.vector3 (0, 0, -stipe_radius (math.pi, t)),

New three.vector3 (-stipe_radius (math.pi * 1.5, t), 0, 0),

], closed = true, curvetype = ‘CATMullrom’, Tension = 0.75);

Var profile_points = curve.getpoints (stipe_rsegments);

For (var i = 0; i

STIPE_POINTS.PUSH (Profile_Points [i] .x, profile_points [i] .y, profile_points [i] .z);




// and the crete a buffergeetry

Var stipe = new three.bufferGeometry ();

Stipe.setttribute (‘Position’, New Three.Bufferattribute (New Float32Array (stipe_points), 3);

Stipe.setIndex (stipe_indices);

stipe.computevertexnormals ();

Stage: Springs, vertices, faces. figure 2

2, bacteria noise

In order to make the bacteriostat look more natural, the surface will change with the height, we define the noise function, the function defines the radius, by changing the angle of the basic spline and the relative height of two parameters. Generate a different radius information. The code is as follows:

Base_Radius = 1; // Mean Radius

Noise_c = 2; // Higher this – Higher The Deformations

// stipe radius as a function of angle and relative position

Function Stipe_Radius (a, t) {

Return Base_Radius + (1 – t) * (1 + Math.random ()) * Noise_c;

Changes of skeleton noise. image 3

As shown in FIG. 3, different radii is generated according to the angle and height by the noise function of the radius.

3, bacterial cap

The method of generating the bacteria can also be accomplished by adding a rotating spline curve on top of the midney handle and then performing parameterization of the curve. Here you can name the surface of the rotation is based on the basis, and then define the position of the base surface on the base spline, and then add a function around the top of the bacteriometer. This parameterized programming way will make it easy to add a noise function. code show as below:

Adiet resolution

CAP_CSEGMENTS = 20; // Angular Resolution



// Cap Surface as a function of polar coordinates

Function Cap_Surface (A0, T0) {

// 1. Compute (a, t) from (A0, T0), E.G Apply Noise

// 2. Compute SPline Value In T

// 3. Rotate it by Angle a arrone end

// 4. Apply Some Other Noises / Transformations …

Return Surface_Point;


// Spawn Surface Vertices with resolution


For (var i = 1; i


For (var j = 0; j

Var a0 = math.pi * 2 / capac_csegments * j;

Var Surface_Point = CAP_SURFACE (A0, T0);

CAP_POINTS.PUSH (Surface_Point.x, Surface_Point.y, Surface_Point.z);




// and the crete a buffergeetry

VAR CAP = New Three.BufferGeometry ();

Cap.setttribute (‘Position’, New Three.Bufferattribute (New Float32Array (CAP_POINTS), 3);

Cap.setIndex (CAP_INDICES);

Cap.computevertexnormals ();

Hat generation stage: spline, vertex, face. Figure 4

As shown in Figure 4, the base plane is generated by the base spline, which is a bacterial cap.

Hat noise

Also in order to make the art look more real, the bacilli needs to add some noise. I divide my pile noise into three categories: radial noise, angular noise, and normal noise. Radial noise affects the relative position of the vertex on the basic spline. The angle noise changes the angle of rotation of the basic spline around the handle. Finally, the normal noise changes the vertices along the base surface. When defining the surface of the collaps in the coordinate system, the twisted application 2D Perlin noise is used, so the NOISEJS library will be used to complete the above functions. code show as below:

Function Radnoise (A, T) {

Return -Math.Abs ??(noise.perlin2 (t * math.cos (a), t * math.sin (a)) * 0.5);


Function Angnoise (a, t) {

Return noise.perlin2 (t * math.cos (a), t * math.sin (a)) * 0.2;


Function Normnoise (A, T) {

Return noise.perlin2 (t * math.cos (a), t * math.sin (a)) * t;


Function Cap_Surface (A0, T0) {

// t0 -> T by Adding radial noise

VAR T = T0 * (1 + Radnoise (A, T0));

// compute normal vector in t

Var Shape_point = CAP_SHAPE.GETPOINTAT (T);

Var tangent = cap_shape.gettangentat (t);

Var Norm = New Three.Vector3 (0,0,0);

Const Z1 = New Three.Vector3 (0,0,1);

Norm.crossVectors (Z1, Tangent);

// a0 -> a by adding angular noise

VAR a = angNOISE (A0, T);

Var Surface_Point = New Three.Vector3 (

Math.cos (a) * shape_point.x,


Math.sin (a) * shape_point.x);

// Normal Noise Coefficient

Var Surfnoise_Val = Normnoise (a, t);

// Finally Surface Point

Surface_point.x + = Norm.x * Math.cos (a) * Surfnoise_VAL;

Surface_point.y + = norm.y * surfnoise_val;

Surface_point.z + = norm.x * math.sin (a) * Surfnoise_VAL;

Return Surface_Point;

Noise components from left to right: radial, angle, normal. Figure 5

As shown in Figure 5, noise, angular noise, and normal noise from left to right, respectively.

The rest of the mushroom: bacterial scale, straw, bacterial ring

The geometry of the strap and the bacterial ring is very similar to the geometry of the bacteria. A noisy vertex can be generated around some random anchors on the surface of the cap and then create ConvexGeometry based on them. code show as below:


Scales_num = 20;


Scale_Radius = 2;

For (var i = 0; i

Var scale_points = [];

// Choose a random center of the scale on the cap

VAR a = math.random () * math.pi * 2;

Var t = math.random ();

Var scale_center = CAP_SURFACE (A, T);

// spawn a Random Point Cloud Around The Scale_Center

For (var j = 0; j

Scale_points.push (New Three.Vector3)

Scale_center.x + (1 – math.random () * 2) * scale_radius,

Scale_center.y + (1 – math.random () * 2) * Scale_Radius,

Scale_center.z + (1 – math.random () * 2) * scale_radius



// Create Convex Geometry Using There Points

Var scale_geometry = new three.convexgeometry (scale_points);

BUFGEOMS.PUSH (Scale_Geometry);


// join all these Geometries INE BUFFERGEMETRY

Var scales = three.buffergemetryutils.mergeBufferGeometries (bufgeoms);

Complete geometric shape of scales, sputum, ring and mushrooms. Image 6

As shown in Figure 6, a complete geometry of the bacteria, strapless pleat, bacterial ring and mushroom is drawn.

Collision check

Since multiple mushrooms are generated in the same scenario, there is a case where the mushrooms will generate cross-laminated situations, so they need to check the collision relationship between them. Here, one code snippet comes from detecting light projections of each grid point, thereby achieving the purpose of checking the collision of mushrooms.

In order to reduce the calculation time, I also generated a low mode when generating this mushroom. Then use this low mode to check it with other mushrooms.

code show as below:

For (var vertexindex = 0; vertexindex


Var localvertex = new three.vector3 (). fromBufferattribute (Player.Geometry.attributes.position, vertexindex) .clone (); var globalvertex = localvertex.applymtrix4 (Player.matrix);

Var directionVector = GlobalVertex.sub (Player.Position);

Var ray = new three.raycaster (Player.Position, DirectionVector.clone (). Normalize ());

Var CollisionResults = ray.intersectObjects (CollidableMeshlist);

IF (CollisionResults.Length> 0 && CollisionResults [0] .distance


// a Collision Occurred … do something …


Simplified model for faster collision checks. Figure 7

As shown in Figure 7, the collision effect of the mushroom is checked.

Rendering and stylization

Initially, I want to achieve the effect of 2D drawing, although all production is made of 3D. In a stylized background, I first thought of the outline effect. Since we are not colored experts, it is just from this example to get the contour effect, and get the pencil painting style of the mushroom contour.

Figure 8

As shown in Figure 8, the pencil painting style of the mushroom is displayed.

Then it is coloring, the texture of the mushroom should have noise and have some soft shadows. If you don’t want to handle UV, a simple way is to use the BufferGeometry API to define the vertex color of the object. Using this method can also parameterize the color of the vertex, that is, add angle and position as parameters to change color, so the generation of noise texture becomes slightly easier.

Figure 9

As shown in Figure 9, add a color to the vertex through the angle and position.

Finally, some global noise and similar film granules have been added using EffectComposer (Film Grain is the random optical texture of analog photographic film). code show as below:

Var renderer = new three.webglrenderer ({antialias: true});

Outline = new three.Outlineeffect (renderer, {thickness: 0.01, alpha: 1, defaultcolor: [0.1, 0.1, 0.1]});

Var composer = new three.effectComposer (OUTLINE);


Var Renderpass = New Three.Renderpass (Scene, Camera);

Composer.Addpass (Renderpass);

Var Filmpass = New Three.FILMPASS

0.20, // noise intensity

0.025, // Scanline Intensity

648, // Scanline Count

False, // grayscale


Composer.Addpass (Filmpass);

Composer.render ();

Almost ready, colored and noise mushrooms. Figure 10

As shown in Figure 10, mushrooms to be completed.

Generate a name

The name is generated. This article uses a simple Marcov chain, which accepts 1K mushroom name training. In order to preprocess and mark these names, I used the Python library YouTokenTome. With it, you can split all names into 200 unique tags, and write their conversion probability to the JavaScript dictionary. The JS side of the code only reads these probability and stacked tag until it generates several words.

The following is some mushroom names generated using this method:

Stricosphate Cinusfusarium Sium Confsisomyc

Etiformansum Poonic

Hellatatum Bataticola

Armillanata Gossypina Mortic

ChoSPorium Anniiff

Fla Po Sporthrina

Third, complete

Figure 11

As shown in Figure 11, 15 mushrooms found in Fxhash.

Ready to release

First, you have to prepare a project published on Fxhash, just change all random calls in the code to the fxrand () method. The main idea is to generate a unique output for each hash, which requires the same output of the same hash. Then test the loop in the sandbox, and finally cast a coin at the time of the casting coin process.

So our “mushroom atlas” was born. You can view and follow its changes here. Although it is unlike some of the previous works, I think this is the most challenging work in my artistic career. People who want to cast this loop can also enjoy the unhealthy beauty in the world of non-qualified parties!

Translator introduction

Cui Wei, 51CTO community editor, senior architect, has 18 years of software development and architectural experience, 10 years of distributed architecture experience. Zeng Yip-pu technical expert. It’s fun to share, write a lot of popular technical articles, and read more than 600,000. “Principle and Practice of Distributed Architecture”.