2015-10-18 15:26:19 +00:00
|
|
|
#include "VegetationModelDefinition.h"
|
|
|
|
|
|
|
|
#include "VegetationDefinition.h"
|
|
|
|
#include "RandomGenerator.h"
|
|
|
|
#include "Matrix4.h"
|
|
|
|
#include "SurfaceMaterial.h"
|
2015-11-09 00:07:33 +00:00
|
|
|
#include "Color.h"
|
2015-10-18 15:26:19 +00:00
|
|
|
#include "PackStream.h"
|
|
|
|
|
2015-11-09 21:38:00 +00:00
|
|
|
VegetationModelDefinition::VegetationModelDefinition(DefinitionNode *parent) : DefinitionNode(parent, "model") {
|
2015-11-09 00:07:33 +00:00
|
|
|
solid_material = new SurfaceMaterial(Color(0.2, 0.15, 0.15));
|
|
|
|
solid_material->reflection = 0.002;
|
|
|
|
solid_material->shininess = 2.0;
|
|
|
|
solid_material->hardness = 0.3;
|
|
|
|
solid_material->validate();
|
|
|
|
|
|
|
|
foliage_material = new SurfaceMaterial(Color(0.4, 0.8, 0.45));
|
|
|
|
foliage_material->reflection = 0.007;
|
|
|
|
foliage_material->shininess = 12.0;
|
|
|
|
foliage_material->hardness = 0.2;
|
|
|
|
foliage_material->validate();
|
2015-10-18 15:26:19 +00:00
|
|
|
|
|
|
|
randomize();
|
|
|
|
}
|
|
|
|
|
2015-11-09 21:38:00 +00:00
|
|
|
VegetationModelDefinition::~VegetationModelDefinition() {
|
2015-10-18 15:26:19 +00:00
|
|
|
delete solid_material;
|
|
|
|
delete foliage_material;
|
|
|
|
}
|
|
|
|
|
2015-11-09 21:38:00 +00:00
|
|
|
void VegetationModelDefinition::save(PackStream *stream) const {
|
2015-10-18 15:26:19 +00:00
|
|
|
int n;
|
|
|
|
solid_material->save(stream);
|
|
|
|
foliage_material->save(stream);
|
|
|
|
|
|
|
|
n = solid_volumes.size();
|
|
|
|
stream->write(&n);
|
2015-11-09 21:38:00 +00:00
|
|
|
for (const auto &solid_volume : solid_volumes) {
|
2015-10-18 15:26:19 +00:00
|
|
|
solid_volume.save(stream);
|
|
|
|
}
|
|
|
|
n = foliage_groups.size();
|
|
|
|
stream->write(&n);
|
2015-11-09 21:38:00 +00:00
|
|
|
for (const auto &foliage_group : foliage_groups) {
|
2015-10-18 15:26:19 +00:00
|
|
|
foliage_group.save(stream);
|
|
|
|
}
|
|
|
|
n = foliage_items.size();
|
|
|
|
stream->write(&n);
|
2015-11-09 21:38:00 +00:00
|
|
|
for (const auto &foliage_item : foliage_items) {
|
2015-10-18 15:26:19 +00:00
|
|
|
foliage_item.save(stream);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-09 21:38:00 +00:00
|
|
|
void VegetationModelDefinition::load(PackStream *stream) {
|
2015-10-18 15:26:19 +00:00
|
|
|
int i, n;
|
|
|
|
solid_material->load(stream);
|
|
|
|
foliage_material->load(stream);
|
|
|
|
|
|
|
|
stream->read(&n);
|
|
|
|
solid_volumes.clear();
|
2015-11-09 21:38:00 +00:00
|
|
|
for (i = 0; i < n; i++) {
|
2015-10-18 15:26:19 +00:00
|
|
|
CappedCylinder solid_volume;
|
|
|
|
solid_volume.load(stream);
|
|
|
|
solid_volumes.push_back(solid_volume);
|
|
|
|
}
|
|
|
|
stream->read(&n);
|
|
|
|
foliage_groups.clear();
|
2015-11-09 21:38:00 +00:00
|
|
|
for (i = 0; i < n; i++) {
|
2015-10-18 15:26:19 +00:00
|
|
|
Sphere foliage_group;
|
|
|
|
foliage_group.load(stream);
|
|
|
|
foliage_groups.push_back(foliage_group);
|
|
|
|
}
|
|
|
|
stream->read(&n);
|
|
|
|
foliage_items.clear();
|
2015-11-09 21:38:00 +00:00
|
|
|
for (i = 0; i < n; i++) {
|
2015-10-18 15:26:19 +00:00
|
|
|
Disk foliage_item;
|
|
|
|
foliage_item.load(stream);
|
|
|
|
foliage_items.push_back(foliage_item);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-09 21:38:00 +00:00
|
|
|
void VegetationModelDefinition::copy(DefinitionNode *destination_) const {
|
2015-10-18 15:26:19 +00:00
|
|
|
VegetationModelDefinition *destination = (VegetationModelDefinition *)destination_;
|
|
|
|
|
|
|
|
solid_material->copy(destination->solid_material);
|
|
|
|
foliage_material->copy(destination->foliage_material);
|
|
|
|
|
|
|
|
destination->solid_volumes.clear();
|
2015-11-09 21:38:00 +00:00
|
|
|
for (const auto &solid_volume : solid_volumes) {
|
2015-10-18 15:26:19 +00:00
|
|
|
destination->solid_volumes.push_back(CappedCylinder(solid_volume));
|
|
|
|
}
|
|
|
|
destination->foliage_groups.clear();
|
2015-11-09 21:38:00 +00:00
|
|
|
for (const auto &foliage_group : foliage_groups) {
|
2015-10-18 15:26:19 +00:00
|
|
|
destination->foliage_groups.push_back(Sphere(foliage_group));
|
|
|
|
}
|
|
|
|
destination->foliage_items.clear();
|
2015-11-09 21:38:00 +00:00
|
|
|
for (const auto &foliage_item : foliage_items) {
|
2015-10-18 15:26:19 +00:00
|
|
|
destination->foliage_items.push_back(Disk(foliage_item));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-09 21:38:00 +00:00
|
|
|
void VegetationModelDefinition::validate() {
|
2015-10-18 15:26:19 +00:00
|
|
|
}
|
|
|
|
|
2015-11-09 21:38:00 +00:00
|
|
|
static inline double randomizeValue(double base, double min_factor, double max_factor) {
|
2015-10-18 15:26:19 +00:00
|
|
|
return base * (min_factor + RandomGenerator::random() * (max_factor - min_factor));
|
|
|
|
}
|
|
|
|
|
2015-11-09 21:38:00 +00:00
|
|
|
static void addBranchRecurse(std::vector<CappedCylinder> &branches, const Vector3 &base, const Vector3 &direction,
|
|
|
|
double radius, double length) {
|
2015-10-18 15:26:19 +00:00
|
|
|
branches.push_back(CappedCylinder(base, direction, radius, length));
|
|
|
|
|
2015-11-09 21:38:00 +00:00
|
|
|
if (length > 0.1) {
|
2015-10-18 15:26:19 +00:00
|
|
|
int split_count = 3;
|
|
|
|
Matrix4 pivot1 = Matrix4::newRotateAxis(randomizeValue(1.0 - 0.6 * length, 0.9, 1.1), VECTOR_EAST);
|
|
|
|
Vector3 new_direction = pivot1.multPoint(direction);
|
2015-11-09 21:38:00 +00:00
|
|
|
for (int i = 0; i < split_count; i++) {
|
|
|
|
Matrix4 pivot2 =
|
|
|
|
Matrix4::newRotateAxis(randomizeValue(M_PI * 2.0 / (double)split_count, 0.9, 1.1), direction);
|
2015-10-18 15:26:19 +00:00
|
|
|
new_direction = pivot2.multPoint(new_direction);
|
|
|
|
|
2015-11-02 19:14:35 +00:00
|
|
|
Vector3 new_base = base.add(direction.scale(randomizeValue(length, 0.4, 1.0)));
|
2015-11-09 21:38:00 +00:00
|
|
|
if (new_base.add(new_direction).y > 0.1) {
|
|
|
|
addBranchRecurse(branches, new_base, new_direction, randomizeValue(radius, 0.45, 0.6),
|
|
|
|
randomizeValue(length, 0.55, 0.85));
|
2015-11-09 00:07:33 +00:00
|
|
|
}
|
2015-10-18 15:26:19 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-09 21:38:00 +00:00
|
|
|
void VegetationModelDefinition::randomize() {
|
2015-10-18 15:26:19 +00:00
|
|
|
// Clear structure
|
|
|
|
solid_volumes.clear();
|
|
|
|
foliage_groups.clear();
|
|
|
|
foliage_items.clear();
|
|
|
|
|
|
|
|
// Add trunk and branches
|
2015-11-09 21:38:00 +00:00
|
|
|
addBranchRecurse(solid_volumes, VECTOR_ZERO, VECTOR_UP, randomizeValue(0.05, 0.6, 1.0),
|
|
|
|
randomizeValue(0.5, 0.8, 1.0));
|
2015-10-18 15:26:19 +00:00
|
|
|
|
|
|
|
// Add foliage groups
|
2015-11-09 21:38:00 +00:00
|
|
|
for (const auto &branch : solid_volumes) {
|
2015-10-18 15:26:19 +00:00
|
|
|
double length = branch.getLength();
|
2015-11-09 21:38:00 +00:00
|
|
|
if (length < 0.2) {
|
2015-10-18 15:26:19 +00:00
|
|
|
double radius = length * 0.5;
|
|
|
|
Vector3 center = branch.getAxis().getOrigin().add(branch.getAxis().getDirection().scale(radius));
|
2015-11-02 19:14:35 +00:00
|
|
|
foliage_groups.push_back(Sphere(center, radius * 3.0));
|
2015-10-18 15:26:19 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add foliage items
|
2015-11-09 21:38:00 +00:00
|
|
|
for (int i = 0; i < 30; i++) {
|
2015-10-18 15:26:19 +00:00
|
|
|
double radius = 0.15;
|
2015-11-04 00:08:48 +00:00
|
|
|
double scale = randomizeValue(radius, 0.5, 1.0);
|
2015-10-18 15:26:19 +00:00
|
|
|
Vector3 dir = Vector3::randomInSphere(1.0 - radius);
|
2015-11-02 19:14:35 +00:00
|
|
|
Vector3 normal = dir.add(Vector3::randomInSphere(0.4)).add(Vector3(0.0, 0.3, 0.0)).normalize();
|
2015-11-04 00:08:48 +00:00
|
|
|
Disk leaf(dir, normal, scale);
|
2015-10-18 15:26:19 +00:00
|
|
|
foliage_items.push_back(leaf);
|
|
|
|
}
|
|
|
|
}
|