Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Provide Texture and Texture3d resources #4

Open
fire opened this issue Oct 27, 2018 · 18 comments
Open

Provide Texture and Texture3d resources #4

fire opened this issue Oct 27, 2018 · 18 comments

Comments

@fire
Copy link
Contributor

fire commented Oct 27, 2018

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.

@Xrayez
Copy link
Owner

Xrayez commented Oct 27, 2018

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:

  1. AnlNoise and OpenSimplexNoise both have similar methods named map_to_image() and get_image().
  2. Both classes provide a way to retrieve noise at coordinates.

Some caveats:

  1. Seamless textures generated with OpenSimplexNoise only support square aspect textures, with AnlNoise one has ability to make textures seamless of any aspect, and restrict "seamlessness" to X/Y coordinates alone.
  2. OpenSimplexNoise can't generate seamless Texture3D because it requires to generate noise in 6D. AnlNoise has such methods like get_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.

@Xrayez
Copy link
Owner

Xrayez commented Oct 27, 2018

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.

@fire
Copy link
Contributor Author

fire commented Oct 27, 2018

As a expedient way of implementing this without a graph editor, one should be able to use the string based evaluator feature of anl.

@fire
Copy link
Contributor Author

fire commented Oct 27, 2018

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.

@Xrayez
Copy link
Owner

Xrayez commented Oct 27, 2018

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

fractal_512x512

I've followed underlying library's interface in order to be consistent with the source, not sure how it's actually implemented.

@fire
Copy link
Contributor Author

fire commented Oct 27, 2018

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.

@fire
Copy link
Contributor Author

fire commented Oct 27, 2018

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!

@Xrayez
Copy link
Owner

Xrayez commented Oct 27, 2018

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.

@fire
Copy link
Contributor Author

fire commented Oct 27, 2018

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.

godot windows tools 64_2018-10-27_14-26-51

Period 128:

godot windows tools 64_2018-10-27_14-27-35

	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);

@fire
Copy link
Contributor Author

fire commented Oct 28, 2018

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.

@fire
Copy link
Contributor Author

fire commented Oct 28, 2018

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.

@fire
Copy link
Contributor Author

fire commented Oct 28, 2018

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.

@Xrayez
Copy link
Owner

Xrayez commented Oct 28, 2018

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.

@fire
Copy link
Contributor Author

fire commented Oct 28, 2018

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.

@fire
Copy link
Contributor Author

fire commented Oct 28, 2018

Removed _generate_vbm function.

@Xrayez
Copy link
Owner

Xrayez commented Oct 28, 2018

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.

@Xrayez
Copy link
Owner

Xrayez commented Nov 17, 2018

@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:

godot-anl/noise.cpp

Lines 823 to 828 in 789934c

for(int i = 0; i < SIZE; ++i) {
w[i * 4 + 0] = (uint8_t)(src_data[i].r * 255);
w[i * 4 + 1] = (uint8_t)(src_data[i].g * 255);
w[i * 4 + 2] = (uint8_t)(src_data[i].b * 255);
w[i * 4 + 3] = (uint8_t)(src_data[i].a * 255);
}

3D:

godot-anl/noise.cpp

Lines 888 to 893 in 789934c

for(int dest = 0, src = SIZE * k; src < SIZE * (k + 1); dest += 4, ++src) { // TODO: optimize (like 2D)?
w[dest + 0] = (uint8_t)(src_data[src].r * 255);
w[dest + 1] = (uint8_t)(src_data[src].g * 255);
w[dest + 2] = (uint8_t)(src_data[src].b * 255);
w[dest + 3] = (uint8_t)(src_data[src].a * 255);
}

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.

@Xrayez
Copy link
Owner

Xrayez commented Nov 18, 2018

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.

@Xrayez Xrayez added this to the 2.1 milestone Nov 18, 2018
@Xrayez Xrayez removed this from the 2.1 milestone Sep 3, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants