Polylight Changes... return a new effect on all modifiers

This commit is contained in:
Shalin Shodhan 2004-07-30 21:04:11 +00:00
parent 8b5014d01e
commit 2ca64d594d
3 changed files with 204 additions and 249 deletions

View File

@ -27,115 +27,6 @@ INLINE PolylightEffect::
PolylightEffect() {
}
////////////////////////////////////////////////////////////////////
// Function: PolylightEffect::is_enabled
// Access: Published
// Description: Returns state of the effect: enabled/disabled
////////////////////////////////////////////////////////////////////
INLINE bool PolylightEffect::
is_enabled() const {
return _enabled;
}
////////////////////////////////////////////////////////////////////
// Function: PolylightEffect::enable
// Access: Published
// Description: Enables the effect
////////////////////////////////////////////////////////////////////
INLINE void PolylightEffect::
enable() {
_enabled=true;
}
////////////////////////////////////////////////////////////////////
// Function: PolylightEffect::disable
// Access: Published
// Description: Disables the effect
////////////////////////////////////////////////////////////////////
INLINE void PolylightEffect::
disable() {
_enabled=false;
}
////////////////////////////////////////////////////////////////////
// Function: PolylightEffect::add_light
// Access: Published
// Description: Add a PolylightNode object to this effect and give it a
// unique name. Returns true if light added
////////////////////////////////////////////////////////////////////
INLINE bool PolylightEffect::
add_light(const string &lightname, const NodePath &newlight) {
nassertr(newlight.node()->is_of_type(PolylightNode::get_class_type()) ,false);
nassertr(newlight.node() != (PolylightNode *)NULL,false);
// Check if light name is unique
if (_lightgroup.find(lightname) != _lightgroup.end()) {
cerr << "Light name already exists. Please choose another name\n";
return false;
}
// Add the light
pair<string,NodePath> _light_to_add(lightname, newlight);
_lightgroup.insert(_light_to_add);
return true;
}
////////////////////////////////////////////////////////////////////
// Function: PolylightEffect::remove_light
// Access: Published
// Description: Remove a light from this effect. Returns true on
// success.
////////////////////////////////////////////////////////////////////
INLINE bool PolylightEffect::
remove_light(const string &lightname) {
// Check if light name exists
if (_lightgroup.find(lightname) == _lightgroup.end()) {
cerr << "Light name does not exist\n";
return false;
}
// Remove light
_lightgroup.erase(lightname);
return true;
}
////////////////////////////////////////////////////////////////////
// Function: PolylightEffect::remove_all
// Access: Published
// Description: Remove all the lights from this effect. Returns
// true on success.
////////////////////////////////////////////////////////////////////
INLINE bool PolylightEffect::
remove_all() {
LIGHTGROUP::const_iterator light_iter;
for (light_iter = _lightgroup.begin(); light_iter != _lightgroup.end(); light_iter++){
string lightname = light_iter->first;
_lightgroup.erase(lightname);
}
return true;
}
////////////////////////////////////////////////////////////////////
// Function: PolylightEffect::set_weight
// Access: Published
// Description: weight is a constant you add (generally 1 and above)
// to make the colorscale brighten the existing color
////////////////////////////////////////////////////////////////////
INLINE bool PolylightEffect::
set_weight(float w) {
// nassertr(w >= 0.0 && w <= 1.0 ,false);
_weight = w;
return true;
}
////////////////////////////////////////////////////////////////////
// Function: PolylightEffect::get_weight
// Access: Published
@ -146,26 +37,6 @@ get_weight() const {
return _weight;
}
////////////////////////////////////////////////////////////////////
// Function: PolylightEffect::set_contrib
// Access: Published
// Description: Set the effect contribution type
// The effects of all the light colors are finally
// divided by the number of lights. The variable
// _contribution_type is a string that controls how
// this division occurs.
// "proximal" : A light only contributes if the node
// is inside its volume
// "all" : All lights added to the effect are used in
// division irrespective of their light volumes
////////////////////////////////////////////////////////////////////
INLINE bool PolylightEffect::
set_contrib(PolylightEffect::Contrib_Type type) {
nassertr(type == CALL || type == CPROXIMAL,false);
_contribution_type = type;
return true;
}
////////////////////////////////////////////////////////////////////
// Function: PolylightEffect::get_contrib
// Access: Published
@ -176,18 +47,6 @@ get_contrib() const {
return _contribution_type;
}
////////////////////////////////////////////////////////////////////
// Function: PolylightEffect::set_effect_center
// Access: Published
// Description: Set the center point of the effect...generally 0,0,0
// and hence the pivot point of the model
////////////////////////////////////////////////////////////////////
INLINE void PolylightEffect::
set_effect_center(LPoint3f effect_center) {
_effect_center = effect_center;
}
////////////////////////////////////////////////////////////////////
// Function: PolylightEffect::get_effect_center
// Access: Published

