NodePath::set_normal_map()

This commit is contained in:
David Rose 2005-08-03 00:44:37 +00:00
parent 64aec0a447
commit e5095d2c31
6 changed files with 179 additions and 54 deletions

View File

@ -501,50 +501,67 @@ munge_texcoord_light_vector(const CullTraverser *traverser) {
++lvi) { ++lvi) {
TextureStage *stage = (*lvi); TextureStage *stage = (*lvi);
NodePath light = tex_gen->get_light(stage); NodePath light = tex_gen->get_light(stage);
nassertv(!light.is_empty()); if (light.is_empty()) {
string source_name = tex_gen->get_source_name(stage); // If a particular light isn't specified in the TexGenAttrib,
Light *light_obj = light.node()->as_light(); // use the most important light in the current state.
nassertv(light_obj != (Light *)NULL); CPT(RenderAttrib) attrib = _state->get_attrib(LightAttrib::get_class_type());
if (attrib != (RenderAttrib *)NULL) {
CPT(LightAttrib) la = DCAST(LightAttrib, attrib);
light = la->get_most_important_light();
/*
if (!light.is_empty()) {
// Remove that light, now that we're accounting for it in
// the normal map.
_state->set_attrib(la->remove_on_light(light));
}
*/
}
}
if (!light.is_empty()) {
string source_name = tex_gen->get_source_name(stage);
Light *light_obj = light.node()->as_light();
nassertv(light_obj != (Light *)NULL);
// Determine the names of the tangent and binormal columns // Determine the names of the tangent and binormal columns
// associated with the stage's texcoord name. // associated with the stage's texcoord name.
CPT(InternalName) tangent_name = InternalName::get_tangent_name(source_name); CPT(InternalName) tangent_name = InternalName::get_tangent_name(source_name);
CPT(InternalName) binormal_name = InternalName::get_binormal_name(source_name); CPT(InternalName) binormal_name = InternalName::get_binormal_name(source_name);
CPT(InternalName) texcoord_name = stage->get_texcoord_name(); CPT(InternalName) texcoord_name = stage->get_texcoord_name();
if (_munged_data->has_column(tangent_name) && if (_munged_data->has_column(tangent_name) &&
_munged_data->has_column(binormal_name)) { _munged_data->has_column(binormal_name)) {
// Create a new column for the new texcoords. // Create a new column for the new texcoords.
PT(GeomVertexData) new_data = _munged_data->replace_column PT(GeomVertexData) new_data = _munged_data->replace_column
(texcoord_name, 3, Geom::NT_float32, Geom::C_texcoord); (texcoord_name, 3, Geom::NT_float32, Geom::C_texcoord);
_munged_data = new_data; _munged_data = new_data;
// Remove this TexGen stage from the state, since we're handling // Remove this TexGen stage from the state, since we're handling
// it now. // it now.
_state = _state->add_attrib(tex_gen->remove_stage(stage)); _state = _state->add_attrib(tex_gen->remove_stage(stage));
// Get the transform from the light to the object. // Get the transform from the light to the object.
CPT(TransformState) light_transform = CPT(TransformState) light_transform =
net_transform->invert_compose(light.get_net_transform()); net_transform->invert_compose(light.get_net_transform());
const LMatrix4f &light_mat = light_transform->get_mat(); const LMatrix4f &light_mat = light_transform->get_mat();
GeomVertexWriter texcoord(new_data, texcoord_name); GeomVertexWriter texcoord(new_data, texcoord_name);
GeomVertexReader vertex(new_data, InternalName::get_vertex()); GeomVertexReader vertex(new_data, InternalName::get_vertex());
GeomVertexReader tangent(new_data, tangent_name); GeomVertexReader tangent(new_data, tangent_name);
GeomVertexReader binormal(new_data, binormal_name); GeomVertexReader binormal(new_data, binormal_name);
GeomVertexReader normal(new_data, InternalName::get_normal()); GeomVertexReader normal(new_data, InternalName::get_normal());
while (!vertex.is_at_end()) { while (!vertex.is_at_end()) {
LPoint3f p = vertex.get_data3f(); LPoint3f p = vertex.get_data3f();
LVector3f t = tangent.get_data3f(); LVector3f t = tangent.get_data3f();
LVector3f b = binormal.get_data3f(); LVector3f b = binormal.get_data3f();
LVector3f n = normal.get_data3f(); LVector3f n = normal.get_data3f();
LVector3f lv; LVector3f lv;
if (light_obj->get_vector_to_light(lv, p, light_mat)) { if (light_obj->get_vector_to_light(lv, p, light_mat)) {
texcoord.add_data3f(lv.dot(t), lv.dot(b), lv.dot(n)); texcoord.add_data3f(lv.dot(t), lv.dot(b), lv.dot(n));
} }
}
} }
} }
} }

