add_random_instances(), get_slope()

This commit is contained in:
David Rose 2010-10-14 21:12:54 +00:00
parent 593393dd64
commit 1c8d2859f1
10 changed files with 253 additions and 33 deletions

View File

@ -95,11 +95,13 @@ ConfigVariableBool speedtree_transmission_lighting
ConfigVariableBool speedtree_detail_layer
("speedtree-detail-layer", false,
PRC_DESC("Undocumented SpeedTree parameter."));
PRC_DESC("True to render the detail texture layer defined on tree and "
"terrain objects, false otherwise."));
ConfigVariableBool speedtree_detail_normal_mapping
("speedtree-detail-normal-mapping", false,
PRC_DESC("True to enable normal maps in SpeedTree."));
PRC_DESC("True to render the detail normal maps defined on tree and "
"terrain objects, false otherwise."));
ConfigVariableBool speedtree_ambient_contrast
("speedtree-ambient-contrast", false,
@ -109,13 +111,10 @@ ConfigVariableDouble speedtree_transmission_scalar
("speedtree-transmission-scalar", 1.0f,
PRC_DESC("Undocumented SpeedTree parameter."));
ConfigVariableDouble speedtree_fog_start_distance
("speedtree-fog-start-distance", 2500.0,
PRC_DESC("Specifies the nearest distance at which fog begins to be visible."));
ConfigVariableDouble speedtree_fog_end_distance
("speedtree-fog-end-distance", 5000.0,
PRC_DESC("Specifies the distance at and beyond which fog is complete."));
ConfigVariableDouble speedtree_fog_distance
("speedtree-fog-distance", "2500 5000",
PRC_DESC("Specifies the nearest and farthest distance of the fog on trees "
"and terrain."));
ConfigVariableDouble speedtree_fog_color
("speedtree-fog-color", "1.0 1.0 1.0",
@ -126,13 +125,9 @@ ConfigVariableDouble speedtree_sky_color
PRC_DESC("Specifies the r g b color of the SpeedTree sky, when the sky "
"is enabled. Currently unused."));
ConfigVariableDouble speedtree_sky_fog_min
("speedtree-sky-fog-min", -0.5,
PRC_DESC("Undocumented SpeedTree parameter."));
ConfigVariableDouble speedtree_sky_fog_max
("speedtree-sky-fog-max", 1.0,
PRC_DESC("Undocumented SpeedTree parameter."));
ConfigVariableDouble speedtree_sky_fog
("speedtree-sky-fog", "-0.5 1.0",
PRC_DESC("Specifies the range of fog in the sky. -1 is down, 1 is up."));
ConfigVariableDouble speedtree_sun_color
("speedtree-sun-color", "1.0 1.0 0.85",
@ -239,6 +234,20 @@ ConfigVariableDouble speedtree_area_scale
"scales from kilometers to feet. You should set a different "
"scale if you use units other than feet."));
ConfigVariableBool speedtree_follow_terrain
("speedtree-follow-terrain", true,
PRC_DESC("Set this true to have trees automatically snap to the terrain "
"height when loaded into a SpeedTree node with a configured "
"terrain. If this is false, you may still call "
"SpeedTreeNode::snap_to_terrain() afterwards."));
ConfigVariableInt speedtree_max_random_try_count
("speedtree-max-random-try-count", 1000,
PRC_DESC("This is a cheesy limit to detect bad parameters passed to "
"SpeedTreeNode::add_random_instances(). If this number of attempts "
"to find a legal place for a tree fail in a row, the parameters "
"are deemed to be in error, and the function fails."));
ConfigVariableBool speedtree_5_2_stf
("speedtree-5-2-stf",
#if SPEEDTREE_VERSION_MAJOR > 5 || (SPEEDTREE_VERSION_MAJOR == 5 && SPEEDTREE_VERSION_MINOR >= 2)

View File

@ -42,8 +42,7 @@ extern ConfigVariableBool speedtree_detail_layer;
extern ConfigVariableBool speedtree_detail_normal_mapping;
extern ConfigVariableBool speedtree_ambient_contrast;
extern ConfigVariableDouble speedtree_transmission_scalar;
extern ConfigVariableDouble speedtree_fog_start_distance;
extern ConfigVariableDouble speedtree_fog_end_distance;
extern ConfigVariableDouble speedtree_fog_distance;
extern ConfigVariableDouble speedtree_fog_color;
extern ConfigVariableDouble speedtree_sky_color;
extern ConfigVariableDouble speedtree_sky_fog_min;
@ -70,6 +69,8 @@ extern ConfigVariableBool speedtree_show_overlays;
extern ConfigVariableInt speedtree_max_num_visible_cells;
extern ConfigVariableDouble speedtree_cull_cell_size;
extern ConfigVariableDouble speedtree_area_scale;
extern ConfigVariableBool speedtree_follow_terrain;
extern ConfigVariableInt speedtree_max_random_try_count;
extern ConfigVariableBool speedtree_5_2_stf;
extern EXPCL_PANDASPEEDTREE void init_libspeedtree();

View File

@ -291,7 +291,13 @@ modify_instance_list(const STTree *tree) {
////////////////////////////////////////////////////////////////////
void SpeedTreeNode::
add_instance(const STTree *tree, const STTransform &transform) {
add_tree(tree).add_instance(transform);
if (speedtree_follow_terrain && has_terrain()) {
STTransform new_transform = transform;
new_transform._pos[2] = _terrain->get_height(new_transform._pos[0], new_transform._pos[1]);
add_tree(tree).add_instance(new_transform);
} else {
add_tree(tree).add_instance(transform);
}
}
////////////////////////////////////////////////////////////////////
@ -353,11 +359,71 @@ add_instances_from(const SpeedTreeNode *other, const TransformState *transform)
for (int i = 0; i < num_instances; ++i) {
CPT(TransformState) other_trans = other_instance_list.get_instance(i);
CPT(TransformState) new_trans = transform->compose(other_trans);
this_instance_list.add_instance(new_trans.p());
if (speedtree_follow_terrain && has_terrain()) {
STTransform new_transform = new_trans;
new_transform._pos[2] = _terrain->get_height(new_transform._pos[0], new_transform._pos[1]);
this_instance_list.add_instance(new_transform);
} else {
this_instance_list.add_instance(new_trans.p());
}
}
}
}
////////////////////////////////////////////////////////////////////
// Function: SpeedTreeNode::add_random_instances
// Access: Published
// Description: Creates a number of random instances of the indicated
// true, within the indicated range. If a terrain is
// present, height_min and height_max restrict trees to
// the (x, y) positions that fall within the indicated
// terrain, and slope_min and slope_max restrict trees
// to the (x, y) positions that have a matching slope.
// If a terrain is not present, height_min and
// height_max specify a random range of Z heights, and
// slope_min and slope_max are ignored.
////////////////////////////////////////////////////////////////////
void SpeedTreeNode::
add_random_instances(const STTree *tree, int quantity,
float x_min, float x_max,
float y_min, float y_max,
float scale_min, float scale_max,
float height_min, float height_max,
float slope_min, float slope_max,
Randomizer &randomizer) {
InstanceList &instance_list = add_tree(tree);
_needs_repopulate = true;
for (int i = 0; i < quantity; ++i) {
STTransform transform;
transform._pos[0] = randomizer.random_real(x_max - x_min) + x_min;
transform._pos[1] = randomizer.random_real(y_max - y_min) + y_min;
transform._rotate = randomizer.random_real(360.0);
transform._scale = randomizer.random_real(scale_max - scale_min) + scale_min;
if (has_terrain()) {
// Spin till we find a valid match with terrain.
int repeat_count = speedtree_max_random_try_count;
while (!_terrain->placement_is_acceptable(transform._pos[0], transform._pos[1], height_min, height_max, slope_min, slope_max)) {
transform._pos[0] = randomizer.random_real(x_max - x_min) + x_min;
transform._pos[1] = randomizer.random_real(y_max - y_min) + y_min;
if (--repeat_count == 0) {
nassert_raise("Exceeded speedtree-max-random-try-count; bad placement parameters?");
return;
}
}
transform._pos[2] = _terrain->get_height(transform._pos[0], transform._pos[1]);
} else {
// No terrain; just pick a random height.
transform._pos[2] = randomizer.random_real(height_max - height_min) + height_min;
}
instance_list.add_instance(transform);
}
}
////////////////////////////////////////////////////////////////////
// Function: SpeedTreeNode::add_from_stf
// Access: Published
@ -472,8 +538,8 @@ add_from_stf(istream &in, const Filename &pathname,
if (!speedtree_5_2_stf) {
// 5.1 or earlier stf files also included these additional
// values, which we will ignore:
float elev_min, elev_max, slope_min, slope_max;
in >> elev_min >> elev_max >> slope_min >> slope_max;
float height_min, height_max, slope_min, slope_max;
in >> height_min >> height_max >> slope_min >> slope_max;
}
if (tree != NULL) {
@ -576,6 +642,10 @@ set_terrain(STTerrain *terrain) {
_terrain_render.SetRenderInfo(trender_info);
_terrain_render.SetHeightHints(terrain->get_min_height(), terrain->get_max_height());
if (speedtree_follow_terrain) {
snap_to_terrain();
}
}
////////////////////////////////////////////////////////////////////
@ -655,12 +725,12 @@ reload_config() {
render_info.m_bDetailNormalMapping = speedtree_detail_normal_mapping;
render_info.m_bAmbientContrast = speedtree_ambient_contrast;
render_info.m_fTransmissionScalar = speedtree_transmission_scalar;
render_info.m_fFogStartDistance = speedtree_fog_start_distance;
render_info.m_fFogEndDistance = speedtree_fog_end_distance;
render_info.m_fFogStartDistance = speedtree_fog_distance[0];
render_info.m_fFogEndDistance = speedtree_fog_distance[1];
render_info.m_vFogColor = SpeedTree::Vec3(speedtree_fog_color[0], speedtree_fog_color[1], speedtree_fog_color[2]);
render_info.m_vSkyColor = SpeedTree::Vec3(speedtree_sky_color[0], speedtree_sky_color[1], speedtree_sky_color[2]);
render_info.m_fSkyFogMin = speedtree_sky_fog_min;
render_info.m_fSkyFogMax = speedtree_sky_fog_max;
render_info.m_fSkyFogMin = speedtree_sky_fog[0];
render_info.m_fSkyFogMax = speedtree_sky_fog[1];
render_info.m_vSunColor = SpeedTree::Vec3(speedtree_sun_color[0], speedtree_sun_color[1], speedtree_sun_color[2]);
render_info.m_fSunSize = speedtree_sun_size;
render_info.m_fSunSpreadExponent = speedtree_sun_spread_exponent;
@ -1445,9 +1515,9 @@ draw_callback(CallbackData *data) {
PStatTimer timer1(_draw_speedtree_trees_pcollector);
// SpeedTree::ETextureAlphaRenderMode mode = SpeedTree::TRANS_TEXTURE_ALPHA_TESTING;
// SpeedTree::ETextureAlphaRenderMode mode = SpeedTree::TRANS_TEXTURE_ALPHA_TO_COVERAGE;
// SpeedTree::ETextureAlphaRenderMode mode = SpeedTree::TRANS_TEXTURE_BLENDING;
SpeedTree::ETextureAlphaRenderMode mode = SpeedTree::TRANS_TEXTURE_NOTHING;
SpeedTree::ETextureAlphaRenderMode mode = SpeedTree::TRANS_TEXTURE_ALPHA_TO_COVERAGE;
//SpeedTree::ETextureAlphaRenderMode mode = SpeedTree::TRANS_TEXTURE_BLENDING;
//SpeedTree::ETextureAlphaRenderMode mode = SpeedTree::TRANS_TEXTURE_NOTHING;
set_transparent_texture_mode(SpeedTree::ETextureAlphaRenderMode(mode));
bool branches = _forest_render.RenderBranches(_visible_trees, SpeedTree::RENDER_PASS_STANDARD);

View File

@ -26,6 +26,7 @@
#include "transformState.h"
#include "nodePath.h"
#include "pStatCollector.h"
#include "randomizer.h"
#include "speedtree_api.h"
class Loader;
@ -115,6 +116,14 @@ PUBLISHED:
void add_instances(const NodePath &root, const TransformState *transform = TransformState::make_identity());
void add_instances_from(const SpeedTreeNode *other);
void add_instances_from(const SpeedTreeNode *other, const TransformState *transform);
void add_random_instances(const STTree *tree, int quantity,
float x_min, float x_max,
float y_min, float y_max,
float scale_min, float scale_max,
float height_min, float height_max,
float slope_min, float slope_max,
Randomizer &randomizer = Randomizer());
bool add_from_stf(const Filename &stf_filename,
const LoaderOptions &options = LoaderOptions());
bool add_from_stf(istream &in, const Filename &pathname,

View File

@ -51,6 +51,17 @@ get_size() const {
return _size;
}
////////////////////////////////////////////////////////////////////
// Function: STBasicTerrain::interpolate
// Access: Protected, Static
// Description: Convenience function to calculate the linear
// interpolation from A to B.
////////////////////////////////////////////////////////////////////
INLINE float STBasicTerrain::
interpolate(float a, float b, float t) {
return (a + (b - a) * t);
}
////////////////////////////////////////////////////////////////////
// Function: STBasicTerrain::InterpolationData::Constructor
// Access: Public
@ -103,8 +114,6 @@ ValueType STBasicTerrain::InterpolationData<ValueType>::
calc_bilinear_interpolation(float u, float v) const {
u -= cfloor(u);
v -= cfloor(v);
nassertr((u >= 0.0f) && (u < 1.0f) &&
(v >= 0.0f) && (v < 1.0f), 0);
u *= (float)_width;
v *= (float)_height;

View File

@ -297,7 +297,7 @@ get_smooth_height(float x, float y, float radius) const {
////////////////////////////////////////////////////////////////////
float STBasicTerrain::
get_slope(float x, float y) const {
return 0.0f;
return _slope_data.calc_bilinear_interpolation(x / _size, y / _size);
}
////////////////////////////////////////////////////////////////////
@ -394,10 +394,102 @@ read_height_map() {
_max_height = max(_max_height, v);
}
}
compute_slope(0.5f);
return true;
}
////////////////////////////////////////////////////////////////////
// Function: STBasicTerrain::compute_slope
// Access: Protected
// Description: Once _height_data has been filled in, compute the
// corresponding values for _slope_data.
////////////////////////////////////////////////////////////////////
void STBasicTerrain::
compute_slope(float smoothing) {
nassertv(!_height_data._data.empty());
int width = _height_data._width;
int height = _height_data._height;
_slope_data.reset(width, height);
float u_spacing = _size / (float)width;
float v_spacing = _size / (float)height;
for (int i = 0; i < width; ++i) {
int left = (i + width - 1) % width;
int right = (i + 1) % width;
for (int j = 0; j < height; ++j) {
int top = (j + height - 1) % height;
int bottom = (j + 1) % height;
float slope = 0.0f;
float this_height = _height_data._data[i + j * width];
slope += catan2(cabs(this_height - _height_data._data[right + j * width]), u_spacing);
slope += catan2(cabs(this_height - _height_data._data[left + j * width]), u_spacing);
slope += catan2(cabs(this_height - _height_data._data[i + top * width]), v_spacing);
slope += catan2(cabs(this_height - _height_data._data[i + bottom * width]), v_spacing);
slope *= (0.5f / MathNumbers::pi_f);
if (slope > 1.0f) {
slope = 1.0f;
}
_slope_data._data[i + j * width] = slope;
}
}
if (smoothing > 0.0f) {
// Create a temporary array for smoothing data.
InterpolationData<float> smoothing_data;
smoothing_data.reset(width, height);
float *smoothed = &smoothing_data._data[0];
int steps = int(smoothing);
float last_interpolation = smoothing - steps;
++steps;
for (int si = 0; si < steps; ++si) {
// compute smoothed normals
for (int i = 0; i < width; ++i) {
int left = (i + width - 1) % width;
int right = (i + 1) % width;
for (int j = 0; j < height; ++j) {
int top = (j + height - 1) % height;
int bottom = (j + 1) % height;
smoothed[i + j * width] = (_slope_data._data[right + j * width] +
_slope_data._data[left + j * width] +
_slope_data._data[i + top * width] +
_slope_data._data[i + bottom * width] +
_slope_data._data[right + top * width] +
_slope_data._data[right + bottom * width] +
_slope_data._data[left + top * width] +
_slope_data._data[left + bottom * width]);
smoothed[i + j * width] *= 0.125f;
}
}
// interpolate or set
if (si == steps - 1) {
// last step, interpolate
for (int i = 0; i < width; ++i) {
for (int j = 0; j < height; ++j) {
_slope_data._data[i + j * width] = interpolate(_slope_data._data[i + j * width], smoothed[i + j * width], last_interpolation);
}
}
} else {
// full smoothing step, copy everything
_slope_data = smoothing_data;
}
}
}
}
////////////////////////////////////////////////////////////////////
// Function: STBasicTerrain::read_quoted_filename
// Access: Private, Static

View File

@ -57,6 +57,9 @@ PUBLISHED:
protected:
bool read_height_map();
void compute_slope(float smoothing);
INLINE float interpolate(float a, float b, float t);
private:
static void read_quoted_filename(Filename &result, istream &in,

View File

@ -129,6 +129,29 @@ get_slope(float x, float y) const {
return 0.0f;
}
////////////////////////////////////////////////////////////////////
// Function: STTerrain::placement_is_acceptable
// Access: Published
// Description: Returns true if the elevation and slope of point (x,
// y) fall within the requested limits, false otherwise.
////////////////////////////////////////////////////////////////////
bool STTerrain::
placement_is_acceptable(float x, float y,
float height_min, float height_max,
float slope_min, float slope_max) {
float height = get_height(x, y);
if (height < height_min || height > height_max) {
return false;
}
float slope = get_slope(x, y);
if (slope < slope_min || slope > slope_max) {
return false;
}
return true;
}
////////////////////////////////////////////////////////////////////
// Function: STTerrain::fill_vertices
// Access: Published, Virtual

View File

@ -65,6 +65,10 @@ PUBLISHED:
virtual float get_smooth_height(float x, float y, float radius) const;
virtual float get_slope(float x, float y) const;
bool placement_is_acceptable(float x, float y,
float height_min, float height_max,
float slope_min, float slope_max);
virtual void fill_vertices(GeomVertexData *data,
float start_x, float start_y,
float size_xy, int num_xy) const;

View File

@ -59,7 +59,7 @@ public:
void write_datagram(BamWriter *manager, Datagram &dg);
void fillin(DatagramIterator &scan, BamReader *manager);
private:
public:
LPoint3f _pos;
float _rotate;
float _scale;