David Roberson |
Greetings fellow script authors!
As we all know, writing a script can be a daunting task. Whether you're an experienced programmer or a novice, there are always hurdles to overcome. Sometimes you may get stuck on a particular section of code, or maybe you're having trouble getting your script to work the way you want it to. Fear not, for this forum thread is dedicated to providing assistance with completing your work-in-progress scripts. Here's how it works: Post your script project in the comments section. Be sure to provide as much detail as possible, including what the script is supposed to do, what language it's written in (if, for example, you are trying to convert some python into lua), and what specific issues you're having trouble with. Other members of the community will read your post and offer their assistance. They may provide suggestions on how to fix the issue, offer code snippets that can help, or even offer to collaborate with you on the project. If you're feeling generous, take a look at other people's projects and offer your own expertise. You never know when you might be able to help someone else out. A few ground rules: Be respectful of others. This is a space for constructive criticism and collaboration, not negativity. Do not post any malicious code or attempt to exploit vulnerabilities in others' code. Keep the discussion focused on script debugging and development. Now, I know the FF Forum are pretty lightly trafficked these days, but I'd like to encourage a bit more interest in and activity on them. I am in the process of expanding my Lua scripting knowledge, recently with the help of ChatGPT. I've found it a good source of information that is difficult to find just searching online. It's a bit of work to get what you're looking for there, as well, so I plan to collect what insights I can and compile them in a more accessible form to share here. So, I'll be posting whatever I can as I go. I hope to lure in a few more with an interest in or more experience with scripting. With that said, I invite you all to start posting your script projects and let's get to work! |
|||||||||||||||||||||||||||||||
Posted: March 5, 2023 9:13 pm | ||||||||||||||||||||||||||||||||
David Roberson |
I'll get the ball rolling with this: I converted Simplex noise written in java to lua and found myself caught on a potential out of bounds error being reported as an attempt to index a `nil` value. I've commented out most of the code and focused in on one point, where I could no longer adequately test the problem. I've put a couple day into this, so it's time to put it out there for someone else to look at it. It could be obvious to a more experienced author what I'm missing. If you give it a look, you have my gratitude!
|
|||||||||||||||||||||||||||||||
Posted: March 5, 2023 9:29 pm | ||||||||||||||||||||||||||||||||
David Roberson |
I had a thought, but it escaped me, Oh, well...
|
|||||||||||||||||||||||||||||||
Posted: March 8, 2023 5:20 pm | ||||||||||||||||||||||||||||||||
David Roberson |
Hmm. I have a long post written up with formatting tags, but it doesn't show up when I post it here. I tried to post it again, but nothing shows. Let's see if breaking it up a bit helps...
Nope. No luck. |
|||||||||||||||||||||||||||||||
Posted: March 8, 2023 6:16 pm | ||||||||||||||||||||||||||||||||
David Roberson |
Since I've been having problems with proper indexing and `nil` values in my 2-4D Simplex and Perlin noise scripts, I took a day off to do a breakdown of the `perlin` noise function I'm using in my spherical Perlin noise, describing what each part does:
`perlin`: This section of the `perlin:noise` function initializes the empty `perlin` table and its empty `p` field using the syntax `perlin = {}`, `perlin.p = {}`., the latter of which is used to store 512 pseudorandom gradient values. In `perlin.p = {}`, `p` is a field (also called a key or a member) of the `perlin` table, which is being assigned a new empty table `{}` as its value. So `p` is a field that consists of a table. If you have a table `perlin` containing three tables `p1`, `p2`, `p3`, the fields should be accessed as `perlin.p1`, `perlin.p2`, `perlin.p3`.
Next, an arbitrary seed value is obtained using the `get_intslider_input()` function of the Filter Forge Scripting API. This value is used to seed the random number generator using `math.randomseed()`.
A `for` loop is then used to fill the `perlin.p` table with 256 randomly generated values between 0 and 255. These values are generated using the `math.random()` function.
`function perlin:noise(x, y, z)`: The main function that returns the noise value for a given point (x,y,z). This section of the `perlin:noise` function takes in 3 input values: `x`, `y`, and `z`. It calculates the noise value at the given coordinate in 3D space. Here are the breakdowns of the operations: The `y` and `z` values are set to 0 if they are not provided as input.
The function calculates the "unit cube" that the point will be located in by using the `math.floor` function to round down the input coordinates to integers and then performing a bitwise AND operation with 255 (which is equivalent to taking the modulo 256). This is done for each coordinate (x, y, and z) to obtain the indices of the cube vertices surrounding the input point.
After calculating the unit cube that the point will be located in, the function calculates the relative positions of the input point within the unit cube by subtracting the floored values fr om the input values. This gives `x`, `y`, and `z` values in the range [0, 1] that represent the position of the input point within the unit cube.
The fractional part of the coordinates of the point within the unit cube are calculated by subtracting the floored (integer part) coordinates fr om the original coordinates.
The `fade` function is applied to each of `x`, `y`, and `z` to smooth the result. The `fade` function is a 6th-degree polynomial that interpolates smoothly between 0 and 1.
The function then declares several variables that will be used later: `u`, `v`, and `w` are the smoothed `x`, `y`, and `z` values, respectively. `p` is a lookup table that stores the permutation of 256 integers used in the calculation of the `noise` function. The remaining variables (`A`, `AA`, `AB`, etc.) will hold the pseudorandom gradient vectors corresponding to the 8 unit cube vertices surrounding the input point. Note that the function has not yet calculated the gradient vectors or the noise value itself. These will be calculated in the following steps of the function. We can now calculate the dot product of each corner vector and the distance vector from the point to that corner. We can also use the fade curve to blend the contributions of each corner vector together. In this section of the `perlin:noise` function, the eight corner points of the unit cube surrounding the input point are identified using a hash function. The operations involved are: Retrieve the permutation table from the `self` table.
Declare 14 local variables to store the values of the corner points.
Overall, these operations perform a series of table lookups to retrieve the values of the corner points of the unit cube surrounding the input point. These corner points are used in the subsequent interpolation steps to calculate the final `perlin:noise` value. This section of the `perlin:noise` function performs the final step of calculating the noise value for the input coordinates by taking the weighted average between all 8 unit cube coordinates surrounding the input coordinate. `self.lerp`: The function is used for linear interpolation. It takes two values `a` and `b`, and a weight `w` and returns the linearly interpolated value between `a` and `b` based on the weight `w`. The nested `self.lerp` functions are used to calculate the weighted average between all 8 unit cube coordinates. The inputs to these functions are the 8 unit cube coordinates and the input coordinate. These 8 unit cube coordinates are labeled with different variable names that correspond to their position in the unit cube, such as `AAA`, `AAB`, `ABA`, etc. Inside each `self.lerp` function, there are two more nested `self.lerp` functions, which are used to interpolate the gradient vectors at each of the 4 corners of the unit cube. The gradient vectors are calculated using the `self:grad` function, which takes a hash value and the input coordinates, and returns a gradient vector.
Overall, the final output of this section is a weighted average of the gradient vectors at the 8 corners of the unit cube, which is the `perlin:noise` value for the input coordinates. This section of the `perlin:noise` function defines a lookup table for the `dot_product` function and a gradient function that finds the dot product between a pseudorandom gradient vector and the vector from an input coordinate to a unit cube vertex. `perlin.dot_product`: This table contains 16 entries, each corresponding to one of the 16 possible bit patterns that can be formed by three bits. Each entry is a function that takes three arguments `x`, `y`, and `z`, which represent the coordinates of a point, and returns the dot product between the pseudorandom gradient vector and the vector from the input point to a unit cube vertex in a particular direction. The directions are determined by the bit pattern associated with the function in the table.
`perlin:grad(hash, x, y, z)`: This method takes four arguments: `hash`, an integer value between 0 and 255; and `x`, `y`, and `z`, which represent the coordinates of a point. The method computes the dot product between the pseudorandom gradient vector associated with the given `hash` value and the vector from the input point to a unit cube vertex. The `hash` value determines which gradient vector to use, and the direction of the vector is determined by the dot product function corresponding to the last three bits of the hash value. The method returns the computed dot product.
`perlin.fade(t)`: The `fade` function is used to smooth the final output of the `perlin:noise` function. It takes a single parameter `t`, which represents the input value to be smoothed. The function uses a quintic (degree-5) polynomial to gradually transition from 0 to 1 as `t` increases from 0 to 1. This helps to reduce the appearance of sharp edges and discontinuities in the output of the `perlin:noise` function.
`perlin.lerp(t, a, b)`: The `lerp` function is a linear interpolation function that is used to combine the weighted average of the dot products of gradient vectors and the input coordinate. It takes three parameters: `t`, `a`, and `b`. The function returns the linear interpolation of `a` and `b` at the ratio of `t`, wh ere `t` ranges from 0 to 1. The resulting value is a weighted average of `a` and `b` wh ere `t` determines the weighting of the two values.
`noise`, `dot_product`, `grad`, `fade` and `lerp` are all functions defined within the `perlin` table using the colon syntax (`[/B]perlin:function()`[/B]). This makes them methods of the `perlin` table, so they can be called using the `:`[/B] syntax (`[/B]perlin:method()`[/B]). Doing an analysis like this is a big step in understanding the algorithms I need to use for scripting. I put a little extra effort into organizing and formatting my notes to share here. I thought people might find this sort of thing helpful, and it sort of fits in with the theme of this thread. If there's a positive response, I'll try to do more of these in cases wh ere I've gotten a script to working as intended. |
|||||||||||||||||||||||||||||||
Posted: March 8, 2023 6:50 pm | ||||||||||||||||||||||||||||||||
emme |
As you mentioned, ChatGPT can be quite helpful with these things, not only for writing scripts and functions, but for explaining them as well. Also, check out shadertoy.com if you haven't already. The shaders are written in GLSL, but there are a lot of great examples to learn from. Good luck with scripting
![]() |
|||||||||||||||||||||||||||||||
Posted: April 2, 2023 7:15 pm | ||||||||||||||||||||||||||||||||
David Roberson |
Yes, it's been really helpful (if occasionally frustrating) for improving my understanding of Lua. I've also found my way to shadertoy.com many times looking for ways to do certain things. I also recommend it, and ChatGPT can help convert the GLSL to Lua if you come across anything good there. Thanks, emme!
|
|||||||||||||||||||||||||||||||
Posted: April 17, 2023 2:33 am | ||||||||||||||||||||||||||||||||
David Roberson |
It's been a long time since I thought of posting here. The lack of discussion, while forgivable, has caused my to throw my scripting questions at ChatGPT or Copilot this past year. Today I had a chat I thought I'd share here. It might help others digging into the same topics, or even prompt some forum input.
Right. So, here you go: Understanding Noise Generation Seeds (and then Diving Deeper) I am working on noise generation scripts using Lua in Filter Forge. While I was at it, I found myself wondering what a seed exactly is. In terms of the noise generated, what does the seed do (break down the function in terms of it effects)? Copilot: Certainly! Let's dive into the fascinating world of seeds in noise generation. **What is a Seed?** A seed, in the context of noise generation algorithms like Stable Diffusion (and even in other areas like procedural terrain generation), is simply a numerical value. It acts as the starting point for generating noise patterns. Here's the plain and simple breakdown: 1. **Seed Is Not the Noise Image Itself**: The seed itself is not the noise pattern you see in the final image. Instead, it's like the initial spark that sets the whole process in motion. 2. **Not All Parameters**: Contrary to misconceptions, the seed doesn't encapsulate all the parameters used for image generation. It's just the starting point, not the entire recipe. 3. **Not Tied to Specific Prompts or Characteristics**: The seed remains detached fr om specific text prompts, poses, clothing, backgrounds, or artistic styles. It's more about the underlying randomness. **How Does It Work?** When you provide a seed, the noise generator algorithm takes that number and uses it to create an initial noise pattern. But here's the interesting part: the noise isn't truly random. It's pseudo-random. In other words, given the same seed, the algorithm will reliably produce the same noise pattern every time. This repeatability opens up some cool possibilities: - **Consistent Reproduction**: If you input the same seed, along with the same prompt and all the other parameters you used initially, you can reliably reproduce a generated image across multiple sessions. It's like having a secret recipe for noise! - **Sharing and Tweaking**: Users can work off someone else's generated image by starting fr om the same seed, prompt, and parameters. Plus, minor tweaks—like adjusting the prompt or parameters—allow you to explore variations without drastically altering the overall composition. - **Seed Characteristics**: Some seeds have been identified as having a higher probability of producing images with specific color palettes or compositions. Knowing these "lucky" seeds can give you a better chance of getting the output you desire. So, in summary, seeds are like the cosmic dice roll that determines the initial noise, and fr om there, the algorithm weaves its magic to create the final image. |
|||||||||||||||||||||||||||||||
Posted: September 8, 2024 5:35 pm | ||||||||||||||||||||||||||||||||
David Roberson |
Heh. Guess that was too long to post. Rather than a series of clips, I'll just share the text for anyone interested. ^_^;
For the full transcript: Understanding Noise Generation Seeds (and then Diving Deeper) |
|||||||||||||||||||||||||||||||
Posted: September 8, 2024 5:47 pm |
Filter Forge has a thriving, vibrant, knowledgeable user community. Feel free to join us and have fun!
33,712 Registered Users
+19 new in 30 days!
153,534 Posts
+31 new in 30 days!
15,348 Topics
+72 new in year!
6 unregistered users.