How to create seamless texture in angular without instructions and examples

Seamless noise is a type of noise that has the property of smoothly transitioning between adjacent areas while generating only one area. It is used in computer graphics, computer animation, game development and other fields to create natural and realistic textures, effects and animations. Due to its seamless nature, such noise allows you to create continuous textures and backgrounds.

We will need the libraries p5.js and open-simplex-noise

We create a project on angular and connect the p5.js library, for convenience I use the abstract class P5JSInvoker.

It will allow us to use basic p5 callbacks (preload, setup, draw) as class methods.

export abstract class P5JSInvoker {
 abstract preload(p: P5.p5InstanceExtensions): void;
 abstract setup(p: P5.p5InstanceExtensions): void;
 abstract draw(p: P5.p5InstanceExtensions): void;




 protected startP5JS(containerElement:HTMLElement):P5.p5InstanceExtensions {
   return new P5(this.generate_sketch(), containerElement);
 }


 private generate_sketch(): any {
   const that = this;


   return ((p: P5) => {
     p.preload = (): void => {
       that.preload(p);
     };


     p.setup = (): void => {
       that.setup(p);
     };


     p.draw = (): void => {
       that.draw(p);
     };
   });
 }
}

Next I create a canvas and a NoiseGenerator class.
Dimensions is responsible for the size of the generation, at the moment it is the size of the entire canvas, and x1, x2, y1, y2 are the scales of the noise itself.
By default I have values ​​0, 10, 0, 10

public setup(p5: p5InstanceExtensions): void {
 this.p5.noSmooth();
 this.p5.createCanvas(
   this.dimensions.x,
   this.dimensions.y,
 );
 this.generator = new NoiseGenerator();
 this.generator.createNoise(this.dimensions.y, this.dimensions.x, this.x1, this.x2, this.y1, this.y2)


 this.p5.noLoop();
 this.container.nativeElement.onclick = () => this.p5.save();
}

Let's take a closer look at it

import {P5InstanceService} from "../services/p5-instance.service";
import {SPACING} from "../constants/constants";
import {Particle} from "./particle";
import {makeNoise4D} from "open-simplex-noise";
import {Vector} from "p5";


export class NoiseGenerator {
 private p5 = P5InstanceService.p5Instance;
 private particles: Particle[][] = [];
 private rows = 0;
 private cols = 0;


 public createNoise(
   height: number,
   width: number,
   x1: number,
   x2: number,
   y1: number,
   y2: number,
 ): void {
   this.p5.noiseSeed(20)
   this.p5.strokeWeight(1);


   this.rows = Math.floor(height / SPACING)
   this.cols = Math.floor(width / SPACING)


   this.seamlessNoise2D(this.cols, this.rows, x1, x2, y1, y2)
 }


 public seamlessNoise2D(bufferWidth: number,
                        bufferHeight: number,
                        x1: number,
                        x2: number,
                        y1: number,
                        y2: number) {
   const noise = makeNoise4D(10);


   for (let x = 0; x < bufferWidth; x++) {
     this.particles[x] = [];


     for (let y = 0; y < bufferHeight; y++) {
       const s = x / bufferWidth;
       const t = y / bufferHeight;
       const dx = x2 - x1;
       const dy = y2 - y1;


       const nx = x1 + Math.cos(s * 2 * Math.PI) * dx / (2 * Math.PI);
       const ny = y1 + Math.cos(t * 2 * Math.PI) * dy / (2 * Math.PI);
       const nz = x1 + Math.sin(s * 2 * Math.PI) * dx / (2 * Math.PI);
       const nw = y1 + Math.sin(t * 2 * Math.PI) * dy / (2 * Math.PI);


       this.particles[x][y] = new Particle(
         new Vector(x * SPACING, y * SPACING),
         this.p5.map(noise(nx, ny, nz, nw), -0.5, 0.5, 0, 255)
       );
     }
   }
 }


 public showParticles(): void {
   this.particles.forEach(p => p.forEach(p => p.show()))
 }
}

Here we create a matrix of particles, the implementation of which can be at your discretion.

SPACING is needed to set the distance between particles. If we need to fill each pixel, then it should be set to 1.

In the makeNoise4D() function, the argument is the noise seed, which can be replaced with any integer for the generation you like.

When creating a Particle instance, we specify the current position and color.
The color is determined using the p5.map method, which transforms the noise range from -0.5 to 0.5 into a color range from 0 to 255.
Typically noise generates values ​​between 0 and 1, but this library produces values ​​between -0.5 and 0.5.
Changing these settings will allow us to control the contrast between black and white areas.

This is the implementation of the particle's show method.

export class Particle {


 constructor(public position: Vector, public color: number) {
 }


 public show(): void {
   this.p5.fill(this.color);
   this.p5.noStroke()
   this.p5.square(this.position.x, this.position.y, SPACING);
 }
}

At this stage we should have an image like this:

If we take this image and copy it as many times as we want, we should not see any seams. That is, the image will work as tiles.

The simplest example of using such noise is the texture of clouds or water:

By increasing the spacing value and increasing the noise scale we can generate tiles for pixel art.

Here I used a second noise to create inclusions like ore or grass.

I pass the second noise on another seed to the Particle object, and by manipulating FILL_AMOUNT I can change the degree of filling.



public show(): void {


 if (this.noise2 > FILL_AMOUNT) {
   const fill = this.p5.map(this.noise2, -0.5, 0.5, 10, 30, false)
   this.p5.fill(70, 50, fill);
 } else {
   const fill = this.p5.map(this.noise, -0.5, 0.5, 25, 50, false)
   this.p5.fill(30, 50, fill);
 }


 this.p5.noStroke()
 this.p5.square(this.position.x, this.position.y, SPACING);
}


In the case of implementing a particle system pattern for our website, we needed to convert the noise matrix into vectors and use it as a force field.

const angle = noise * this.p5.TWO_PI * 4
const vector = Vector.fromAngle(angle).normalize();

It is also necessary to copy the noise matrix on all four sides of the saved area, since particles may extend beyond its boundaries.

Instead of a conclusion

The pattern is needed to create visual harmony and structure of the image, it is created to attract the attention of users and makes the company's symbols memorable and overall it is beautiful. You can see what the pattern we developed looks like here. If you have any questions, ask them in the comments, offer your own implementation of seamless noise.

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *