Skip to content

Commit a419e30

Browse files
committed
Added advanced diffuse shading models.
The traditional Lambertian model can only realistically simulate the diffuse component of _smooth_ surfaces; this commit adds two alternative models that give more realistic results for non-smooth surfaces: The _Lommel-Seeliger_ model mimics very porous or dusty surfaces. While it has no parameters in and of itself, it is frequently used in a weighted average with the Lambertian model. To activate the Lommel-Seeliger model in POV-Ray, use `diffuse FLOAT lommel_seeliger on` for the pure model, or `diffuse FLOAT lommel_seeliger FLOAT` for a blend with the Lambertian model. The default is `lommel_seeliger 0.0`, indicating a blend of 0% Lommel-Seeliger and 100% Lambertian. The _Oren-Nayar_ model extends the Lambertian model to mimic rough (but not porous) surfaces. To activate it in POV-Ray, use `diffuse FLOAT oren_nayar FLOAT`, where the parameter specifies the desired roughness (the _sigma_ parameter in the Oren-Nayar equations). The default is `oren_nayar 0.0`, indicating a perfectly smooth surface, in which case the Oren-Nayar model simplifies to the Lambertian model. _NOTE:_ The new diffuse shading models are still highly experimental, and changes in syntax and/or functionality are almost guaranteed; most notably, the interaction with the `diffuse albedo FLOAT` syntax and the finish-level `fresnel` keyword still needs to be reviewed and possibly modified. Also, the parameterization of the Oren-Nayar model may be changed to better match the `roughness` parameterization for specular highlights.
1 parent 0a062cc commit a419e30

File tree

9 files changed

+121
-24
lines changed

9 files changed

+121
-24
lines changed

source/base/version.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@
4545
#define OFFICIAL_VERSION_STRING "3.7.1"
4646
#define OFFICIAL_VERSION_NUMBER 371
4747

48-
#define POV_RAY_PRERELEASE "alpha.8514084"
48+
#define POV_RAY_PRERELEASE "alpha.8545805"
4949

5050
#if (POV_RAY_IS_AUTOBUILD == 1) && ((POV_RAY_IS_OFFICIAL == 1) || (POV_RAY_IS_SEMI_OFFICIAL == 1))
5151
#ifdef POV_RAY_PRERELEASE

source/core/material/texture.cpp

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1153,18 +1153,21 @@ FINISH *Create_Finish()
11531153
New->Reflection_Max.Clear();
11541154
New->Reflection_Min.Clear();
11551155

1156-
New->Reflection_Fresnel = false;
1157-
New->Reflection_Falloff = 1; /* Added by MBP 8/27/98 */
1158-
New->Diffuse = 0.6;
1159-
New->DiffuseBack = 0.0;
1160-
New->Brilliance = 1.0;
1161-
New->BrillianceOut = 1.0;
1162-
New->BrillianceAdjust = 1.0;
1163-
New->BrillianceAdjustRad = 1.0;
1164-
New->Phong = 0.0;
1165-
New->Phong_Size = 40.0;
1166-
New->Specular = 0.0;
1167-
New->Roughness = 1.0 / 0.05;
1156+
New->Reflection_Fresnel = false;
1157+
New->Reflection_Falloff = 1; /* Added by MBP 8/27/98 */
1158+
New->Diffuse = 0.6;
1159+
New->DiffuseBack = 0.0;
1160+
New->Brilliance = 1.0;
1161+
New->BrillianceOut = 1.0;
1162+
New->BrillianceAdjust = 1.0;
1163+
New->BrillianceAdjustRad = 1.0;
1164+
New->LommelSeeligerWeight = 0.0;
1165+
New->OrenNayarA = 1.0;
1166+
New->OrenNayarB = 0.0;
1167+
New->Phong = 0.0;
1168+
New->Phong_Size = 40.0;
1169+
New->Specular = 0.0;
1170+
New->Roughness = 1.0 / 0.05;
11681171

11691172
New->Crand = 0.0;
11701173

