Explorar o código

Add roughness and metallic material parameters for PBR

rdb %!s(int64=10) %!d(string=hai) anos
pai
achega
ffabf6925c

+ 90 - 0
panda/src/egg/eggMaterial.I

@@ -246,6 +246,96 @@ get_shininess() const {
   }
   }
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: EggMaterial::set_roughness
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE void EggMaterial::
+set_roughness(double roughness) {
+  _roughness = roughness;
+  _flags |= F_roughness;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggMaterial::clear_roughness
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE void EggMaterial::
+clear_roughness() {
+  _flags &= ~F_roughness;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggMaterial::has_roughness
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE bool EggMaterial::
+has_roughness() const {
+  return (_flags & F_roughness) != 0;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggMaterial::get_roughness
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE double EggMaterial::
+get_roughness() const {
+  if (has_roughness()) {
+    return _roughness;
+  } else {
+    return 1.0;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggMaterial::set_metallic
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE void EggMaterial::
+set_metallic(double metallic) {
+  _metallic = metallic;
+  _flags |= F_metallic;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggMaterial::clear_metallic
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE void EggMaterial::
+clear_metallic() {
+  _flags &= ~F_metallic;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggMaterial::has_metallic
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE bool EggMaterial::
+has_metallic() const {
+  return (_flags & F_metallic) != 0;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggMaterial::get_metallic
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE double EggMaterial::
+get_metallic() const {
+  if (has_metallic()) {
+    return _metallic;
+  } else {
+    return 0.0;
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: EggMaterial::set_local
 //     Function: EggMaterial::set_local
 //       Access: Public
 //       Access: Public

+ 20 - 0
panda/src/egg/eggMaterial.cxx

@@ -44,6 +44,8 @@ EggMaterial(const EggMaterial &copy)
     _emit(copy._emit),
     _emit(copy._emit),
     _spec(copy._spec),
     _spec(copy._spec),
     _shininess(copy._shininess),
     _shininess(copy._shininess),
+    _roughness(copy._roughness),
+    _metallic(copy._metallic),
     _local(copy._local),
     _local(copy._local),
     _flags(copy._flags)
     _flags(copy._flags)
 {
 {
@@ -117,6 +119,16 @@ write(ostream &out, int indent_level) const {
       << "<Scalar> shininess { " << get_shininess() << " }\n";
       << "<Scalar> shininess { " << get_shininess() << " }\n";
   }
   }
 
 
+  if (has_roughness()) {
+    indent(out, indent_level + 2)
+      << "<Scalar> roughness { " << get_roughness() << " }\n";
+  }
+
+  if (has_metallic()) {
+    indent(out, indent_level + 2)
+      << "<Scalar> metallic { " << get_metallic() << " }\n";
+  }
+
   if (has_local()) {
   if (has_local()) {
     indent(out, indent_level + 2)
     indent(out, indent_level + 2)
       << "<Scalar> local { " << get_local() << " }\n";
       << "<Scalar> local { " << get_local() << " }\n";
@@ -152,6 +164,8 @@ is_equivalent_to(const EggMaterial &other, int eq) const {
         (has_emit() && get_emit() != other.get_emit()) ||
         (has_emit() && get_emit() != other.get_emit()) ||
         (has_spec() && get_spec() != other.get_spec()) ||
         (has_spec() && get_spec() != other.get_spec()) ||
         (has_shininess() && get_shininess() != other.get_shininess()) ||
         (has_shininess() && get_shininess() != other.get_shininess()) ||
+        (has_roughness() && get_roughness() != other.get_roughness()) ||
+        (has_metallic() && get_metallic() != other.get_metallic()) ||
         (has_local() && get_local() != other.get_local())) {
         (has_local() && get_local() != other.get_local())) {
       return false;
       return false;
     }
     }
@@ -196,6 +210,12 @@ sorts_less_than(const EggMaterial &other, int eq) const {
     if (has_shininess() && get_shininess() != other.get_shininess()) {
     if (has_shininess() && get_shininess() != other.get_shininess()) {
       return get_shininess() < other.get_shininess();
       return get_shininess() < other.get_shininess();
     }
     }
+    if (has_roughness() && get_roughness() != other.get_roughness()) {
+      return get_roughness() < other.get_roughness();
+    }
+    if (has_metallic() && get_metallic() != other.get_metallic()) {
+      return get_metallic() < other.get_metallic();
+    }
     if (has_local() && get_local() != other.get_local()) {
     if (has_local() && get_local() != other.get_local()) {
       return get_local() < other.get_local();
       return get_local() < other.get_local();
     }
     }

+ 26 - 1
panda/src/egg/eggMaterial.h

@@ -65,11 +65,32 @@ PUBLISHED:
   INLINE bool has_shininess() const;
   INLINE bool has_shininess() const;
   INLINE double get_shininess() const;
   INLINE double get_shininess() const;
 
 
+  INLINE void set_roughness(double roughness);
+  INLINE void clear_roughness();
+  INLINE bool has_roughness() const;
+  INLINE double get_roughness() const;
+
+  INLINE void set_metallic(double metallic);
+  INLINE void clear_metallic();
+  INLINE bool has_metallic() const;
+  INLINE double get_metallic() const;
+
   INLINE void set_local(bool local);
   INLINE void set_local(bool local);
   INLINE void clear_local();
   INLINE void clear_local();
   INLINE bool has_local() const;
   INLINE bool has_local() const;
   INLINE bool get_local() const;
   INLINE bool get_local() const;
 
 
+PUBLISHED:
+  MAKE_PROPERTY2(diff, has_diff, get_diff, set_diff, clear_diff);
+  MAKE_PROPERTY2(amb, has_amb, get_amb, set_amb, clear_amb);
+  MAKE_PROPERTY2(emit, has_emit, get_emit, set_emit, clear_emit);
+  MAKE_PROPERTY2(spec, has_spec, get_spec, set_spec, clear_spec);
+  MAKE_PROPERTY2(shininess, has_shininess, get_shininess, set_shininess, clear_shininess);
+  MAKE_PROPERTY2(roughness, has_roughness, get_roughness, set_roughness, clear_roughness);
+  MAKE_PROPERTY2(metallic, has_metallic, get_metallic, set_metallic, clear_metallic);
+
+  MAKE_PROPERTY2(local, has_local, get_local, set_local, clear_local);
+
 private:
 private:
   enum Flags {
   enum Flags {
     F_diff      = 0x001,
     F_diff      = 0x001,
@@ -77,7 +98,9 @@ private:
     F_emit      = 0x004,
     F_emit      = 0x004,
     F_spec      = 0x008,
     F_spec      = 0x008,
     F_shininess = 0x010,
     F_shininess = 0x010,
-    F_local     = 0x020
+    F_roughness = 0x020,
+    F_metallic  = 0x040,
+    F_local     = 0x080
   };
   };
 
 
   LColor _diff;
   LColor _diff;
@@ -85,6 +108,8 @@ private:
   LColor _emit;
   LColor _emit;
   LColor _spec;
   LColor _spec;
   double _shininess;
   double _shininess;
+  double _roughness;
+  double _metallic;
   bool _local;
   bool _local;
   int _flags;
   int _flags;
 
 

+ 6 - 0
panda/src/egg/parser.cxx.prebuilt

@@ -3004,6 +3004,12 @@ yyreduce:
   } else if (cmp_nocase_uh(name, "shininess") == 0) {
   } else if (cmp_nocase_uh(name, "shininess") == 0) {
     material->set_shininess(value);
     material->set_shininess(value);
 
 
+  } else if (cmp_nocase_uh(name, "roughness") == 0) {
+    material->set_roughness(value);
+
+  } else if (cmp_nocase_uh(name, "metallic") == 0) {
+    material->set_metallic(value);
+
   } else if (cmp_nocase_uh(name, "local") == 0) {
   } else if (cmp_nocase_uh(name, "local") == 0) {
     material->set_local(value != 0.0);
     material->set_local(value != 0.0);
 
 

+ 6 - 0
panda/src/egg/parser.yxx

@@ -828,6 +828,12 @@ material_body:
   } else if (cmp_nocase_uh(name, "shininess") == 0) {
   } else if (cmp_nocase_uh(name, "shininess") == 0) {
     material->set_shininess(value);
     material->set_shininess(value);
 
 
+  } else if (cmp_nocase_uh(name, "roughness") == 0) {
+    material->set_roughness(value);
+
+  } else if (cmp_nocase_uh(name, "metallic") == 0) {
+    material->set_metallic(value);
+
   } else if (cmp_nocase_uh(name, "local") == 0) {
   } else if (cmp_nocase_uh(name, "local") == 0) {
     material->set_local(value != 0.0);
     material->set_local(value != 0.0);
 
 

+ 6 - 0
panda/src/egg2pg/eggRenderState.cxx

@@ -513,6 +513,12 @@ get_material_attrib(const EggMaterial *egg_mat, bool bface) {
   if (egg_mat->has_shininess()) {
   if (egg_mat->has_shininess()) {
     mat->set_shininess(egg_mat->get_shininess());
     mat->set_shininess(egg_mat->get_shininess());
   }
   }
+  if (egg_mat->has_roughness()) {
+    mat->set_roughness(egg_mat->get_roughness());
+  }
+  if (egg_mat->has_metallic()) {
+    mat->set_metallic(egg_mat->get_metallic());
+  }
   if (egg_mat->has_local()) {
   if (egg_mat->has_local()) {
     mat->set_local(egg_mat->get_local());
     mat->set_local(egg_mat->get_local());
   }
   }

+ 10 - 1
panda/src/egg2pg/eggSaver.cxx

@@ -1047,7 +1047,16 @@ get_egg_material(Material *mat) {
       temp.set_emit(mat->get_emission());
       temp.set_emit(mat->get_emission());
     }
     }
 
 
-    temp.set_shininess(mat->get_shininess());
+    if (mat->has_roughness()) {
+      temp.set_roughness(mat->get_roughness());
+    } else {
+      temp.set_shininess(mat->get_shininess());
+    }
+
+    if (mat->has_metallic()) {
+      temp.set_metallic(mat->get_metallic());
+    }
+
     temp.set_local(mat->get_local());
     temp.set_local(mat->get_local());
 
 
     return _materials.create_unique_material(temp, ~EggMaterial::E_mref_name);
     return _materials.create_unique_material(temp, ~EggMaterial::E_mref_name);

+ 44 - 10
panda/src/gobj/material.I

@@ -24,7 +24,9 @@ Material(const string &name) : Namable(name) {
   _diffuse.set(1.0f, 1.0f, 1.0f, 1.0f);
   _diffuse.set(1.0f, 1.0f, 1.0f, 1.0f);
   _specular.set(0.0f, 0.0f, 0.0f, 1.0f);
   _specular.set(0.0f, 0.0f, 0.0f, 1.0f);
   _emission.set(0.0f, 0.0f, 0.0f, 1.0f);
   _emission.set(0.0f, 0.0f, 0.0f, 1.0f);
-  _shininess = 0.0;
+  _shininess = 0;
+  _roughness = 1;
+  _metallic = 0;
   _flags = 0;
   _flags = 0;
 }
 }
 
 
@@ -219,18 +221,50 @@ get_shininess() const {
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: Material::set_shininess
+//     Function: Material::has_metallic
 //       Access: Published
 //       Access: Published
-//  Description: Sets the shininess exponent of the material.  This
-//               controls the size of the specular highlight spot.  In
-//               general, larger number produce a smaller specular
-//               highlight, which makes the object appear shinier.
-//               Smaller numbers produce a larger highlight, which
-//               makes the object appear less shiny.
+//  Description: Returns true if the metallic has been explicitly
+//               set for this material, false otherwise.
+////////////////////////////////////////////////////////////////////
+INLINE bool Material::
+has_metallic() const {
+  return (_flags & F_metallic) != 0;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Material::get_metallic
+//       Access: Published
+//  Description: Returns the metallic setting, if it has been set.
+//               Returns 0 if it has not been set.
+////////////////////////////////////////////////////////////////////
+INLINE PN_stdfloat Material::
+get_metallic() const {
+  return _metallic;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Material::clear_metallic
+//       Access: Published
+//  Description: Removes the explicit metallic setting from the material.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE void Material::
 INLINE void Material::
-set_shininess(PN_stdfloat shininess) {
-  _shininess = shininess;
+clear_metallic() {
+  if (enforce_attrib_lock) {
+    nassertv(!is_attrib_locked());
+  }
+  _flags &= ~F_metallic;
+  _metallic = 0;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Material::has_roughness
+//       Access: Published
+//  Description: Returns true if the roughness has been explicitly
+//               set for this material, false otherwise.
+////////////////////////////////////////////////////////////////////
+INLINE bool Material::
+has_roughness() const {
+  return (_flags & F_roughness) != 0;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////

+ 126 - 3
panda/src/gobj/material.cxx

@@ -36,6 +36,8 @@ operator = (const Material &copy) {
   _specular = copy._specular;
   _specular = copy._specular;
   _emission = copy._emission;
   _emission = copy._emission;
   _shininess = copy._shininess;
   _shininess = copy._shininess;
+  _roughness = copy._roughness;
+  _metallic = copy._metallic;
   _flags = copy._flags & (~F_attrib_lock);
   _flags = copy._flags & (~F_attrib_lock);
 }
 }
 
 
@@ -136,6 +138,93 @@ set_emission(const LColor &color) {
   _flags |= F_emission;
   _flags |= F_emission;
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: Material::set_shininess
+//       Access: Published
+//  Description: Sets the shininess exponent of the material.  This
+//               controls the size of the specular highlight spot.  In
+//               general, larger number produce a smaller specular
+//               highlight, which makes the object appear shinier.
+//               Smaller numbers produce a larger highlight, which
+//               makes the object appear less shiny.
+//
+//               This is usually in the range 0..128.
+//
+//               Setting a shininess value removes any previous
+//               roughness assignment.
+////////////////////////////////////////////////////////////////////
+void Material::
+set_shininess(PN_stdfloat shininess) {
+  _shininess = shininess;
+  _flags &= ~F_roughness;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Material::get_roughness
+//       Access: Published
+//  Description: Returns the roughness previously specified by
+//               set_roughness.  If none was previously set, this
+//               value is computed from the shininess value.
+////////////////////////////////////////////////////////////////////
+PN_stdfloat Material::
+get_roughness() const {
+  if ((_flags & F_roughness) == 0) {
+    // Calculate roughness from blinn-phong shininess.
+    return csqrt(csqrt(2 / (_shininess + 2)));
+  } else {
+    return _roughness;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Material::set_roughness
+//       Access: Published
+//  Description: Sets the roughness exponent of the material, where
+//               0 is completely shiny (infinite shininess), and
+//               1 is a completely dull object (0 shininess).  This
+//               is a different, more perceptually intuitive way of
+//               controlling the size of the specular spot, and more
+//               commonly used in physically-based rendering.
+//
+//               Setting a roughness recalculates the shininess value.
+////////////////////////////////////////////////////////////////////
+void Material::
+set_roughness(PN_stdfloat roughness) {
+  _roughness = roughness;
+  _flags |= F_roughness;
+
+  // Calculate the specular exponent from the roughness as it is used
+  // in Blinn-Phong shading model.  We use the popular Disney method
+  // of squaring the roughness to get a more perceptually linear scale.
+  // From: http://graphicrants.blogspot.de/2013/08/specular-brdf-reference.html
+  if (roughness <= 0 || IS_NEARLY_ZERO(roughness)) {
+    _shininess = make_inf((PN_stdfloat)0);
+  } else {
+    PN_stdfloat alpha = roughness * roughness;
+    _shininess = 2 / (alpha * alpha) - 2;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Material::set_metallic
+//       Access: Published
+//  Description: Sets the metallic setting of the material, which is
+//               is used for physically-based rendering models.
+//               This is usually 0 for dielectric materials and 1
+//               for metals.  It usually does not make sense to set
+//               this to a value other than 0 or 1.
+////////////////////////////////////////////////////////////////////
+void Material::
+set_metallic(PN_stdfloat metallic) {
+  if (enforce_attrib_lock) {
+    if ((_flags & F_metallic) == 0) {
+      nassertv(!is_attrib_locked());
+    }
+  }
+  _metallic = metallic;
+  _flags |= F_metallic;
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: Material::compare_to
 //     Function: Material::compare_to
 //       Access: Published
 //       Access: Published
@@ -189,8 +278,15 @@ output(ostream &out) const {
   if (has_emission()) {
   if (has_emission()) {
     out << " e(" << get_emission() << ")";
     out << " e(" << get_emission() << ")";
   }
   }
-  out << " s" << get_shininess()
-      << " l" << get_local()
+  if (_flags & F_roughness) {
+    out << " r" << get_roughness();
+  } else {
+    out << " s" << get_shininess();
+  }
+  if (has_metallic()) {
+    out << " m" << _metallic;
+  }
+  out << " l" << get_local()
       << " t" << get_twoside();
       << " t" << get_twoside();
 }
 }
 
 
@@ -214,7 +310,14 @@ write(ostream &out, int indent_level) const {
   if (has_emission()) {
   if (has_emission()) {
     indent(out, indent_level + 2) << "emission = " << get_emission() << "\n";
     indent(out, indent_level + 2) << "emission = " << get_emission() << "\n";
   }
   }
-  indent(out, indent_level + 2) << "shininess = " << get_shininess() << "\n";
+  if (_flags & F_roughness) {
+    indent(out, indent_level + 2) << "roughness = " << get_roughness() << "\n";
+  } else {
+    indent(out, indent_level + 2) << "shininess = " << get_shininess() << "\n";
+  }
+  if (has_metallic()) {
+    indent(out, indent_level + 2) << "metallic = " << get_metallic() << "\n";
+  }
   indent(out, indent_level + 2) << "local = " << get_local() << "\n";
   indent(out, indent_level + 2) << "local = " << get_local() << "\n";
   indent(out, indent_level + 2) << "twoside = " << get_twoside() << "\n";
   indent(out, indent_level + 2) << "twoside = " << get_twoside() << "\n";
 }
 }
@@ -245,7 +348,18 @@ write_datagram(BamWriter *manager, Datagram &me) {
   _specular.write_datagram(me);
   _specular.write_datagram(me);
   _emission.write_datagram(me);
   _emission.write_datagram(me);
   me.add_stdfloat(_shininess);
   me.add_stdfloat(_shininess);
+
+  if (_flags & F_roughness) {
+    me.add_stdfloat(_roughness);
+  } else {
+    me.add_stdfloat(_shininess);
+  }
+
   me.add_int32(_flags);
   me.add_int32(_flags);
+
+  if (_flags & F_metallic) {
+    me.add_stdfloat(_metallic);
+  }
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -281,4 +395,13 @@ fillin(DatagramIterator &scan, BamReader *manager) {
   _emission.read_datagram(scan);
   _emission.read_datagram(scan);
   _shininess = scan.get_stdfloat();
   _shininess = scan.get_stdfloat();
   _flags = scan.get_int32();
   _flags = scan.get_int32();
+
+  if (_flags & F_roughness) {
+    // The shininess we read is actually a roughness value.
+    set_roughness(_shininess);
+  }
+
+  if (_flags & F_metallic) {
+    _metallic = scan.get_stdfloat();
+  }
 }
 }

+ 32 - 13
panda/src/gobj/material.h

@@ -44,40 +44,38 @@ PUBLISHED:
   INLINE const LColor &get_ambient() const;
   INLINE const LColor &get_ambient() const;
   void set_ambient(const LColor &color);
   void set_ambient(const LColor &color);
   INLINE void clear_ambient();
   INLINE void clear_ambient();
-  MAKE_PROPERTY2(ambient, has_ambient, get_ambient,
-                          set_ambient, clear_ambient);
 
 
   INLINE bool has_diffuse() const;
   INLINE bool has_diffuse() const;
   INLINE const LColor &get_diffuse() const;
   INLINE const LColor &get_diffuse() const;
   void set_diffuse(const LColor &color);
   void set_diffuse(const LColor &color);
   INLINE void clear_diffuse();
   INLINE void clear_diffuse();
-  MAKE_PROPERTY2(diffuse, has_diffuse, get_diffuse,
-                          set_diffuse, clear_diffuse);
 
 
   INLINE bool has_specular() const;
   INLINE bool has_specular() const;
   INLINE const LColor &get_specular() const;
   INLINE const LColor &get_specular() const;
   void set_specular(const LColor &color);
   void set_specular(const LColor &color);
   INLINE void clear_specular();
   INLINE void clear_specular();
-  MAKE_PROPERTY2(specular, has_specular, get_specular,
-                           set_specular, clear_specular);
 
 
   INLINE bool has_emission() const;
   INLINE bool has_emission() const;
   INLINE const LColor &get_emission() const;
   INLINE const LColor &get_emission() const;
   void set_emission(const LColor &color);
   void set_emission(const LColor &color);
   INLINE void clear_emission();
   INLINE void clear_emission();
-  MAKE_PROPERTY2(emission, has_emission, get_emission,
-                           set_emission, clear_emission);
 
 
   INLINE PN_stdfloat get_shininess() const;
   INLINE PN_stdfloat get_shininess() const;
-  INLINE void set_shininess(PN_stdfloat shininess);
-  MAKE_PROPERTY(shininess, get_shininess, set_shininess);
+  void set_shininess(PN_stdfloat shininess);
+
+  INLINE bool has_roughness() const;
+  PN_stdfloat get_roughness() const;
+  void set_roughness(PN_stdfloat roughness);
+
+  INLINE bool has_metallic() const;
+  INLINE PN_stdfloat get_metallic() const;
+  void set_metallic(PN_stdfloat metallic);
+  INLINE void clear_metallic();
 
 
   INLINE bool get_local() const;
   INLINE bool get_local() const;
   INLINE void set_local(bool local);
   INLINE void set_local(bool local);
   INLINE bool get_twoside() const;
   INLINE bool get_twoside() const;
   INLINE void set_twoside(bool twoside);
   INLINE void set_twoside(bool twoside);
-  MAKE_PROPERTY(local, get_local, set_local);
-  MAKE_PROPERTY(twoside, get_twoside, set_twoside);
 
 
   INLINE bool operator == (const Material &other) const;
   INLINE bool operator == (const Material &other) const;
   INLINE bool operator != (const Material &other) const;
   INLINE bool operator != (const Material &other) const;
@@ -91,12 +89,31 @@ PUBLISHED:
   INLINE bool is_attrib_locked() const;
   INLINE bool is_attrib_locked() const;
   INLINE void set_attrib_lock();
   INLINE void set_attrib_lock();
 
 
+PUBLISHED:
+  MAKE_PROPERTY2(ambient, has_ambient, get_ambient,
+                          set_ambient, clear_ambient);
+  MAKE_PROPERTY2(diffuse, has_diffuse, get_diffuse,
+                          set_diffuse, clear_diffuse);
+  MAKE_PROPERTY2(specular, has_specular, get_specular,
+                           set_specular, clear_specular);
+  MAKE_PROPERTY2(emission, has_emission, get_emission,
+                           set_emission, clear_emission);
+
+  MAKE_PROPERTY(shininess, get_shininess, set_shininess);
+  MAKE_PROPERTY(roughness, get_roughness, set_roughness);
+  MAKE_PROPERTY(metallic, get_metallic, set_metallic);
+
+  MAKE_PROPERTY(local, get_local, set_local);
+  MAKE_PROPERTY(twoside, get_twoside, set_twoside);
+
 private:
 private:
   LColor _ambient;
   LColor _ambient;
   LColor _diffuse;
   LColor _diffuse;
   LColor _specular;
   LColor _specular;
   LColor _emission;
   LColor _emission;
   PN_stdfloat _shininess;
   PN_stdfloat _shininess;
+  PN_stdfloat _roughness;
+  PN_stdfloat _metallic;
 
 
   static PT(Material) _default;
   static PT(Material) _default;
 
 
@@ -107,7 +124,9 @@ private:
     F_emission    = 0x008,
     F_emission    = 0x008,
     F_local       = 0x010,
     F_local       = 0x010,
     F_twoside     = 0x020,
     F_twoside     = 0x020,
-    F_attrib_lock = 0x040
+    F_attrib_lock = 0x040,
+    F_roughness   = 0x080,
+    F_metallic    = 0x100,
   };
   };
   int _flags;
   int _flags;