diff --git a/panda/src/display/config_display.cxx b/panda/src/display/config_display.cxx index 0d219273e5..a62e6a4fb0 100644 --- a/panda/src/display/config_display.cxx +++ b/panda/src/display/config_display.cxx @@ -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 " diff --git a/panda/src/display/config_display.h b/panda/src/display/config_display.h index be71d0b63d..23afbf578f 100644 --- a/panda/src/display/config_display.h +++ b/panda/src/display/config_display.h @@ -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; diff --git a/panda/src/display/graphicsEngine.cxx b/panda/src/display/graphicsEngine.cxx index c7fd463e76..71ad115e8c 100644 --- a/panda/src/display/graphicsEngine.cxx +++ b/panda/src/display/graphicsEngine.cxx @@ -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 AlreadyCulled; + typedef pair CullKey; + typedef pmap 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. diff --git a/panda/src/display/graphicsStateGuardian.cxx b/panda/src/display/graphicsStateGuardian.cxx index 9ccb360443..75a238b06e 100644 --- a/panda/src/display/graphicsStateGuardian.cxx +++ b/panda/src/display/graphicsStateGuardian.cxx @@ -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); } diff --git a/panda/src/display/graphicsStateGuardian.h b/panda/src/display/graphicsStateGuardian.h index fccee6ca8f..8e7867b583 100644 --- a/panda/src/display/graphicsStateGuardian.h +++ b/panda/src/display/graphicsStateGuardian.h @@ -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(); diff --git a/panda/src/glstuff/glCgShaderContext_src.cxx b/panda/src/glstuff/glCgShaderContext_src.cxx index e861703f5b..1502b2dd8d 100644 --- a/panda/src/glstuff/glCgShaderContext_src.cxx +++ b/panda/src/glstuff/glCgShaderContext_src.cxx @@ -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) { diff --git a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx b/panda/src/glstuff/glGraphicsStateGuardian_src.cxx index 36ff0dec8e..d57778f53b 100644 --- a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx +++ b/panda/src/glstuff/glGraphicsStateGuardian_src.cxx @@ -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(); diff --git a/panda/src/glstuff/glShaderContext_src.cxx b/panda/src/glstuff/glShaderContext_src.cxx index 9bd2fd73ef..924ae98b2d 100644 --- a/panda/src/glstuff/glShaderContext_src.cxx +++ b/panda/src/glstuff/glShaderContext_src.cxx @@ -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; } diff --git a/panda/src/gobj/shader.cxx b/panda/src/gobj/shader.cxx index 1f126108c3..97717f591b 100644 --- a/panda/src/gobj/shader.cxx +++ b/panda/src/gobj/shader.cxx @@ -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; diff --git a/panda/src/gobj/shader.h b/panda/src/gobj/shader.h index 250b7915c7..f376740da2 100644 --- a/panda/src/gobj/shader.h +++ b/panda/src/gobj/shader.h @@ -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; diff --git a/panda/src/gsgbase/graphicsStateGuardianBase.h b/panda/src/gsgbase/graphicsStateGuardianBase.h index 8cbccf25a3..96d5ed310b 100644 --- a/panda/src/gsgbase/graphicsStateGuardianBase.h +++ b/panda/src/gsgbase/graphicsStateGuardianBase.h @@ -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); diff --git a/panda/src/pgraphnodes/lightLensNode.cxx b/panda/src/pgraphnodes/lightLensNode.cxx index c26f0cd9c4..4116998a80 100644 --- a/panda/src/pgraphnodes/lightLensNode.cxx +++ b/panda/src/pgraphnodes/lightLensNode.cxx @@ -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(); diff --git a/panda/src/pgraphnodes/shaderGenerator.cxx b/panda/src/pgraphnodes/shaderGenerator.cxx index 56527b0298..702b9f3130 100644 --- a/panda/src/pgraphnodes/shaderGenerator.cxx +++ b/panda/src/pgraphnodes/shaderGenerator.cxx @@ -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; iget_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 texcoord_fregs; - pvector dlightcoord_fregs; - pvector slightcoord_fregs; + pvector 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()) { diff --git a/panda/src/pgraphnodes/shaderGenerator.h b/panda/src/pgraphnodes/shaderGenerator.h index f10115b970..50c35d2d89 100644 --- a/panda/src/pgraphnodes/shaderGenerator.h +++ b/panda/src/pgraphnodes/shaderGenerator.h @@ -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 _alights; - pvector _dlights; - pvector _plights; - pvector _slights; - pvector _alights_np; - pvector _dlights_np; - pvector _plights_np; - pvector _slights_np; + pvector _lights; + pvector _lights_np; bool _vertex_colors; bool _flat_colors;