source/core/material/texture.h

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,32 @@ struct Texture_Struct : public Pattern_Struct
118118
struct Finish_Struct
119119
{
120120
SNGL Diffuse, DiffuseBack, Brilliance, BrillianceOut, BrillianceAdjust, BrillianceAdjustRad;
121+
122+
/// How much of the diffuse contribution should be computed using the Lommel-Seeliger model.
123+
///
124+
/// By default, POV-Ray uses a Lambertian-based diffuse reflectivity model. While this model is useful for
125+
/// comparatively smooth surfaces, rough surfaces are better simulated using other models, one of the simplest
126+
/// being the Lommel-Seeliger model. In astronomy, a weighted average of the Lambertian and Lommel-Seeliger models
127+
/// is frequently used.
128+
SNGL LommelSeeligerWeight;
129+
130+
/// @name Oren-Nayar diffuse model parameters.
131+
///
132+
/// By default, POV-Ray uses a Lambertian-based diffuse reflectivity model. While this model is useful for
133+
/// comparatively smooth surfaces, rough surfaces are better simulated using other models, one of which is the
134+
/// (simplified) Oren-Nayar model, being a superset of the Lambertian model and governed by the following
135+
/// parameters.
136+
///
137+
/// @{
138+
139+
/// Factor A of the simplified Oren-Nayar model, defaulting to 1.0 for the Lambertian model.
140+
SNGL OrenNayarA;
141+
142+
/// Factor B of the simplified Oren-Nayar model, defaulting to 0.0 for the Lambertian model.
143+
SNGL OrenNayarB;
144+
145+
/// @}
146+
121147
SNGL Specular, Roughness;
122148
SNGL Phong, Phong_Size;
123149
SNGL Irid, Irid_Film_Thickness, Irid_Turb;
@@ -129,9 +155,16 @@ struct Finish_Struct
129155
SNGL Reflection_Falloff; // Added by MBP 8/27/98
130156
bool Reflection_Fresnel;
131157
bool Fresnel;
132-
SNGL Reflect_Metallic; // MBP
133-
int Conserve_Energy; // added by NK Dec 19 1999
134-
bool UseSubsurface; // whether to use subsurface light transport
158+
SNGL Reflect_Metallic; // MBP
159+
int Conserve_Energy; // added by NK Dec 19 1999
160+
bool UseSubsurface; // whether to use subsurface light transport
161+
162+
void SetOrenNayarSigma(double sigma)
163+
{
164+
double sigmaSqr = sigma*sigma;
165+
OrenNayarA = 1.0 - 0.50 * sigmaSqr / (sigmaSqr + 0.57);
166+
OrenNayarB = 0.45 * sigmaSqr / (sigmaSqr + 0.09);
167+
}
135168
};
136169

137170

