Files
academy2/modules/world/world_terrain_lod.cpp
2021-07-31 03:37:28 +03:00

179 lines
5.2 KiB
C++

#include <core/hash_map.h>
#include <core/math/vector3.h>
#include <scene/resources/packed_scene.h>
#include <scene/resources/primitive_meshes.h>
#include <scene/3d/mesh_instance.h>
#include "direct_lod_multimesh.h"
#include "world_chunk.h"
#include "terrain_object.h"
#include "world_terrain_lod.h"
void WorldTerrainLod::init_lod(int mind, int maxd,
float density_range)
{
int i;
min_dist = mind;
max_dist = maxd;
this->density_range = density_range;
}
void WorldTerrainLod::update()
{
}
void WorldTerrainLod::create_chunk(const WorldChunk *chunk, const List<TerrainObject> &obj_list)
{
int i, j, id;
if (mesh_h.has(chunk->get_loc()))
return;
int lod_offset = 1 << chunk->get_lod();
int obj_count = obj_list.size();
printf("create_chunk started %d\n", obj_count);
LodMultiMesh3D *mi = memnew(LodMultiMesh3D);
id = 0;
int rcount = chunk->get_transforms_count() / lod_offset;
const Transform *xfptr = chunk->get_transforms();
const float *variances = chunk->get_variance();
Vector<int> ids;
ids.resize(rcount);
printf("ids size: %d rcount: %d\n", ids.size(), rcount);
HashMap<int, List<Transform> > instances;
for (j = 0; j < rcount; j++) {
float variance = variances[j * lod_offset];
int obj_id = (int)(variance * obj_count);
printf("3 %d %d", j, rcount);
ids.write[j] = obj_id;
if (!instances.has(obj_id))
instances[obj_id] = List<Transform>();
instances[obj_id].push_back(xfptr[j * lod_offset]);
printf("6");
}
const List<TerrainObject>::Element *e = obj_list.front();
int count = 0;
while (e) {
printf("obj: %d\n", count);
const TerrainObject *obj = &e->get();
if (!instances.has(count))
instances[count] = List<Transform>();
Ref<Mesh> mesh = obj->get_mesh(chunk->get_lod());
printf("lod: %d mesh: %p, instance count: %d\n", chunk->get_lod(), mesh.ptr(), instances[count].size());
mi->add_mesh(obj->get_mesh(chunk->get_lod()));
mi->set_instance_count(count, instances[count].size());
const List<Transform>::Element *ep = instances[count].front();
int pcount = 0;
while (ep) {
const Transform &pxform = ep->get();
printf("ep %d %d %ls\n", count, pcount, String(pxform.origin).c_str());
mi->set_instance_transform(count, pcount++, pxform);
ep = ep->next();
}
e = e->next();
count++;
}
#if 0
for (j = 0; j < mesh_grass.size(); j++) {
if (!new_points[*org].has(j))
continue;
const List<struct new_point> &nps = new_points[*org][j];
mi->add_mesh(mesh_grass[j]);
mi->set_instance_count(id, nps.size());
const List<struct new_point>::Element *e = nps.front();
int icount = 0;
while(e) {
mi->set_instance_transform(id, icount++, e->get().xform);
e = e->next();
}
id++;
}
#endif
mi->hide();
mi->set_world(NULL);
mi->set_global_transform(Transform(Basis(), chunk->get_loc().to_vec3()));
meshes.push_back(mi);
mesh_h[chunk->get_loc()] = mi;
mi->set_world(gworld.ptr());
mi->show();
}
void WorldTerrainLod::cleanup(const Transform &vxform)
{
if (meshes.size() > 0)
printf("meshes.size() %p %d\n", this, meshes.size());
List<LodMultiMesh3D *>::Element *e = meshes.front();
while(e) {
LodMultiMesh3D *ve = e->get();
List<LodMultiMesh3D *>::Element *ne = e->next();
Vector3 rpos = ve->get_center();
Vector3 vpos = vxform.origin;
Vector3i loc(ve->get_global_transform().origin);
if (!valid_org(vxform, ve->get_global_transform().origin, 0.5f)) {
memfree(ve);
meshes.erase(e);
mesh_h.erase(loc);
}
e = ne;
}
}
static inline bool too_close(const Transform &vxform, const Vector3 &org, float zmin)
{
Vector3 lpoint = vxform.xform_inv(org);
if (-lpoint.z < zmin)
return true;
return false;
}
bool WorldTerrainLod::valid_org(const Transform &vxform, const Vector3 &org, float margin) const
{
bool ret = true;
float view_angle = M_PI / 3.0f;
float view_s = Math::sin(view_angle);
if (too_close(vxform, org, min_dist))
return false;
// if (vxform.origin.distance_squared_to(org) > max_dist * max_dist)
// return false;
//if (min_dist > 0 && vxform.origin.distance_squared_to(org) < min_dist * min_dist)
// return false;
Vector3 lpoint = vxform.xform_inv(org);
/* View is in -Z direction */
if (lpoint.z > -min_dist + margin || lpoint.z < -max_dist - margin)
ret = false;
if (lpoint.x < -view_s * max_dist -8.0f - margin|| lpoint.x > view_s * max_dist + 8.0f + margin)
ret = false;
if (lpoint.y < -36.0f || lpoint.y > 36.0f)
ret = false;
return ret;
}
void WorldTerrainLod::update_visibility(const Transform &vxform)
{
List<LodMultiMesh3D *>::Element *e = meshes.front();
while(e) {
LodMultiMesh3D *mi = e->get();
Transform xform = mi->get_global_transform();
// Vector3 lpoint = vxform.xform_inv(xform.origin);
if (mi->is_visible() && !valid_org(vxform, xform.origin, 1.0f)) {
mi->hide();
mi->set_world(NULL);
} else if (!mi->is_visible() && valid_org(vxform, xform.origin, 0.0f)) {
mi->show();
mi->set_world(gworld.ptr());
}
e = e->next();
}
}
void WorldTerrainLod::set_world(Ref<World> world)
{
if (!world.ptr())
printf("exited world %p\n", gworld.ptr());
gworld = world;
List<LodMultiMesh3D *>::Element *e = meshes.front();
while(e) {
LodMultiMesh3D *mi = e->get();
mi->set_world(gworld.ptr());
e = e->next();
}
if (gworld.ptr())
printf("entered world %p\n", gworld.ptr());
}