From 005bc25282e46a493f9575193c7a4e2df1091fe6 Mon Sep 17 00:00:00 2001 From: Josh Yelon Date: Mon, 4 Feb 2008 22:49:48 +0000 Subject: [PATCH] Added light ramps and gloss maps --- panda/src/pgraph/Sources.pp | 3 + panda/src/pgraph/attribSlots.I | 1 + panda/src/pgraph/attribSlots.cxx | 61 ++------ panda/src/pgraph/attribSlots.h | 7 +- panda/src/pgraph/config_pgraph.cxx | 3 + panda/src/pgraph/pgraph_composite3.cxx | 1 + panda/src/pgraph/shaderGenerator.cxx | 188 +++++++++++++++++-------- panda/src/pgraph/shaderGenerator.h | 4 +- 8 files changed, 160 insertions(+), 108 deletions(-) diff --git a/panda/src/pgraph/Sources.pp b/panda/src/pgraph/Sources.pp index b7154386ec..3c40c81653 100644 --- a/panda/src/pgraph/Sources.pp +++ b/panda/src/pgraph/Sources.pp @@ -61,6 +61,7 @@ lensNode.I lensNode.h \ light.I light.h \ lightAttrib.I lightAttrib.h \ + lightRampAttrib.I lightRampAttrib.h \ lightLensNode.I lightLensNode.h \ lightNode.I lightNode.h \ loader.I loader.h \ @@ -172,6 +173,7 @@ lensNode.cxx \ light.cxx \ lightAttrib.cxx \ + lightRampAttrib.cxx \ lightLensNode.cxx \ lightNode.cxx \ loader.cxx \ @@ -278,6 +280,7 @@ lensNode.I lensNode.h \ light.I light.h \ lightAttrib.I lightAttrib.h \ + lightRampAttrib.I lightRampAttrib.h \ lightLensNode.I lightLensNode.h \ lightNode.I lightNode.h \ loader.I loader.h \ diff --git a/panda/src/pgraph/attribSlots.I b/panda/src/pgraph/attribSlots.I index 91aea86da2..cb2b18a886 100644 --- a/panda/src/pgraph/attribSlots.I +++ b/panda/src/pgraph/attribSlots.I @@ -26,6 +26,7 @@ INLINE void AttribSlots:: clear_to_zero() { _alpha_test = NULL; _antialias = NULL; + _audio_volume = NULL; _clip_plane = NULL; _color = NULL; _color_blend = NULL; diff --git a/panda/src/pgraph/attribSlots.cxx b/panda/src/pgraph/attribSlots.cxx index 1039ba9fa7..549c0f75f8 100644 --- a/panda/src/pgraph/attribSlots.cxx +++ b/panda/src/pgraph/attribSlots.cxx @@ -47,6 +47,7 @@ initialize_defvals() { _defvals._depth_write = DCAST(DepthWriteAttrib,DepthWriteAttrib::make(DepthWriteAttrib::M_on)); _defvals._fog = DCAST(FogAttrib,FogAttrib::make_off()); _defvals._light = DCAST(LightAttrib,LightAttrib::make_all_off()); + _defvals._light_ramp = DCAST(LightRampAttrib,LightRampAttrib::make_identity()); _defvals._material = DCAST(MaterialAttrib,MaterialAttrib::make_off()); _defvals._render_mode = DCAST(RenderModeAttrib,RenderModeAttrib::make(RenderModeAttrib::M_unchanged)); _defvals._rescale_normal = DCAST(RescaleNormalAttrib,RescaleNormalAttrib::make_default()); @@ -75,6 +76,7 @@ initialize_defvals() { _defvals._depth_write = DCAST(DepthWriteAttrib,_defvals._depth_write->make_default()); _defvals._fog = DCAST(FogAttrib,_defvals._fog->make_default()); _defvals._light = DCAST(LightAttrib,_defvals._light->make_default()); + _defvals._light_ramp = DCAST(LightRampAttrib,_defvals._light_ramp->make_default()); _defvals._material = DCAST(MaterialAttrib,_defvals._material->make_default()); _defvals._render_mode = DCAST(RenderModeAttrib,_defvals._render_mode->make_default()); _defvals._rescale_normal = DCAST(RescaleNormalAttrib,_defvals._rescale_normal->make_default()); @@ -118,6 +120,7 @@ AttribSlots(const AttribSlots ©) : _depth_write(copy._depth_write), _fog(copy._fog), _light(copy._light), + _light_ramp(copy._light_ramp), _material(copy._material), _render_mode(copy._render_mode), _rescale_normal(copy._rescale_normal), @@ -153,6 +156,7 @@ operator =(const AttribSlots &src) { _depth_write = src._depth_write; _fog = src._fog; _light = src._light; + _light_ramp = src._light_ramp; _material = src._material; _render_mode = src._render_mode; _rescale_normal = src._rescale_normal; @@ -188,55 +192,20 @@ get_slot(int n) const { case 12: return DCAST(RenderAttrib, _depth_write); case 13: return DCAST(RenderAttrib, _fog); case 14: return DCAST(RenderAttrib, _light); - case 15: return DCAST(RenderAttrib, _material); - case 16: return DCAST(RenderAttrib, _render_mode); - case 17: return DCAST(RenderAttrib, _rescale_normal); - case 18: return DCAST(RenderAttrib, _shade_model); - case 19: return DCAST(RenderAttrib, _shader); - case 20: return DCAST(RenderAttrib, _stencil); - case 21: return DCAST(RenderAttrib, _tex_gen); - case 22: return DCAST(RenderAttrib, _tex_matrix); - case 23: return DCAST(RenderAttrib, _texture); - case 24: return DCAST(RenderAttrib, _transparency); + case 15: return DCAST(RenderAttrib, _light_ramp); + case 16: return DCAST(RenderAttrib, _material); + case 17: return DCAST(RenderAttrib, _render_mode); + case 18: return DCAST(RenderAttrib, _rescale_normal); + case 19: return DCAST(RenderAttrib, _shade_model); + case 20: return DCAST(RenderAttrib, _shader); + case 21: return DCAST(RenderAttrib, _stencil); + case 22: return DCAST(RenderAttrib, _tex_gen); + case 23: return DCAST(RenderAttrib, _tex_matrix); + case 24: return DCAST(RenderAttrib, _texture); + case 25: return DCAST(RenderAttrib, _transparency); default: nassertr(false, NULL); return NULL; } } -//////////////////////////////////////////////////////////////////// -// Function: AttribSlots::set_slot -// Access: Public -// Description: set the contents of the nth slot. -//////////////////////////////////////////////////////////////////// -void AttribSlots:: -set_slot(int n, const RenderAttrib *val) { - switch(n) { - case 0: _alpha_test = DCAST(AlphaTestAttrib, val); break; - case 1: _antialias = DCAST(AntialiasAttrib, val); break; - case 2: _audio_volume = DCAST(AudioVolumeAttrib, val); break; - case 3: _clip_plane = DCAST(ClipPlaneAttrib, val); break; - case 4: _color = DCAST(ColorAttrib, val); break; - case 5: _color_blend = DCAST(ColorBlendAttrib, val); break; - case 6: _color_scale = DCAST(ColorScaleAttrib, val); break; - case 7: _color_write = DCAST(ColorWriteAttrib, val); break; - case 8: _cull_bin = DCAST(CullBinAttrib, val); break; - case 9: _cull_face = DCAST(CullFaceAttrib, val); break; - case 10: _depth_offset = DCAST(DepthOffsetAttrib, val); break; - case 11: _depth_test = DCAST(DepthTestAttrib, val); break; - case 12: _depth_write = DCAST(DepthWriteAttrib, val); break; - case 13: _fog = DCAST(FogAttrib, val); break; - case 14: _light = DCAST(LightAttrib, val); break; - case 15: _material = DCAST(MaterialAttrib, val); break; - case 16: _render_mode = DCAST(RenderModeAttrib, val); break; - case 17: _rescale_normal = DCAST(RescaleNormalAttrib, val); break; - case 18: _shade_model = DCAST(ShadeModelAttrib, val); break; - case 19: _shader = DCAST(ShaderAttrib, val); break; - case 20: _stencil = DCAST(StencilAttrib, val); break; - case 21: _tex_gen = DCAST(TexGenAttrib, val); break; - case 22: _tex_matrix = DCAST(TexMatrixAttrib, val); break; - case 23: _texture = DCAST(TextureAttrib, val); break; - case 24: _transparency = DCAST(TransparencyAttrib, val); break; - default: nassertv(false); - } -} diff --git a/panda/src/pgraph/attribSlots.h b/panda/src/pgraph/attribSlots.h index 2e5c230c06..64248105ac 100644 --- a/panda/src/pgraph/attribSlots.h +++ b/panda/src/pgraph/attribSlots.h @@ -26,6 +26,7 @@ #include "renderAttrib.h" #include "alphaTestAttrib.h" #include "antialiasAttrib.h" +#include "audioVolumeAttrib.h" #include "clipPlaneAttrib.h" #include "colorAttrib.h" #include "colorBlendAttrib.h" @@ -38,6 +39,7 @@ #include "depthWriteAttrib.h" #include "fogAttrib.h" #include "lightAttrib.h" +#include "lightRampAttrib.h" #include "materialAttrib.h" #include "renderModeAttrib.h" #include "rescaleNormalAttrib.h" @@ -48,7 +50,6 @@ #include "texGenAttrib.h" #include "textureAttrib.h" #include "transparencyAttrib.h" -#include "audioVolumeAttrib.h" //////////////////////////////////////////////////////////////////// // Class : AttribSlots @@ -74,6 +75,7 @@ class EXPCL_PANDA_PGRAPH AttribSlots CPT(DepthWriteAttrib) _depth_write; CPT(FogAttrib) _fog; CPT(LightAttrib) _light; + CPT(LightRampAttrib) _light_ramp; CPT(MaterialAttrib) _material; CPT(RenderModeAttrib) _render_mode; CPT(RescaleNormalAttrib) _rescale_normal; @@ -95,9 +97,8 @@ class EXPCL_PANDA_PGRAPH AttribSlots public: // Each "array" reference requires a switch and a DCAST, so it's not overly fast. - enum { slot_count=24 }; + enum { slot_count=26 }; const RenderAttrib *get_slot(int n) const; - void set_slot(int n, const RenderAttrib *attrib); private: static AttribSlots _defvals; diff --git a/panda/src/pgraph/config_pgraph.cxx b/panda/src/pgraph/config_pgraph.cxx index 4530d310b9..bb74872e9e 100644 --- a/panda/src/pgraph/config_pgraph.cxx +++ b/panda/src/pgraph/config_pgraph.cxx @@ -53,6 +53,7 @@ #include "lensNode.h" #include "light.h" #include "lightAttrib.h" +#include "lightRampAttrib.h" #include "lightLensNode.h" #include "lightNode.h" #include "loader.h" @@ -403,6 +404,7 @@ init_libpgraph() { LensNode::init_type(); Light::init_type(); LightAttrib::init_type(); + LightRampAttrib::init_type(); LightLensNode::init_type(); LightNode::init_type(); Loader::init_type(); @@ -482,6 +484,7 @@ init_libpgraph() { GeomNode::register_with_read_factory(); LensNode::register_with_read_factory(); LightAttrib::register_with_read_factory(); + LightRampAttrib::register_with_read_factory(); LODNode::register_with_read_factory(); MaterialAttrib::register_with_read_factory(); ModelNode::register_with_read_factory(); diff --git a/panda/src/pgraph/pgraph_composite3.cxx b/panda/src/pgraph/pgraph_composite3.cxx index c713f1681a..d59094a10c 100644 --- a/panda/src/pgraph/pgraph_composite3.cxx +++ b/panda/src/pgraph/pgraph_composite3.cxx @@ -2,6 +2,7 @@ #include "lensNode.cxx" #include "light.cxx" #include "lightAttrib.cxx" +#include "lightRampAttrib.cxx" #include "lightLensNode.cxx" #include "lightNode.cxx" #include "loader.cxx" diff --git a/panda/src/pgraph/shaderGenerator.cxx b/panda/src/pgraph/shaderGenerator.cxx index 91daf8f209..53c115a44b 100644 --- a/panda/src/pgraph/shaderGenerator.cxx +++ b/panda/src/pgraph/shaderGenerator.cxx @@ -15,41 +15,6 @@ // panda3d-general@lists.sourceforge.net . // //////////////////////////////////////////////////////////////////// -// -// Lighting calculations. These can be done either in tangent space -// or model space. Doing them in tangent space is necessary for -// normal mapping. However, it is only possible if tangents have -// been computed. If not, then model space is the only option. -// The parameters needed for lighting are: -// -// Model Space: -// -// vshader: -// model-space normal - varying -// model-space vertex position - varying -// fshader: -// model-space normal - varying -// model-space vertex position - varying -// model-space light position (spot or point) - uniform -// model-space light vector (directional) - uniform -// model-space eye position - uniform -// -// Tangent Space: -// -// vshader: -// model-space normal - varying -// model-space tangent - varying -// model-space binormal - varying -// model-space light position (spot or point) - uniform -// model-space light vector (directional) - uniform -// model-space eye position - uniform -// fshader: -// model-space vertex position - varying -// tangent-space light vector, one per light - varying -// tangent-space eye vector - varying -// model-space light position (spot) - uniform -// -///////////////////////////////////////////////////////////////////// #include "renderState.h" @@ -244,7 +209,7 @@ analyze_renderstate(const RenderState *rs) { } } - // Determine whether model-space or tangent-space lighting is recommended. + // Determine whether lighting is needed. if (_attribs._light->get_num_on_lights() > 0) { _lighting = true; @@ -295,9 +260,36 @@ analyze_renderstate(const RenderState *rs) { if ((s[0]!=0.0)||(s[1]!=0.0)||(s[2]!=0.0)) { _have_specular = true; } + } else if (_map_index_gloss >= 0) { + _have_specular = true; } } + // Decide whether to separate ambient and diffuse calculations. + + if (_have_ambient && _have_diffuse) { + if (_material->has_ambient()) { + if (_material->has_diffuse()) { + _separate_ambient_diffuse = _material->get_ambient() != _material->get_diffuse(); + } else { + _separate_ambient_diffuse = true; + } + } else { + if (_material->has_diffuse()) { + _separate_ambient_diffuse = true; + } else { + _separate_ambient_diffuse = false; + } + } + } + + if (_attribs._light_ramp->get_mode() != LightRampAttrib::LRT_identity) { + if (_separate_ambient_diffuse) { + pgraph_cat.error() << "Light Ramp incompatible with separate ambient/diffuse\n"; + _separate_ambient_diffuse = false; + } + } + // Does the shader need material properties as input? _need_material_props = @@ -325,6 +317,7 @@ clear_analysis() { _have_diffuse = false; _have_emission = false; _have_specular = false; + _separate_ambient_diffuse = false; _map_index_normal = -1; _map_index_height = -1; _map_index_glow = -1; @@ -381,18 +374,22 @@ create_shader_attrib(const string &txt) { // - vertex colors // - lighting // - normal maps +// - gloss maps // - materials, but not updates to materials // - modulated 2D textures +// - texture stage modes: modulate, decal, add +// - light ramps (for cartoon shading) // // Not yet supported: // - 3D textures // - cube textures -// - texture stage modes: decal, blend, replace, add, etc. +// - texture stage modes: replace, blend // - color scale attrib // - texgen // - texmatrix -// - gloss maps -// - glow maps +// - glow maps (not yet sure what these should do) +// - other TextureStage::Modes +// - cartoon thresholding and other special effects // //////////////////////////////////////////////////////////////////// CPT(RenderAttrib) ShaderGenerator:: @@ -527,16 +524,6 @@ synthesize_shader(const RenderState *rs) { } if (_lighting) { - text << "\t // Begin model-space light calculations\n"; - if (_have_ambient) { - text << "\t float4 tot_ambient = float4(0,0,0,0);\n"; - } - if (_have_diffuse) { - text << "\t float4 tot_diffuse = float4(0,0,0,0);\n"; - } - if (_have_specular) { - text << "\t float4 tot_specular = float4(0,0,0,0);\n"; - } if (_map_index_normal) { text << "\t // Translate tangent-space normal in map to model-space.\n"; text << "\t float3 tsnormal = ((float3)tex" << _map_index_normal << " * 2) - 1;\n"; @@ -545,14 +532,40 @@ synthesize_shader(const RenderState *rs) { text << "\t l_normal+= l_binormal * tsnormal.y;\n"; text << "\t l_normal = normalize(l_normal);\n"; } else { + text << "\t // Correct the surface normal for interpolation effects\n"; text << "\t l_normal = normalize(l_normal);\n"; } + text << "\t // Begin model-space light calculations\n"; text << "\t float ldist,lattenv,langle;\n"; text << "\t float4 lcolor,lspec,lvec,lpoint,latten,ldir,leye,lhalf;\n"; + if (_separate_ambient_diffuse) { + if (_have_ambient) { + text << "\t float4 tot_ambient = float4(0,0,0,0);\n"; + } + if (_have_diffuse) { + text << "\t float4 tot_diffuse = float4(0,0,0,0);\n"; + } + } else { + if (_have_ambient || _have_diffuse) { + text << "\t float4 tot_diffuse = float4(0,0,0,0);\n"; + } + } + if (_have_specular) { + text << "\t float4 tot_specular = float4(0,0,0,0);\n"; + if (_material->has_specular()) { + text << "\t float shininess = attr_material[3].w;\n"; + } else { + 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"; - text << "\t tot_ambient += lcolor;\n"; + if (_separate_ambient_diffuse) { + text << "\t tot_ambient += lcolor;\n"; + } else { + text << "\t tot_diffuse += lcolor;\n"; + } } for (int i=0; i<(int)_dlights.size(); i++) { text << "\t // Directional Light " << i << "\n"; @@ -567,7 +580,7 @@ synthesize_shader(const RenderState *rs) { } else { text << "\t lhalf = dlight_dlight" << i << "_rel_model[3];\n"; } - text << "\t lspec *= pow(saturate(dot(l_normal, lhalf.xyz)), attr_material[3].w);\n"; + text << "\t lspec *= pow(saturate(dot(l_normal, lhalf.xyz)), shininess);\n"; text << "\t tot_specular += lspec;\n"; } } @@ -590,7 +603,7 @@ synthesize_shader(const RenderState *rs) { text << "\t lhalf = normalize(lvec - row1_view_to_model);\n"; } text << "\t lspec *= lattenv;\n"; - text << "\t lspec *= pow(saturate(dot(l_normal, lhalf.xyz)), attr_material[3].w);\n"; + text << "\t lspec *= pow(saturate(dot(l_normal, lhalf.xyz)), shininess);\n"; text << "\t tot_specular += lspec;\n"; } } @@ -617,18 +630,47 @@ synthesize_shader(const RenderState *rs) { text << "\t lhalf = normalize(lvec - row1_view_to_model);\n"; } text << "\t lspec *= lattenv;\n"; - text << "\t lspec *= pow(saturate(dot(l_normal, lhalf.xyz)), attr_material[3].w);\n"; + text << "\t lspec *= pow(saturate(dot(l_normal, lhalf.xyz)), shininess);\n"; text << "\t tot_specular += lspec;\n"; } } + switch (_attribs._light_ramp->get_mode()) { + case LightRampAttrib::LRT_identity: + break; + case LightRampAttrib::LRT_single_threshold: + { + float t = _attribs._light_ramp->get_threshold(0); + float l0 = _attribs._light_ramp->get_level(0); + float l1 = _attribs._light_ramp->get_level(1); + text << "\t // Single-threshold light ramp\n"; + text << "\t float lr_in = dot(tot_diffuse.rgb, float3(0.33,0.34,0.33));\n"; + text << "\t float lr_out = (lr_in < " << t << ") ? " << l0 << ":" << l1 << ";\n"; + text << "\t tot_diffuse = tot_diffuse * (lr_out / lr_in);\n"; + break; + } + case LightRampAttrib::LRT_double_threshold: + { + float t0 = _attribs._light_ramp->get_threshold(0); + float t1 = _attribs._light_ramp->get_threshold(1); + float l0 = _attribs._light_ramp->get_level(0); + float l1 = _attribs._light_ramp->get_level(1); + float l2 = _attribs._light_ramp->get_level(2); + text << "\t // Double-threshold light ramp\n"; + text << "\t float lr_in = dot(tot_diffuse.rgb, float3(0.33,0.34,0.33));\n"; + text << "\t float lr_out = " << l0 << "\n"; + text << "\t if (lr_in > " << t0 << ") lr_out=" << l1 << ";\n"; + text << "\t if (lr_in > " << t1 << ") lr_out=" << l2 << ";\n"; + text << "\t tot_diffuse = tot_diffuse * (lr_out / lr_in);\n"; + break; + } + } text << "\t // Begin model-space light summation\n"; - if (_have_emission) { text << "\t o_color = attr_material[2];\n"; } else { text << "\t o_color = float4(0,0,0,0);\n"; } - if (_have_ambient) { + if ((_have_ambient)&&(_separate_ambient_diffuse)) { if (_material->has_ambient()) { text << "\t o_color += tot_ambient * attr_material[0];\n"; } else if (_vertex_colors) { @@ -669,14 +711,44 @@ synthesize_shader(const RenderState *rs) { } for (int i=0; i<_num_textures; i++) { TextureStage *stage = _attribs._texture->get_on_stage(i); - if ((stage->get_mode() != TextureStage::M_normal)&& - (stage->get_mode() != TextureStage::M_normal_height)) { + switch (stage->get_mode()) { + case TextureStage::M_modulate: + case TextureStage::M_modulate_glow: + case TextureStage::M_modulate_gloss: text << "\t o_color *= tex" << i << ";\n"; + break; + case TextureStage::M_decal: + text << "\t o_color.rgb = lerp(o_color, tex" << i << ", tex" << i << ".a).rgb;\n"; + break; + case TextureStage::M_blend: + pgraph_cat.error() << "TextureStage::Mode BLEND not yet supported in per-pixel mode.\n"; + break; + case TextureStage::M_replace: + pgraph_cat.error() << "TextureStage::Mode REPLACE not yet supported in per-pixel mode.\n"; + break; + case TextureStage::M_add: + text << "\t o_color.rbg = o_color.rgb + tex" << i << ".rgb;\n"; + text << "\t o_color.a = o_color.a * tex" << i << ".a;\n"; + break; + case TextureStage::M_combine: + pgraph_cat.error() << "TextureStage::Mode COMBINE not yet supported in per-pixel mode.\n"; + break; + case TextureStage::M_blend_color_scale: + pgraph_cat.error() << "TextureStage::Mode BLEND_COLOR_SCALE not yet supported in per-pixel mode.\n"; + break; + default: + break; } } if (_lighting) { if (_have_specular) { - text << "\t o_color += tot_specular;\n"; + if (_material->has_specular()) { + text << "\t tot_specular *= attr_material[3];\n"; + } + if (_map_index_gloss >= 0) { + text << "\t tot_specular *= tex" << _map_index_gloss << ".a;\n"; + } + text << "\t o_color.rgb = o_color.rgb + tot_specular.rgb;\n"; } } text << "}\n"; diff --git a/panda/src/pgraph/shaderGenerator.h b/panda/src/pgraph/shaderGenerator.h index 31b45b81c4..fc175575c2 100644 --- a/panda/src/pgraph/shaderGenerator.h +++ b/panda/src/pgraph/shaderGenerator.h @@ -110,7 +110,9 @@ protected: bool _have_diffuse; bool _have_emission; bool _have_specular; - + + bool _separate_ambient_diffuse; + int _map_index_normal; int _map_index_height; int _map_index_glow;