source/core/render/trace.cpp

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2373,19 +2373,37 @@ void Trace::ComputeShadowColour(const LightSource &lightsource, Intersection& is
23732373
void Trace::ComputeDiffuseColour(const FINISH *finish, const Vector3d& lightDirection, const Vector3d& eyeDirection, const Vector3d& layer_normal, MathColour& colour, const MathColour& light_colour,
23742374
const MathColour& layer_pigment_colour, double relativeIor, double attenuation, bool backside)
23752375
{
2376-
double cos_angle_of_incidence, intensity;
2376+
double cos_in, cos_out, intensity;
23772377
double diffuse = (backside? finish->DiffuseBack : finish->Diffuse) * finish->BrillianceAdjust;
23782378

23792379
if (diffuse <= 0.0)
23802380
return;
23812381

2382-
cos_angle_of_incidence = dot(layer_normal, lightDirection);
2382+
cos_in = dot(layer_normal, lightDirection);
23832383

23842384
// Brilliance is likely to be 1.0 (default value)
23852385
if(finish->Brilliance != 1.0)
2386-
intensity = pow(fabs(cos_angle_of_incidence), (double) finish->Brilliance);
2386+
intensity = pow(fabs(cos_in), (double) finish->Brilliance);
23872387
else
2388-
intensity = fabs(cos_angle_of_incidence);
2388+
intensity = fabs(cos_in);
2389+
2390+
if (finish->Fresnel || (finish->LommelSeeligerWeight != 0.0) || (finish->OrenNayarB != 0.0))
2391+
cos_out = -dot(layer_normal, eyeDirection);
2392+
2393+
if (finish->LommelSeeligerWeight != 0.0)
2394+
intensity *= (1.0 - finish->LommelSeeligerWeight + finish->LommelSeeligerWeight / (cos_in + cos_out));
2395+
2396+
if (finish->OrenNayarB != 0.0)
2397+
{
2398+
Vector3d projected_in = lightDirection - layer_normal * cos_in;
2399+
Vector3d projected_out = -eyeDirection - layer_normal * cos_out;
2400+
double cos_phi = dot(projected_in, projected_out);
2401+
double theta_in = acos(cos_in);
2402+
double theta_out = acos(cos_out);
2403+
double alpha = max(theta_in, theta_out);
2404+
double beta = min(theta_in, theta_out);
2405+
intensity *= (finish->OrenNayarA + finish->OrenNayarB*max(0.0,cos_phi)*sin(alpha)*tan(beta));
2406+
}
23892407

23902408
intensity *= diffuse * attenuation;
23912409

@@ -2395,9 +2413,8 @@ void Trace::ComputeDiffuseColour(const FINISH *finish, const Vector3d& lightDire
23952413
if (finish->Fresnel)
23962414
{
23972415
MathColour cs1, cs2;
2398-
ComputeFresnel(cs1, MathColour(0.0), MathColour(1.0), cos_angle_of_incidence, relativeIor);
2399-
cos_angle_of_incidence = -dot(layer_normal, eyeDirection);
2400-
ComputeFresnel(cs2, MathColour(0.0), MathColour(1.0), cos_angle_of_incidence, relativeIor);
2416+
ComputeFresnel(cs1, MathColour(0.0), MathColour(1.0), cos_in, relativeIor);
2417+
ComputeFresnel(cs2, MathColour(0.0), MathColour(1.0), cos_out, relativeIor);
24012418
colour += intensity * layer_pigment_colour * light_colour * cs1 * cs2;
24022419
}
24032420
else

source/parser/parser.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,9 @@ struct ExperimentalFlags
156156
{
157157
bool backsideIllumination : 1;
158158
bool functionHf : 1;
159+
bool lommelSeeliger : 1;
159160
bool meshCamera : 1;
161+
bool orenNayar : 1;
160162
bool slopeAltitude : 1;
161163
bool spline : 1;
162164
bool subsurface : 1;
@@ -166,7 +168,9 @@ struct ExperimentalFlags
166168
ExperimentalFlags() :
167169
backsideIllumination(false),
168170
functionHf(false),
171+
lommelSeeliger(false),
169172
meshCamera(false),
173+
orenNayar(false),
170174
slopeAltitude(false),
171175
spline(false),
172176
subsurface(false),

source/parser/parser_materials.cpp

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2371,6 +2371,18 @@ void Parser::Parse_Finish (FINISH **Finish_Ptr)
23712371
mExperimentalFlags.backsideIllumination = true;
23722372
END_CASE
23732373

2374+
CASE (LOMMEL_SEELIGER_TOKEN)
2375+
New->LommelSeeligerWeight = Parse_Float ();
2376+
mExperimentalFlags.lommelSeeliger = true;
2377+
END_CASE
2378+
2379+
CASE (OREN_NAYAR_TOKEN)
2380+
New->SetOrenNayarSigma(Parse_Float ());
2381+
mExperimentalFlags.orenNayar = true;
2382+
PossibleError("Parameterization of the Oren-Nayar diffuse model has not been finalized yet."
2383+
" Expect future versions of POV-Ray to render this scene differently without warning.");
2384+
END_CASE
2385+
23742386
CASE (REFLECTION_TOKEN)
23752387
{
23762388
bool found_second_color = false;
@@ -2598,6 +2610,30 @@ void Parser::Parse_Finish (FINISH **Finish_Ptr)
25982610
END_EXPECT /* End of finish_mods */
25992611
#endif
26002612

2613+
if ((New->OrenNayarA != 1.0) || (New->OrenNayarB != 0.0))
2614+
{
2615+
if (New->Fresnel)
2616+
PossibleError("Finish-level 'fresnel' keyword found in combination with the Oren-Nayar diffuse model."
2617+
" The interaction of these features has not been finalized yet, and is known to be bogus."
2618+
" Expect future versions of POV-Ray to render this scene differently without warning.");
2619+
if (diffuseAdjust)
2620+
PossibleError("'diffuse albedo' found in combination with the Oren-Nayar diffuse model."
2621+
" The interaction of these features has not been finalized yet."
2622+
" Expect future versions of POV-Ray to render this scene differently without warning.");
2623+
}
2624+
2625+
if (New->LommelSeeligerWeight != 0.0)
2626+
{
2627+
if (New->Fresnel)
2628+
PossibleError("Finish-level 'fresnel' keyword found in combination with the Lommel-Seeliger diffuse model."
2629+
" The interaction of these features has not been finalized yet, and is known to be bogus."
2630+
" Expect future versions of POV-Ray to render this scene differently without warning.");
2631+
if (diffuseAdjust)
2632+
PossibleError("'diffuse albedo' found in combination with the Lommel_Seeliger diffuse model."
2633+
" The interaction of these features has not been finalized yet."
2634+
" Expect future versions of POV-Ray to render this scene differently without warning.");
2635+
}
2636+
26012637
if ((sceneData->EffectiveLanguageVersion() >= 370) && ambientSet)
26022638
{
26032639
// As of version 3.7, use of "ambient" to model glowing materials is deprecated, and "emission" should be used

source/parser/reservedwords.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,7 @@ const RESERVED_WORD Reserved_Words[LAST_TOKEN] = {
320320
{LOCAL_TOKEN, "local"},
321321
{LOCATION_TOKEN, "location"},
322322
{LOG_TOKEN, "log"},
323+
{LOMMEL_SEELIGER_TOKEN, "lommel_seeliger"},
323324
{LOOKS_LIKE_TOKEN, "looks_like"},
324325
{LOOK_AT_TOKEN, "look_at"},
325326
{LOW_ERROR_FACTOR_TOKEN, "low_error_factor" },
@@ -389,6 +390,7 @@ const RESERVED_WORD Reserved_Words[LAST_TOKEN] = {
389390
{ON_TOKEN, "on"},
390391
{OPEN_TOKEN, "open"},
391392
{OPTIONAL_TOKEN, "optional"},
393+
{OREN_NAYAR_TOKEN, "oren_nayar"},
392394
{ORIENTATION_TOKEN, "orientation"},
393395
{ORIENT_TOKEN,"orient"},
394396
{ORTHOGRAPHIC_TOKEN, "orthographic"},

source/parser/reservedwords.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,7 @@ enum TOKEN_IDS
249249
LEOPARD_TOKEN,
250250
LIGHT_SOURCE_TOKEN,
251251
LOCATION_TOKEN,
252+
LOMMEL_SEELIGER_TOKEN,
252253
LOOKS_LIKE_TOKEN,
253254
LOOK_AT_TOKEN,
254255
MANDEL_TOKEN,
@@ -269,6 +270,7 @@ enum TOKEN_IDS
269270
ONCE_TOKEN,
270271
ONION_TOKEN,
271272
OPTIONAL_TOKEN,
273+
OREN_NAYAR_TOKEN,
272274
OVUS_TOKEN,
273275
PERCENT_TOKEN,
274276
PHASE_TOKEN,

unix/VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
3.7.1-alpha.8514084
1+
3.7.1-alpha.8545805

0 commit comments

Comments
 (0)