View File

@ -36,13 +36,40 @@ TypeHandle PolylightEffect::_type_handle;
CPT(RenderEffect) PolylightEffect::
make() {
PolylightEffect *effect = new PolylightEffect;
effect->enable();
effect->set_contrib(CPROXIMAL);
effect->set_weight(0.9);
effect->_contribution_type = CPROXIMAL;
effect->_weight = 0.9;
effect->_effect_center = LPoint3f(0.0,0.0,0.0);
return return_new(effect);
}
////////////////////////////////////////////////////////////////////
// Function: PolylightEffect::make
// Access: Published, Static
// Description: Constructs a new PolylightEffect object.
////////////////////////////////////////////////////////////////////
CPT(RenderEffect) PolylightEffect::
make(float weight, Contrib_Type contrib, LPoint3f effect_center) {
PolylightEffect *effect = new PolylightEffect;
effect->_contribution_type = contrib;
effect->_weight = weight;
effect->_effect_center = effect_center;
return return_new(effect);
}
////////////////////////////////////////////////////////////////////
// Function: PolylightEffect::make
// Access: Published, Static
// Description: Constructs a new PolylightEffect object.
////////////////////////////////////////////////////////////////////
CPT(RenderEffect) PolylightEffect::
make(float weight, Contrib_Type contrib, LPoint3f effect_center, LIGHTGROUP lights) {
PolylightEffect *effect = new PolylightEffect;
effect->_contribution_type = contrib;
effect->_weight = weight;
effect->_effect_center = effect_center;
effect->_lightgroup = lights;
return return_new(effect);
}
////////////////////////////////////////////////////////////////////
// Function: PolylightEffect::has_cull_callback
@ -55,7 +82,7 @@ make() {
////////////////////////////////////////////////////////////////////
bool PolylightEffect::
has_cull_callback() const {
return is_enabled();
return true;
}
////////////////////////////////////////////////////////////////////
@ -79,11 +106,9 @@ void PolylightEffect::
cull_callback(CullTraverser *, CullTraverserData &data,
CPT(TransformState) &node_transform,
CPT(RenderState) &node_state) const {
if (is_enabled()) {
CPT(RenderAttrib) poly_light_attrib = do_poly_light(&data, node_transform);
CPT(RenderState) poly_light_state = RenderState::make(poly_light_attrib);
node_state = node_state->compose(poly_light_state);
}
CPT(RenderAttrib) poly_light_attrib = do_poly_light(&data, node_transform);
CPT(RenderState) poly_light_state = RenderState::make(poly_light_attrib);
node_state = node_state->compose(poly_light_state);
}
////////////////////////////////////////////////////////////////////
@ -104,82 +129,78 @@ do_poly_light(const CullTraverserData *data, const TransformState *node_transfor
r = 1.0;
g = 1.0;
b = 1.0;
if (is_enabled()) {
LIGHTGROUP::const_iterator light_iter;
// Cycle through all the lights in this effect's lightgroup
for (light_iter = _lightgroup.begin(); light_iter != _lightgroup.end(); light_iter++){
const PolylightNode *light = DCAST(PolylightNode,light_iter->second.node());
// light holds the current PolylightNode
if (light->is_enabled()) { // if enabled get all the properties
float light_radius = light->get_radius();
PolylightNode::Attenuation_Type light_attenuation = light->get_attenuation();
float light_a0 = light->get_a0();
float light_a1 = light->get_a1();
float light_a2 = light->get_a2();
if (light_a0 == 0 && light_a1 == 0 && light_a2 == 0) { // To prevent division by zero
light_a0 = 1.0;
}
Colorf light_color;
if (light->is_flickering()) { // If flickering, modify color
light_color = light->flicker();
} else {
light_color = light->get_color_scenegraph();
}
// Calculate the distance of the node from the light
//dist = light_iter->second->get_distance(data->_node_path.get_node_path());
const NodePath lightnp = light_iter->second;
LPoint3f point = data->_node_path.get_node_path().get_relative_point(lightnp,
light->get_pos());
dist = (point - _effect_center).length();
LIGHTGROUP::const_iterator light_iter;
// Cycle through all the lights in this effect's lightgroup
for (light_iter = _lightgroup.begin(); light_iter != _lightgroup.end(); light_iter++){
const PolylightNode *light = DCAST(PolylightNode, (*light_iter).node());
// light holds the current PolylightNode
if (light->is_enabled()) { // if enabled get all the properties
float light_radius = light->get_radius();
PolylightNode::Attenuation_Type light_attenuation = light->get_attenuation();
float light_a0 = light->get_a0();
float light_a1 = light->get_a1();
float light_a2 = light->get_a2();
if (light_a0 == 0 && light_a1 == 0 && light_a2 == 0) { // To prevent division by zero
light_a0 = 1.0;
}
Colorf light_color;
if (light->is_flickering()) { // If flickering, modify color
light_color = light->flicker();
} else {
light_color = light->get_color_scenegraph();
}
// Calculate the distance of the node from the light
//dist = light_iter->second->get_distance(data->_node_path.get_node_path());
const NodePath lightnp = *light_iter;
LPoint3f point = data->_node_path.get_node_path().get_relative_point(lightnp,
light->get_pos());
dist = (point - _effect_center).length();
if (dist < light_radius) { // If node is in range of this light
if (light_attenuation == PolylightNode::ALINEAR) {
light_scale = (light_radius - dist)/light_radius;
} else if (light_attenuation == PolylightNode::AQUADRATIC) {
fd = 1.0 / (light_a0 + light_a1 * dist + light_a2 * dist * dist);
if (fd < 1.0) {
light_scale = fd;
} else {
light_scale = 1.0;
}
} else {
light_scale = 1.0;
}
// Keep accumulating each lights contribution... we divide by
// number of lights later.
Rcollect += light_color[0] * light_scale;
Gcollect += light_color[1] * light_scale;
Bcollect += light_color[2] * light_scale;
num_lights++;
} // if dist< radius
} // if light is enabled
} // for all lights
if (dist < light_radius) { // If node is in range of this light
if (light_attenuation == PolylightNode::ALINEAR) {
light_scale = (light_radius - dist)/light_radius;
} else if (light_attenuation == PolylightNode::AQUADRATIC) {
fd = 1.0 / (light_a0 + light_a1 * dist + light_a2 * dist * dist);
if (fd < 1.0) {
light_scale = fd;
} else {
light_scale = 1.0;
}
} else {
light_scale = 1.0;
}
// Keep accumulating each lights contribution... we divide by
// number of lights later.
Rcollect += light_color[0] * light_scale;
Gcollect += light_color[1] * light_scale;
Bcollect += light_color[2] * light_scale;
num_lights++;
} // if dist< radius
} // if light is enabled
} // for all lights
if ( _contribution_type == CALL) {
// Sometimes to prevent snapping of color at light volume boundaries
// just divide total contribution by all the lights in the effect
// whether or not they contribute color
num_lights = _lightgroup.size();
}
if (num_lights == 0) {
no_lights_closeby = true;
num_lights = 1;
}
Rcollect /= num_lights;
Gcollect /= num_lights;
Bcollect /= num_lights;
if (!no_lights_closeby) {
//r = 1.0 + ((1.0 - _weight) + Rcollect * _weight);
//g = 1.0 + ((1.0 - _weight) + Gcollect * _weight);
//b = 1.0 + ((1.0 - _weight) + Bcollect * _weight);
r = _weight + Rcollect;
g = _weight + Gcollect;
b = _weight + Bcollect;
}
if ( _contribution_type == CALL) {
// Sometimes to prevent snapping of color at light volume boundaries
// just divide total contribution by all the lights in the effect
// whether or not they contribute color
num_lights = _lightgroup.size();
}
if (num_lights == 0) {
no_lights_closeby = true;
num_lights = 1;
}
Rcollect /= num_lights;
Gcollect /= num_lights;
Bcollect /= num_lights;
if (!no_lights_closeby) {
//r = 1.0 + ((1.0 - _weight) + Rcollect * _weight);
//g = 1.0 + ((1.0 - _weight) + Gcollect * _weight);
//b = 1.0 + ((1.0 - _weight) + Bcollect * _weight);
r = _weight + Rcollect;
g = _weight + Gcollect;
b = _weight + Bcollect;
}
return ColorScaleAttrib::make(LVecBase4f(r, g, b, 1.0));
}
@ -204,10 +225,6 @@ compare_to_impl(const RenderEffect *other) const {
const PolylightEffect *ta;
DCAST_INTO_R(ta, other, 0);
if (_enabled != ta->_enabled) {
return _enabled ? 1 : -1;
}
if (_contribution_type != ta->_contribution_type) {
return _contribution_type < ta->_contribution_type ? -1 : 1;
}
@ -223,3 +240,86 @@ compare_to_impl(const RenderEffect *other) const {
return 0;
}
////////////////////////////////////////////////////////////////////
// Function: PolylightEffect::add_light
// Access: Published
// Description: Add a PolylightNode object to this effect and return
// a new effect
////////////////////////////////////////////////////////////////////
CPT(RenderEffect) PolylightEffect::
add_light(const NodePath &newlight) {
_lightgroup.push_back(newlight);
return make(_weight,_contribution_type, _effect_center,
_lightgroup);
}
////////////////////////////////////////////////////////////////////
// Function: PolylightEffect::remove_light
// Access: Published
// Description: Remove a light from this effect. Return the new updated
// effect
////////////////////////////////////////////////////////////////////
CPT(RenderEffect) PolylightEffect::
remove_light(const NodePath &newlight) {
LIGHTGROUP::iterator light_iter;
light_iter = find(_lightgroup.begin(),_lightgroup.end(), newlight);
if(light_iter == _lightgroup.end()) {
cerr << "Light Not Found!\n";
} else {
// Remove light
_lightgroup.erase(light_iter);
}
return make(_weight, _contribution_type, _effect_center,
_lightgroup);
}
////////////////////////////////////////////////////////////////////
// Function: PolylightEffect::set_weight
// Access: Published
// Description: Set weight and return a new effect... the reason
// this couldnt be done through make was because
// that would return a new effect without the
// lightgroup which is static and cant be accessed
// Here, we just pass that to the make
////////////////////////////////////////////////////////////////////
CPT(RenderEffect) PolylightEffect::
set_weight(float w) {
return make(w,_contribution_type, _effect_center,
_lightgroup);
}
////////////////////////////////////////////////////////////////////
// Function: PolylightEffect::set_contrib
// Access: Published
// Description: Set Contrib Type and return a new effect... the reason
// this couldnt be done through make was because
// that would return a new effect without the
// lightgroup which is static and cant be accessed
// Here, we just pass that to the make
////////////////////////////////////////////////////////////////////
CPT(RenderEffect) PolylightEffect::
set_contrib(Contrib_Type ct) {
return make(_weight, ct, _effect_center,
_lightgroup);
}
////////////////////////////////////////////////////////////////////
// Function: PolylightEffect::set_effect_center
// Access: Published
// Description: Set weight and return a new effect... the reason
// this couldnt be done through make was because
// that would return a new effect without the
// lightgroup which is static and cant be accessed
// Here, we just pass that to the make
////////////////////////////////////////////////////////////////////
CPT(RenderEffect) PolylightEffect::
set_effect_center(LPoint3f ec) {
return make(_weight,_contribution_type, ec,
_lightgroup);
}

View File

@ -34,15 +34,13 @@
// Class : PolylightEffect
// Description : A PolylightEffect can be used on a node to define a
// LightGroup for that node. A LightGroup contains
// Polylights which are essentially nodes that add
// PolylightNodes which are essentially nodes that add
// color to the polygons of a model based on distance.
// PolylightNode is a cheap way to get lighting effects
// specially for night scenes
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA PolylightEffect : public RenderEffect {
private:
INLINE PolylightEffect();
PUBLISHED:
enum Contrib_Type {
@ -50,18 +48,25 @@ PUBLISHED:
CALL,
};
private:
INLINE PolylightEffect();
Contrib_Type _contribution_type;
float _weight;
typedef pvector< NodePath > LIGHTGROUP;
LIGHTGROUP _lightgroup;
LPoint3f _effect_center;
PUBLISHED:
static CPT(RenderEffect) make();
INLINE void enable();
INLINE void disable();
INLINE bool add_light(const string &lightname, const NodePath &newlight);
INLINE bool remove_light(const string &lightname);
INLINE bool remove_all();
INLINE bool set_weight(float w);
static CPT(RenderEffect) make(float weight, Contrib_Type contrib, LPoint3f effect_center);
static CPT(RenderEffect) make(float weight, Contrib_Type contrib, LPoint3f effect_center, LIGHTGROUP lights);
CPT(RenderEffect) add_light(const NodePath &newlight);
CPT(RenderEffect) remove_light(const NodePath &newlight);
CPT(RenderEffect) set_weight(float w);
CPT(RenderEffect) set_contrib(Contrib_Type c);
CPT(RenderEffect) set_effect_center(LPoint3f ec);
INLINE float get_weight() const;
INLINE bool set_contrib(Contrib_Type type);
INLINE Contrib_Type get_contrib() const;
INLINE bool is_enabled()const;
INLINE void set_effect_center(LPoint3f effect_center);
INLINE LPoint3f get_effect_center()const;
public:
@ -75,15 +80,6 @@ public:
protected:
virtual int compare_to_impl(const RenderEffect *other) const;
private:
bool _enabled;
Contrib_Type _contribution_type;
float _weight;
typedef pmap<string, NodePath> LIGHTGROUP;
LIGHTGROUP _lightgroup;
LPoint3f _effect_center;
public:
static TypeHandle get_class_type() {
return _type_handle;