Advertisement

Fractal dimension

Started by March 29, 2021 01:10 AM
18 comments, last by taby 3 years, 9 months ago

JoeJ said:
Still excited to look some fractal videos on YT, though.

https://www.youtube.com/watch?v=l_h2VEaTBBI

Procedural you say? Imagine the cities, and alien worlds this thing could generate in the future.

Don't want to steal the post. Just dropping this here. Bye!

Wow, so that's what we get from ML + fractals. Interesting!

The problem with fractals is this:

NikiTo said:
Imagine the cities, and alien worlds this thing could generate in the future.

The imagination and the dream is big. There's kind of a promise, an expectation…

But it lacks art control. You can not build cities or anything specific you want with some math formulas. You can not change a certain spot - change one thing, and the whole thing changes. Usually in an unexpected way, and mostly the result looks shitty.

But maybe ML can do this… : )

Advertisement
I have this one printed by Shapeways!

Nice : ) How do you mesh those fractals?

Personally i tried it with voxelizing a mandelbulb, but for high quality i need multisampling, which is too expensive to make fractals a useful primitive for modeling.

It would work better for me if o had a signed distance function, but i don't know how to do that. IQ has a tutorial for 2D Mandelbrot on his page, but did not look into it and assume it's not that easy to figure out distance functions.

I use Marching Cubes to generate the meshes. The magnitude of the trajectories' end points are fed in as the values, and the isovalue is the threshold value (e..g, 4.0). Extremely straightforward once you've done it once or twice. I assume that Mandelbulb also has a threshold value?

use Marching Cubes to generate the meshes.

I do the same, basically. But to get a estimate of where inside a voxel the surface is, i either use density (in case of meshes where i preprocess a high res voxelization and making mips turns binary voxels into a density volume), or i use signed distance functions (boxes, spheres etc.).

To get a good scalar density, i need to multisample the fractals 4^3 times per voxel. If i do only once, i get aliasing exposing the global grid. I see such stairstepping artifacts in above screenshot, which is not acceptable to me. Would be fine only for a preview while editing.

Well, maybe i'll dive into distance functions sometime, but i'd also need to learn the other things fractal artists use, like domain warping trickery. But too much other things on my plate…

Fractal worlds would be awesome for games. Wonder why we still don't have that… (Beautiful Desolation had a bit of it, recently)

Advertisement

There is a solution to the aliasing problem, for fractals anyway. Here is the standard, aliased version, versus a better approximation:

I use a custom vertex interpolation function. No mesh smoothing was performed, nor needed.

Here is the linear vertex interpolation (from Paul Bourke's website):

vertex_3 marching_cubes::vertex_interp(const float isovalue, vertex_3 p1, vertex_3 p2, float valp1, float valp2)
{
	// Sort the vertices so that cracks don't mess up the water-tightness of the mesh.
	// Note: the cracks don't appear if you use doubles instead of floats.
	if (p2 < p1)
	{
		vertex_3 tempv = p2;
		p2 = p1;
		p1 = tempv;

		float tempf = valp2;
		valp2 = valp1;
		valp1 = tempf;
	}

	const float epsilon = 1e-10f;

	if(fabs(isovalue - valp1) < epsilon)
		return(p1);

	if(fabs(isovalue - valp2) < epsilon)
		return(p2);

	if(fabs(valp1 - valp2) < epsilon)
		return(p1);

	float mu = (isovalue - valp1) / (valp2 - valp1);

	return p1 + (p2 - p1)*mu;
}

Here is the alternative that makes for much better meshes:

vertex_3 quaternion_julia_set::vertex_interp_float(vertex_3 v0, vertex_3 v1, float val_v0, float val_v1)
{
	// Sort the vertices so that way the same two vertices will always produce the same result
	// regardless of the order in which they were passed into the function.
	//
	// This may seem unnecessary, but adding two floats can produce different results depending
	// on their order, if the very rightmost decimal places are in use.
	if(v0 > v1)
	{
		vertex_3 temp(v0);
		float temp_val = val_v0;

		v0 = v1;
		val_v0 = val_v1;

		v1 = temp;
		val_v1 = temp_val;
	}

	// Start half-way between the vertices.
	vertex_3 result = (v0 + v1)*0.5f;

	// Refine the result, if need be.
	if(0 < vertex_refinement_steps)
	{
		vertex_3 forward, backward;

		// If p1 is outside of the surface and p2 is inside of the surface ...
		if(val_v0 > val_v1)
		{
			forward = v0;
			backward = v1;
		}
		else
		{
			forward = v1;
			backward = v0;
		}

		for(size_t i = 0; i < vertex_refinement_steps; i++)
		{
			// If point is in the quaternion Julia set, then move forward by 1/2 of a step, else move backward by 1/2 of a step ...
			if(threshold > eqparser.iterate(quaternion(result.x, result.y, result.z, z_w), max_iterations, threshold))
			{
				backward = result;
				result += (forward - result)*0.5f;
			}
			else
			{
				forward = result;
				result += (backward - result)*0.5f;
			}
		}
	}

	return result;
}

 

 

Interesting idea, so you do some limited iterative search i guess, which is much cheaper than multi sampling the whole cell.
I could do this too, will remember it…

Though, having distance allows blending of geometry, which is really a great feature to have. This picture for example:

… is made from just SDF cubes with soft blending. Not perfect yet because cubes still ‘poke through’, but i have some idea to replace cubes with a ‘Shapel’ primitive, which can model local curvature from parabolic functions…

This opens up some kind of ‘modeling with particles’, which seems something new and promising. Can be easily mixed with procedural generation and simulation, like i did here to get cracks in a rock.

That’s super cool.

This topic is closed to new replies.

Advertisement