Improve shadow system, add point light shadows, GLSL shadow inputs

This commit is contained in:
rdb 2015-12-07 21:12:07 +01:00
parent 571fd7d72e
commit 25451feb87
14 changed files with 796 additions and 520 deletions

View File

@ -445,6 +445,12 @@ ConfigVariableDouble pixel_zoom
("pixel-zoom", 1.0,
PRC_DESC("The default pixel_zoom factor for new windows."));
ConfigVariableInt shadow_depth_bits
("shadow-depth-bits", 24,
PRC_DESC("The minimum number of depth buffer bits requested when rendering "
"shadow maps. Set this to 32 for more depth resolution in shadow "
"maps."));
ConfigVariableColor background_color
("background-color", "0.41 0.41 0.41 0.0",
PRC_DESC("Specifies the rgb(a) value of the default background color for a "

View File

@ -102,6 +102,7 @@ extern EXPCL_PANDA_DISPLAY ConfigVariableInt stencil_bits;
extern EXPCL_PANDA_DISPLAY ConfigVariableInt accum_bits;
extern EXPCL_PANDA_DISPLAY ConfigVariableInt multisamples;
extern EXPCL_PANDA_DISPLAY ConfigVariableInt back_buffers;
extern EXPCL_PANDA_DISPLAY ConfigVariableInt shadow_depth_bits;
extern EXPCL_PANDA_DISPLAY ConfigVariableDouble pixel_zoom;

View File

@ -1480,7 +1480,8 @@ cull_to_bins(const GraphicsEngine::Windows &wlist, Thread *current_thread) {
// Keep track of the cameras we have already used in this thread to
// render DisplayRegions.
typedef pmap<NodePath, DisplayRegion *> AlreadyCulled;
typedef pair<NodePath, int> CullKey;
typedef pmap<CullKey, DisplayRegion *> AlreadyCulled;
AlreadyCulled already_culled;
size_t wlist_size = wlist.size();
@ -1495,7 +1496,9 @@ cull_to_bins(const GraphicsEngine::Windows &wlist, Thread *current_thread) {
DisplayRegionPipelineReader *dr_reader =
new DisplayRegionPipelineReader(dr, current_thread);
NodePath camera = dr_reader->get_camera();
AlreadyCulled::iterator aci = already_culled.insert(AlreadyCulled::value_type(camera, (DisplayRegion *)NULL)).first;
int lens_index = dr_reader->get_lens_index();
AlreadyCulled::iterator aci = already_culled.insert(AlreadyCulled::value_type(CullKey(camera, lens_index), (DisplayRegion *)NULL)).first;
if ((*aci).second == NULL) {
// We have not used this camera already in this thread.
// Perform the cull operation.

View File

@ -967,9 +967,15 @@ fetch_specified_value(Shader::ShaderMatSpec &spec, int altered) {
spec._value.set_row(3, v);
return &spec._value;
case Shader::SMF_transform_plight:
spec._value = spec._cache[0];
spec._value.set_row(2, spec._cache[1].xform_point(spec._cache[0].get_row3(2)));
return &spec._value;
{
// Careful not to touch the w component, which contains the near value.
spec._value = spec._cache[0];
LPoint3 point = spec._cache[1].xform_point(spec._cache[0].get_row3(2));
spec._value(2, 0) = point[0];
spec._value(2, 1) = point[1];
spec._value(2, 2) = point[2];
return &spec._value;
}
case Shader::SMF_transform_slight:
spec._value = spec._cache[0];
spec._value.set_row(2, spec._cache[1].xform_point(spec._cache[0].get_row3(2)));
@ -1152,7 +1158,9 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name,
get_scene()->get_world_transform()->get_mat();
LVecBase3 p = (t.xform_point(lt->get_point()));
LVecBase3 a = lt->get_attenuation();
t = LMatrix4(c[0],c[1],c[2],c[3],s[0],s[1],s[2],s[3],p[0],p[1],p[2],0,a[0],a[1],a[2],0);
PN_stdfloat near = lt->get_lens(0)->get_near();
PN_stdfloat far = lt->get_lens(0)->get_far();
t = LMatrix4(c[0],c[1],c[2],c[3],s[0],s[1],s[2],s[3],p[0],p[1],p[2],near,a[0],a[1],a[2],far);
return &t;
}
case Shader::SMO_slight_x: {
@ -1405,8 +1413,19 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name,
calc_projection_mat(lens)->get_mat();
return &t;
}
case Shader::SMO_mat_constant_x_attrib: {
if (_target_shader->has_shader_input(name)) {
// There is an input specifying precisely this whole thing, with
// dot and all. Support this, even if only for backward compatibility.
return &_target_shader->get_shader_input_matrix(name, t);
}
const NodePath &np = _target_shader->get_shader_input_nodepath(name->get_parent());
nassertr(!np.is_empty(), &LMatrix4::ident_mat());
return fetch_specified_member(np, name->get_basename(), t);
}
case Shader::SMO_vec_constant_x_attrib: {
// This system is not ideal. It will be improved in the future.
if (_target_shader->has_shader_input(name)) {
// There is an input specifying precisely this whole thing, with
// dot and all. Support this, even if only for backward compatibility.
@ -1421,205 +1440,33 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name,
const NodePath &np = _target_shader->get_shader_input_nodepath(name->get_parent());
nassertr(!np.is_empty(), &LMatrix4::ident_mat());
CPT_InternalName attrib = name->get_basename();
return fetch_specified_member(np, name->get_basename(), t);
}
case Shader::SMO_light_source_i_attrib: {
const LightAttrib *target_light;
_target_rs->get_attrib_def(target_light);
static const CPT_InternalName IN_ambient("ambient");
static const CPT_InternalName IN_diffuse("diffuse");
static const CPT_InternalName IN_specular("specular");
static const CPT_InternalName IN_position("position");
static const CPT_InternalName IN_halfVector("halfVector");
static const CPT_InternalName IN_spotDirection("spotDirection");
static const CPT_InternalName IN_spotCutoff("spotCutoff");
static const CPT_InternalName IN_spotCosCutoff("spotCosCutoff");
static const CPT_InternalName IN_spotExponent("spotExponent");
static const CPT_InternalName IN_constantAttenuation("constantAttenuation");
static const CPT_InternalName IN_linearAttenuation("linearAttenuation");
static const CPT_InternalName IN_quadraticAttenuation("quadraticAttenuation");
// We want to ignore ambient lights. To that effect, iterate through
// the list of lights. In the future, we will improve this system, by
// also filtering down to the number of lights specified by the shader.
int i = 0;
if (attrib == IN_ambient) {
Light *light = np.node()->as_light();
nassertr(light != (Light *)NULL, &LMatrix4::ident_mat());
if (np.node()->is_of_type(AmbientLight::get_class_type())) {
LColor c = light->get_color();
c.componentwise_mult(_light_color_scale);
t.set_row(3, c);
} else {
// Non-ambient lights don't currently have an ambient color in Panda3D.
t.set_row(3, LColor(0.0f, 0.0f, 0.0f, 1.0f));
int num_on_lights = target_light->get_num_on_lights();
for (int li = 0; li < num_on_lights; li++) {
NodePath light = target_light->get_on_light(li);
nassertr(!light.is_empty(), &LMatrix4::ident_mat());
Light *light_obj = light.node()->as_light();
nassertr(light_obj != (Light *)NULL, &LMatrix4::ident_mat());
if (light_obj->get_type() != AmbientLight::get_class_type()) {
if (i++ == index) {
return fetch_specified_member(light, name, t);
}
}
return &t;
} else if (attrib == IN_diffuse) {
Light *light = np.node()->as_light();
nassertr(light != (Light *)NULL, &LMatrix4::ones_mat());
if (np.node()->is_of_type(AmbientLight::get_class_type())) {
// Ambient light has no diffuse color.
t.set_row(3, LColor(0.0f, 0.0f, 0.0f, 1.0f));
} else {
LColor c = light->get_color();
c.componentwise_mult(_light_color_scale);
t.set_row(3, c);
}
return &t;
} else if (attrib == IN_specular) {
Light *light = np.node()->as_light();
nassertr(light != (Light *)NULL, &LMatrix4::ones_mat());
t.set_row(3, light->get_specular_color());
return &t;
} else if (attrib == IN_position) {
if (np.node()->is_of_type(AmbientLight::get_class_type())) {
// Ambient light has no position.
t = LMatrix4(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);
return &t;
} else if (np.node()->is_of_type(DirectionalLight::get_class_type())) {
DirectionalLight *light;
DCAST_INTO_R(light, np.node(), &LMatrix4::ident_mat());
CPT(TransformState) transform = np.get_transform(_scene_setup->get_scene_root().get_parent());
LVector3 dir = -(light->get_direction() * transform->get_mat());
dir *= get_scene()->get_cs_world_transform()->get_mat();
t = LMatrix4(0,0,0,0,0,0,0,0,0,0,0,0,dir[0],dir[1],dir[2],0);
return &t;
} else {
LightLensNode *light;
DCAST_INTO_R(light, np.node(), &LMatrix4::ident_mat());
Lens *lens = light->get_lens();
nassertr(lens != (Lens *)NULL, &LMatrix4::ident_mat());
CPT(TransformState) transform =
get_scene()->get_cs_world_transform()->compose(
np.get_transform(_scene_setup->get_scene_root().get_parent()));
const LMatrix4 &light_mat = transform->get_mat();
LPoint3 pos = lens->get_nodal_point() * light_mat;
t = LMatrix4::translate_mat(pos);
return &t;
}
} else if (attrib == IN_halfVector) {
if (np.node()->is_of_type(AmbientLight::get_class_type())) {
// Ambient light has no half-vector.
t = LMatrix4(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);
return &t;
} else if (np.node()->is_of_type(DirectionalLight::get_class_type())) {
DirectionalLight *light;
DCAST_INTO_R(light, np.node(), &LMatrix4::ident_mat());
CPT(TransformState) transform = np.get_transform(_scene_setup->get_scene_root().get_parent());
LVector3 dir = -(light->get_direction() * transform->get_mat());
dir *= get_scene()->get_cs_world_transform()->get_mat();
dir.normalize();
dir += LVector3(0, 0, 1);
dir.normalize();
t = LMatrix4(0,0,0,0,0,0,0,0,0,0,0,0,dir[0],dir[1],dir[2],1);
return &t;
} else {
LightLensNode *light;
DCAST_INTO_R(light, np.node(), &LMatrix4::ident_mat());
Lens *lens = light->get_lens();
nassertr(lens != (Lens *)NULL, &LMatrix4::ident_mat());
CPT(TransformState) transform =
get_scene()->get_cs_world_transform()->compose(
np.get_transform(_scene_setup->get_scene_root().get_parent()));
const LMatrix4 &light_mat = transform->get_mat();
LPoint3 pos = lens->get_nodal_point() * light_mat;
pos.normalize();
pos += LVector3(0, 0, 1);
pos.normalize();
t = LMatrix4(0,0,0,0,0,0,0,0,0,0,0,0,pos[0],pos[1],pos[2],1);
return &t;
}
} else if (attrib == IN_spotDirection) {
if (np.node()->is_of_type(AmbientLight::get_class_type())) {
// Ambient light has no spot direction.
t.set_row(3, LVector3(0.0f, 0.0f, 0.0f));
return &t;
} else {
LightLensNode *light;
DCAST_INTO_R(light, np.node(), &LMatrix4::ident_mat());
Lens *lens = light->get_lens();
nassertr(lens != (Lens *)NULL, &LMatrix4::ident_mat());
CPT(TransformState) transform =
get_scene()->get_cs_world_transform()->compose(
np.get_transform(_scene_setup->get_scene_root().get_parent()));
const LMatrix4 &light_mat = transform->get_mat();
LVector3 dir = lens->get_view_vector() * light_mat;
t.set_row(3, dir);
return &t;
}
} else if (attrib == IN_spotCutoff) {
if (np.node()->is_of_type(Spotlight::get_class_type())) {
LightLensNode *light;
DCAST_INTO_R(light, np.node(), &LMatrix4::ident_mat());
Lens *lens = light->get_lens();
nassertr(lens != (Lens *)NULL, &LMatrix4::ident_mat());
float cutoff = lens->get_hfov() * 0.5f;
t.set_row(3, LVecBase4(cutoff));
return &t;
} else {
// Other lights have no cut-off.
t.set_row(3, LVecBase4(180));
return &t;
}
} else if (attrib == IN_spotCosCutoff) {
if (np.node()->is_of_type(Spotlight::get_class_type())) {
LightLensNode *light;
DCAST_INTO_R(light, np.node(), &LMatrix4::ident_mat());
Lens *lens = light->get_lens();
nassertr(lens != (Lens *)NULL, &LMatrix4::ident_mat());
float cutoff = lens->get_hfov() * 0.5f;
t.set_row(3, LVecBase4(ccos(deg_2_rad(cutoff))));
return &t;
} else {
// Other lights have no cut-off.
t.set_row(3, LVecBase4(-1));
return &t;
}
} else if (attrib == IN_spotExponent) {
Light *light = np.node()->as_light();
nassertr(light != (Light *)NULL, &LMatrix4::ident_mat());
t.set_row(3, LVecBase4(light->get_exponent()));
return &t;
} else if (attrib == IN_constantAttenuation) {
Light *light = np.node()->as_light();
nassertr(light != (Light *)NULL, &LMatrix4::ones_mat());
t.set_row(3, LVecBase4(light->get_attenuation()[0]));
return &t;
} else if (attrib == IN_linearAttenuation) {
Light *light = np.node()->as_light();
nassertr(light != (Light *)NULL, &LMatrix4::ident_mat());
t.set_row(3, LVecBase4(light->get_attenuation()[1]));
return &t;
} else if (attrib == IN_quadraticAttenuation) {
Light *light = np.node()->as_light();
nassertr(light != (Light *)NULL, &LMatrix4::ident_mat());
t.set_row(3, LVecBase4(light->get_attenuation()[2]));
return &t;
} else {
display_cat.error()
<< "Shader input requests invalid attribute " << *name
<< " from node " << np << "\n";
return &LMatrix4::ident_mat();
}
// TODO: dummy light
nassertr(false, &LMatrix4::ident_mat());
}
default:
nassertr(false /*should never get here*/, &LMatrix4::ident_mat());
@ -1627,6 +1474,346 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name,
}
}
////////////////////////////////////////////////////////////////////
// Function: GraphicsStateGuardian::fetch_specified_member
// Access: Public
// Description: Given a NodePath passed into a shader input that is
// a structure, fetches the value for the given member.
////////////////////////////////////////////////////////////////////
const LMatrix4 *GraphicsStateGuardian::
fetch_specified_member(const NodePath &np, CPT_InternalName attrib, LMatrix4 &t) {
// This system is not ideal. It will be improved in the future.
static const CPT_InternalName IN_ambient("ambient");
static const CPT_InternalName IN_diffuse("diffuse");
static const CPT_InternalName IN_specular("specular");
static const CPT_InternalName IN_position("position");
static const CPT_InternalName IN_halfVector("halfVector");
static const CPT_InternalName IN_spotDirection("spotDirection");
static const CPT_InternalName IN_spotCutoff("spotCutoff");
static const CPT_InternalName IN_spotCosCutoff("spotCosCutoff");
static const CPT_InternalName IN_spotExponent("spotExponent");
static const CPT_InternalName IN_attenuation("attenuation");
static const CPT_InternalName IN_constantAttenuation("constantAttenuation");
static const CPT_InternalName IN_linearAttenuation("linearAttenuation");
static const CPT_InternalName IN_quadraticAttenuation("quadraticAttenuation");
static const CPT_InternalName IN_shadowMatrix("shadowMatrix");
if (attrib == IN_ambient) {
Light *light = np.node()->as_light();
nassertr(light != (Light *)NULL, &LMatrix4::ident_mat());
if (np.node()->is_of_type(AmbientLight::get_class_type())) {
LColor c = light->get_color();
c.componentwise_mult(_light_color_scale);
t.set_row(3, c);
} else {
// Non-ambient lights don't currently have an ambient color in Panda3D.
t.set_row(3, LColor(0.0f, 0.0f, 0.0f, 1.0f));
}
return &t;
} else if (attrib == IN_diffuse) {
Light *light = np.node()->as_light();
nassertr(light != (Light *)NULL, &LMatrix4::ones_mat());
if (np.node()->is_of_type(AmbientLight::get_class_type())) {
// Ambient light has no diffuse color.
t.set_row(3, LColor(0.0f, 0.0f, 0.0f, 1.0f));
} else {
LColor c = light->get_color();
c.componentwise_mult(_light_color_scale);
t.set_row(3, c);
}
return &t;
} else if (attrib == IN_specular) {
Light *light = np.node()->as_light();
nassertr(light != (Light *)NULL, &LMatrix4::ones_mat());
t.set_row(3, light->get_specular_color());
return &t;
} else if (attrib == IN_position) {
if (np.node()->is_of_type(AmbientLight::get_class_type())) {
// Ambient light has no position.
t = LMatrix4(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);
return &t;
} else if (np.node()->is_of_type(DirectionalLight::get_class_type())) {
DirectionalLight *light;
DCAST_INTO_R(light, np.node(), &LMatrix4::ident_mat());
CPT(TransformState) transform = np.get_transform(_scene_setup->get_scene_root().get_parent());
LVector3 dir = -(light->get_direction() * transform->get_mat());
dir *= get_scene()->get_cs_world_transform()->get_mat();
t = LMatrix4(0,0,0,0,0,0,0,0,0,0,0,0,dir[0],dir[1],dir[2],0);
return &t;
} else {
LightLensNode *light;
DCAST_INTO_R(light, np.node(), &LMatrix4::ident_mat());
Lens *lens = light->get_lens();
nassertr(lens != (Lens *)NULL, &LMatrix4::ident_mat());
CPT(TransformState) transform =
get_scene()->get_cs_world_transform()->compose(
np.get_transform(_scene_setup->get_scene_root().get_parent()));
const LMatrix4 &light_mat = transform->get_mat();
LPoint3 pos = lens->get_nodal_point() * light_mat;
t = LMatrix4::translate_mat(pos);
return &t;
}
} else if (attrib == IN_halfVector) {
if (np.node()->is_of_type(AmbientLight::get_class_type())) {
// Ambient light has no half-vector.
t = LMatrix4(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);
return &t;
} else if (np.node()->is_of_type(DirectionalLight::get_class_type())) {
DirectionalLight *light;
DCAST_INTO_R(light, np.node(), &LMatrix4::ident_mat());
CPT(TransformState) transform = np.get_transform(_scene_setup->get_scene_root().get_parent());
LVector3 dir = -(light->get_direction() * transform->get_mat());
dir *= get_scene()->get_cs_world_transform()->get_mat();
dir.normalize();
dir += LVector3(0, 0, 1);
dir.normalize();
t = LMatrix4(0,0,0,0,0,0,0,0,0,0,0,0,dir[0],dir[1],dir[2],1);
return &t;
} else {
LightLensNode *light;
DCAST_INTO_R(light, np.node(), &LMatrix4::ident_mat());
Lens *lens = light->get_lens();
nassertr(lens != (Lens *)NULL, &LMatrix4::ident_mat());
CPT(TransformState) transform =
get_scene()->get_cs_world_transform()->compose(
np.get_transform(_scene_setup->get_scene_root().get_parent()));
const LMatrix4 &light_mat = transform->get_mat();
LPoint3 pos = lens->get_nodal_point() * light_mat;
pos.normalize();
pos += LVector3(0, 0, 1);
pos.normalize();
t = LMatrix4(0,0,0,0,0,0,0,0,0,0,0,0,pos[0],pos[1],pos[2],1);
return &t;
}
} else if (attrib == IN_spotDirection) {
if (np.node()->is_of_type(AmbientLight::get_class_type())) {
// Ambient light has no spot direction.
t.set_row(3, LVector3(0.0f, 0.0f, 0.0f));
return &t;
} else {
LightLensNode *light;
DCAST_INTO_R(light, np.node(), &LMatrix4::ident_mat());
Lens *lens = light->get_lens();
nassertr(lens != (Lens *)NULL, &LMatrix4::ident_mat());
CPT(TransformState) transform =
get_scene()->get_cs_world_transform()->compose(
np.get_transform(_scene_setup->get_scene_root().get_parent()));
const LMatrix4 &light_mat = transform->get_mat();
LVector3 dir = lens->get_view_vector() * light_mat;
t.set_row(3, dir);
return &t;
}
} else if (attrib == IN_spotCutoff) {
if (np.node()->is_of_type(Spotlight::get_class_type())) {
LightLensNode *light;
DCAST_INTO_R(light, np.node(), &LMatrix4::ident_mat());
Lens *lens = light->get_lens();
nassertr(lens != (Lens *)NULL, &LMatrix4::ident_mat());
float cutoff = lens->get_hfov() * 0.5f;
t.set_row(3, LVecBase4(cutoff));
return &t;
} else {
// Other lights have no cut-off.
t.set_row(3, LVecBase4(180));
return &t;
}
} else if (attrib == IN_spotCosCutoff) {
if (np.node()->is_of_type(Spotlight::get_class_type())) {
LightLensNode *light;
DCAST_INTO_R(light, np.node(), &LMatrix4::ident_mat());
Lens *lens = light->get_lens();
nassertr(lens != (Lens *)NULL, &LMatrix4::ident_mat());
float cutoff = lens->get_hfov() * 0.5f;
t.set_row(3, LVecBase4(ccos(deg_2_rad(cutoff))));
return &t;
} else {
// Other lights have no cut-off.
t.set_row(3, LVecBase4(-1));
return &t;
}
} else if (attrib == IN_spotExponent) {
Light *light = np.node()->as_light();
nassertr(light != (Light *)NULL, &LMatrix4::ident_mat());
t.set_row(3, LVecBase4(light->get_exponent()));
return &t;
} else if (attrib == IN_attenuation) {
Light *light = np.node()->as_light();
nassertr(light != (Light *)NULL, &LMatrix4::ones_mat());
t.set_row(3, LVecBase4(light->get_attenuation(), 0));
return &t;
} else if (attrib == IN_constantAttenuation) {
Light *light = np.node()->as_light();
nassertr(light != (Light *)NULL, &LMatrix4::ones_mat());
t.set_row(3, LVecBase4(light->get_attenuation()[0]));
return &t;
} else if (attrib == IN_linearAttenuation) {
Light *light = np.node()->as_light();
nassertr(light != (Light *)NULL, &LMatrix4::ident_mat());
t.set_row(3, LVecBase4(light->get_attenuation()[1]));
return &t;
} else if (attrib == IN_quadraticAttenuation) {
Light *light = np.node()->as_light();
nassertr(light != (Light *)NULL, &LMatrix4::ident_mat());
t.set_row(3, LVecBase4(light->get_attenuation()[2]));
return &t;
} else if (attrib == IN_shadowMatrix) {
LensNode *lnode;
DCAST_INTO_R(lnode, np.node(), &LMatrix4::ident_mat());
Lens *lens = lnode->get_lens();
static const LMatrix4 biasmat(0.5f, 0.0f, 0.0f, 0.0f,
0.0f, 0.5f, 0.0f, 0.0f,
0.0f, 0.0f, 0.5f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f);
t = get_external_transform()->get_mat() *
get_scene()->get_camera_transform()->get_mat() *
np.get_net_transform()->get_inverse()->get_mat() *
LMatrix4::convert_mat(_coordinate_system, lens->get_coordinate_system()) *
lens->get_projection_mat() * biasmat;
return &t;
} else {
display_cat.error()
<< "Shader input requests invalid attribute " << *attrib
<< " from node " << np << "\n";
return &LMatrix4::ident_mat();
}
}
////////////////////////////////////////////////////////////////////
// Function: GraphicsStateGuardian::fetch_specified_texture
// Access: Public
// Description: Like fetch_specified_value, but for texture inputs.
////////////////////////////////////////////////////////////////////
PT(Texture) GraphicsStateGuardian::
fetch_specified_texture(Shader::ShaderTexSpec &spec, SamplerState &sampler,
int &view) {
switch (spec._part) {
case Shader::STO_named_input:
// Named texture input.
if (!_target_shader->has_shader_input(spec._name)) {
// Is this a member of something, like a node?
const InternalName *parent = spec._name->get_parent();
if (parent != InternalName::get_root() &&
_target_shader->has_shader_input(parent)) {
// Yes, grab the node.
const string &basename = spec._name->get_basename();
NodePath np = _target_shader->get_shader_input_nodepath(parent);
if (basename == "shadowMap") {
PT(Texture) tex = get_shadow_map(np);
if (tex != (Texture *)NULL) {
sampler = tex->get_default_sampler();
}
return tex;
} else {
if (spec._stage == 0) {
display_cat.error()
<< "Shader input " << *parent
<< " has no member named " << basename << ".\n";
spec._stage = -1;
}
}
} else {
// This used to be legal for some reason, so don't trigger the assert.
// Prevent flood, though, so abuse the _stage flag to indicate whether
// we've already errored about this.
if (spec._stage == 0) {
display_cat.error()
<< "Shader input " << *spec._name << " is not present.\n";
spec._stage = -1;
}
}
} else {
// Just a regular texture input.
return _target_shader->get_shader_input_texture(spec._name, &sampler);
}
break;
case Shader::STO_stage_i:
{
// We get the TextureAttrib directly from the _target_rs, not the
// filtered TextureAttrib in _target_texture.
const TextureAttrib *texattrib;
_target_rs->get_attrib_def(texattrib);
if (spec._stage < texattrib->get_num_on_stages()) {
TextureStage *stage = texattrib->get_on_stage(spec._stage);
sampler = texattrib->get_on_sampler(stage);
view += stage->get_tex_view_offset();
return texattrib->get_on_texture(stage);
}
}
break;
case Shader::STO_light_i_shadow_map:
{
const LightAttrib *target_light;
_target_rs->get_attrib_def(target_light);
// We want to ignore ambient lights. To that effect, iterate through
// the list of lights. In the future, we will improve this system, by
// also filtering down to the number of lights specified by the shader.
int i = 0;
int num_on_lights = target_light->get_num_on_lights();
for (int li = 0; li < num_on_lights; li++) {
NodePath light = target_light->get_on_light(li);
nassertr(!light.is_empty(), NULL);
Light *light_obj = light.node()->as_light();
nassertr(light_obj != (Light *)NULL, NULL);
if (light_obj->get_type() != AmbientLight::get_class_type()) {
if (i++ == spec._stage) {
PT(Texture) tex = get_shadow_map(light);
if (tex != (Texture *)NULL) {
sampler = tex->get_default_sampler();
}
return tex;
}
}
}
}
break;
default:
nassertr(false, NULL);
break;
}
return NULL;
}
////////////////////////////////////////////////////////////////////
// Function: GraphicsStateGuardian::fetch_ptr_parameter
// Access: Public
@ -2579,8 +2766,8 @@ do_issue_light() {
int num_enabled = 0;
int num_on_lights = 0;
const LightAttrib *target_light = (const LightAttrib *)
_target_rs->get_attrib_def(LightAttrib::get_class_slot());
const LightAttrib *target_light;
_target_rs->get_attrib_def(target_light);
if (display_cat.is_spam()) {
display_cat.spam()
@ -3161,6 +3348,42 @@ async_reload_texture(TextureContext *tc) {
_loader->load_async(request);
}
////////////////////////////////////////////////////////////////////
// Function: GraphicsStateGuardian::get_shadow_map
// Access: Protected
// Description: Returns a shadow map for the given light source.
// If none exists, it is created, using the given host
// window to create the buffer, or the current window
// if that is set to NULL.
////////////////////////////////////////////////////////////////////
PT(Texture) GraphicsStateGuardian::
get_shadow_map(const NodePath &light_np, GraphicsOutputBase *host) {
nassertr(light_np.node()->is_of_type(DirectionalLight::get_class_type()) ||
light_np.node()->is_of_type(PointLight::get_class_type()) ||
light_np.node()->is_of_type(Spotlight::get_class_type()), NULL);
PT(LightLensNode) light = DCAST(LightLensNode, light_np.node());
if (light == NULL || !light->_shadow_caster) {
//TODO: return dummy shadow map (all white).
return NULL;
}
// See if we already have a buffer. If not, create one.
if (light->_sbuffers.count(this) == 0) {
if (host == (GraphicsOutputBase *)NULL) {
host = _current_display_region->get_window();
}
nassertr(host != NULL, NULL);
// Nope, the light doesn't have a buffer for our GSG. Make one.
return make_shadow_buffer(light_np, host);
} else {
// There's already a buffer - use that.
return light->_sbuffers[this]->get_texture();
}
}
////////////////////////////////////////////////////////////////////
// Function: GraphicsStateGuardian::make_shadow_buffer
// Access: Protected
@ -3186,13 +3409,17 @@ make_shadow_buffer(const NodePath &light_np, GraphicsOutputBase *host) {
nassertr(light->_sbuffers.count(this) == 0, NULL);
display_cat.debug() << "Constructing shadow buffer for light '" << light->get_name()
<< "', size=" << light->_sb_xsize << "x" << light->_sb_ysize
<< ", sort=" << light->_sb_sort << "\n";
if (display_cat.is_debug()) {
display_cat.debug()
<< "Constructing shadow buffer for light '" << light->get_name()
<< "', size=" << light->_sb_xsize << "x" << light->_sb_ysize
<< ", sort=" << light->_sb_sort << "\n";
}
// Setup some flags and properties
// Determine the properties for creating the depth buffer.
FrameBufferProperties fbp;
fbp.set_depth_bits(1); // We only need depth
fbp.set_depth_bits(shadow_depth_bits);
WindowProperties props = WindowProperties::size(light->_sb_xsize, light->_sb_ysize);
int flags = GraphicsPipe::BF_refuse_window;
if (is_point) {
@ -3228,12 +3455,12 @@ make_shadow_buffer(const NodePath &light_np, GraphicsOutputBase *host) {
tex->set_border_color(LVecBase4(1, 1, 1, 1));
}
if (get_supports_shadow_filter()) {
// Note: cube map shadow filtering doesn't seem to work in Cg.
if (get_supports_shadow_filter() && !is_point) {
// If we have the ARB_shadow extension, enable shadow filtering.
tex->set_minfilter(SamplerState::FT_shadow);
tex->set_magfilter(SamplerState::FT_shadow);
} else {
// We only accept linear - this tells the GPU to use hardware PCF.
tex->set_minfilter(SamplerState::FT_linear);
tex->set_magfilter(SamplerState::FT_linear);
}

View File

@ -263,6 +263,9 @@ public:
const LMatrix4 *fetch_specified_value(Shader::ShaderMatSpec &spec, int altered);
const LMatrix4 *fetch_specified_part(Shader::ShaderMatInput input, InternalName *name,
LMatrix4 &t, int index);
const LMatrix4 *fetch_specified_member(const NodePath &np, CPT_InternalName member, LMatrix4 &t);
PT(Texture) fetch_specified_texture(Shader::ShaderTexSpec &spec,
SamplerState &sampler, int &view);
const Shader::ShaderPtrData *fetch_ptr_parameter(const Shader::ShaderPtrSpec& spec);
virtual void prepare_display_region(DisplayRegionPipelineReader *dr);
@ -348,7 +351,8 @@ public:
static void create_gamma_table (PN_stdfloat gamma, unsigned short *red_table, unsigned short *green_table, unsigned short *blue_table);
virtual PT(Texture) make_shadow_buffer(const NodePath &light_np, GraphicsOutputBase *host);
PT(Texture) get_shadow_map(const NodePath &light_np, GraphicsOutputBase *host=NULL);
PT(Texture) make_shadow_buffer(const NodePath &light_np, GraphicsOutputBase *host);
#ifdef DO_PSTATS
static void init_frame_pstats();

View File

@ -1090,26 +1090,16 @@ update_shader_texture_bindings(ShaderContext *prev) {
continue;
}
int texunit = cgGetParameterResourceIndex(p);
Texture *tex = NULL;
int view = _glgsg->get_current_tex_view_offset();
SamplerState sampler;
if (id != NULL) {
tex = _glgsg->_target_shader->get_shader_input_texture(id, &sampler);
} else {
if (spec._stage >= texattrib->get_num_on_stages()) {
// Apply a white texture in order to make it easier to use a shader
// that takes a texture on a model that doesn't have a texture applied.
_glgsg->_glActiveTexture(GL_TEXTURE0 + texunit);
_glgsg->apply_white_texture();
continue;
}
TextureStage *stage = texattrib->get_on_stage(spec._stage);
tex = texattrib->get_on_texture(stage);
sampler = texattrib->get_on_sampler(stage);
view += stage->get_tex_view_offset();
PT(Texture) tex = _glgsg->fetch_specified_texture(spec, sampler, view);
if (tex.is_null()) {
// Apply a white texture in order to make it easier to use a shader
// that takes a texture on a model that doesn't have a texture applied.
_glgsg->_glActiveTexture(GL_TEXTURE0 + i);
_glgsg->apply_white_texture();
continue;
}
if (spec._suffix != 0) {

View File

@ -6841,7 +6841,7 @@ bind_light(Spotlight *light_obj, const NodePath &light, int light_id) {
call_glLightfv(id, GL_POSITION, fpos);
call_glLightfv(id, GL_SPOT_DIRECTION, dir);
glLightf(id, GL_SPOT_EXPONENT, light_obj->get_exponent());
glLightf(id, GL_SPOT_EXPONENT, max(min(light_obj->get_exponent(), (PN_stdfloat)128), (PN_stdfloat)0));
glLightf(id, GL_SPOT_CUTOFF, lens->get_hfov() * 0.5f);
const LVecBase3 &att = light_obj->get_attenuation();

View File

@ -25,6 +25,7 @@
#include "fogAttrib.h"
#include "lightAttrib.h"
#include "clipPlaneAttrib.h"
#include "ambientLight.h"
TypeHandle CLP(ShaderContext)::_type_handle;
@ -799,8 +800,29 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) {
for (bind._index = 0; bind._index < param_size; ++bind._index) {
_shader->_mat_spec.push_back(bind);
}
_shader->_mat_deps |= bind._dep[0];
return;
} else if (matrix_name.size() > 15 &&
matrix_name.substr(0, 12) == "LightSource[" &&
sscanf(matrix_name.c_str(), "LightSource[%d].%s", &bind._index, name_buffer) == 2) {
// A matrix member of a p3d_LightSource struct.
if (strncmp(name_buffer, "shadowMatrix", 127) == 0) {
if (inverse) {
// Tack inverse back onto the end.
strcpy(name_buffer + strlen(name_buffer), "Inverse");
}
bind._func = Shader::SMF_first;
bind._part[0] = Shader::SMO_light_source_i_attrib;
bind._arg[0] = InternalName::make(name_buffer);
bind._part[1] = Shader::SMO_identity;
} else {
GLCAT.error() << "p3d_LightSource struct does not provide a matrix named " << matrix_name << "!\n";
return;
}
} else {
GLCAT.error() << "Unrecognized uniform matrix name '" << matrix_name << "'!\n";
return;
@ -813,6 +835,7 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) {
if (size > 7 && noprefix.substr(0, 7) == "Texture") {
Shader::ShaderTexSpec bind;
bind._id = arg_id;
bind._part = Shader::STO_stage_i;
bind._name = 0;
string tail;
@ -991,6 +1014,78 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) {
_shader->_mat_deps |= bind._dep[0];
return;
}
if (size > 15 && noprefix.substr(0, 12) == "LightSource[") {
int index;
if (sscanf(noprefix.c_str(), "LightSource[%d].%s", &index, name_buffer) == 2) {
// A member of a p3d_LightSource struct.
string member_name(name_buffer);
if (member_name == "shadowMap") {
switch (param_type) {
#ifndef OPENGLES
case GL_SAMPLER_CUBE_SHADOW:
#endif // !OPENGLES
case GL_SAMPLER_2D:
case GL_SAMPLER_2D_SHADOW:
case GL_SAMPLER_CUBE:
{
Shader::ShaderTexSpec bind;
bind._id = arg_id;
bind._part = Shader::STO_light_i_shadow_map;
bind._name = 0;
bind._desired_type = Texture::TT_2d_texture;
bind._stage = index;
if (get_sampler_texture_type(bind._desired_type, param_type)) {
_glgsg->_glUniform1i(p, _shader->_tex_spec.size());
_shader->_tex_spec.push_back(bind);
}
return;
}
default:
GLCAT.error()
<< "Invalid type for p3d_LightSource[].shadowMap input!\n";
return;
}
} else {
// A non-sampler attribute of a numbered light source.
Shader::ShaderMatSpec bind;
bind._id = arg_id;
bind._func = Shader::SMF_first;
bind._index = index;
bind._part[0] = Shader::SMO_light_source_i_attrib;
bind._arg[0] = InternalName::make(member_name);
bind._dep[0] = Shader::SSD_general | Shader::SSD_light | Shader::SSD_frame | Shader::SSD_transform;
bind._part[1] = Shader::SMO_identity;
bind._arg[1] = NULL;
bind._dep[1] = Shader::SSD_NONE;
switch (param_type) {
case GL_FLOAT:
bind._piece = Shader::SMP_row3x1;
break;
case GL_FLOAT_VEC2:
bind._piece = Shader::SMP_row3x2;
break;
case GL_FLOAT_VEC3:
bind._piece = Shader::SMP_row3x3;
break;
case GL_FLOAT_VEC4:
bind._piece = Shader::SMP_row3;
break;
default:
GLCAT.error()
<< "p3d_LightSource[]." << member_name << " should be float or vec\n";
return;
}
_shader->_mat_spec.push_back(bind);
_shader->_mat_deps |= bind._dep[0] | bind._dep[1];
return;
}
}
}
if (noprefix == "TransformTable") {
if (param_type != GL_FLOAT_MAT4) {
GLCAT.error()
@ -1119,6 +1214,7 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) {
case GL_SAMPLER_CUBE: {
Shader::ShaderTexSpec bind;
bind._id = arg_id;
bind._part = Shader::STO_named_input;
bind._name = InternalName::make(param_name);
bind._desired_type = Texture::TT_2d_texture;
bind._stage = 0;
@ -1159,9 +1255,19 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) {
bind._id = arg_id;
bind._piece = Shader::SMP_whole;
bind._func = Shader::SMF_first;
bind._part[0] = Shader::SMO_mat_constant_x;
bind._arg[0] = InternalName::make(param_name);
bind._dep[0] = Shader::SSD_general | Shader::SSD_shaderinputs | Shader::SSD_frame;
PT(InternalName) iname = InternalName::make(param_name);
if (iname->get_parent() != InternalName::get_root()) {
// It might be something like an attribute of a shader
// input, like a light parameter. It might also just be
// a custom struct parameter. We can't know yet, sadly.
bind._part[0] = Shader::SMO_mat_constant_x_attrib;
bind._arg[0] = InternalName::make(param_name);
bind._dep[0] = Shader::SSD_general | Shader::SSD_shaderinputs | Shader::SSD_frame | Shader::SSD_transform;
} else {
bind._part[0] = Shader::SMO_mat_constant_x;
bind._arg[0] = InternalName::make(param_name);
bind._dep[0] = Shader::SSD_general | Shader::SSD_shaderinputs | Shader::SSD_frame;
}
bind._part[1] = Shader::SMO_identity;
bind._arg[1] = NULL;
bind._dep[1] = Shader::SSD_NONE;
@ -2260,46 +2366,19 @@ update_shader_texture_bindings(ShaderContext *prev) {
}
#endif
// We get the TextureAttrib directly from the _target_rs, not the
// filtered TextureAttrib in _target_texture.
const TextureAttrib *texattrib;
_glgsg->_target_rs->get_attrib_def(texattrib);
//const TextureAttrib *texattrib;
//_state_rs->get_attrib_def(TextureAttrib::get_class_slot());
for (int i = 0; i < (int)_shader->_tex_spec.size(); ++i) {
Shader::ShaderTexSpec &spec = _shader->_tex_spec[i];
const InternalName *id = spec._name;
Texture *tex = NULL;
int view = _glgsg->get_current_tex_view_offset();
SamplerState sampler;
if (id != NULL) {
// Named texture input.
if (!_glgsg->_target_shader->has_shader_input(id)) {
// This used to be legal for some reason, so don't trigger the assert.
GLCAT.error()
<< "Shader input " << *id << " is not present.\n";
continue;
}
tex = _glgsg->_target_shader->get_shader_input_texture(id, &sampler);
} else {
if (spec._stage >= texattrib->get_num_on_stages()) {
// Apply a white texture in order to make it easier to use a shader
// that takes a texture on a model that doesn't have a texture applied.
_glgsg->_glActiveTexture(GL_TEXTURE0 + i);
_glgsg->apply_white_texture();
continue;
}
TextureStage *stage = texattrib->get_on_stage(spec._stage);
tex = texattrib->get_on_texture(stage);
sampler = texattrib->get_on_sampler(stage);
view += stage->get_tex_view_offset();
}
if (tex == NULL) {
PT(Texture) tex = _glgsg->fetch_specified_texture(spec, sampler, view);
if (tex.is_null()) {
// Apply a white texture in order to make it easier to use a shader
// that takes a texture on a model that doesn't have a texture applied.
_glgsg->_glActiveTexture(GL_TEXTURE0 + i);
_glgsg->apply_white_texture();
continue;
}

View File

@ -478,6 +478,9 @@ cp_dependency(ShaderMatInput inp) {
if ((inp == SMO_light_ambient) ||
(inp == SMO_light_source_i_attrib)) {
dep |= SSD_light;
if (inp == SMO_light_source_i_attrib) {
dep |= SSD_transform;
}
}
if ((inp == SMO_light_product_i_ambient) ||
(inp == SMO_light_product_i_diffuse) ||
@ -976,6 +979,17 @@ compile_parameter(ShaderArgInfo &p, int *arg_dim) {
bind._arg[0] = NULL;
bind._part[1] = SMO_identity;
bind._arg[1] = NULL;
} else if (pieces[1] == "ambient") {
if (!cp_errchk_parameter_float(p,3,4)) {
return false;
}
bind._id = p._id;
bind._piece = SMP_row3;
bind._func = SMF_first;
bind._part[0] = SMO_light_ambient;
bind._arg[0] = NULL;
bind._part[1] = SMO_identity;
bind._arg[1] = NULL;
} else {
cp_report_error(p,"Unknown attr parameter.");
return false;
@ -1218,6 +1232,7 @@ compile_parameter(ShaderArgInfo &p, int *arg_dim) {
bind._id = p._id;
bind._name = 0;
bind._stage = atoi(pieces[1].c_str());
bind._part = STO_stage_i;
switch (p._type) {
case SAT_sampler1d: bind._desired_type = Texture::TT_1d_texture; break;
case SAT_sampler2d: bind._desired_type = Texture::TT_2d_texture; break;
@ -1239,6 +1254,31 @@ compile_parameter(ShaderArgInfo &p, int *arg_dim) {
return true;
}
if (pieces[0] == "shadow") {
if ((!cp_errchk_parameter_in(p)) ||
(!cp_errchk_parameter_uniform(p)) ||
(!cp_errchk_parameter_sampler(p)))
return false;
if (pieces.size() != 2) {
cp_report_error(p, "Invalid parameter name");
return false;
}
ShaderTexSpec bind;
bind._id = p._id;
bind._name = InternalName::make(pieces[1])->append("shadowMap");
bind._stage = -1;
bind._part = STO_named_input;
switch (p._type) {
case SAT_sampler2d: bind._desired_type = Texture::TT_2d_texture; break;
case SAT_sampler_cube: bind._desired_type = Texture::TT_cube_map; break;
default:
cp_report_error(p, "Invalid type for a shadow-parameter");
return false;
}
_tex_spec.push_back(bind);
return true;
}
// Keywords to fetch texture parameter data.
if (pieces[0] == "texpad") {
@ -1347,6 +1387,7 @@ compile_parameter(ShaderArgInfo &p, int *arg_dim) {
ShaderTexSpec bind;
bind._id = p._id;
bind._name = kinputname;
bind._part = STO_named_input;
bind._desired_type = Texture::TT_1d_texture;
_tex_spec.push_back(bind);
return true;
@ -1355,6 +1396,7 @@ compile_parameter(ShaderArgInfo &p, int *arg_dim) {
ShaderTexSpec bind;
bind._id = p._id;
bind._name = kinputname;
bind._part = STO_named_input;
bind._desired_type = Texture::TT_2d_texture;
_tex_spec.push_back(bind);
return true;
@ -1363,6 +1405,7 @@ compile_parameter(ShaderArgInfo &p, int *arg_dim) {
ShaderTexSpec bind;
bind._id = p._id;
bind._name = kinputname;
bind._part = STO_named_input;
bind._desired_type = Texture::TT_3d_texture;
_tex_spec.push_back(bind);
return true;
@ -1371,6 +1414,7 @@ compile_parameter(ShaderArgInfo &p, int *arg_dim) {
ShaderTexSpec bind;
bind._id = p._id;
bind._name = kinputname;
bind._part = STO_named_input;
bind._desired_type = Texture::TT_2d_texture_array;
_tex_spec.push_back(bind);
return true;
@ -1379,6 +1423,7 @@ compile_parameter(ShaderArgInfo &p, int *arg_dim) {
ShaderTexSpec bind;
bind._id = p._id;
bind._name = kinputname;
bind._part = STO_named_input;
bind._desired_type = Texture::TT_cube_map;
_tex_spec.push_back(bind);
return true;
@ -1387,6 +1432,7 @@ compile_parameter(ShaderArgInfo &p, int *arg_dim) {
ShaderTexSpec bind;
bind._id = p._id;
bind._name = kinputname;
bind._part = STO_named_input;
bind._desired_type = Texture::TT_buffer_texture;
_tex_spec.push_back(bind);
return true;
@ -1395,6 +1441,7 @@ compile_parameter(ShaderArgInfo &p, int *arg_dim) {
ShaderTexSpec bind;
bind._id = p._id;
bind._name = kinputname;
bind._part = STO_named_input;
bind._desired_type = Texture::TT_cube_map_array;
_tex_spec.push_back(bind);
return true;

View File

@ -197,6 +197,16 @@ public:
SMO_INVALID
};
enum ShaderTexInput {
STO_INVALID,
STO_named_input,
STO_named_stage,
STO_stage_i,
STO_light_i_shadow_map,
};
enum ShaderArgClass {
SAC_scalar,
SAC_vector,
@ -380,6 +390,7 @@ public:
struct ShaderTexSpec {
ShaderArgId _id;
PT(InternalName) _name;
ShaderTexInput _part;
int _stage;
int _desired_type;
PT(InternalName) _suffix;

View File

@ -227,10 +227,6 @@ public:
virtual void bind_light(Spotlight *light_obj, const NodePath &light,
int light_id) { }
// This function creates a shadow mapping buffer. This is not put in ShaderGenerator
// because that would cause circular dependencies.
virtual PT(Texture) make_shadow_buffer(const NodePath &light_np, GraphicsOutputBase *host)=0;
PUBLISHED:
static GraphicsStateGuardianBase *get_default_gsg();
static void set_default_gsg(GraphicsStateGuardianBase *default_gsg);

View File

@ -81,6 +81,13 @@ void LightLensNode::
clear_shadow_buffers() {
ShadowBuffers::iterator it;
for(it = _sbuffers.begin(); it != _sbuffers.end(); ++it) {
PT(Texture) tex = (*it).second->get_texture();
if (tex) {
// Clear it to all ones, so that any shaders that might still
// be using it will see the shadows being disabled.
tex->set_clear_color(LColor(1));
tex->clear_image();
}
(*it).first->remove_window((*it).second);
}
_sbuffers.clear();

View File

@ -204,21 +204,25 @@ analyze_renderstate(const RenderState *rs) {
// verify_enforce_attrib_lock();
_state = rs;
const AuxBitplaneAttrib *aux_bitplane = DCAST(AuxBitplaneAttrib, rs->get_attrib_def(AuxBitplaneAttrib::get_class_slot()));
const AuxBitplaneAttrib *aux_bitplane;
rs->get_attrib_def(aux_bitplane);
int outputs = aux_bitplane->get_outputs();
// Decide whether or not we need alpha testing or alpha blending.
const AlphaTestAttrib *alpha_test = DCAST(AlphaTestAttrib, rs->get_attrib_def(AlphaTestAttrib::get_class_slot()));
const AlphaTestAttrib *alpha_test;
rs->get_attrib_def(alpha_test);
if ((alpha_test->get_mode() != RenderAttrib::M_none)&&
(alpha_test->get_mode() != RenderAttrib::M_always)) {
_have_alpha_test = true;
}
const ColorBlendAttrib *color_blend = DCAST(ColorBlendAttrib, rs->get_attrib_def(ColorBlendAttrib::get_class_slot()));
const ColorBlendAttrib *color_blend;
rs->get_attrib_def(color_blend);
if (color_blend->get_mode() != ColorBlendAttrib::M_none) {
_have_alpha_blend = true;
}
const TransparencyAttrib *transparency = DCAST(TransparencyAttrib, rs->get_attrib_def(TransparencyAttrib::get_class_slot()));
const TransparencyAttrib *transparency;
rs->get_attrib_def(transparency);
if ((transparency->get_mode() == TransparencyAttrib::M_alpha)||
(transparency->get_mode() == TransparencyAttrib::M_dual)) {
_have_alpha_blend = true;
@ -257,57 +261,71 @@ analyze_renderstate(const RenderState *rs) {
// Count number of textures.
const TextureAttrib *texture = DCAST(TextureAttrib, rs->get_attrib_def(TextureAttrib::get_class_slot()));
const TextureAttrib *texture;
rs->get_attrib_def(texture);
_num_textures = texture->get_num_on_stages();
// Determine whether or not vertex colors or flat colors are present.
const ColorAttrib *color = DCAST(ColorAttrib, rs->get_attrib_def(ColorAttrib::get_class_slot()));
const ColorAttrib *color;
rs->get_attrib_def(color);
if (color->get_color_type() == ColorAttrib::T_vertex) {
_vertex_colors = true;
} else if (color->get_color_type() == ColorAttrib::T_flat) {
_flat_colors = true;
}
// Find the material.
const MaterialAttrib *material;
rs->get_attrib_def(material);
if (!material->is_off()) {
_material = material->get_material();
} else {
_material = Material::get_default();
}
// Break out the lights by type.
_shadows = false;
const LightAttrib *la = DCAST(LightAttrib, rs->get_attrib_def(LightAttrib::get_class_slot()));
for (int i=0; i<la->get_num_on_lights(); i++) {
const LightAttrib *la;
rs->get_attrib_def(la);
for (int i = 0; i < la->get_num_on_lights(); ++i) {
NodePath light = la->get_on_light(i);
nassertv(!light.is_empty());
PandaNode *light_obj = light.node();
nassertv(light_obj != (PandaNode *)NULL);
if (light_obj->get_type() == AmbientLight::get_class_type()) {
_alights_np.push_back(light);
_alights.push_back((AmbientLight*)light_obj);
}
else if (light_obj->get_type() == DirectionalLight::get_class_type()) {
_dlights_np.push_back(light);
_dlights.push_back((DirectionalLight*)light_obj);
if (DCAST(LightLensNode, light_obj)->is_shadow_caster()) {
_shadows = true;
}
}
else if (light_obj->get_type() == PointLight::get_class_type()) {
_plights_np.push_back(light);
_plights.push_back((PointLight*)light_obj);
}
else if (light_obj->get_type() == Spotlight::get_class_type()) {
_slights_np.push_back(light);
_slights.push_back((Spotlight*)light_obj);
if (_material->has_ambient()) {
LColor a = _material->get_ambient();
if ((a[0]!=0.0)||(a[1]!=0.0)||(a[2]!=0.0)) {
_have_ambient = true;
}
} else {
_have_ambient = true;
}
_lighting = true;
} else if (light_obj->is_of_type(LightLensNode::get_class_type())) {
_lights_np.push_back(light);
_lights.push_back((LightLensNode *)light_obj);
if (DCAST(LightLensNode, light_obj)->is_shadow_caster()) {
_shadows = true;
}
_lighting = true;
_need_eye_normal = true;
}
}
// See if there is a normal map, height map, gloss map, or glow map.
// Also check if anything has TexGen.
const TexGenAttrib *tex_gen = DCAST(TexGenAttrib, rs->get_attrib_def(TexGenAttrib::get_class_slot()));
for (int i=0; i<_num_textures; i++) {
const TexGenAttrib *tex_gen;
rs->get_attrib_def(tex_gen);
for (int i = 0; i < _num_textures; ++i) {
TextureStage *stage = texture->get_on_stage(i);
TextureStage::Mode mode = stage->get_mode();
if ((mode == TextureStage::M_normal)||
@ -352,43 +370,15 @@ analyze_renderstate(const RenderState *rs) {
}
}
// Determine whether lighting is needed.
if (la->get_num_on_lights() > 0) {
_lighting = true;
_need_eye_normal = true;
}
// Determine whether we should normalize the normals.
const RescaleNormalAttrib *rescale;
rs->get_attrib_def(rescale);
_normalize_normals = (rescale->get_mode() != RescaleNormalAttrib::M_none);
// Find the material.
const MaterialAttrib *material = DCAST(MaterialAttrib, rs->get_attrib_def(MaterialAttrib::get_class_slot()));
if (!material->is_off()) {
_material = material->get_material();
} else {
_material = Material::get_default();
}
// Decide which material modes need to be calculated.
if (_lighting && (_alights.size() > 0)) {
if (_material->has_ambient()) {
LColor a = _material->get_ambient();
if ((a[0]!=0.0)||(a[1]!=0.0)||(a[2]!=0.0)) {
_have_ambient = true;
}
} else {
_have_ambient = true;
}
}
if (_lighting && (_dlights.size() + _plights.size() + _slights.size())) {
if (_lighting) {
if (_material->has_diffuse()) {
LColor d = _material->get_diffuse();
if ((d[0]!=0.0)||(d[1]!=0.0)||(d[2]!=0.0)) {
@ -406,7 +396,7 @@ analyze_renderstate(const RenderState *rs) {
}
}
if (_lighting && (_dlights.size() + _plights.size() + _slights.size())) {
if (_lighting) {
if (_material->has_specular()) {
LColor s = _material->get_specular();
if ((s[0]!=0.0)||(s[1]!=0.0)||(s[2]!=0.0)) {
@ -416,12 +406,7 @@ analyze_renderstate(const RenderState *rs) {
_have_specular = true;
}
if (_plights.size() + _slights.size() > 0) {
_need_eye_position = true;
} else if (_have_specular && _material->get_local()) {
_need_eye_position = true;
}
_need_eye_position = true;
}
// Decide whether to separate ambient and diffuse calculations.
@ -442,8 +427,8 @@ analyze_renderstate(const RenderState *rs) {
}
}
const LightRampAttrib *light_ramp = DCAST(LightRampAttrib, rs->get_attrib_def(LightRampAttrib::get_class_slot()));
if (_lighting &&
const LightRampAttrib *light_ramp;
if (_lighting && rs->get_attrib(light_ramp) &&
(light_ramp->get_mode() != LightRampAttrib::LRT_identity)) {
_separate_ambient_diffuse = true;
}
@ -463,13 +448,15 @@ analyze_renderstate(const RenderState *rs) {
// Check for clip planes.
const ClipPlaneAttrib *clip_plane = DCAST(ClipPlaneAttrib, rs->get_attrib_def(ClipPlaneAttrib::get_class_slot()));
const ClipPlaneAttrib *clip_plane;
rs->get_attrib_def(clip_plane);
_num_clip_planes = clip_plane->get_num_on_planes();
if (_num_clip_planes > 0) {
_need_world_position = true;
}
const ShaderAttrib *shader_attrib = DCAST(ShaderAttrib, rs->get_attrib_def(ShaderAttrib::get_class_slot()));
const ShaderAttrib *shader_attrib;
rs->get_attrib_def(shader_attrib);
if (shader_attrib->auto_shader()) {
_auto_normal_on = shader_attrib->auto_normal_on();
_auto_glow_on = shader_attrib->auto_glow_on();
@ -479,8 +466,8 @@ analyze_renderstate(const RenderState *rs) {
}
// Check for fog.
const FogAttrib *fog = DCAST(FogAttrib, rs->get_attrib_def(FogAttrib::get_class_slot()));
if (!fog->is_off()) {
const FogAttrib *fog;
if (rs->get_attrib(fog) && !fog->is_off()) {
_fog = true;
}
}
@ -533,14 +520,8 @@ clear_analysis() {
_auto_ramp_on = false;
_auto_shadow_on = false;
_alights.clear();
_dlights.clear();
_plights.clear();
_slights.clear();
_alights_np.clear();
_dlights_np.clear();
_plights_np.clear();
_slights_np.clear();
_lights.clear();
_lights_np.clear();
}
////////////////////////////////////////////////////////////////////
@ -553,75 +534,14 @@ clear_analysis() {
CPT(RenderAttrib) ShaderGenerator::
create_shader_attrib(const string &txt) {
PT(Shader) shader = Shader::make(txt, Shader::SL_Cg);
CPT(RenderAttrib) shattr = ShaderAttrib::make();
shattr = DCAST(ShaderAttrib, shattr)->set_shader(shader);
if (_lighting) {
for (int i=0; i < (int)_alights.size(); i++) {
shattr = DCAST(ShaderAttrib, shattr)->set_shader_input(InternalName::make("alight", i), _alights_np[i]);
}
for (int i=0; i < (int)_dlights.size(); i++) {
shattr = DCAST(ShaderAttrib, shattr)->set_shader_input(InternalName::make("dlight", i), _dlights_np[i]);
if (_shadows && _dlights[i]->_shadow_caster) {
PT(Texture) tex = update_shadow_buffer(_dlights_np[i]);
if (tex == NULL) {
pgraphnodes_cat.error() << "Failed to create shadow buffer for DirectionalLight '" << _dlights[i]->get_name() << "'!\n";
}
shattr = DCAST(ShaderAttrib, shattr)->set_shader_input(InternalName::make("dlighttex", i), tex);
} else {
_dlights[i]->clear_shadow_buffers();
}
}
for (int i=0; i < (int)_plights.size(); i++) {
shattr = DCAST(ShaderAttrib, shattr)->set_shader_input(InternalName::make("plight", i), _plights_np[i]);
}
for (int i=0; i < (int)_slights.size(); i++) {
shattr = DCAST(ShaderAttrib, shattr)->set_shader_input(InternalName::make("slight", i), _slights_np[i]);
if (_shadows && _slights[i]->_shadow_caster) {
PT(Texture) tex = update_shadow_buffer(_slights_np[i]);
if (tex == NULL) {
pgraphnodes_cat.error() << "Failed to create shadow buffer for Spotlight '" << _slights[i]->get_name() << "'!\n";
}
shattr = DCAST(ShaderAttrib, shattr)->set_shader_input(InternalName::make("slighttex", i), tex);
} else {
_slights[i]->clear_shadow_buffers();
}
}
CPT(RenderAttrib) shattr = ShaderAttrib::make(shader);
for (size_t i = 0; i < _lights.size(); ++i) {
shattr = DCAST(ShaderAttrib, shattr)->set_shader_input(InternalName::make("light", i), _lights_np[i]);
}
return shattr;
}
////////////////////////////////////////////////////////////////////
// Function: ShaderGenerator::update_shadow_buffer
// Access: Protected, Virtual
// Description: Updates the depth buffer of the specified light,
// if it is configured to cast shadows.
// Only call this function for DirectionalLights
// and Spotlights. Returns the depth texture.
////////////////////////////////////////////////////////////////////
PT(Texture) ShaderGenerator::
update_shadow_buffer(NodePath light_np) {
// Make sure everything is valid.
nassertr(light_np.node()->is_of_type(DirectionalLight::get_class_type()) ||
light_np.node()->is_of_type(Spotlight::get_class_type()), NULL);
PT(LightLensNode) light = DCAST(LightLensNode, light_np.node());
if (light == NULL || !light->_shadow_caster) {
return NULL;
}
// See if we already have a buffer. If not, create one.
Texture *tex;
if (light->_sbuffers.count(_gsg) == 0) {
// Nope, the light doesn't have a buffer for our GSG. Make one.
tex = _gsg->make_shadow_buffer(light_np, _host);
} else {
// There's already a buffer - use that.
tex = light->_sbuffers[_gsg]->get_texture();
}
nassertr(tex != NULL, NULL);
return tex;
}
////////////////////////////////////////////////////////////////////
// Function: ShaderGenerator::synthesize_shader
// Access: Published, Virtual
@ -674,8 +594,7 @@ synthesize_shader(const RenderState *rs, const GeomVertexAnimationSpec &anim) {
string tangent_input;
string binormal_input;
pmap<const InternalName *, const char *> texcoord_fregs;
pvector<const char *> dlightcoord_fregs;
pvector<const char *> slightcoord_fregs;
pvector<const char *> lightcoord_fregs;
const char *world_position_freg = 0;
const char *world_normal_freg = 0;
const char *eye_position_freg = 0;
@ -790,25 +709,18 @@ synthesize_shader(const RenderState *rs, const GeomVertexAnimationSpec &anim) {
text << "\t uniform float4 mspos_view,\n";
text << "\t out float3 l_eyevec,\n";
}
if (_lighting) {
if (_shadows && _auto_shadow_on) {
for (int i=0; i < (int)_dlights.size(); i++) {
if (_dlights[i]->_shadow_caster) {
dlightcoord_fregs.push_back(alloc_freg());
text << "\t uniform float4x4 trans_model_to_clip_of_dlight" << i << ",\n";
text << "\t out float4 l_dlightcoord" << i << " : " << dlightcoord_fregs[i] << ",\n";
if (_lighting && _shadows && _auto_shadow_on) {
for (size_t i = 0; i < _lights.size(); ++i) {
if (_lights[i]->_shadow_caster) {
lightcoord_fregs.push_back(alloc_freg());
if (_lights[i]->is_of_type(PointLight::get_class_type())) {
text << "\t uniform float4x4 trans_model_to_light" << i << ",\n";
} else {
dlightcoord_fregs.push_back(NULL);
}
}
for (int i=0; i < (int)_slights.size(); i++) {
if (_slights[i]->_shadow_caster) {
slightcoord_fregs.push_back(alloc_freg());
text << "\t uniform float4x4 trans_model_to_clip_of_slight" << i << ",\n";
text << "\t out float4 l_slightcoord" << i << " : " << slightcoord_fregs[i] << ",\n";
} else {
slightcoord_fregs.push_back(NULL);
text << "\t uniform float4x4 trans_model_to_clip_of_light" << i << ",\n";
}
text << "\t out float4 l_lightcoord" << i << " : " << lightcoord_fregs[i] << ",\n";
} else {
lightcoord_fregs.push_back(NULL);
}
}
}
@ -904,14 +816,13 @@ synthesize_shader(const RenderState *rs, const GeomVertexAnimationSpec &anim) {
}
if (_shadows && _auto_shadow_on) {
text << "\t float4x4 biasmat = {0.5f, 0.0f, 0.0f, 0.5f, 0.0f, 0.5f, 0.0f, 0.5f, 0.0f, 0.0f, 0.5f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f};\n";
for (int i=0; i < (int)_dlights.size(); i++) {
if (_dlights[i]->_shadow_caster) {
text << "\t l_dlightcoord" << i << " = mul(biasmat, mul(trans_model_to_clip_of_dlight" << i << ", vtx_position));\n";
}
}
for (int i=0; i < (int)_slights.size(); i++) {
if (_slights[i]->_shadow_caster) {
text << "\t l_slightcoord" << i << " = mul(biasmat, mul(trans_model_to_clip_of_slight" << i << ", vtx_position));\n";
for (size_t i = 0; i < _lights.size(); ++i) {
if (_lights[i]->_shadow_caster) {
if (_lights[i]->is_of_type(PointLight::get_class_type())) {
text << "\t l_lightcoord" << i << " = mul(trans_model_to_light" << i << ", vtx_position);\n";
} else {
text << "\t l_lightcoord" << i << " = mul(biasmat, mul(trans_model_to_clip_of_light" << i << ", vtx_position));\n";
}
}
}
}
@ -962,33 +873,27 @@ synthesize_shader(const RenderState *rs, const GeomVertexAnimationSpec &anim) {
text << "\t in float3 l_binormal : " << binormal_freg << ",\n";
}
if (_lighting) {
for (int i=0; i < (int)_alights.size(); i++) {
text << "\t uniform float4 alight_alight" << i << ",\n";
}
for (int i=0; i < (int)_dlights.size(); i++) {
text << "\t uniform float4x4 dlight_dlight" << i << "_rel_view,\n";
if (_shadows && _dlights[i]->_shadow_caster && _auto_shadow_on) {
if (_use_shadow_filter) {
text << "\t uniform sampler2DShadow k_dlighttex" << i << ",\n";
} else {
text << "\t uniform sampler2D k_dlighttex" << i << ",\n";
}
text << "\t in float4 l_dlightcoord" << i << " : " << dlightcoord_fregs[i] << ",\n";
for (size_t i = 0; i < _lights.size(); ++i) {
if (_lights[i]->is_of_type(DirectionalLight::get_class_type())) {
text << "\t uniform float4x4 dlight_light" << i << "_rel_view,\n";
} else if (_lights[i]->is_of_type(PointLight::get_class_type())) {
text << "\t uniform float4x4 plight_light" << i << "_rel_view,\n";
} else if (_lights[i]->is_of_type(Spotlight::get_class_type())) {
text << "\t uniform float4x4 slight_light" << i << "_rel_view,\n";
text << "\t uniform float4 satten_light" << i << ",\n";
}
}
for (int i=0; i < (int)_plights.size(); i++) {
text << "\t uniform float4x4 plight_plight" << i << "_rel_view,\n";
}
for (int i=0; i < (int)_slights.size(); i++) {
text << "\t uniform float4x4 slight_slight" << i << "_rel_view,\n";
text << "\t uniform float4 satten_slight" << i << ",\n";
if (_shadows && _slights[i]->_shadow_caster && _auto_shadow_on) {
if (_use_shadow_filter) {
text << "\t uniform sampler2DShadow k_slighttex" << i << ",\n";
if (_shadows && _lights[i]->_shadow_caster && _auto_shadow_on) {
if (_lights[i]->is_of_type(PointLight::get_class_type())) {
text << "\t uniform samplerCUBE shadow_light" << i << ",\n";
} else if (_use_shadow_filter) {
text << "\t uniform sampler2DShadow shadow_light" << i << ",\n";
} else {
text << "\t uniform sampler2D k_slighttex" << i << ",\n";
text << "\t uniform sampler2D shadow_light" << i << ",\n";
}
text << "\t in float4 l_slightcoord" << i << " : " << slightcoord_fregs[i] << ",\n";
text << "\t in float4 l_lightcoord" << i << " : " << lightcoord_fregs[i] << ",\n";
}
}
if (_need_material_props) {
@ -1017,6 +922,7 @@ synthesize_shader(const RenderState *rs, const GeomVertexAnimationSpec &anim) {
for (int i=0; i<_num_clip_planes; ++i) {
text << "\t uniform float4 clipplane_" << i << ",\n";
}
text << "\t uniform float4 attr_ambient,\n";
text << "\t uniform float4 attr_colorscale\n";
text << ") {\n";
// Clipping first!
@ -1149,7 +1055,8 @@ synthesize_shader(const RenderState *rs, const GeomVertexAnimationSpec &anim) {
if (_lighting) {
text << "\t // Begin view-space light calculations\n";
text << "\t float ldist,lattenv,langle;\n";
text << "\t float4 lcolor,lspec,lvec,lpoint,latten,ldir,leye,lhalf;\n";
text << "\t float4 lcolor,lspec,lpoint,latten,ldir,leye;\n";
text << "\t float3 lvec,lhalf;\n";
if (_shadows && _auto_shadow_on) {
text << "\t float lshad;\n";
}
@ -1173,26 +1080,24 @@ synthesize_shader(const RenderState *rs, const GeomVertexAnimationSpec &anim) {
text << "\t float shininess = 50; // no shininess specified, using default\n";
}
}
for (int i=0; i < (int)_alights.size(); i++) {
text << "\t // Ambient Light " << i << "\n";
text << "\t lcolor = alight_alight" << i << ";\n";
if (_separate_ambient_diffuse && _have_ambient) {
text << "\t tot_ambient += lcolor;\n";
} else if(_have_diffuse) {
text << "\t tot_diffuse += lcolor;\n";
}
if (_separate_ambient_diffuse && _have_ambient) {
text << "\t tot_ambient += attr_ambient;\n";
} else if(_have_diffuse) {
text << "\t tot_diffuse += attr_ambient;\n";
}
for (int i=0; i < (int)_dlights.size(); i++) {
}
for (size_t i = 0; i < _lights.size(); ++i) {
if (_lights[i]->is_of_type(DirectionalLight::get_class_type())) {
text << "\t // Directional Light " << i << "\n";
text << "\t lcolor = dlight_dlight" << i << "_rel_view[0];\n";
text << "\t lspec = dlight_dlight" << i << "_rel_view[1];\n";
text << "\t lvec = dlight_dlight" << i << "_rel_view[2];\n";
text << "\t lcolor = dlight_light" << i << "_rel_view[0];\n";
text << "\t lspec = dlight_light" << i << "_rel_view[1];\n";
text << "\t lvec = dlight_light" << i << "_rel_view[2].xyz;\n";
text << "\t lcolor *= saturate(dot(l_eye_normal.xyz, lvec.xyz));\n";
if (_shadows && _dlights[i]->_shadow_caster && _auto_shadow_on) {
if (_shadows && _lights[i]->_shadow_caster && _auto_shadow_on) {
if (_use_shadow_filter) {
text << "\t lshad = shadow2DProj(k_dlighttex" << i << ", l_dlightcoord" << i << ").r;\n";
text << "\t lshad = shadow2DProj(shadow_light" << i << ", l_lightcoord" << i << ").r;\n";
} else {
text << "\t lshad = tex2Dproj(k_dlighttex" << i << ", l_dlightcoord" << i << ").r > l_dlightcoord" << i << ".z / l_dlightcoord" << i << ".w;\n";
text << "\t lshad = tex2Dproj(shadow_light" << i << ", l_lightcoord" << i << ").r > l_lightcoord" << i << ".z / l_lightcoord" << i << ".w;\n";
}
text << "\t lcolor *= lshad;\n";
text << "\t lspec *= lshad;\n";
@ -1202,59 +1107,64 @@ synthesize_shader(const RenderState *rs, const GeomVertexAnimationSpec &anim) {
}
if (_have_specular) {
if (_material->get_local()) {
text << "\t lhalf = normalize(lvec - normalize(l_eye_position));\n";
text << "\t lhalf = normalize(lvec - normalize(l_eye_position.xyz));\n";
} else {
text << "\t lhalf = dlight_dlight" << i << "_rel_view[3];\n";
text << "\t lhalf = dlight_light" << i << "_rel_view[3].xyz;\n";
}
text << "\t lspec *= pow(saturate(dot(l_eye_normal.xyz, lhalf.xyz)), shininess);\n";
text << "\t lspec *= pow(saturate(dot(l_eye_normal.xyz, lhalf)), shininess);\n";
text << "\t tot_specular += lspec;\n";
}
}
for (int i=0; i < (int)_plights.size(); i++) {
} else if (_lights[i]->is_of_type(PointLight::get_class_type())) {
text << "\t // Point Light " << i << "\n";
text << "\t lcolor = plight_plight" << i << "_rel_view[0];\n";
text << "\t lspec = plight_plight" << i << "_rel_view[1];\n";
text << "\t lpoint = plight_plight" << i << "_rel_view[2];\n";
text << "\t latten = plight_plight" << i << "_rel_view[3];\n";
text << "\t lvec = lpoint - l_eye_position;\n";
text << "\t ldist = length(float3(lvec));\n";
text << "\t lcolor = plight_light" << i << "_rel_view[0];\n";
text << "\t lspec = plight_light" << i << "_rel_view[1];\n";
text << "\t lpoint = plight_light" << i << "_rel_view[2];\n";
text << "\t latten = plight_light" << i << "_rel_view[3];\n";
text << "\t lvec = lpoint.xyz - l_eye_position.xyz;\n";
text << "\t ldist = length(lvec);\n";
text << "\t lvec /= ldist;\n";
text << "\t lattenv = 1/(latten.x + latten.y*ldist + latten.z*ldist*ldist);\n";
text << "\t lcolor *= lattenv * saturate(dot(l_eye_normal.xyz, lvec.xyz));\n";
text << "\t lcolor *= lattenv * saturate(dot(l_eye_normal.xyz, lvec));\n";
if (_shadows && _lights[i]->_shadow_caster && _auto_shadow_on) {
text << "\t ldist = max(abs(l_lightcoord" << i << ".x), max(abs(l_lightcoord" << i << ".y), abs(l_lightcoord" << i << ".z)));\n";
text << "\t ldist = ((latten.w+lpoint.w)/(latten.w-lpoint.w))+((-2*latten.w*lpoint.w)/(ldist * (latten.w-lpoint.w)));\n";
text << "\t lshad = texCUBE(shadow_light" << i << ", l_lightcoord" << i << ".xyz).r >= ldist * 0.5 + 0.5;\n";
text << "\t lcolor *= lshad;\n";
text << "\t lspec *= lshad;\n";
}
if (_have_diffuse) {
text << "\t tot_diffuse += lcolor;\n";
}
if (_have_specular) {
if (_material->get_local()) {
text << "\t lhalf = normalize(lvec - normalize(l_eye_position));\n";
text << "\t lhalf = normalize(lvec - normalize(l_eye_position.xyz));\n";
} else {
text << "\t lhalf = normalize(lvec - float4(0, 1, 0, 0));\n";
text << "\t lhalf = normalize(lvec - float3(0, 1, 0));\n";
}
text << "\t lspec *= lattenv;\n";
text << "\t lspec *= pow(saturate(dot(l_eye_normal.xyz, lhalf.xyz)), shininess);\n";
text << "\t lspec *= pow(saturate(dot(l_eye_normal.xyz, lhalf)), shininess);\n";
text << "\t tot_specular += lspec;\n";
}
}
for (int i=0; i < (int)_slights.size(); i++) {
} else if (_lights[i]->is_of_type(Spotlight::get_class_type())) {
text << "\t // Spot Light " << i << "\n";
text << "\t lcolor = slight_slight" << i << "_rel_view[0];\n";
text << "\t lspec = slight_slight" << i << "_rel_view[1];\n";
text << "\t lpoint = slight_slight" << i << "_rel_view[2];\n";
text << "\t ldir = slight_slight" << i << "_rel_view[3];\n";
text << "\t latten = satten_slight" << i << ";\n";
text << "\t lvec = lpoint - l_eye_position;\n";
text << "\t ldist = length(float3(lvec));\n";
text << "\t lcolor = slight_light" << i << "_rel_view[0];\n";
text << "\t lspec = slight_light" << i << "_rel_view[1];\n";
text << "\t lpoint = slight_light" << i << "_rel_view[2];\n";
text << "\t ldir = slight_light" << i << "_rel_view[3];\n";
text << "\t latten = satten_light" << i << ";\n";
text << "\t lvec = lpoint.xyz - l_eye_position.xyz;\n";
text << "\t ldist = length(lvec);\n";
text << "\t lvec /= ldist;\n";
text << "\t langle = saturate(dot(ldir.xyz, lvec.xyz));\n";
text << "\t langle = saturate(dot(ldir.xyz, lvec));\n";
text << "\t lattenv = 1/(latten.x + latten.y*ldist + latten.z*ldist*ldist);\n";
text << "\t lattenv *= pow(langle, latten.w);\n";
text << "\t if (langle < ldir.w) lattenv = 0;\n";
text << "\t lcolor *= lattenv * saturate(dot(l_eye_normal.xyz, lvec.xyz));\n";
if (_shadows && _slights[i]->_shadow_caster && _auto_shadow_on) {
text << "\t lcolor *= lattenv * saturate(dot(l_eye_normal.xyz, lvec));\n";
if (_shadows && _lights[i]->_shadow_caster && _auto_shadow_on) {
if (_use_shadow_filter) {
text << "\t lshad = shadow2DProj(k_slighttex" << i << ", l_slightcoord" << i << ").r;\n";
text << "\t lshad = shadow2DProj(shadow_light" << i << ", l_lightcoord" << i << ").r;\n";
} else {
text << "\t lshad = tex2Dproj(k_slighttex" << i << ", l_slightcoord" << i << ").r > l_slightcoord" << i << ".z / l_slightcoord" << i << ".w;\n";
text << "\t lshad = tex2Dproj(shadow_light" << i << ", l_lightcoord" << i << ").r > l_lightcoord" << i << ".z / l_lightcoord" << i << ".w;\n";
}
text << "\t lcolor *= lshad;\n";
text << "\t lspec *= lshad;\n";
@ -1265,15 +1175,17 @@ synthesize_shader(const RenderState *rs, const GeomVertexAnimationSpec &anim) {
}
if (_have_specular) {
if (_material->get_local()) {
text << "\t lhalf = normalize(lvec - normalize(l_eye_position));\n";
text << "\t lhalf = normalize(lvec - normalize(l_eye_position.xyz));\n";
} else {
text << "\t lhalf = normalize(lvec - float4(0,1,0,0));\n";
text << "\t lhalf = normalize(lvec - float3(0,1,0));\n";
}
text << "\t lspec *= lattenv;\n";
text << "\t lspec *= pow(saturate(dot(l_eye_normal.xyz, lhalf.xyz)), shininess);\n";
text << "\t lspec *= pow(saturate(dot(l_eye_normal.xyz, lhalf)), shininess);\n";
text << "\t tot_specular += lspec;\n";
}
}
}
if (_lighting) {
const LightRampAttrib *light_ramp = DCAST(LightRampAttrib, rs->get_attrib_def(LightRampAttrib::get_class_slot()));
if (_auto_ramp_on && _have_diffuse) {
switch (light_ramp->get_mode()) {

View File

@ -77,7 +77,6 @@ PUBLISHED:
protected:
CPT(RenderAttrib) create_shader_attrib(const string &txt);
PT(Texture) update_shadow_buffer(NodePath light_np);
static const string combine_mode_as_string(CPT(TextureStage) stage,
TextureStage::CombineMode c_mode, bool alpha, short texindex);
static const string combine_source_as_string(CPT(TextureStage) stage,
@ -101,14 +100,8 @@ protected:
Material *_material;
int _num_textures;
pvector <AmbientLight *> _alights;
pvector <DirectionalLight *> _dlights;
pvector <PointLight *> _plights;
pvector <Spotlight *> _slights;
pvector <NodePath> _alights_np;
pvector <NodePath> _dlights_np;
pvector <NodePath> _plights_np;
pvector <NodePath> _slights_np;
pvector<LightLensNode *> _lights;
pvector<NodePath> _lights_np;
bool _vertex_colors;
bool _flat_colors;