Setting random image texture on randomized number of torus from image array

Hello, I am working on a code in webgl in the p5js web editor that calls in a random number of spinning torus, spinning at different speeds and angles, which are all defined. I have set the texture to pull from an array of image assets, but as of now when the code loads all the torus have the same image as texture. I would like each torus to display a different image from an array upon reload, without changing the random functions of the rest of the code (numtorus, width, radius, angle, etc). I have tried to define an array of images but have run into problems with defining texture as random even if the images are set in an array.

let bg
let img
let numTorus
let angle = []
let radius = []
let torusWidth = []

function setup() {
  bg = loadImage('');
  createCanvas(600, 600, WEBGL)
  setAttributes("antialias", true)
  textureWrap(REPEAT)
  randomSeed(42)
}


function preload() 
{
  bg = loadImage('lava2.jpg')
  img = random([
    loadImage("lava2.jpg"),
    loadImage("cable tangle.jpg"),
    loadImage("ocean trash.jpg"),
    loadImage("pangea1.png"),
    loadImage("openpits small.jpg"),
    loadImage("undersea cable.jpg"),
    loadImage("content aware yareta.jpg")
  ])

  // 1-6, 6-15, 15-30: 5, 90, 5 
  numTorus = Math.floor(random(1, 30))
  console.log('numTorus:', numTorus)
  
  for (let i = 0; i < numTorus; ++i) {
    // 0.5-2, 0.5-6
    torusWidth.push(random(0.5, 50))
    radius.push(random(1, 225))
    angle.push(random(0.00009, 0.005))
    console.log('angle:',i, angle[i])
    console.log('radius:',i, radius[i])
    console.log('torusWidth:', i, torusWidth[i])

  }
}

function draw() {
  
  noStroke()
  // texture(bg)
  // translate(0,0,-400)
  // plane(1200, 1200)
  // translate(0,0,400)
  texture(img)
  background('black')
  directionalLight(250, 250, 250, 0, 0, -1)
  
  for (let i = 0; i < numTorus; ++i) {
    rotateX(frameCount * angle[i])
    rotateY(frameCount * angle[i])
    rotateZ(frameCount * angle[i])
    torus(radius[i], torusWidth[i], 50, 50)
  }
}

Im a beginner with p5js, any help appreciated. Thank you so much!

code looks fine to me. i see you say you have you tried loading the images into an array outside of the random call to see if it works and you say it doesn’t which is weird. you just want a different image to be selected each run and not for each element correct? here is a version of what i assume you want (which is a different image for each run) that works as to that spec.

but honestly i see nothing wrong with your code and the only thing that might be causing drama is perfoming the loadImage inside the array generation inside the call to random but if you’ve tried that i am stumped. i’m sure someone will have and answer.

if it was the other version you were looking for you can see it here

edit: also i didn’t have your images so i just generated some to use so it could also be an issue with the file paths you are using?

Hi @hotfooted thank you so much for replying. Yes, the code I shared works for all toruses having the same image, but not for each torus having a different one, which is the second version you shared. I was looking at it and wondering how i could build on this second version using my images and not generated number images as you used, where would these inputs go and how? The file paths are all jpegs that i uploaded in my assets

it’d be something like

let bg
let img
let numTorus
let angle = []
let radius = []
let torusWidth = []
let textureArray;

function setup() {
  bg = loadImage('');
  createCanvas(600, 600, WEBGL)
  setAttributes("antialias", true)
  textureWrap(REPEAT)
  randomSeed(42)
}

function preload() 
{
  bg = loadImage('lava2.jpg')
  textureArray = [
    loadImage("lava2.jpg"),
    loadImage("cable tangle.jpg"),
    loadImage("ocean trash.jpg"),
    loadImage("pangea1.png"),
    loadImage("openpits small.jpg"),
    loadImage("undersea cable.jpg"),
    loadImage("content aware yareta.jpg")
  ]
  shuffle(textureArray, true);
  
  // 1-6, 6-15, 15-30: 5, 90, 5 
  numTorus = floor(random(1, 30))
  
  console.log('numTorus:', numTorus)
  
  for (let i = 0; i < numTorus; ++i) {
    // 0.5-2, 0.5-6
    torusWidth.push(random(0.5, 50))
    radius.push(random(1, 225))
    angle.push(random(0.00009, 0.005))
    console.log('angle:',i, angle[i])
    console.log('radius:',i, radius[i])
    console.log('torusWidth:', i, torusWidth[i])
  }
}