View File

@ -544,6 +544,34 @@ filter_to_max(int max_lights) const {
return light_attrib; return light_attrib;
} }
////////////////////////////////////////////////////////////////////
// Function: LightAttrib::get_most_important_light
// Access: Public
// Description: Returns the most important light (that is, the light
// with the highest priority) in the LightAttrib,
// excluding any ambient lights. Returns an empty
// NodePath if no non-ambient lights are found.
////////////////////////////////////////////////////////////////////
NodePath LightAttrib::
get_most_important_light() const {
NodePath best;
CompareLightPriorities compare;
Lights::const_iterator li;
for (li = _on_lights.begin(); li != _on_lights.end(); ++li) {
const NodePath &np = (*li);
nassertr(!np.is_empty() && np.node()->as_light() != (Light *)NULL, NodePath());
if (!np.node()->is_exact_type(AmbientLight::get_class_type())) {
if (best.is_empty() || compare(np, best)) {
best = np;
}
}
}
return best;
}
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: LightAttrib::issue // Function: LightAttrib::issue
// Access: Public, Virtual // Access: Public, Virtual

View File

@ -92,6 +92,7 @@ PUBLISHED:
CPT(RenderAttrib) remove_off_light(const NodePath &light) const; CPT(RenderAttrib) remove_off_light(const NodePath &light) const;
CPT(LightAttrib) filter_to_max(int max_lights) const; CPT(LightAttrib) filter_to_max(int max_lights) const;
NodePath get_most_important_light() const;
public: public:
virtual void issue(GraphicsStateGuardianBase *gsg) const; virtual void issue(GraphicsStateGuardianBase *gsg) const;

View File

