thomasp85 / particles

A particle simulation engine based on a port of d3-force
Other
118 stars 9 forks source link

Possible issue with velocity decay #12

Open jwretham opened 1 year ago

jwretham commented 1 year ago

Hi Thomas, hope you're good.

I make generative art/animation (mostly in R) and I've been exploring your brilliant Particles library (inspired by your art) as I think there's massive potential for some really interesting pieces. Hoping I can get your help with an issue which could be a bug (but more likely I'm just misunderstanding something)

I'm working on some code where I want to create a simulation which reacts to a new (randomly generated) field force every 10 evolutions (10 is an arbitrary number - eventually this will be triggered by an audio input). Each evolution is plotted and exporting, capturing the simulation.

The idea is that the particles in the simulation will be 're-energised' every 10 frames, energetically reacting to the new field force.

What I'm finding however is that even though I have the velocity decay set to 0, the velocity decays to 0 after 20 frames or so and the following field forces don't have any effect.

I suspect I'm doing something wrong with the 'reheat' function but I can't find much in the way of documentation/examples.

Was wondering if you could possibly take a look at my code and let me know if you can see where I'm going wrong?

library(particles)
library(tidygraph)
library(ggplot2)
library(tidyr)
library(scales)
library(av)

root_dir <- "C:\\Local workspace\\Art\\simulations\\frames"

# function  to create flow field
generate_field_function <- function(size=10){

  # generate input
  grid <- long_grid(seq(1, size, length.out = size*size), seq(1, size, length.out = size*size))

  # generate perlin grid
  grid$noise <- gen_perlin(grid$x, grid$y)

  # rescale and reformat
  grid <- as.data.frame(grid)
  grid$noise <- scales::rescale(grid$noise, to=c(0,7))
  grid <- grid %>% pivot_wider(names_from = x, values_from = noise)
  colnames(grid) <- paste0("V",1:size*size)
  grid <- as.matrix(grid)
}

plot_function <- function(sim){

  # count number of existing files (used as counter)
  count_existing_files <- length(list.files(root_dir))
  new_file <- count_existing_files + 1

  # plot
  plt <-
    ggplot(as_tibble(sim)) + 
    geom_point(aes(x, y), size = 0.5, stroke=0.5, alpha=1) +
    theme_void()

  # save plot to directory
  frame_no <- str_pad(new_file, 4, pad = "0")
  dir.create(file.path(root_dir), showWarnings = FALSE)
  ggsave(paste0(frame_no,".png"),  plot = plt,  device = png, path = root_dir, height=600, width=600,  units="px")

  # if frame multiple of 10 then generate new flow field and reheat simulation
  if(new_file %% 10 == 0){

    print("new grid")

    new_grid <- generate_field_function(10)

    new_sim <- sim %>%
      unwield(1) %>%
      wield(field_force, angle=new_grid, vel=1) %>%
      reheat(1) 

    return(new_sim)
  }
}

# generate initial flow gird
grid <- generate_field_function(10)

# run simulation
create_empty(1000) %>% 
  simulate(setup = aquarium_genesis(), alpha_decay=0) %>% 
  wield(field_force, angle=grid, vel=1) %>% 
  evolve(100, on_generation= plot_function) 

# generate video from exported plots
png_files <- list.files(root_dir, pattern = ".*png$", full.names = TRUE)
av_encode_video(png_files, "C:\\Local workspace\\Art\\simulations\\simulation_export_1.mp4",
                framerate = 10)

Any ideas/tips you can give are appreciated

Thanks

Joe