Skip to content

Some Patterns

Video Lecture

Section Video Links
Some Patterns Patterns Some Patterns 

 (Pay Per View)

You can use PayPal to purchase a one time viewing of this video for $1.49 USD.

Pay Per View Terms

  • One viewing session of this video will cost the equivalent of $1.49 USD in your currency.
  • After successful purchase, the video will automatically start playing.
  • You can pause, replay and go fullscreen as many times as needed in one single session for up to an hour.
  • Do not refresh the browser since it will invalidate the session.
  • If you want longer-term access to all videos, consider purchasing full access through Udemy or YouTube Memberships instead.
  • This Pay Per View option does not permit downloading this video for later viewing or sharing.
  • All videos are Copyright © 2019-2025 Sean Bradley, all rights reserved.

Description

Note

In this lesson, we also introduce the TSL named imports of fract, step, length, sin, cos, atan.

Now we will use some mathematics to draw some pretty patterns.

You will see at the end, that variations of only a few methods can produce vastly different results.

We will begin by using inline functions, and then move onto TSL functions.

Start Script

./src/main.ts

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
import './style.css'
import * as THREE from 'three/webgpu'
import { Fn, positionLocal } from 'three/tsl'
import { OrbitControls } from 'three/addons/controls/OrbitControls.js'

const scene = new THREE.Scene()

const camera = new THREE.PerspectiveCamera(
  75,
  window.innerWidth / window.innerHeight,
  0.1,
  10
)
camera.position.z = 1

const renderer = new THREE.WebGPURenderer()
renderer.setSize(window.innerWidth, window.innerHeight)
document.body.appendChild(renderer.domElement)
renderer.setAnimationLoop(animate)

window.addEventListener('resize', function () {
  camera.aspect = window.innerWidth / window.innerHeight
  camera.updateProjectionMatrix()
  renderer.setSize(window.innerWidth, window.innerHeight)
})

const controls = new OrbitControls(camera, renderer.domElement)
controls.enableDamping = true

const main = Fn(() => {
  const p = positionLocal.toVar()

  return p
})

const material = new THREE.NodeMaterial()
//material.fragmentNode = main()
material.fragmentNode = positionLocal

const mesh = new THREE.Mesh(new THREE.PlaneGeometry(), material)
scene.add(mesh)

// renderer.debug.getShaderAsync(scene, camera, mesh).then((e) => {
//   //console.log(e.vertexShader)
//   console.log(e.fragmentShader)
// })

function animate() {
  controls.update()

  renderer.render(scene, camera)
}

Example 1 : Checkered Cube

const material = new THREE.NodeMaterial()
material.fragmentNode = positionLocal.mul(4.9999).fract().step(0.5)

const mesh = new THREE.Mesh(new THREE.BoxGeometry(), material)
scene.add(mesh)
<>

Example 2 : Ringed Cube

const material = new THREE.NodeMaterial()
material.fragmentNode = positionLocal.length().mul(15).fract().step(0.5)

const mesh = new THREE.Mesh(new THREE.BoxGeometry(), material)
scene.add(mesh)
<>

Example 3 : Animated Resizing Rings

const main = Fn(() => {
  const p = positionLocal.toVar()

  p.mulAssign(5)
  p.assign(p.fract().sub(0.5))
  p.assign(length(p))
  p.assign(sin(p.mul(10).add(time)))
  p.assign(abs(p))
  p.assign(step(0.5, p))

  return p
})

const material = new THREE.NodeMaterial()
material.fragmentNode = main()

const mesh = new THREE.Mesh(new THREE.PlaneGeometry(), material)
scene.add(mesh)
<>

Example 4 : Psychedelic Swirl

const main = Fn(() => {
  const p = positionLocal.toVar()

  p.assign(rotateUV(p.xy, time, vec2()))

  p.assign(length(p.mul(5)).sub(atan(p.zy, p.zx)).mul(5))
  p.sinAssign()
  p.mulAssign(5)

  p.assign(vec3(p.x.add(sin(time).mul(5)), p.y.add(cos(time).mul(5)), 0))

  return p
})

const material = new THREE.NodeMaterial()
material.fragmentNode = main()

const mesh = new THREE.Mesh(new THREE.PlaneGeometry(), material)
scene.add(mesh)
<>