function draw() {
  background(255);
  noStroke()
  // texture(bg)
  // translate(0,0,-400)
  // plane(1200, 1200)
  // translate(0,0,400)

  background('black')
  directionalLight(250, 250, 250, 0, 0, -1)

  for (let i = 0; i < numTorus; i++) {  
    texture(textureArray[i]);
    rotateX(frameCount * angle[i])
    rotateY(frameCount * angle[i])
    rotateZ(frameCount * angle[i])
    torus(radius[i], torusWidth[i], 50, 50)
  }
}

wait i see what you mean. if you have an unequal amount of textures to numTorus how would it work. the best i can offer before i’ve had a coffee is just mod i over the size of the textureArray. so basically this

  for (let i = 0; i < numTorus; i++) {  
    texture(textureArray[i]);
    rotateX(frameCount * angle[i])
    rotateY(frameCount * angle[i])
    rotateZ(frameCount * angle[i])
    torus(radius[i], torusWidth[i], 50, 50)
  }
}

would become

  for (let i = 0; i < numTorus; i++) {  
    texture(textureArray[i % textureArray.length]);
    rotateX(frameCount * angle[i])
    rotateY(frameCount * angle[i])
    rotateZ(frameCount * angle[i])
    torus(radius[i], torusWidth[i], 50, 50)
  }
}

or you ensure you have an equal amount of the two. i’ll wake up and come back and see what your thoughts on it are

…1 coffee later

the problem with using the mod i technique is you end up with repetition (or at least i believe you will, i can’t run the code atm) a way to avoid that would be the to maintain an array of indices into a texture array and have the indices array shuffled instead.

let bg
let img
let numTorus
let angle = []
let radius = []
let torusWidth = []
let textures;
let textureIndices;

function setup() {
  bg = loadImage('');
  createCanvas(600, 600, WEBGL)
  setAttributes("antialias", true)
  textureWrap(REPEAT)
  randomSeed(42)
}

function preload() 
{
  // 1-6, 6-15, 15-30: 5, 90, 5 
  numTorus = floor(random(1, 30))
  
  bg = loadImage('lava2.jpg')
  textures = [
    loadImage("lava2.jpg"),
    loadImage("cable tangle.jpg"),
    loadImage("ocean trash.jpg"),
    loadImage("pangea1.png"),
    loadImage("openpits small.jpg"),
    loadImage("undersea cable.jpg"),
    loadImage("content aware yareta.jpg")
  ]
  textureIndices = [];
  for(var i = 0; i < numTorus; i++) {
    textureIndices.push(i % textures.length);
  }
  shuffle(textureIndices, true);
  
  console.log('numTorus:', numTorus)
  
  for (let i = 0; i < numTorus; ++i) {
    // 0.5-2, 0.5-6
    torusWidth.push(random(0.5, 50))
    radius.push(random(1, 225))
    angle.push(random(0.00009, 0.005))
    console.log('angle:',i, angle[i])
    console.log('radius:',i, radius[i])
    console.log('torusWidth:', i, torusWidth[i])
  }
}

function draw() {
  background(255);
  noStroke()
  // texture(bg)
  // translate(0,0,-400)
  // plane(1200, 1200)
  // translate(0,0,400)

  background('black')
  directionalLight(250, 250, 250, 0, 0, -1)

  for (let i = 0; i < numTorus; i++) {  
    texture(textures[textureIndices[i]]);
    rotateX(frameCount * angle[i])
    rotateY(frameCount * angle[i])
    rotateZ(frameCount * angle[i])
    torus(radius[i], torusWidth[i], 50, 50)
  }
}

@hotfooted you are a genius!!!
Sorry it took me a minute to circle back to this.
I added in my image assets and bingo, your latest code with the texture indices prompt is the missing piece I was looking for. I couldnt find any resource links to it in the p5js library for some reason.
There is some repetition but I do plan to create more textures, so in essence the amount of different versions is quite infinite.
Thank you so much again, I will post the final code and link to the project once its done!

happy to help. glad you got it sorted. :+1: