Add roughness and metallic material parameters for PBR

This commit is contained in:
rdb 2015-12-27 23:33:56 +01:00
parent 9e14c16e1a
commit ffabf6925c
10 changed files with 366 additions and 28 deletions

View File

@ -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
// Access: Public

View File

@ -44,6 +44,8 @@ EggMaterial(const EggMaterial &copy)
_emit(copy._emit),
_spec(copy._spec),
_shininess(copy._shininess),
_roughness(copy._roughness),
_metallic(copy._metallic),
_local(copy._local),
_flags(copy._flags)
{
@ -117,6 +119,16 @@ write(ostream &out, int indent_level) const {
<< "<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()) {
indent(out, indent_level + 2)
<< "<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_spec() && get_spec() != other.get_spec()) ||
(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())) {
return false;
}
@ -196,6 +210,12 @@ sorts_less_than(const EggMaterial &other, int eq) const {
if (has_shininess() && 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()) {
return get_local() < other.get_local();
}

View File

@ -65,11 +65,32 @@ PUBLISHED:
INLINE bool has_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 clear_local();
INLINE bool has_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:
enum Flags {
F_diff = 0x001,
@ -77,7 +98,9 @@ private:
F_emit = 0x004,
F_spec = 0x008,
F_shininess = 0x010,
F_local = 0x020
F_roughness = 0x020,
F_metallic = 0x040,
F_local = 0x080
};
LColor _diff;
@ -85,6 +108,8 @@ private:
LColor _emit;
LColor _spec;
double _shininess;
double _roughness;
double _metallic;
bool _local;
int _flags;

View File

@ -3004,6 +3004,12 @@ yyreduce:
} else if (cmp_nocase_uh(name, "shininess") == 0) {
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) {
material->set_local(value != 0.0);

View File

@ -828,6 +828,12 @@ material_body:
} else if (cmp_nocase_uh(name, "shininess") == 0) {
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) {
material->set_local(value != 0.0);

View File

@ -513,6 +513,12 @@ get_material_attrib(const EggMaterial *egg_mat, bool bface) {
if (egg_mat->has_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()) {
mat->set_local(egg_mat->get_local());
}

View File

@ -1047,7 +1047,16 @@ get_egg_material(Material *mat) {
temp.set_emit(mat->get_emission());
}
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());
return _materials.create_unique_material(temp, ~EggMaterial::E_mref_name);

View File

@ -24,7 +24,9 @@ Material(const string &name) : Namable(name) {
_diffuse.set(1.0f, 1.0f, 1.0f, 1.0f);
_specular.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;
}
@ -219,18 +221,50 @@ get_shininess() const {
}
////////////////////////////////////////////////////////////////////
// Function: Material::set_shininess
// Function: Material::has_metallic
// 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::
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;
}
////////////////////////////////////////////////////////////////////

View File

@ -36,6 +36,8 @@ operator = (const Material &copy) {
_specular = copy._specular;
_emission = copy._emission;
_shininess = copy._shininess;
_roughness = copy._roughness;
_metallic = copy._metallic;
_flags = copy._flags & (~F_attrib_lock);
}
@ -136,6 +138,93 @@ set_emission(const LColor &color) {
_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
// Access: Published
@ -189,8 +278,15 @@ output(ostream &out) const {
if (has_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();
}
@ -214,7 +310,14 @@ write(ostream &out, int indent_level) const {
if (has_emission()) {
indent(out, indent_level + 2) << "emission = " << get_emission() << "\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) << "twoside = " << get_twoside() << "\n";
}
@ -245,7 +348,18 @@ write_datagram(BamWriter *manager, Datagram &me) {
_specular.write_datagram(me);
_emission.write_datagram(me);
me.add_stdfloat(_shininess);
if (_flags & F_roughness) {
me.add_stdfloat(_roughness);
} else {
me.add_stdfloat(_shininess);
}
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);
_shininess = scan.get_stdfloat();
_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();
}
}

View File

@ -44,40 +44,38 @@ PUBLISHED:
INLINE const LColor &get_ambient() const;
void set_ambient(const LColor &color);
INLINE void clear_ambient();
MAKE_PROPERTY2(ambient, has_ambient, get_ambient,
set_ambient, clear_ambient);
INLINE bool has_diffuse() const;
INLINE const LColor &get_diffuse() const;
void set_diffuse(const LColor &color);
INLINE void clear_diffuse();
MAKE_PROPERTY2(diffuse, has_diffuse, get_diffuse,
set_diffuse, clear_diffuse);
INLINE bool has_specular() const;
INLINE const LColor &get_specular() const;
void set_specular(const LColor &color);
INLINE void clear_specular();
MAKE_PROPERTY2(specular, has_specular, get_specular,
set_specular, clear_specular);
INLINE bool has_emission() const;
INLINE const LColor &get_emission() const;
void set_emission(const LColor &color);
INLINE void clear_emission();
MAKE_PROPERTY2(emission, has_emission, get_emission,
set_emission, clear_emission);
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 void set_local(bool local);
INLINE bool get_twoside() const;
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;
@ -91,12 +89,31 @@ PUBLISHED:
INLINE bool is_attrib_locked() const;
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:
LColor _ambient;
LColor _diffuse;
LColor _specular;
LColor _emission;
PN_stdfloat _shininess;
PN_stdfloat _roughness;
PN_stdfloat _metallic;
static PT(Material) _default;
@ -107,7 +124,9 @@ private:
F_emission = 0x008,
F_local = 0x010,
F_twoside = 0x020,
F_attrib_lock = 0x040
F_attrib_lock = 0x040,
F_roughness = 0x080,
F_metallic = 0x100,
};
int _flags;