mirror of
https://github.com/panda3d/panda3d.git
synced 2025-09-30 08:44:19 -04:00
add_random_instances(), get_slope()
This commit is contained in:
parent
593393dd64
commit
1c8d2859f1
@ -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)
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user