|
|
@@ -31,6 +31,7 @@ PT(Material) Material::_default;
|
|
|
void Material::
|
|
|
operator = (const Material ©) {
|
|
|
Namable::operator = (copy);
|
|
|
+ _base_color = copy._base_color;
|
|
|
_ambient = copy._ambient;
|
|
|
_diffuse = copy._diffuse;
|
|
|
_specular = copy._specular;
|
|
|
@@ -38,9 +39,80 @@ operator = (const Material ©) {
|
|
|
_shininess = copy._shininess;
|
|
|
_roughness = copy._roughness;
|
|
|
_metallic = copy._metallic;
|
|
|
+ _refractive_index = copy._refractive_index;
|
|
|
_flags = copy._flags & (~F_attrib_lock);
|
|
|
}
|
|
|
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: Material::set_base_color
|
|
|
+// Access: Published
|
|
|
+// Description: Specifies the base color of the material. In
|
|
|
+// conjunction with set_metallic, this is an alternate
|
|
|
+// way to specify the color of a material. For
|
|
|
+// dielectrics, this will determine the value of the
|
|
|
+// diffuse color, and for metals, this will determine
|
|
|
+// the value of the specular color.
|
|
|
+//
|
|
|
+// Setting this will clear an explicit specular,
|
|
|
+// diffuse or ambient color assignment.
|
|
|
+//
|
|
|
+// If this is not set, the object color will be used.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+void Material::
|
|
|
+set_base_color(const LColor &color) {
|
|
|
+ if (enforce_attrib_lock) {
|
|
|
+ if ((_flags & F_base_color) == 0) {
|
|
|
+ nassertv(!is_attrib_locked());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ _base_color = color;
|
|
|
+ _flags |= F_base_color | F_metallic;
|
|
|
+ _flags &= ~(F_ambient | F_diffuse | F_specular);
|
|
|
+
|
|
|
+ // Recalculate the diffuse and specular colors.
|
|
|
+ _ambient = _base_color;
|
|
|
+ _diffuse = _base_color * (1 - _metallic);
|
|
|
+
|
|
|
+ PN_stdfloat f0 = 0;
|
|
|
+ if (_refractive_index >= 1) {
|
|
|
+ f0 = (_refractive_index - 1) / (_refractive_index + 1);
|
|
|
+ f0 *= f0;
|
|
|
+ f0 *= (1 - _metallic);
|
|
|
+ }
|
|
|
+ _specular.set(f0, f0, f0, 0);
|
|
|
+ _specular += _base_color * _metallic;
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: Material::clear_base_color
|
|
|
+// Access: Published
|
|
|
+// Description: Removes the explicit base_color color from the material.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+void Material::
|
|
|
+clear_base_color() {
|
|
|
+ if (enforce_attrib_lock) {
|
|
|
+ nassertv(!is_attrib_locked());
|
|
|
+ }
|
|
|
+ _flags &= ~F_base_color;
|
|
|
+ _base_color.set(0.0f, 0.0f, 0.0f, 0.0f);
|
|
|
+
|
|
|
+ if ((_flags & F_ambient) == 0) {
|
|
|
+ _ambient.set(0, 0, 0, 0);
|
|
|
+ }
|
|
|
+ if ((_flags & F_diffuse) == 0) {
|
|
|
+ _diffuse.set(0, 0, 0, 0);
|
|
|
+ }
|
|
|
+ if ((_flags & F_specular) == 0) {
|
|
|
+ // Recalculate the specular color.
|
|
|
+ PN_stdfloat f0 = 0;
|
|
|
+ if (_refractive_index >= 1) {
|
|
|
+ f0 = (_refractive_index - 1) / (_refractive_index + 1);
|
|
|
+ f0 *= f0;
|
|
|
+ }
|
|
|
+ _specular.set(f0, f0, f0, 0);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
// Function: Material::set_ambient
|
|
|
// Access: Published
|
|
|
@@ -92,7 +164,7 @@ set_diffuse(const LColor &color) {
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
// Function: Material::set_specular
|
|
|
// Access: Published
|
|
|
-// Description: Specifies the diffuse color setting of the material.
|
|
|
+// Description: Specifies the specular color setting of the material.
|
|
|
// This will be multiplied by any lights in effect on
|
|
|
// the material to compute the color of specular
|
|
|
// highlights on the object.
|
|
|
@@ -100,7 +172,9 @@ set_diffuse(const LColor &color) {
|
|
|
// This is the highlight color of an object: the color
|
|
|
// of small highlight reflections.
|
|
|
//
|
|
|
-// If this is not set, highlights will not appear.
|
|
|
+// If this is not set, the specular color is taken from
|
|
|
+// the index of refraction, which is 1 by default
|
|
|
+// (meaning no specular reflections are generated).
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
void Material::
|
|
|
set_specular(const LColor &color) {
|
|
|
@@ -113,6 +187,29 @@ set_specular(const LColor &color) {
|
|
|
_flags |= F_specular;
|
|
|
}
|
|
|
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: Material::clear_specular
|
|
|
+// Access: Published
|
|
|
+// Description: Removes the explicit specular color from the material.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+void Material::
|
|
|
+clear_specular() {
|
|
|
+ if (enforce_attrib_lock) {
|
|
|
+ nassertv(!is_attrib_locked());
|
|
|
+ }
|
|
|
+ _flags &= ~F_specular;
|
|
|
+
|
|
|
+ // Recalculate the specular color from the refractive index.
|
|
|
+ PN_stdfloat f0 = 0;
|
|
|
+ if (_refractive_index >= 1) {
|
|
|
+ f0 = (_refractive_index - 1) / (_refractive_index + 1);
|
|
|
+ f0 *= f0;
|
|
|
+ f0 *= (1 - _metallic);
|
|
|
+ }
|
|
|
+ _specular.set(f0, f0, f0, 0);
|
|
|
+ _specular += _base_color * _metallic;
|
|
|
+}
|
|
|
+
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
// Function: Material::set_emission
|
|
|
// Access: Published
|
|
|
@@ -211,8 +308,10 @@ set_roughness(PN_stdfloat roughness) {
|
|
|
// 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.
|
|
|
+// for metals. It really does not make sense to set
|
|
|
+// this to a value other than 0 or 1, but it is
|
|
|
+// nonetheless a float for compatibility with tools
|
|
|
+// that allow setting this to values other than 0 or 1.
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
void Material::
|
|
|
set_metallic(PN_stdfloat metallic) {
|
|
|
@@ -223,6 +322,80 @@ set_metallic(PN_stdfloat metallic) {
|
|
|
}
|
|
|
_metallic = metallic;
|
|
|
_flags |= F_metallic;
|
|
|
+
|
|
|
+ // Recalculate the diffuse and specular.
|
|
|
+ if ((_flags & F_diffuse) == 0) {
|
|
|
+ _diffuse = _base_color * (1 - _metallic);
|
|
|
+ }
|
|
|
+ if ((_flags & F_specular) == 0) {
|
|
|
+ // Recalculate the specular color.
|
|
|
+ PN_stdfloat f0 = 0;
|
|
|
+ if (_refractive_index >= 1) {
|
|
|
+ f0 = (_refractive_index - 1) / (_refractive_index + 1);
|
|
|
+ f0 *= f0;
|
|
|
+ f0 *= (1 - _metallic);
|
|
|
+ }
|
|
|
+ _specular.set(f0, f0, f0, 0);
|
|
|
+ _specular += _base_color * _metallic;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: Material::clear_metallic
|
|
|
+// Access: Published
|
|
|
+// Description: Removes the explicit metallic setting from the material.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+void Material::
|
|
|
+clear_metallic() {
|
|
|
+ if (enforce_attrib_lock) {
|
|
|
+ nassertv(!is_attrib_locked());
|
|
|
+ }
|
|
|
+ _flags &= ~F_metallic;
|
|
|
+ _metallic = 0;
|
|
|
+
|
|
|
+ // If we had a base color, recalculate the diffuse and specular.
|
|
|
+ if (_flags & F_base_color) {
|
|
|
+ if ((_flags & F_diffuse) == 0) {
|
|
|
+ _diffuse = _base_color;
|
|
|
+ }
|
|
|
+ if ((_flags & F_specular) == 0) {
|
|
|
+ // Recalculate the specular color.
|
|
|
+ PN_stdfloat f0 = 0;
|
|
|
+ if (_refractive_index >= 1) {
|
|
|
+ f0 = (_refractive_index - 1) / (_refractive_index + 1);
|
|
|
+ f0 *= f0;
|
|
|
+ }
|
|
|
+ _specular.set(f0, f0, f0, 0);
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: Material::set_refractive_index
|
|
|
+// Access: Published
|
|
|
+// Description: Sets the index of refraction of the material, which
|
|
|
+// is used to determine the specular color in absence
|
|
|
+// of an explicit specular color assignment.
|
|
|
+// This is usually 1.5 for dielectric materials. It
|
|
|
+// is not very useful for metals, since they cannot
|
|
|
+// be described as easily with a single number.
|
|
|
+//
|
|
|
+// Should be 1 or higher. The default is 1.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+void Material::
|
|
|
+set_refractive_index(PN_stdfloat refractive_index) {
|
|
|
+ _refractive_index = refractive_index;
|
|
|
+ _flags |= F_refractive_index;
|
|
|
+
|
|
|
+ if ((_flags & F_specular) == 0) {
|
|
|
+ // Recalculate the specular color.
|
|
|
+ PN_stdfloat f0 = 0;
|
|
|
+ if (_refractive_index >= 1) {
|
|
|
+ f0 = (_refractive_index - 1) / (_refractive_index + 1);
|
|
|
+ f0 *= f0;
|
|
|
+ }
|
|
|
+ _specular.set(f0, f0, f0, 0);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
@@ -239,6 +412,9 @@ compare_to(const Material &other) const {
|
|
|
if (_flags != other._flags) {
|
|
|
return _flags - other._flags;
|
|
|
}
|
|
|
+ if (has_base_color() && get_base_color() != other.get_base_color()) {
|
|
|
+ return get_base_color().compare_to(other.get_base_color());
|
|
|
+ }
|
|
|
if (has_ambient() && get_ambient() != other.get_ambient()) {
|
|
|
return get_ambient().compare_to(other.get_ambient());
|
|
|
}
|
|
|
@@ -254,6 +430,12 @@ compare_to(const Material &other) const {
|
|
|
if (get_shininess() != other.get_shininess()) {
|
|
|
return get_shininess() < other.get_shininess() ? -1 : 1;
|
|
|
}
|
|
|
+ if (get_metallic() != other.get_metallic()) {
|
|
|
+ return get_metallic() < other.get_metallic() ? -1 : 1;
|
|
|
+ }
|
|
|
+ if (get_refractive_index() != other.get_refractive_index()) {
|
|
|
+ return get_refractive_index() < other.get_refractive_index() ? -1 : 1;
|
|
|
+ }
|
|
|
|
|
|
return strcmp(get_name().c_str(), other.get_name().c_str());
|
|
|
}
|
|
|
@@ -266,14 +448,21 @@ compare_to(const Material &other) const {
|
|
|
void Material::
|
|
|
output(ostream &out) const {
|
|
|
out << "Material " << get_name();
|
|
|
- if (has_ambient()) {
|
|
|
- out << " a(" << get_ambient() << ")";
|
|
|
- }
|
|
|
- if (has_diffuse()) {
|
|
|
- out << " d(" << get_diffuse() << ")";
|
|
|
+ if (has_base_color()) {
|
|
|
+ out << " c(" << get_base_color() << ")";
|
|
|
+ } else {
|
|
|
+ if (has_ambient()) {
|
|
|
+ out << " a(" << get_ambient() << ")";
|
|
|
+ }
|
|
|
+ if (has_diffuse()) {
|
|
|
+ out << " d(" << get_diffuse() << ")";
|
|
|
+ }
|
|
|
+ if (has_specular()) {
|
|
|
+ out << " s(" << get_specular() << ")";
|
|
|
+ }
|
|
|
}
|
|
|
- if (has_specular()) {
|
|
|
- out << " s(" << get_specular() << ")";
|
|
|
+ if (has_refractive_index()) {
|
|
|
+ out << " ior" << get_refractive_index();
|
|
|
}
|
|
|
if (has_emission()) {
|
|
|
out << " e(" << get_emission() << ")";
|
|
|
@@ -283,7 +472,7 @@ output(ostream &out) const {
|
|
|
} else {
|
|
|
out << " s" << get_shininess();
|
|
|
}
|
|
|
- if (has_metallic()) {
|
|
|
+ if (_flags & F_metallic) {
|
|
|
out << " m" << _metallic;
|
|
|
}
|
|
|
out << " l" << get_local()
|
|
|
@@ -298,6 +487,9 @@ output(ostream &out) const {
|
|
|
void Material::
|
|
|
write(ostream &out, int indent_level) const {
|
|
|
indent(out, indent_level) << "Material " << get_name() << "\n";
|
|
|
+ if (has_base_color()) {
|
|
|
+ indent(out, indent_level + 2) << "base_color = " << get_ambient() << "\n";
|
|
|
+ }
|
|
|
if (has_ambient()) {
|
|
|
indent(out, indent_level + 2) << "ambient = " << get_ambient() << "\n";
|
|
|
}
|
|
|
@@ -306,6 +498,8 @@ write(ostream &out, int indent_level) const {
|
|
|
}
|
|
|
if (has_specular()) {
|
|
|
indent(out, indent_level + 2) << "specular = " << get_specular() << "\n";
|
|
|
+ } else {
|
|
|
+ indent(out, indent_level + 2) << "refractive_index = " << get_refractive_index() << "\n";
|
|
|
}
|
|
|
if (has_emission()) {
|
|
|
indent(out, indent_level + 2) << "emission = " << get_emission() << "\n";
|
|
|
@@ -343,11 +537,19 @@ register_with_read_factory() {
|
|
|
void Material::
|
|
|
write_datagram(BamWriter *manager, Datagram &me) {
|
|
|
me.add_string(get_name());
|
|
|
- _ambient.write_datagram(me);
|
|
|
- _diffuse.write_datagram(me);
|
|
|
- _specular.write_datagram(me);
|
|
|
+
|
|
|
+ me.add_int32(_flags);
|
|
|
+
|
|
|
+ if (_flags & F_metallic) {
|
|
|
+ // Metalness workflow.
|
|
|
+ _base_color.write_datagram(me);
|
|
|
+ me.add_stdfloat(_metallic);
|
|
|
+ } else {
|
|
|
+ _ambient.write_datagram(me);
|
|
|
+ _diffuse.write_datagram(me);
|
|
|
+ _specular.write_datagram(me);
|
|
|
+ }
|
|
|
_emission.write_datagram(me);
|
|
|
- me.add_stdfloat(_shininess);
|
|
|
|
|
|
if (_flags & F_roughness) {
|
|
|
me.add_stdfloat(_roughness);
|
|
|
@@ -355,11 +557,7 @@ write_datagram(BamWriter *manager, Datagram &me) {
|
|
|
me.add_stdfloat(_shininess);
|
|
|
}
|
|
|
|
|
|
- me.add_int32(_flags);
|
|
|
-
|
|
|
- if (_flags & F_metallic) {
|
|
|
- me.add_stdfloat(_metallic);
|
|
|
- }
|
|
|
+ me.add_stdfloat(_refractive_index);
|
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
@@ -389,19 +587,40 @@ make_Material(const FactoryParams ¶ms) {
|
|
|
void Material::
|
|
|
fillin(DatagramIterator &scan, BamReader *manager) {
|
|
|
set_name(scan.get_string());
|
|
|
- _ambient.read_datagram(scan);
|
|
|
- _diffuse.read_datagram(scan);
|
|
|
- _specular.read_datagram(scan);
|
|
|
- _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 (manager->get_file_minor_ver() >= 39) {
|
|
|
+ _flags = scan.get_int32();
|
|
|
|
|
|
- if (_flags & F_metallic) {
|
|
|
- _metallic = scan.get_stdfloat();
|
|
|
+ if (_flags & F_metallic) {
|
|
|
+ // Metalness workflow: read base color and metallic
|
|
|
+ _base_color.read_datagram(scan);
|
|
|
+ set_metallic(scan.get_stdfloat());
|
|
|
+
|
|
|
+ } else {
|
|
|
+ _ambient.read_datagram(scan);
|
|
|
+ _diffuse.read_datagram(scan);
|
|
|
+ _specular.read_datagram(scan);
|
|
|
+ }
|
|
|
+ _emission.read_datagram(scan);
|
|
|
+
|
|
|
+ if (_flags & F_roughness) {
|
|
|
+ set_roughness(scan.get_stdfloat());
|
|
|
+ } else {
|
|
|
+ _shininess = scan.get_stdfloat();
|
|
|
+ }
|
|
|
+ _refractive_index = scan.get_stdfloat();
|
|
|
+
|
|
|
+ } else {
|
|
|
+ _ambient.read_datagram(scan);
|
|
|
+ _diffuse.read_datagram(scan);
|
|
|
+ _specular.read_datagram(scan);
|
|
|
+ _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);
|
|
|
+ }
|
|
|
}
|
|
|
}
|