godot-anl
godot-anl copied to clipboard
Provide Texture and Texture3d resources
Provide Texture and Texture3d resources and if possible refactor the engine so both Texture and Texture3d opensimplex and anl classes can coexist from the same parent class.
Yeah I think it would be nice to be able to use the same API for different kinds of noise types. ANL's noise is a bit strange beast though, meaning that it is evaluated through noise indexes. As you can see, the index is passed around quite often between methods, so AnlNoise
reference could use the last index to create textures by default.
Godot's NoiseTexture
could accept AnlNoise
reference which inherits from mentioned parent class:
OpenSimplexNoise
< Noise
AnlNoise
< Noise
It would be a matter of:
var ns = NoiseTexture.new()
var anl = AnlNoise.new()
ns.noise = anl
Some other points:
-
AnlNoise
andOpenSimplexNoise
both have similar methods namedmap_to_image()
andget_image()
. - Both classes provide a way to retrieve noise at coordinates.
Some caveats:
- Seamless textures generated with
OpenSimplexNoise
only support square aspect textures, withAnlNoise
one has ability to make textures seamless of any aspect, and restrict "seamlessness" to X/Y coordinates alone. -
OpenSimplexNoise
can't generate seamlessTexture3D
because it requires to generate noise in 6D.AnlNoise
has such methods likeget_scalar_6d()
.
Take in mind that AnlNoise
is quite slow to be used at run-time, so it's mostly suitable for generating textures and/or levels that are pre-generated.
So in theory I think it's doable.
Another thing I've noticed is that AnlNoise
should be a resource so that it can be saved... But the noise itself needs to be constructed from calling and passing indexes of resulting noise functions which is only possible from code, making it impossible to save it on disk, unlike OpenSimplexNoise
that has exposed properties such as octaves
or lacunarity
. The only property exposed in AnlNoise
is the last index passed to kernel.
So in order to salvage this issue there certainly needs to be a way to construct noise visually, see #5. That way AnlNoise
could have some kind of graph
property with defined output node which is essentially an index evaluated in kernel.
As a expedient way of implementing this without a graph editor, one should be able to use the string based evaluator feature of anl.
I was able to create this for 2d texture but I'm unable to do the math for the octave based fbm.
Index last_layer = anl_noise->fractal_layer(anl::BASIS_SIMPLEX,anl::INTERP_QUINTIC, 1.0f, 1.0f/get_period(), get_seed());
for (unsigned int c = 0; c < get_octaves() - 1; ++c) {
Index next_layer = anl_noise->fractal_layer(anl::BASIS_SIMPLEX,anl::INTERP_QUINTIC, 1.0f, 1.0f/get_period(), get_seed());
last_layer = anl_noise->add(last_layer, next_layer);
}
layer = last_layer;
This results in a black image. My goal is to get all the parameters - seed, octaves, period, persistence, lacunarity.
I tried a few combinations a few days ago, but I don't have those anymore.
As a expedient way of implementing this without a graph editor, one should be able to use the string based evaluator feature of anl.
Yeah this should be easier to implement but I would not rely on expression builder because it's buggy.
This results in a black image. My goal is to get all the parameters - seed, octaves, period, persistence, lacunarity.
Honestly I haven't yet mastered all these functions myself but I don't think that fractal_layer
is meant to be evaluated directly but rather passed to fractal
:
var n = AnlNoise.new()
var quintic = n.constant(3)
# Notice quintic interpolation is passed by index, not enum value.
# I think this is done to use different kind of interpolation at each coordinate... or a bug
var fractal_layer = n.fractal_layer(AnlNoise.BASIS_SIMPLEX, quintic, 1, 10, 1, 1)
var fractal = n.fractal(n.zero(), fractal_layer, n.one(), n.point5(), n.constant(5), n.constant(4))
var result = n.clamp(fractal, n.zero(), n.one()) # discard lower range noise
Result
I've followed underlying library's interface in order to be consistent with the source, not sure how it's actually implemented.
Getting weird results with:
https://i.imgur.com/pYIgic6.png
Index fractal_layer = anl_noise->fractal_layer(anl::BASIS_SIMPLEX, anl::INTERP_QUINTIC, 1.0f, 1.0f, get_seed());
Index fractal = anl_noise->fractal(anl_noise->seed(get_seed()), fractal_layer, get_persistence(), get_lacunarity(), get_octaves(), 1.0f);
Index x = anl_noise->scale_x(fractal, get_period());
layer = anl_noise->scale_y(x, get_period());
Opps missed your message.
This is what I have:
Index quintic = anl_noise->constant(3);
//Notice quintic interpolation is passed by index, not enum value.
//I think this is done to use different kind of interpolation at each coordinate... or a bug
Index fractal_layer = anl_noise->fractal_layer(anl::BasisTypes::BASIS_SIMPLEX, quintic, 1, 10, 1, 1);
Index persistence = anl_noise->constant(get_persistence());
Index lacunarity = anl_noise->constant(get_lacunarity());
Index octave = anl_noise->constant(get_octaves());
Index period = anl_noise->constant(1.0f / get_period());
Index fractal = anl_noise->fractal(anl_noise->zero(), fractal_layer, persistence, lacunarity, octave, period);
layer = anl_noise->clamp(fractal, anl_noise->zero(), anl_noise->one()); //discard lower range noise
Period isn't doing what I want, but it outputs!
Nice, yeah sure you'll always get something different from using other implementation. The way seamless mode works might also differ.
I wonder whether you're just trying to make AnlNoise
to do what OpenSimplexNoise
does in that case.
You got it. I want the AnlNoise to do exactly what OpenSimplexNoise does currently, because my goal is to have a different implementation of seamless 3d noise to compare against the OpenSimplex tileable 3d implementation.
I got period doing something reasonable:
Period 1.
Period 128:
Index quintic = anl_noise->constant(3);
//Notice quintic interpolation is passed by index, not enum value.
//I think this is done to use different kind of interpolation at each coordinate... or a bug
Index seed_index = anl_noise->constant(get_seed());
Index fractal_layer = anl_noise->fractal_layer(anl::BasisTypes::BASIS_SIMPLEX, quintic, 1, 10, 1, 1);
Index persistence_index = anl_noise->constant(get_persistence());
Index lacunarity_index = anl_noise->constant(get_lacunarity());
Index octave_index = anl_noise->constant(get_octaves());
Index period_index = anl_noise->constant(p_size / get_period());
Index fractal = anl_noise->fractal(seed_index, fractal_layer, persistence_index, lacunarity_index, octave_index, period_index);
layer = anl_noise->clamp(fractal, anl_noise->zero(), anl_noise->one()); //discard lower range noise
return anl_noise->map_to_image(Vector2(p_size, p_size), layer, anl::SEAMLESS_XY);
I was able to do 3d noise, but it's very difficult to tell between the seamless and non seamless.
Also I need a way to invert the value. Basically do 1 - value or -value + 1.
My approach is to have the same interface as opensimplex which seems to be an implementation of [fbm], so that's what I've emulated here.
I've also done the noise parent class separation, however I was wondering how to do the getting x,y,z,w coordinates from the noise. Currently I've only made generating a vector of images and generate images as the required interface of the Noise class.
Did the noise parent class seperation and tweaked the period scale.
My repos are https://github.com/fire/godot/tree/noise_texture_3d and https://github.com/fire/godot-anl
Please review.
I've also done the noise parent class separation, however I was wondering how to do the getting x,y,z,w coordinates from the noise. Currently I've only made generating a vector of images and generate images as the required interface of the Noise class.
The way you get noise at coordinates in your code seems alright but parameters don't need to be reinitialized after each query.
I would rename AccidentalNoise
to AccidentalFractalNoise
because this is rather a particular implementation. This is why I want to create VisualAnlNoise
so that this can be done in editor easily. But these specific implementations doesn't seem to hurt, especially if they're common.
Renamed AccidentalNoise to AccidentalFractalNoise and made it a child of FractalBrownianNoise which has the octaves, persistence and lacunarity variables. Defaulted texture noise and texture noise 3d to it.
Removed _generate_vbm function.
Yeah, this feels more modular, I also think it would be possible to change/refactor AnlNoise
to extend Noise
directly, that would require renaming some methods for getting noise to match the interface, so that you don't use AnlNoise
instance as a proxy.
@fire I've been working on a major update for 2.0. There are quite a lot of changes:
As a expedient way of implementing this without a graph editor, one should be able to use the string based evaluator feature of anl.
Implemented expression property from which noise can be evaluated. Made AccidentalNoise
a resource so it can be saved with expression.
noise->set_expression("simplexBasis(0)")
noise->get_image(100, 100)
Notice _map_to_image
is only used internally now, and noise is configured via properties (mapping mode, ranges, format etc).
Visual noise editor plugin is implemented, so you can experiment with this too!
Currently adapting your code for mapping 3D noise with mentioned changes to API, so if you're interested you can test it before I can merge it (don't know how to test it out):
https://github.com/Xrayez/godot-anl/tree/map-image-3d
2D: https://github.com/Xrayez/godot-anl/blob/789934ce32709bb77c692eaed7e11d9d800edb59/noise.cpp#L823-L828
3D: https://github.com/Xrayez/godot-anl/blob/789934ce32709bb77c692eaed7e11d9d800edb59/noise.cpp#L888-L893
I want to optimize this like:
for(int dest = 0, src = SIZE * k; src < SIZE * (k + 1); ++dest, ++src) {
w[dest * 4 + 0] = (uint8_t)(src_data[src].r * 255);
w[dest * 4 + 1] = (uint8_t)(src_data[src].g * 255);
w[dest * 4 + 2] = (uint8_t)(src_data[src].b * 255);
w[dest * 4 + 3] = (uint8_t)(src_data[src].a * 255);
}
But I'm afraid to break it!
I can coauthor you or you can make a pull request from the whole branch if you choose to do so, I'd appreciate that.
Merged 3D noise image feature as is, co-authored, thanks!
The issue will remain open until Godot provides necessary API for the noise, so this should probably go for 2.1 or so.