This commit is contained in:
David Rose 2010-10-13 23:08:57 +00:00
parent fa68ec6a52
commit 267114bd09
6 changed files with 371 additions and 135 deletions

View File

@ -151,16 +151,6 @@ ConfigVariableDouble speedtree_sun_fog_bloom
("speedtree-sun-fog-bloom", 0.0,
PRC_DESC("Undocumented SpeedTree parameter."));
ConfigVariableDouble speedtree_ambient_color
("speedtree-ambient-color", "1 1 1",
PRC_DESC("Specifies the r g b color of the ambient light on SpeedTree "
"surfaces."));
ConfigVariableDouble speedtree_diffuse_color
("speedtree-diffuse-color", "1 1 1",
PRC_DESC("Specifies the r g b color of the diffuse light on SpeedTree "
"surfaces."));
ConfigVariableDouble speedtree_specular_color
("speedtree-specular-color", "1 1 1",
PRC_DESC("Specifies the r g b color of the specular reflections on SpeedTree "
@ -171,16 +161,17 @@ ConfigVariableDouble speedtree_emissive_color
PRC_DESC("Specifies the r g b color of the emissive light effect on SpeedTree "
"surfaces."));
ConfigVariableInt speedtree_num_shadow_maps
("speedtree-num-shadow-maps", 3,
PRC_DESC("Specifies the number of shadow maps to use to render SpeedTree "
"shadows."));
ConfigVariableInt speedtree_shadow_map_resolution
("speedtree-shadow-map-resolution", 0, //1024,
PRC_DESC("Specifies the resolution for rendering shadow maps. Should "
"be a power of 2. Specify 0 to disable shadowing in SpeedTree. "
"Currently unsupported."));
"be a power of 2. Specify 0 to disable shadowing in SpeedTree."));
ConfigVariableDouble speedtree_cascading_shadow_splits
("speedtree-cascading-shadow-splits", "200 400 600",
PRC_DESC("Specifies the shadow split distance, in spatial units, for "
"each of shadow map to be rendered. The number of values also "
"implies the number of shadow maps, to a maximum value compiled "
"within SpeedTree (typically 4)."));
ConfigVariableBool speedtree_smooth_shadows
("speedtree-smooth-shadows", false,
@ -198,6 +189,11 @@ ConfigVariableBool speedtree_frond_rippling
("speedtree-frond-rippling", true,
PRC_DESC("True to allow fronds to respond to the global wind."));
ConfigVariableBool speedtree_show_overlays
("speedtree-show-overlays", false,
PRC_DESC("True to draw onscreen overlays showing the generated "
"shadow map(s)."));
ConfigVariableInt speedtree_max_num_visible_cells
("speedtree-max-num-visible-cells", 75,
PRC_DESC("Specifies the maximum number of cells in a single SpeedTree forest "

View File

@ -52,17 +52,17 @@ extern ConfigVariableDouble speedtree_sun_color;
extern ConfigVariableDouble speedtree_sun_size;
extern ConfigVariableDouble speedtree_sun_spread_exponent;
extern ConfigVariableDouble speedtree_sun_fog_bloom;
extern ConfigVariableDouble speedtree_ambient_color;
extern ConfigVariableDouble speedtree_diffuse_color;
extern ConfigVariableDouble speedtree_specular_color;
extern ConfigVariableDouble speedtree_emissive_color;
extern ConfigVariableInt speedtree_num_shadow_maps;
extern ConfigVariableInt speedtree_shadow_map_resolution;
extern ConfigVariableDouble speedtree_cascading_shadow_splits;
extern ConfigVariableBool speedtree_smooth_shadows;
extern ConfigVariableBool speedtree_show_shadow_splits_on_terrain;
extern ConfigVariableBool speedtree_wind_enabled;
extern ConfigVariableBool speedtree_frond_rippling;
extern ConfigVariableBool speedtree_show_overlays;
extern ConfigVariableInt speedtree_max_num_visible_cells;
extern ConfigVariableDouble speedtree_cull_cell_size;
extern ConfigVariableBool speedtree_5_2_stf;

View File

@ -29,6 +29,7 @@
#include "textureAttrib.h"
#include "lightAttrib.h"
#include "directionalLight.h"
#include "ambientLight.h"
#include "loader.h"
#include "deg_2_rad.h"
#include "sceneGraphReducer.h"
@ -68,10 +69,7 @@ SpeedTreeNode(const string &name) :
//set_internal_bounds(new OmniBoundingVolume);
// set_internal_bounds(new BoundingSphere(LPoint3f::zero(), 10.0f));
// Intialize the render params.
SpeedTree::SForestRenderInfo render_info;
// First, get the shader directory.
// Intialize the render params. First, get the shader directory.
Filename shaders_dir = speedtree_shaders_dir;
// We expect the shader directory to contain at least this one token
@ -107,42 +105,12 @@ SpeedTreeNode(const string &name) :
}
#endif
SpeedTree::SForestRenderInfo render_info;
render_info.m_strShaderPath = _os_shaders_dir.c_str();
render_info.m_nMaxAnisotropy = speedtree_max_anisotropy;
render_info.m_bHorizontalBillboards = speedtree_horizontal_billboards;
render_info.m_fAlphaTestScalar = speedtree_alpha_test_scalar;
render_info.m_bZPrePass = speedtree_z_pre_pass;
render_info.m_nMaxBillboardImagesByBase = speedtree_max_billboard_images_by_base;
render_info.m_fVisibility = speedtree_visibility;
render_info.m_fGlobalLightScalar = speedtree_global_light_scalar;
render_info.m_sLightMaterial.m_vAmbient = SpeedTree::Vec4(speedtree_ambient_color[0], speedtree_ambient_color[1], speedtree_ambient_color[2], 1.0f);
render_info.m_sLightMaterial.m_vDiffuse = SpeedTree::Vec4(speedtree_diffuse_color[0], speedtree_diffuse_color[1], speedtree_diffuse_color[2], 1.0f);
render_info.m_sLightMaterial.m_vSpecular = SpeedTree::Vec4(speedtree_specular_color[0], speedtree_specular_color[1], speedtree_specular_color[2], 1.0f);
render_info.m_sLightMaterial.m_vEmissive = SpeedTree::Vec4(speedtree_emissive_color[0], speedtree_emissive_color[1], speedtree_emissive_color[2], 1.0f);
render_info.m_bSpecularLighting = speedtree_specular_lighting;
render_info.m_bTransmissionLighting = speedtree_transmission_lighting;
render_info.m_bDetailLayer = speedtree_detail_layer;
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_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_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;
render_info.m_fSunFogBloom = speedtree_sun_fog_bloom;
render_info.m_nNumShadowMaps = speedtree_num_shadow_maps;
render_info.m_nShadowMapResolution = speedtree_shadow_map_resolution;
render_info.m_bSmoothShadows = speedtree_smooth_shadows;
render_info.m_bShowShadowSplitsOnTerrain = speedtree_show_shadow_splits_on_terrain;
render_info.m_bWindEnabled = speedtree_wind_enabled;
render_info.m_bFrondRippling = speedtree_frond_rippling;
_forest_render.SetRenderInfo(render_info);
// Now apply the rest of the config settings.
reload_config();
}
////////////////////////////////////////////////////////////////////
@ -191,8 +159,7 @@ add_tree(const STTree *tree) {
if (!_forest_render.RegisterTree((SpeedTree::CTree *)tree->get_tree())) {
speedtree_cat.warning()
<< "Failed to register tree " << tree->get_fullpath() << "\n";
speedtree_cat.warning()
<< SpeedTree::CCore::GetError() << "\n";
write_error(speedtree_cat.warning());
}
}
@ -220,8 +187,7 @@ remove_tree(const STTree *tree) {
if (!_forest_render.UnregisterTree(tree->get_tree())) {
speedtree_cat.warning()
<< "Failed to unregister tree " << tree->get_fullpath() << "\n";
speedtree_cat.warning()
<< SpeedTree::CCore::GetError() << "\n";
write_error(speedtree_cat.warning());
}
_needs_repopulate = true;
@ -249,8 +215,7 @@ remove_all_trees() {
if (!_forest_render.UnregisterTree(tree->get_tree())) {
speedtree_cat.warning()
<< "Failed to unregister tree " << tree->get_fullpath() << "\n";
speedtree_cat.warning()
<< SpeedTree::CCore::GetError() << "\n";
write_error(speedtree_cat.warning());
}
delete instance_list;
}
@ -562,6 +527,8 @@ setup_terrain(const Filename &terrain_file) {
void SpeedTreeNode::
set_terrain(STTerrain *terrain) {
_terrain = NULL;
_needs_repopulate = true;
if (terrain == (STTerrain *)NULL) {
return;
}
@ -577,33 +544,27 @@ set_terrain(STTerrain *terrain) {
_terrain_render.SetShaderLoader(_forest_render.GetShaderLoader());
SpeedTree::STerrainRenderInfo render_info;
render_info.m_strShaderPath = _os_shaders_dir.c_str();
SpeedTree::STerrainRenderInfo trender_info;
trender_info.m_strShaderPath = _os_shaders_dir.c_str();
string os_specific = terrain->get_normal_map().to_os_specific();
render_info.m_strNormalMap = os_specific.c_str();
trender_info.m_strNormalMap = os_specific.c_str();
os_specific = terrain->get_splat_map().to_os_specific();
render_info.m_strSplatMap = os_specific.c_str();
trender_info.m_strSplatMap = os_specific.c_str();
for (int i = 0; i < SpeedTree::c_nNumTerrainSplatLayers; ++i) {
os_specific = terrain->get_splat_layer(i).to_os_specific();
render_info.m_astrSplatLayers[i] = os_specific.c_str();
render_info.m_afSplatTileValues[i] = terrain->get_splat_layer_tiling(i);
trender_info.m_astrSplatLayers[i] = os_specific.c_str();
trender_info.m_afSplatTileValues[i] = terrain->get_splat_layer_tiling(i);
}
render_info.m_fNormalMapBlueScale = 1.0f;
render_info.m_bShadowsEnabled = false;
render_info.m_bZPrePass = false;
trender_info.m_fNormalMapBlueScale = 1.0f;
trender_info.m_bShadowsEnabled = false; // what does this do?
trender_info.m_bZPrePass = false;
_terrain_render.SetRenderInfo(render_info);
_terrain_render.SetMaxAnisotropy(speedtree_max_anisotropy);
_terrain_render.SetHint(SpeedTree::CTerrain::HINT_MAX_NUM_VISIBLE_CELLS,
speedtree_max_num_visible_cells);
_visible_terrain.Reserve(speedtree_max_num_visible_cells);
_terrain_render.SetRenderInfo(trender_info);
_terrain_render.SetHeightHints(terrain->get_min_height(), terrain->get_max_height());
_needs_repopulate = true;
}
////////////////////////////////////////////////////////////////////
@ -642,6 +603,74 @@ snap_to_terrain() {
_needs_repopulate = true;
}
////////////////////////////////////////////////////////////////////
// Function: SpeedTreeNode::reload_config
// Access: Published
// Description: Re-reads the current setting of all of the relevant
// config variables and applies them to this node. This
// can be called after changing config settings, to make
// them apply to this particular node.
////////////////////////////////////////////////////////////////////
void SpeedTreeNode::
reload_config() {
_shadow_infos.clear();
int num_shadow_maps = speedtree_cascading_shadow_splits.get_num_words();
if (num_shadow_maps > SpeedTree::c_nMaxNumShadowMaps) {
speedtree_cat.warning()
<< "SpeedTree is current compiled to support a maximum of "
<< SpeedTree::c_nMaxNumShadowMaps << " shadow maps.\n";
num_shadow_maps = SpeedTree::c_nMaxNumShadowMaps;
}
_shadow_infos.insert(_shadow_infos.begin(), num_shadow_maps, ShadowInfo());
for (int smi = 0; smi < num_shadow_maps; ++smi) {
_shadow_infos[smi]._shadow_split = speedtree_cascading_shadow_splits[smi];
}
SpeedTree::SForestRenderInfo render_info = _forest_render.GetRenderInfo();
render_info.m_nMaxAnisotropy = speedtree_max_anisotropy;
render_info.m_bHorizontalBillboards = speedtree_horizontal_billboards;
render_info.m_fAlphaTestScalar = speedtree_alpha_test_scalar;
render_info.m_bZPrePass = speedtree_z_pre_pass;
render_info.m_nMaxBillboardImagesByBase = speedtree_max_billboard_images_by_base;
render_info.m_fVisibility = speedtree_visibility;
render_info.m_fGlobalLightScalar = speedtree_global_light_scalar;
render_info.m_sLightMaterial.m_vSpecular = SpeedTree::Vec4(speedtree_specular_color[0], speedtree_specular_color[1], speedtree_specular_color[2], 1.0f);
render_info.m_sLightMaterial.m_vEmissive = SpeedTree::Vec4(speedtree_emissive_color[0], speedtree_emissive_color[1], speedtree_emissive_color[2], 1.0f);
render_info.m_bSpecularLighting = speedtree_specular_lighting;
render_info.m_bTransmissionLighting = speedtree_transmission_lighting;
render_info.m_bDetailLayer = speedtree_detail_layer;
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_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_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;
render_info.m_fSunFogBloom = speedtree_sun_fog_bloom;
render_info.m_nNumShadowMaps = num_shadow_maps;
render_info.m_nShadowMapResolution = speedtree_shadow_map_resolution;
render_info.m_bSmoothShadows = speedtree_smooth_shadows;
render_info.m_bShowShadowSplitsOnTerrain = speedtree_show_shadow_splits_on_terrain;
render_info.m_bWindEnabled = speedtree_wind_enabled;
render_info.m_bFrondRippling = speedtree_frond_rippling;
_forest_render.SetRenderInfo(render_info);
_terrain_render.SetMaxAnisotropy(speedtree_max_anisotropy);
_terrain_render.SetHint(SpeedTree::CTerrain::HINT_MAX_NUM_VISIBLE_CELLS,
speedtree_max_num_visible_cells);
_visible_terrain.Reserve(speedtree_max_num_visible_cells);
_needs_repopulate = true;
}
////////////////////////////////////////////////////////////////////
// Function: SpeedTreeNode::authorize
// Access: Published, Static
@ -679,7 +708,9 @@ authorize(const string &license) {
////////////////////////////////////////////////////////////////////
SpeedTreeNode::
SpeedTreeNode(const SpeedTreeNode &copy) :
PandaNode(copy)
PandaNode(copy),
_os_shaders_dir(copy._os_shaders_dir),
_shadow_infos(copy._shadow_infos)
#ifdef ST_DELETE_FOREST_HACK
// Early versions of SpeedTree don't destruct unused CForestRender
// objects correctly. To avoid crashes, we have to leak these
@ -690,6 +721,13 @@ SpeedTreeNode(const SpeedTreeNode &copy) :
init_node();
_forest_render.SetRenderInfo(copy._forest_render.GetRenderInfo());
_terrain_render.SetRenderInfo(copy._terrain_render.GetRenderInfo());
// No way to copy these parameters, so we just re-assign them.
_terrain_render.SetMaxAnisotropy(speedtree_max_anisotropy);
_terrain_render.SetHint(SpeedTree::CTerrain::HINT_MAX_NUM_VISIBLE_CELLS,
speedtree_max_num_visible_cells);
_visible_terrain.Reserve(speedtree_max_num_visible_cells);
Trees::const_iterator ti;
for (ti = copy._trees.begin(); ti != copy._trees.end(); ++ti) {
@ -698,14 +736,15 @@ SpeedTreeNode(const SpeedTreeNode &copy) :
if (!_forest_render.RegisterTree((SpeedTree::CTree *)tree->get_tree())) {
speedtree_cat.warning()
<< "Failed to register tree " << tree->get_fullpath() << "\n";
speedtree_cat.warning()
<< SpeedTree::CCore::GetError() << "\n";
write_error(speedtree_cat.warning());
}
_trees.push_back(new InstanceList(*instance_list));
}
_trees.sort();
set_terrain(copy._terrain);
_needs_repopulate = true;
mark_internal_bounds_stale();
}
@ -878,38 +917,75 @@ cull_callback(CullTraverser *trav, CullTraverserData &data) {
// Check lighting state. SpeedTree only supports a single
// directional light; we look for a directional light in the
// lighting state and pass its direction to SpeedTree.
NodePath light;
// lighting state and pass its direction and color to SpeedTree. We
// also accumulate the ambient light colors.
Colorf ambient_color(0.0f, 0.0f, 0.0f, 0.0f);
DirectionalLight *dlight = NULL;
NodePath dlight_np;
Colorf diffuse_color;
int diffuse_priority = 0;
const LightAttrib *la = DCAST(LightAttrib, state->get_attrib(LightAttrib::get_class_slot()));
if (la != (LightAttrib *)NULL) {
light = la->get_most_important_light();
for (int i = 0; i < la->get_num_on_lights(); ++i) {
NodePath light = la->get_on_light(i);
if (!light.is_empty() && light.node()->is_of_type(DirectionalLight::get_class_type())) {
// A directional light.
DirectionalLight *light_obj = DCAST(DirectionalLight, light.node());
if (dlight == NULL || light_obj->get_priority() > dlight->get_priority()) {
// Here's the most important directional light.
dlight = light_obj;
dlight_np = light;
}
} else if (!light.is_empty() && light.node()->is_of_type(AmbientLight::get_class_type())) {
// An ambient light. We keep the color only.
AmbientLight *light_obj = DCAST(AmbientLight, light.node());
ambient_color += light_obj->get_color();
}
}
}
if (!light.is_empty() && light.node()->is_of_type(DirectionalLight::get_class_type())) {
DirectionalLight *light_obj = DCAST(DirectionalLight, light.node());
CPT(TransformState) transform = light.get_transform(trav->get_scene()->get_scene_root().get_parent());
LVector3f dir = light_obj->get_direction() * transform->get_mat();
if (dlight != (DirectionalLight *)NULL) {
CPT(TransformState) transform = dlight_np.get_transform(trav->get_scene()->get_scene_root().get_parent());
LVector3f dir = dlight->get_direction() * transform->get_mat();
_light_dir = SpeedTree::Vec3(dir[0], dir[1], dir[2]);
diffuse_color = dlight->get_color();
} else {
// No light. But there's no way to turn off lighting in
// SpeedTree. In lieu of this, we just shine a light from
// above.
_light_dir = SpeedTree::Vec3(0.0, 0.0, -1.0);
// Also, we set ambient and diffuse colors to the same full-white
// value.
ambient_color.set(1.0f, 1.0f, 1.0f, 1.0f);
diffuse_color.set(1.0f, 1.0f, 1.0f, 1.0f);
}
SpeedTree::SForestRenderInfo render_info = _forest_render.GetRenderInfo();
render_info.m_sLightMaterial.m_vAmbient = SpeedTree::Vec4(ambient_color[0], ambient_color[1], ambient_color[2], 1.0f);
render_info.m_sLightMaterial.m_vDiffuse = SpeedTree::Vec4(diffuse_color[0], diffuse_color[1], diffuse_color[2], 1.0f);
_forest_render.SetRenderInfo(render_info);
_forest_render.SetLightDir(_light_dir);
SpeedTree::st_float32 updated_splits[SpeedTree::c_nMaxNumShadowMaps];
memset(updated_splits, 0, sizeof(updated_splits));
for (int smi = 0; smi < (int)_shadow_infos.size(); ++smi) {
updated_splits[smi] = _shadow_infos[smi]._shadow_split;
};
static const float shadow_fade = 0.25;
_forest_render.SetCascadedShadowMapDistances(updated_splits, lens->get_far());
_forest_render.SetShadowFadePercentage(shadow_fade);
if (!_needs_repopulate) {
// Don't bother culling now unless we're correctly fully
// populated. (Culling won't be accurate unless the forest has
// been populated, but we have to be in the draw traversal to
// populate.)
_forest_render.CullAndComputeLOD(_view, _visible_trees);
if (has_terrain()) {
_terrain_render.CullAndComputeLOD(_view, _visible_terrain);
}
cull_forest();
}
// Recurse onto the node's children.
@ -1052,6 +1128,52 @@ write(ostream &out, int indent_level) const {
*/
}
////////////////////////////////////////////////////////////////////
// Function: SpeedTreeNode::write_error
// Access: Public, Static
// Description: Writes the current SpeedTree error message to the
// indicated stream.
////////////////////////////////////////////////////////////////////
void SpeedTreeNode::
write_error(ostream &out) {
const char *error = SpeedTree::CCore::GetError();
if (error != (const char *)NULL) {
out << error;
}
out << "\n";
}
////////////////////////////////////////////////////////////////////
// Function: SpeedTreeNode::set_transparent_texture_mode
// Access: Protected
// Description: Uses SpeedTree::CRenderState to set the indicated
// transparency mode.
////////////////////////////////////////////////////////////////////
void SpeedTreeNode::
set_transparent_texture_mode(SpeedTree::ETextureAlphaRenderMode eMode) const {
// turn all modes off (no telling what render state the client
// application might be in before this call)
SpeedTree::CRenderState::SetBlending(false);
SpeedTree::CRenderState::SetAlphaTesting(false);
SpeedTree::CRenderState::SetAlphaToCoverage(false);
switch (eMode) {
case SpeedTree::TRANS_TEXTURE_ALPHA_TESTING:
SpeedTree::CRenderState::SetAlphaTesting(true);
break;
case SpeedTree::TRANS_TEXTURE_ALPHA_TO_COVERAGE:
SpeedTree::CRenderState::SetAlphaToCoverage(true);
break;
case SpeedTree::TRANS_TEXTURE_BLENDING:
SpeedTree::CRenderState::SetBlending(true);
break;
default:
// intentionally do nothing (TRANS_TEXTURE_NOTHING)
break;
}
}
////////////////////////////////////////////////////////////////////
// Function: SpeedTreeNode::init_node
// Access: Private
@ -1129,8 +1251,7 @@ repopulate() {
speedtree_cat.warning()
<< "Failed to add " << instances.size()
<< " instances for " << *tree << "\n";
speedtree_cat.warning()
<< SpeedTree::CCore::GetError() << "\n";
write_error(speedtree_cat.warning());
}
}
@ -1259,15 +1380,34 @@ draw_callback(CallbackData *data) {
setup_for_render(gsg);
if (_terrain_render.IsEnabled()) {
// Set some initial state requirements.
SpeedTree::CRenderState::SetAlphaFunction(SpeedTree::ALPHAFUNC_GREATER, 0.0f);
// start the forest render
_forest_render.StartRender();
if (_forest_render.ShadowsAreEnabled()) {
// Update the shadow maps. TODO: consider updating these only
// every once in a while, instead of every frame, as a simple
// optimization.
render_forest_into_shadow_maps();
_forest_render.ClearBoundTextures( );
}
if (!_forest_render.UploadViewShaderParameters(_view)) {
speedtree_cat.warning()
<< "Couldn't set view parameters\n";
write_error(speedtree_cat.warning());
}
if (has_terrain()) {
// Is this needed for terrain?
_terrain_render.UploadShaderConstants
(&_forest_render, _light_dir,
(&_forest_render, _light_dir,
_forest_render.GetRenderInfo().m_sLightMaterial);
// set terrain render states
//SetTransparentTextureMode(TRANS_TEXTURE_NOTHING);
set_transparent_texture_mode(SpeedTree::TRANS_TEXTURE_NOTHING);
// render actual terrain
bool terrain = _terrain_render.Render
@ -1278,16 +1418,18 @@ draw_callback(CallbackData *data) {
if (!terrain) {
speedtree_cat.warning()
<< "Failed to render terrain\n";
speedtree_cat.warning()
<< SpeedTree::CCore::GetError() << "\n";
write_error(speedtree_cat.warning());
// Clear the terrain so we don't keep spamming error messages.
_terrain = NULL;
}
// restore default forest rendering states
//SetTransparentTextureMode(ETextureAlphaRenderMode(m_uiTransparentTextureRenderMode));
}
// start the forest render
_forest_render.StartRender();
// 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;
set_transparent_texture_mode(SpeedTree::ETextureAlphaRenderMode(mode));
bool branches = _forest_render.RenderBranches(_visible_trees, SpeedTree::RENDER_PASS_STANDARD);
bool fronds = _forest_render.RenderFronds(_visible_trees, SpeedTree::RENDER_PASS_STANDARD);
@ -1299,17 +1441,78 @@ draw_callback(CallbackData *data) {
speedtree_cat.warning()
<< "Failed to render forest completely: "
<< branches << " " << fronds << " " << leaf_meshes << " " << leaf_cards << " " << billboards << "\n";
speedtree_cat.warning()
<< SpeedTree::CCore::GetError() << "\n";
write_error(speedtree_cat.warning());
}
_forest_render.EndRender();
// SpeedTree leaves the graphics state indeterminate. But this
// doesn't help?
if (_forest_render.ShadowsAreEnabled() && speedtree_show_overlays) {
_forest_render.RenderOverlays();
}
// SpeedTree leaves the graphics state indeterminate. Make sure
// Panda doesn't rely on anything in the state.
geom_cbdata->set_lost_state(true);
}
////////////////////////////////////////////////////////////////////
// Function: SpeedTreeNode::render_forest_into_shadow_maps
// Access: Private
// Description: Renders the forest from the point of view of the
// light, to fill up the shadow map(s).
////////////////////////////////////////////////////////////////////
void SpeedTreeNode::
render_forest_into_shadow_maps() {
bool success = true;
// d3d10 allows A2C on render targets, so make sure to turn it off
SpeedTree::CRenderState::SetMultisampling(false);
SpeedTree::CRenderState::SetAlphaToCoverage(false);
#if defined(SPEEDTREE_OPENGL)
// Ensure the viewport is not constrained. SpeedTree doesn't expect
// that.
glDisable(GL_SCISSOR_TEST);
#endif
for (int smi = 0; smi < (int)_shadow_infos.size(); ++smi) {
const SpeedTree::CView &light_view = _shadow_infos[smi]._light_view;
const SpeedTree::SForestCullResults &light_cull = _shadow_infos[smi]._light_cull;
if (_forest_render.BeginShadowMap(smi, light_view)) {
success &= _forest_render.UploadViewShaderParameters(light_view);
// branch geometry can be rendered with backfacing triangle
// removed, so a closer tolerance can be used
SpeedTree::CRenderState::SetPolygonOffset(1.0f, 0.125f);
success &= _forest_render.RenderBranches(light_cull, SpeedTree::RENDER_PASS_SHADOW);
// the remaining geometry types cannot be backface culled, so we
// need a much more aggressive offset
SpeedTree::CRenderState::SetPolygonOffset(10.0f, 1.0f);
success &= _forest_render.RenderFronds(light_cull, SpeedTree::RENDER_PASS_SHADOW);
success &= _forest_render.RenderLeafMeshes(light_cull, SpeedTree::RENDER_PASS_SHADOW);
success &= _forest_render.RenderLeafCards(light_cull, SpeedTree::RENDER_PASS_SHADOW, light_view);
// We don't bother to render billboard geometry into the shadow
// map(s).
success &= _forest_render.EndShadowMap(smi);
}
}
// SpeedTree::CRenderState::SetMultisampling(m_sUserSettings.m_nSampleCount > 0);
if (!success) {
speedtree_cat.warning()
<< "Failed to render shadow maps\n";
write_error(speedtree_cat.warning());
}
}
////////////////////////////////////////////////////////////////////
// Function: SpeedTreeNode::setup_for_render
// Access: Private
@ -1395,10 +1598,11 @@ setup_for_render(GraphicsStateGuardian *gsg) {
if (!_forest_render.InitTreeGraphics((SpeedTree::CTreeRender *)tree->get_tree(),
max_instances, speedtree_horizontal_billboards,
os_textures_dir.c_str())) {
speedtree_cat.warning()
<< "Failed to init tree graphics for " << *tree << "\n";
speedtree_cat.warning()
<< SpeedTree::CCore::GetError() << "\n";
if (speedtree_cat.is_debug()) {
speedtree_cat.debug()
<< "Failed to init tree graphics for " << *tree << "\n";
write_error(speedtree_cat.debug());
}
}
}
@ -1406,8 +1610,7 @@ setup_for_render(GraphicsStateGuardian *gsg) {
if (!_forest_render.InitGraphics(false)) {
speedtree_cat.warning()
<< "Failed to init graphics\n";
speedtree_cat.warning()
<< SpeedTree::CCore::GetError() << "\n";
write_error(speedtree_cat.warning());
_is_valid = false;
return;
}
@ -1429,32 +1632,49 @@ setup_for_render(GraphicsStateGuardian *gsg) {
_terrain->get_st_vertex_format())) {
speedtree_cat.warning()
<< "Failed to init terrain\n";
speedtree_cat.warning()
<< SpeedTree::CCore::GetError() << "\n";
write_error(speedtree_cat.warning());
}
}
// If we needed to repopulate, it means we didn't cull in the cull
// traversal. Do it now.
_forest_render.CullAndComputeLOD(_view, _visible_trees);
if (has_terrain()) {
_terrain_render.CullAndComputeLOD(_view, _visible_terrain);
}
cull_forest();
_needs_repopulate = false;
}
if (has_terrain()) {
update_terrain_cells();
}
}
if (!_forest_render.UploadViewShaderParameters(_view)) {
speedtree_cat.warning()
<< "Couldn't set view parameters\n";
speedtree_cat.warning()
<< SpeedTree::CCore::GetError() << "\n";
////////////////////////////////////////////////////////////////////
// Function: SpeedTreeNode::cull_forest
// Access: Private
// Description: Calls the SpeedTree methods to perform the needed
// cull calculations.
////////////////////////////////////////////////////////////////////
void SpeedTreeNode::
cull_forest() {
_forest_render.CullAndComputeLOD(_view, _visible_trees);
if (has_terrain()) {
_terrain_render.CullAndComputeLOD(_view, _visible_terrain);
}
if (_forest_render.ShadowsAreEnabled()) {
for (int smi = 0; smi < (int)_shadow_infos.size(); ++smi) {
SpeedTree::CView &light_view = _shadow_infos[smi]._light_view;
SpeedTree::SForestCullResultsRender &light_cull = _shadow_infos[smi]._light_cull;
_forest_render.ComputeLightView
(_forest_render.GetLightDir(), _view.GetFrustumPoints(), smi,
light_view, 0.0f);
light_view.SetLodRefPoint(_view.GetCameraPos());
_forest_render.CullAndComputeLOD(light_view, light_cull, false);
}
}
}
////////////////////////////////////////////////////////////////////
// Function: SpeedTreeNode::print_forest_stats
// Access: Private

View File

@ -46,8 +46,7 @@ class Loader;
// Panda3D scene graph.
//
// SpeedTree also includes some support for simple
// terrain and grass systems, but that support is not
// (yet) implemented within this layer.
// terrain and grass systems.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDASPEEDTREE SpeedTreeNode : public PandaNode {
private:
@ -128,6 +127,8 @@ PUBLISHED:
void snap_to_terrain();
void reload_config();
static bool authorize(const string &license = "");
public:
@ -153,6 +154,11 @@ public:
virtual void output(ostream &out) const;
virtual void write(ostream &out, int indent_level) const;
static void write_error(ostream &out);
protected:
void set_transparent_texture_mode(SpeedTree::ETextureAlphaRenderMode eMode) const;
private:
void init_node();
void r_add_instances(PandaNode *node, const TransformState *transform,
@ -162,7 +168,10 @@ private:
void update_terrain_cells();
bool validate_api(GraphicsStateGuardian *gsg);
void draw_callback(CallbackData *cbdata);
void render_forest_into_shadow_maps();
void setup_for_render(GraphicsStateGuardian *gsg);
void cull_forest();
void print_forest_stats(const SpeedTree::CForest::SPopulationStats &forest_stats) const;
private:
@ -217,6 +226,17 @@ private:
SpeedTree::Vec3 _light_dir;
class ShadowInfo {
public:
ShadowInfo() {};
SpeedTree::CView _light_view;
SpeedTree::SForestCullResultsRender _light_cull;
float _shadow_split;
};
typedef pvector<ShadowInfo> ShadowInfos;
ShadowInfos _shadow_infos;
static bool _authorized;
static bool _done_first_init;

View File

@ -109,6 +109,7 @@ clear() {
bool STBasicTerrain::
setup_terrain(const Filename &terrain_filename) {
_is_valid = false;
set_name(terrain_filename.get_basename());
VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();

View File

@ -56,8 +56,7 @@ STTree(const Filename &fullpath) :
if (!_tree.LoadTree(os_fullpath.c_str())) {
speedtree_cat.warning()
<< "Couldn't read: " << _fullpath << "\n";
speedtree_cat.warning()
<< SpeedTree::CCore::GetError() << "\n";
SpeedTreeNode::write_error(speedtree_cat.warning());
return;
}