@ -43,6 +43,7 @@
#include "transparencyAttrib.h" #include "transparencyAttrib.h"
#include "antialiasAttrib.h" #include "antialiasAttrib.h"
#include "texProjectorEffect.h" #include "texProjectorEffect.h"
#include "texturePool.h"
#include "planeNode.h" #include "planeNode.h"
#include "lensNode.h" #include "lensNode.h"
#include "materialPool.h" #include "materialPool.h"
@ -3529,6 +3530,82 @@ project_texture(TextureStage *stage, Texture *tex, const NodePath &projector) {
set_tex_projector(stage, NodePath(), projector); set_tex_projector(stage, NodePath(), projector);
} }
////////////////////////////////////////////////////////////////////
// Function: NodePath::set_normal_map
// Access: Published
// Description: A convenience function to set up a normal map on this
// geometry. This uses the single highest-priority
// light on the object only. It also requires
// multitexture, and consumes at least two texture
// stages, in addition to what may already be in use.
//
// The normal_map parameter is the texture that contains
// the normal map information (with a 3-d delta vector
// encoded into the r,g,b of each texel). texcoord_name is
// the name of the texture coordinate set that contains
// the tangent and binormal we wish to use.
//
// Only one normal map may be in effect through this
// interface at any given time.
////////////////////////////////////////////////////////////////////
void NodePath::
set_normal_map(Texture *normal_map, const string &texcoord_name) {
clear_normal_map();
// First, we apply the normal map itself, to the bottom layer.
PT(TextureStage) normal_map_ts = new TextureStage("normal_map");
normal_map_ts->set_texcoord_name(texcoord_name);
normal_map_ts->set_sort(-20);
normal_map_ts->set_mode(TextureStage::M_replace);
set_texture(normal_map_ts, normal_map);
// Then, we apply a normalization map, to normalize, per-pixel, the
// vector to the light.
PT(Texture) normalization_map = TexturePool::get_normalization_cube_map(32);
PT(TextureStage) normalization_map_ts = new TextureStage("normalization_map");
normalization_map_ts->set_combine_rgb
(TextureStage::CM_dot3_rgb,
TextureStage::CS_texture, TextureStage::CO_src_color,
TextureStage::CS_previous, TextureStage::CO_src_color);
normalization_map_ts->set_texcoord_name("light_vector");
normalization_map_ts->set_sort(-15);
set_texture(normalization_map_ts, normalization_map);
// Finally, we enable M_light_vector texture coordinate generation.
set_tex_gen(normalization_map_ts, TexGenAttrib::M_light_vector,
texcoord_name, NodePath());
}
////////////////////////////////////////////////////////////////////
// Function: NodePath::clear_normal_map
// Access: Published
// Description: Undoes the effect of a previous call to
// set_normal_map().
////////////////////////////////////////////////////////////////////
void NodePath::
clear_normal_map() {
// Scan through the TextureStages, and if we find any whose name
// matches one of the stages that would have been left by
// set_normal_map(), remove it from the state.
CPT(RenderAttrib) attrib =
get_state()->get_attrib(TextureAttrib::get_class_type());
if (attrib != (const RenderAttrib *)NULL) {
const TextureAttrib *ta = DCAST(TextureAttrib, attrib);
for (int i = 0; i < ta->get_num_on_stages(); i++) {
TextureStage *stage = ta->get_on_stage(i);
if (stage->get_name() == "normal_map") {
clear_texture(stage);
} else if (stage->get_name() == "normalization_map") {
clear_texture(stage);
clear_tex_gen(stage);
}
}
}
}
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: NodePath::find_texture // Function: NodePath::find_texture
// Access: Published // Access: Published

View File

@ -600,6 +600,9 @@ PUBLISHED:
void project_texture(TextureStage *stage, Texture *tex, const NodePath &projector); void project_texture(TextureStage *stage, Texture *tex, const NodePath &projector);
INLINE void clear_project_texture(TextureStage *stage); INLINE void clear_project_texture(TextureStage *stage);
void set_normal_map(Texture *normal_map, const string &texcoord_name = string());
void clear_normal_map();
Texture *find_texture(const string &name) const; Texture *find_texture(const string &name) const;
Texture *find_texture(TextureStage *stage) const; Texture *find_texture(TextureStage *stage) const;
TextureCollection find_all_textures() const; TextureCollection find_all_textures() const;

View File

@ -93,20 +93,19 @@ add_stage(TextureStage *stage, TexGenAttrib::Mode mode,
case M_light_vector: case M_light_vector:
{ {
Light *light_obj = NULL;
if (!light.is_empty()) { if (!light.is_empty()) {
light_obj = light.node()->as_light(); Light *light_obj = light.node()->as_light();
if (light_obj == (Light *)NULL) {
ostringstream strm;
strm << "Not a light: " << light;
nassert_raise(strm.str());
mode_def._light = NodePath();
}
} }
if (light_obj == (Light *)NULL) {
ostringstream strm;
strm << "Not a light: " << light;
nassert_raise(strm.str());
} else { attrib->_light_vectors.insert(stage);
attrib->_light_vectors.insert(stage); attrib->_geom_rendering |= Geom::GR_texcoord_light_vector;
attrib->_geom_rendering |= Geom::GR_texcoord_light_vector; attrib->_num_light_vectors++;
attrib->_num_light_vectors++;
}
} }
break; break;