summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpommicket <pommicket@gmail.com>2022-12-21 15:10:22 -0500
committerpommicket <pommicket@gmail.com>2022-12-21 15:10:22 -0500
commit1bc45db77e3d1aaf6c620248b8e598cdc212112f (patch)
treeeb534b13feb2e4e8ca1a6783b22f46f0fc043019
parentc81d53fa47863d80436ce808b16c836ea6d3e16c (diff)
params, twisty
-rw-r--r--gen_random/src/lib.rs143
-rw-r--r--gen_random_proc_macro/src/lib.rs93
-rw-r--r--src/fshader_main.glsl5
-rw-r--r--src/main.rs1
-rw-r--r--src/sdf.rs63
5 files changed, 171 insertions, 134 deletions
diff --git a/gen_random/src/lib.rs b/gen_random/src/lib.rs
index 07da6b5..4bd67be 100644
--- a/gen_random/src/lib.rs
+++ b/gen_random/src/lib.rs
@@ -4,12 +4,28 @@ use std::rc::Rc;
use std::sync::Arc;
use std::cell::{Cell, RefCell};
+pub trait GenRandomParams: Sized + Default + Copy {
+ fn inc_depth(self) -> Self;
+}
+
+impl GenRandomParams for () {
+ fn inc_depth(self) -> Self {
+ ()
+ }
+}
+
+impl GenRandomParams for i64 {
+ fn inc_depth(self) -> Self {
+ self - 1
+ }
+}
+
/// Generate random structs and enums!
///
/// You don't need to implement this trait yourself — instead, use the `derive` macro:
/// ```
/// use gen_random_proc_macro::GenRandom;
-/// use gen_random::GenRandom;
+/// use gen_random::{GenRandom, GenRandomParams};
///
/// #[derive(GenRandom, Debug)]
/// enum MyType {
@@ -36,132 +52,125 @@ use std::cell::{Cell, RefCell};
/// }
/// ```
-pub trait GenRandom: Sized {
- /// To allow recursive structs like binary trees,
- /// we provide a `max_depth` functionality.
- /// If your struct isn't recursive, you can use [GenRandom::gen_random] instead.
- /// If `max_depth <= 0` the **first** variant of an `enum` is always chosen
- /// (so make sure `Empty` or whatever comes first).
- /// For `Option<T>`, if `max_depth <= 0`, `None` is always chosen.
- fn gen_random_max_depth(rng: &mut impl Rng, max_depth: isize) -> Self;
+pub trait GenRandom<Params: GenRandomParams>: Sized {
+ /// Generate a random value with parameters.
+ fn gen_random_params(rng: &mut impl Rng, params: Params) -> Self;
- /// Generate a random instance of this struct using the given random number generator.
+ /// Generate a random value
fn gen_random(rng: &mut impl Rng) -> Self {
- Self::gen_random_max_depth(rng, isize::MAX)
+ Self::gen_random_params(rng, Params::default())
}
- /// Generate a random instance of this struct using `rand::thread_rng()` with a maximum depth.
- fn gen_thread_random_max_depth(max_depth: isize) -> Self {
+ /// Generate a random instance of this struct using `rand::thread_rng()` with parameters.
+ fn gen_thread_random_params(params: Params) -> Self {
let mut thread_rng = rand::thread_rng();
- Self::gen_random_max_depth(&mut thread_rng, max_depth)
+ Self::gen_random_params(&mut thread_rng, params)
}
/// Generate a random instance of this struct using `rand::thread_rng()`.
fn gen_thread_random() -> Self {
- Self::gen_thread_random_max_depth(isize::MAX)
+ Self::gen_thread_random_params(Params::default())
}
}
-pub fn gen_random_vec<T: GenRandom>(rng: &mut impl Rng, len: usize) -> Vec<T> {
+pub fn gen_random_vec<P: GenRandomParams, T: GenRandom<P>>(rng: &mut impl Rng, len: usize) -> Vec<T> {
(0..len).map(|_| T::gen_random(rng)).collect()
}
-pub fn gen_thread_random_vec<T: GenRandom>(len: usize) -> Vec<T> {
+pub fn gen_thread_random_vec<P: GenRandomParams, T: GenRandom<P>>(len: usize) -> Vec<T> {
gen_random_vec(&mut rand::thread_rng(), len)
}
-impl GenRandom for f32 {
- fn gen_random_max_depth(rng: &mut impl Rng, _depth: isize) -> Self {
+impl<Params: GenRandomParams> GenRandom<Params> for f32 {
+ fn gen_random_params(rng: &mut impl Rng, _params: Params) -> Self {
rng.gen_range(0.0..1.0)
}
}
-impl GenRandom for f64 {
- fn gen_random_max_depth(rng: &mut impl Rng, _depth: isize) -> Self {
+impl<Params: GenRandomParams> GenRandom<Params> for f64 {
+ fn gen_random_params(rng: &mut impl Rng, _params: Params) -> Self {
rng.gen_range(0.0..1.0)
}
}
-impl<T: GenRandom> GenRandom for Box<T> {
- fn gen_random_max_depth(rng: &mut impl Rng, depth: isize) -> Self {
- Box::new(T::gen_random_max_depth(rng, depth))
+impl<Params: GenRandomParams, T: GenRandom<Params>> GenRandom<Params> for Box<T> {
+ fn gen_random_params(rng: &mut impl Rng, params: Params) -> Self {
+ Box::new(T::gen_random_params(rng, params))
}
}
-impl<T: GenRandom> GenRandom for [T; 1] {
- fn gen_random_max_depth(rng: &mut impl Rng, depth: isize) -> Self {
- [T::gen_random_max_depth(rng, depth)]
+impl<Params: GenRandomParams, T: GenRandom<Params>> GenRandom<Params> for [T; 1] {
+ fn gen_random_params(rng: &mut impl Rng, params: Params) -> Self {
+ [T::gen_random_params(rng, params)]
}
}
-impl<T: GenRandom> GenRandom for [T; 2] {
- fn gen_random_max_depth(rng: &mut impl Rng, depth: isize) -> Self {
- [T::gen_random_max_depth(rng, depth), T::gen_random_max_depth(rng, depth)]
+impl<Params: GenRandomParams, T: GenRandom<Params>> GenRandom<Params> for [T; 2] {
+ fn gen_random_params(rng: &mut impl Rng, params: Params) -> Self {
+ [T::gen_random_params(rng, params), T::gen_random_params(rng, params)]
}
}
-impl<T: GenRandom> GenRandom for [T; 3] {
- fn gen_random_max_depth(rng: &mut impl Rng, depth: isize) -> Self {
- [T::gen_random_max_depth(rng, depth), T::gen_random_max_depth(rng, depth), T::gen_random_max_depth(rng, depth)]
+impl<Params: GenRandomParams, T: GenRandom<Params>> GenRandom<Params> for [T; 3] {
+ fn gen_random_params(rng: &mut impl Rng, params: Params) -> Self {
+ [T::gen_random_params(rng, params), T::gen_random_params(rng, params), T::gen_random_params(rng, params)]
}
}
-impl<T: GenRandom> GenRandom for [T; 4] {
- fn gen_random_max_depth(rng: &mut impl Rng, depth: isize) -> Self {
- [T::gen_random_max_depth(rng, depth), T::gen_random_max_depth(rng, depth), T::gen_random_max_depth(rng, depth), T::gen_random_max_depth(rng, depth)]
+impl<Params: GenRandomParams, T: GenRandom<Params>> GenRandom<Params> for [T; 4] {
+ fn gen_random_params(rng: &mut impl Rng, params: Params) -> Self {
+ [T::gen_random_params(rng, params), T::gen_random_params(rng, params), T::gen_random_params(rng, params), T::gen_random_params(rng, params)]
}
}
-impl<T: GenRandom> GenRandom for (T, T) {
- fn gen_random_max_depth(rng: &mut impl Rng, depth: isize) -> Self {
- (T::gen_random_max_depth(rng, depth), T::gen_random_max_depth(rng, depth))
+impl<Params: GenRandomParams, T: GenRandom<Params>> GenRandom<Params> for (T, T) {
+ fn gen_random_params(rng: &mut impl Rng, params: Params) -> Self {
+ (T::gen_random_params(rng, params), T::gen_random_params(rng, params))
}
}
-impl<T: GenRandom> GenRandom for (T, T, T) {
- fn gen_random_max_depth(rng: &mut impl Rng, depth: isize) -> Self {
- (T::gen_random_max_depth(rng, depth), T::gen_random_max_depth(rng, depth), T::gen_random_max_depth(rng, depth))
+impl<Params: GenRandomParams, T: GenRandom<Params>> GenRandom<Params> for (T, T, T) {
+ fn gen_random_params(rng: &mut impl Rng, params: Params) -> Self {
+ (T::gen_random_params(rng, params), T::gen_random_params(rng, params), T::gen_random_params(rng, params))
}
}
-impl<T: GenRandom> GenRandom for (T, T, T, T) {
- fn gen_random_max_depth(rng: &mut impl Rng, depth: isize) -> Self {
- (T::gen_random_max_depth(rng, depth), T::gen_random_max_depth(rng, depth), T::gen_random_max_depth(rng, depth), T::gen_random_max_depth(rng, depth))
+impl<Params: GenRandomParams, T: GenRandom<Params>> GenRandom<Params> for (T, T, T, T) {
+ fn gen_random_params(rng: &mut impl Rng, params: Params) -> Self {
+ (T::gen_random_params(rng, params), T::gen_random_params(rng, params), T::gen_random_params(rng, params), T::gen_random_params(rng, params))
}
}
-impl<T: GenRandom> GenRandom for Rc<T> {
- fn gen_random_max_depth(rng: &mut impl Rng, depth: isize) -> Self {
- Self::new(T::gen_random_max_depth(rng, depth))
+impl<Params: GenRandomParams, T: GenRandom<Params>> GenRandom<Params> for Rc<T> {
+ fn gen_random_params(rng: &mut impl Rng, params: Params) -> Self {
+ Self::new(T::gen_random_params(rng, params))
}
}
-impl<T: GenRandom> GenRandom for Arc<T> {
- fn gen_random_max_depth(rng: &mut impl Rng, depth: isize) -> Self {
- Self::new(T::gen_random_max_depth(rng, depth))
+impl<Params: GenRandomParams, T: GenRandom<Params>> GenRandom<Params> for Arc<T> {
+ fn gen_random_params(rng: &mut impl Rng, params: Params) -> Self {
+ Self::new(T::gen_random_params(rng, params))
}
}
-impl<T: GenRandom> GenRandom for Cell<T> {
- fn gen_random_max_depth(rng: &mut impl Rng, depth: isize) -> Self {
- Self::new(T::gen_random_max_depth(rng, depth))
+impl<Params: GenRandomParams, T: GenRandom<Params>> GenRandom<Params> for Cell<T> {
+ fn gen_random_params(rng: &mut impl Rng, params: Params) -> Self {
+ Self::new(T::gen_random_params(rng, params))
}
}
-impl<T: GenRandom> GenRandom for RefCell<T> {
- fn gen_random_max_depth(rng: &mut impl Rng, depth: isize) -> Self {
- Self::new(T::gen_random_max_depth(rng, depth))
+impl<Params: GenRandomParams, T: GenRandom<Params>> GenRandom<Params> for RefCell<T> {
+ fn gen_random_params(rng: &mut impl Rng, params: Params) -> Self {
+ Self::new(T::gen_random_params(rng, params))
}
}
-impl<T: GenRandom> GenRandom for Option<T> {
- fn gen_random_max_depth(rng: &mut impl Rng, depth: isize) -> Self {
- if depth <= 0 {
- None
- } else if rng.gen_range(0..2) == 0 {
+impl<Params: GenRandomParams, T: GenRandom<Params>> GenRandom<Params> for Option<T> {
+ fn gen_random_params(rng: &mut impl Rng, params: Params) -> Self {
+ if rng.gen_range(0..2) == 0 {
None
} else {
- Some(T::gen_random_max_depth(rng, depth))
+ Some(T::gen_random_params(rng, params))
}
}
}
@@ -171,7 +180,7 @@ impl<T: GenRandom> GenRandom for Option<T> {
mod tests {
extern crate gen_random_proc_macro;
extern crate rand;
- use super::{gen_thread_random_vec, GenRandom};
+ use super::{gen_thread_random_vec, GenRandom, GenRandomParams};
use gen_random_proc_macro::GenRandom;
#[derive(GenRandom, Debug)]
@@ -202,10 +211,12 @@ mod tests {
}
#[derive(GenRandom, Debug)]
+ #[params(i64)]
enum BinaryTree {
#[prob(1)]
Empty,
#[prob(99)]
+ #[only_if(params >= 0)]
Node(f64, Box<BinaryTree>, Box<BinaryTree>)
}
@@ -252,8 +263,8 @@ mod tests {
}
#[test]
- fn binary_tree_max_depth() {
- let bintree = BinaryTree::gen_thread_random_max_depth(5);
+ fn binary_tree_params() {
+ let bintree = BinaryTree::gen_thread_random_params(5);
println!("{bintree:?}");
}
}
diff --git a/gen_random_proc_macro/src/lib.rs b/gen_random_proc_macro/src/lib.rs
index 9b7a771..961b2a0 100644
--- a/gen_random_proc_macro/src/lib.rs
+++ b/gen_random_proc_macro/src/lib.rs
@@ -10,7 +10,7 @@ use std::any::type_name;
use quote::quote;
/// See `gen_random::GenRandom`.
-#[proc_macro_derive(GenRandom, attributes(prob, scale, bias))]
+#[proc_macro_derive(GenRandom, attributes(prob, scale, bias, params, only_if))]
pub fn gen_random_derive(input: TokenStream) -> TokenStream {
// Construct a representation of Rust code as a syntax tree
// that we can manipulate
@@ -19,7 +19,7 @@ pub fn gen_random_derive(input: TokenStream) -> TokenStream {
impl_gen_random(&ast)
}
-fn get_attribute(attrs: &[syn::Attribute], name: &str) -> Option<proc_macro2::TokenStream> {
+fn get_attribute(attrs: &[syn::Attribute], name: &str) -> Option<TokenStream2> {
let attr = attrs.iter().find(|a| {
let path = &a.path;
if let Some(ident) = path.get_ident() {
@@ -56,14 +56,14 @@ fn parse_attribute_value<T: FromStr>(attrs: &[syn::Attribute], name: &str) -> Op
Some(value)
}
-fn generate_fields(fields: &syn::Fields) -> impl quote::ToTokens {
+fn generate_fields(fields: &syn::Fields, params_type: &TokenStream2) -> impl quote::ToTokens {
let mut field_values = quote! {};
for field in fields.iter() {
if let Some(name) = &field.ident {
field_values.extend(quote! {#name: });
}
let ty = &field.ty;
- field_values.extend(quote! { <#ty as GenRandom>::gen_random_max_depth(rng, _depth - 1) });
+ field_values.extend(quote! { <#ty as GenRandom<#params_type>>::gen_random_params(rng, <#params_type as GenRandomParams>::inc_depth(params)) });
if let Some(scale) = get_attribute(&field.attrs, "scale") {
field_values.extend(quote! { * ( #scale ) });
@@ -93,95 +93,64 @@ fn generate_fields(fields: &syn::Fields) -> impl quote::ToTokens {
}
}
-// very very precise summation algorithm
-// see https://en.wikipedia.org/wiki/Kahan_summation_algorithm
-fn kahan_sum(it: impl IntoIterator<Item = f64>) -> f64 {
- let mut it = it.into_iter();
- let mut sum = 0.0;
- let mut c = 0.0;
- while let Some(x) = it.next() {
- let y = x - c;
- let t = sum + y;
- c = (t - sum) - y;
- sum = t;
- }
- sum
-}
-
fn impl_gen_random(ast: &syn::DeriveInput) -> TokenStream {
let name = &ast.ident;
let mut function_body;
+ let params_type = get_attribute(&ast.attrs, "params").unwrap_or(quote! { () });
match &ast.data {
syn::Data::Enum(enumeration) => {
let variants = &enumeration.variants;
+ function_body = quote! {
+ let mut prob_sum = 0.0;
+ };
- let prob_sum = kahan_sum(variants.iter().map(|variant| {
- match parse_attribute_value(&variant.attrs, "prob") {
+ for variant in variants.iter() {
+ match parse_attribute_value::<f64>(&variant.attrs, "prob") {
Some(prob) => if prob >= 0.0 {
- prob
+ let only_if = get_attribute(&variant.attrs, "only_if")
+ .unwrap_or(quote! { true });
+
+ function_body.extend(quote! {
+ if #only_if { prob_sum += #prob; }
+ });
} else {
panic!("Variant {} has negative probability", variant.ident)
},
None => panic!("Variant {} has no probability", variant.ident)
}
- }));
-
- if prob_sum <= f64::EPSILON {
- panic!("Sum of probabilties is (basically) zero.");
}
- // ideally we would just do
- // let mut variant: f64 = rng.gen_range(0.0..prob_sum);
- // variant -= variant1_probability;
- // if variant < 0.0 { bla bla bla }
- // variant -= variant2_probability;
- // if variant < 0.0 { bla bla bla }
- // etc.
- // but because of floating point imprecision, it's possible
- // that all if conditions are false.
- // however we know that for each subtraction at most one ULP is lost.
- // so we'll be fine as long as we put the end of the range at
- // prob_sum * (1.0 - (variant_count + 2) * ULP)
- // the + 2 is for the imprecision lost in kahan_sum and one more just to be sure.
-
- let variant_max = prob_sum * (1.0 - f64::EPSILON * (variants.len() + 2) as f64);
- function_body = quote! {
- let mut variant: f64 = rng.gen_range(0.0..=#variant_max);
- };
-
- // this test value ensures that the gen_random function never panicks.
- let mut test_variant = variant_max;
+ let compensation = (variants.len() + 1) as f64 * f64::EPSILON;
+ function_body.extend(quote! {
+ let mut variant: f64 = rng.gen_range(0.0..prob_sum - #compensation);
+ });
// parse enum fields
for variant in variants.iter() {
// Note: None case was checked above when computing prob_sum
let probability: f64 = parse_attribute_value(&variant.attrs, "prob").unwrap();
+ let only_if = get_attribute(&variant.attrs, "only_if")
+ .unwrap_or(quote! { true });
let name = &variant.ident;
- let field_values = generate_fields(&variant.fields);
+ let field_values = generate_fields(&variant.fields, &params_type);
function_body.extend(quote! {
- variant -= #probability;
- // note: if _depth <= 0, we will always return the first variant.
- if _depth <= 0 || variant < 0.0 { return Self::#name #field_values; }
+ if #only_if {
+ variant -= #probability;
+ if variant < 0.0 { return Self::#name #field_values; }
+ }
});
- test_variant -= probability;
-
-
- }
-
- if test_variant >= 0.0 {
- panic!("i did floating-point math wrong. this should never happen. (test_variant = {test_variant})");
}
function_body.extend(quote! {
- panic!("RNG returned value outside of range.")
+ panic!("RNG returned value outside of range (this should never happen).")
});
},
syn::Data::Struct(structure) => {
- let field_values = generate_fields(&structure.fields);
+ let field_values = generate_fields(&structure.fields, &params_type);
function_body = quote! {
Self #field_values
};
@@ -190,8 +159,8 @@ fn impl_gen_random(ast: &syn::DeriveInput) -> TokenStream {
};
let gen = quote! {
- impl GenRandom for #name {
- fn gen_random_max_depth(rng: &mut impl rand::Rng, _depth: isize) -> Self {
+ impl GenRandom<#params_type> for #name {
+ fn gen_random_params(rng: &mut impl rand::Rng, params: #params_type) -> Self {
#function_body
}
}
diff --git a/src/fshader_main.glsl b/src/fshader_main.glsl
index 9e9334e..116fcd7 100644
--- a/src/fshader_main.glsl
+++ b/src/fshader_main.glsl
@@ -37,13 +37,12 @@ vec3 hsv_to_rgb(vec3 hsv) {
vec3 get_color(vec3 p) {
if (u_hsv != 0) {
- vec3 hsv = get_color_(p);
+ vec3 hsv = clamp(get_color_(p), 0.0, 1.0);
// make sure object isn't too dark so we can actually see it
hsv.z = mix(hsv.z, 1.0, 0.5);
return hsv_to_rgb(hsv);
} else {
- // we're not clamping this because it makes a cool glowing effect if we don't
- vec3 color = get_color_(p);
+ vec3 color = clamp(get_color_(p), 0.0, 1.0);
return mix(color, vec3(1.0), 0.2);
}
}
diff --git a/src/main.rs b/src/main.rs
index f77a3b7..598a12a 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -152,6 +152,7 @@ impl Programs {
let source_main = include_str!("fshader_main.glsl");
let source_test = include_str!("fshader_test.glsl");
let source_common = include_str!("fshader_common.glsl");
+ println!("{:?}",scene.sdf);
let mut sdf = String::new();
let mut get_color = String::new();
diff --git a/src/sdf.rs b/src/sdf.rs
index 1ced6b0..8975d05 100644
--- a/src/sdf.rs
+++ b/src/sdf.rs
@@ -3,7 +3,7 @@ extern crate rand;
extern crate serde;
extern crate serde_cbor;
-use gen_random::GenRandom;
+use gen_random::{GenRandom, GenRandomParams};
use gen_random_proc_macro::GenRandom;
use rand::Rng;
use serde::{Deserialize, Serialize};
@@ -15,8 +15,31 @@ macro_rules! write_str {
($( $arg:tt )*) => { write!($($arg)*).unwrap() }
}
+#[derive(Copy, Clone)]
+pub struct SdfParams {
+ max_depth: i32
+}
+
+impl Default for SdfParams {
+ fn default() -> Self {
+ Self {
+ max_depth: 5
+ }
+ }
+}
+
+impl GenRandomParams for SdfParams {
+ fn inc_depth(self) -> Self {
+ Self {
+ max_depth: self.max_depth - 1,
+ ..self
+ }
+ }
+}
+
/// these are constant across 3D space, not across time/user input/etc.
#[derive(Debug, GenRandom, Serialize, Deserialize)]
+#[params(SdfParams)]
pub enum Constant {
#[prob(0.0)]
F32(f32),
@@ -115,6 +138,7 @@ impl Display for Constant {
}
#[derive(GenRandom, Debug, Serialize, Deserialize)]
+#[params(SdfParams)]
pub struct Constant3(Constant, Constant, Constant);
impl std::ops::Add<f32> for Constant3 {
@@ -145,10 +169,12 @@ impl Display for Constant3 {
}
#[derive(GenRandom, Debug, Serialize, Deserialize)]
+#[params(SdfParams)]
pub enum R3ToR3 {
#[prob(0)]
Identity,
#[prob(6)]
+ #[only_if(params.max_depth >= 0)]
Compose(Box<R3ToR3>, Box<R3ToR3>),
#[prob(1)]
Translate(Constant3),
@@ -169,21 +195,26 @@ pub enum R3ToR3 {
#[prob(2)]
#[bias(0.01)]
Sigmoid, //based on sigmoid(x) = 1 / (1 + e^-x)
+ #[prob(2)]
+ Twisty,
}
// note : i dont think R → R transformations really accomplish that much
// that can't be done with R³ → R³.
#[derive(GenRandom, Debug, Serialize, Deserialize)]
+#[params(SdfParams)]
pub enum RToR {
#[prob(1)]
Identity,
#[prob(0)]
+ #[only_if(params.max_depth >= 0)]
Compose(Box<RToR>, Box<RToR>),
#[prob(0)]
Subtract(Constant),
}
#[derive(GenRandom, Debug, Serialize, Deserialize)]
+#[params(SdfParams)]
pub enum R3ToR {
#[prob(1)]
Sphere(Constant),
@@ -204,12 +235,16 @@ pub enum R3ToR {
thickness: Constant,
},
#[prob(8)]
+ #[only_if(params.max_depth >= 0)]
Compose(Box<R3ToR3>, Box<R3ToR>, Box<RToR>),
#[prob(4)]
+ #[only_if(params.max_depth >= 0)]
Mix(Box<R3ToR>, Box<R3ToR>, Constant),
#[prob(2)]
+ #[only_if(params.max_depth >= 0)]
SmoothMin(Box<R3ToR>, Box<R3ToR>),
#[prob(2)]
+ #[only_if(params.max_depth >= 0)]
Min(Box<R3ToR>, Box<R3ToR>),
}
@@ -316,7 +351,7 @@ impl fmt::Display for GLSLType {
}
}
-trait Function: Sized + Default + GenRandom + ImportExport {
+trait Function: Sized + Default + GenRandom<SdfParams> + ImportExport {
/// appends `code` with glsl code to apply the function to the input variable.
/// returns the output variable.
#[must_use]
@@ -344,9 +379,12 @@ trait Function: Sized + Default + GenRandom + ImportExport {
fn good_random(rng: &mut impl Rng, function_length: usize) -> Self {
let default_len = Self::default().export_string().len();
for max_depth in 1.. {
+ let params = SdfParams {
+ max_depth
+ };
let mut functions = vec![];
for _i in 0..20 {
- let f = Self::gen_random_max_depth(rng, max_depth);
+ let f = Self::gen_random_params(rng, params);
let len = f.export_string().len().saturating_sub(default_len);
functions.push((len, f));
}
@@ -485,6 +523,25 @@ impl Function for R3ToR3 {
);
output
}
+ Twisty => {
+ let a = var.next();
+ let theta = var.next();
+ let output = var.next();
+ write_str!(
+ code,
+ "vec2 {a} = vec2(cos({input}.x), sin({input}.y));\n"
+ );
+ write_str!(
+ code,
+ "float {theta} = {input}.z * sqrt(2.0);\n"
+ );
+ write_str!(
+ code,
+ "vec3 {output} = vec3({a}.x*cos({theta})+{a}.y*sin({theta}),
+ {a}.y*cos({theta})-{a}.x*sin({theta}),{input}.z) * (1.0/4.0);\n"
+ );
+ output
+ }
}
}
}