Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import godot;
- import godot.core;
- import godot.object;
- import godot.node.all;
- import godot.progressbar;
- import godot.arraymesh;
- import godot.multimesh;
- import godot.mesh;
- import godot.meshdatatool;
- import godot.input;
- import godot.inputevent.all;
- import godot.resourceloader;
- import godot.packedscene;
- import godot.visualscriptyield;
- import std.random;
- import std.math;
- import array = std.container.array;
- import std.stdio;
- mixin GodotNativeLibrary!(
- "planetgenerator",
- Planetgenerator
- );
- class Planetgenerator : GodotScript!WorldEnvironment
- {
- alias owner this;
- typeof(Random(unpredictableSeed)) rnd;
- @OnReady!(gs!"container/progress") ProgressBar progress;
- @OnReady!(gs!"planet/Planet") MeshInstance planet;
- MeshInstance mesh_original;
- @Method _ready()
- {
- rnd = Random(unpredictableSeed);
- mesh_original = MeshInstance._new();
- mesh_original.mesh = planet.mesh;
- Input.setMouseMode(Input.MouseMode.mouseModeHidden);
- makePlanet();
- }
- @Method _input(InputEvent event)
- {
- if(event.isActionPressed(gs!"ui_accept"))
- {
- if(!progress.visible)
- makePlanet();
- }
- }
- @Method makePlanet()
- {
- Ref!MeshDataTool surf = MeshDataTool._new();
- surf.createFromSurface(mesh_original.mesh.as!ArrayMesh, 0L);
- // the tree (pos, normal) pairs
- array.Array!PosNormal tree_pairs;
- // show the progress bar
- progress.show();
- enum max_iterations = 145;
- //writeln("surf.getVertexCount ", surf.getVertexCount);
- foreach(j; 0..max_iterations)
- {
- // wait a frame to prevent freezing the game
- //yield(get_tree(), "idle_frame")
- //auto vsy = VisualScriptYield._new();
- // show progress in the progress bar
- progress.maxValue = max_iterations;
- progress.value = j;
- immutable dir = Vector3(
- uniform!"[]"(-1.0f, 1.0f, rnd),
- uniform!"[]"(-1.0f, 1.0f, rnd),
- uniform!"[]"(-1.0f, 1.0f, rnd)
- ).normalized();
- // push/pull all vertices (this is the slow part)
- foreach(i; 0..surf.getVertexCount)
- {
- Vector3 v = surf.getVertex(i);
- Vector3 norm = surf.getVertexNormal(i);
- float dot = norm.normalized().dot(dir);
- enum sharpness = 50; // how sharp the edges are
- dot = exp(dot*sharpness) / (exp(dot*sharpness) + 1.0) - 0.5; // sigmoid function
- v += dot * norm * 0.01;
- surf.setVertex(i, v);
- }
- }
- enum min_dist = 0.9; // deep sea
- enum max_dist = 1.1; // mountains
- enum vegetation_dist = 1.03; // ideal height for vegetation to grow
- enum beach_dist = 1.0; // beach level
- // finally set uv.x according to distance to center, which colors the terrain depending on elevation
- foreach(i; 0..surf.getVertexCount)
- {
- auto v = surf.getVertex(i);
- auto dist = v.length;
- auto dist_normalized = (dist-min_dist) / (max_dist-min_dist); // bring dist to 0..1 range
- auto uv = Vector2(dist_normalized, 0.0);
- surf.setVertexUv(i, uv);
- }
- // also recalculate face normals (TODO smooth 'em!)
- foreach(i; 0..surf.getFaceCount)
- {
- long v1i = surf.getFaceVertex(i, 0);
- long v2i = surf.getFaceVertex(i, 1);
- long v3i = surf.getFaceVertex(i, 2);
- Vector3 v1 = surf.getVertex(v1i);
- Vector3 v2 = surf.getVertex(v2i);
- Vector3 v3 = surf.getVertex(v3i);
- // calculate normal for this face
- Vector3 norm = -(v2 - v1).normalized().cross((v3 - v1).normalized()).normalized();
- surf.setVertexNormal(v1i, norm);
- surf.setVertexNormal(v2i, norm);
- surf.setVertexNormal(v3i, norm);
- }
- // place trees
- foreach(i; 0..surf.getVertexCount)
- {
- Vector3 v = surf.getVertex(i);
- auto dist = v.length();
- Vector3 norm = surf.getVertexNormal(i);
- // place tree with chance depending on difference between ideal height and current vertex height
- auto chance = 1.0 / (1.0 + pow(fabs(dist - vegetation_dist) * 10.0, 2.0) * 10000.0);
- bool is_underwater = dist <= beach_dist;
- if (!is_underwater && uniform!"[]"(0.0f, 1.0f, rnd) < chance)
- tree_pairs.insertBack(PosNormal(v, norm));
- }
- // commit the mesh
- Ref!ArrayMesh mmesh = ArrayMesh._new();
- surf.commitToSurface(mmesh);
- getNode(gs!"planet/Planet").as!MeshInstance.mesh = mmesh;
- // -------- place trees in the scene -------------
- // get the tree mesh from tree.dae and intialize the multimesh, used for quickly drawing lots of trees
- //auto tree = ResourcePreloader().getResource(gs!"res://tree.dae").as!PackedScene.instance();
- Ref!PackedScene tree = ResourceLoader.load(gs!"res://tree.dae").as!PackedScene;
- MeshInstance tree_mesh = tree.instance.getNode(gs!"tree").as!MeshInstance;
- Ref!MultiMesh multimesh = getNode(gs!"planet/trees").as!MultiMeshInstance.multimesh;
- multimesh.mesh = tree_mesh.mesh;
- multimesh.instanceCount = tree_pairs.length;
- {
- size_t i = 0;
- foreach (immutable ref tree_pair; tree_pairs)
- {
- Vector3 pos = getNode(gs!"planet").as!Spatial.toGlobal(tree_pair.pos);
- // orient the tree to the face normal and randomly rotate it along the normal
- Vector3 y = tree_pair.normal;
- Vector3 x = tree_pair.normal.cross(Vector3(0.0, 1.0, 0.0)).normalized(); // NOTE this will go wrong if the normal is exactly (0, 1, 0)
- Vector3 z = x.cross(y).normalized();
- Basis basis = Basis(x, y, z).rotated(y, uniform!"[]"(0.0f, 2.0f*PI, rnd))
- .scaled(Vector3(1.0, 1.0, 1.0) * uniform!"[]"(0.01f, 0.03f, rnd) / 2.0); // scale the tree randomly
- // set the transform of the multimesh at this index
- multimesh.setInstanceTransform(i, Transform(basis, pos));
- ++i;
- }
- }
- // hide the progress bar
- progress.hide();
- }
- @Method _process(float delta)
- {
- // rotate cam
- getNode(gs!"cam_root").as!Spatial.rotateY(delta / 3.0);
- }
- }
- struct PosNormal
- {
- Vector3 pos;
- Vector3 normal;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement