Skip to content

Commit c95f67a

Browse files
committed
docs: Fix specification clarity of smoothstep
It was pointed out on Slack by Arnon Marcus that the spec's description of smoothstep was ambiguous about the behavior when edge0==edge1==x: does it return 0 or 1 here? The implementation returned 1, which I think is the "correct" behavior in the sense that when edge0==edge1, the results should match the step() function with that edge. * Fix the descriptions in the spec to match the implementation and what I think is the best behavior. * Also change paremter names edge0/edge1 to low/high, which I think is much more clearly self-documenting. Signed-off-by: Larry Gritz <lg@larrygritz.com>
1 parent 9f4aa5e commit c95f67a

File tree

3 files changed

+67
-70
lines changed

3 files changed

+67
-70
lines changed

src/doc/languagespec.tex

+18-19
Original file line numberDiff line numberDiff line change
@@ -3488,23 +3488,23 @@ \section{Pattern generation}
34883488
performed component-by-component (separately for $x$, $y$, and $z$).
34893489
\apiend
34903490

3491-
\apiitem{float {\ce linearstep} (float edge0, float edge1, float x) \\
3492-
\emph{type} {\ce linearstep} (\emph{type} edge0, \emph{type} edge1, \emph{type} x)}
3491+
\apiitem{float {\ce linearstep} (float low, float high, float x) \\
3492+
\emph{type} {\ce linearstep} (\emph{type} low, \emph{type} high, \emph{type} x)}
34933493
\indexapi{linearstep()}
3494-
Returns 0 if $x \le {\mathit edge0}$, and 1 if $x \ge {\mathit edge1}$,
3494+
Returns 0 if $x \le {\mathit low}$, and 1 if $x \ge {\mathit high}$,
34953495
and performs a linear
3496-
interpolation between 0 and 1 when ${\mathit edge0} < x < {\mathit edge1}$.
3497-
This is equivalent to {\cf step(edge0, x)} when {\cf edge0 == edge1}.
3496+
interpolation between 0 and 1 when ${\mathit low} < x < {\mathit high}$.
3497+
This is equivalent to {\cf step(low, x)} when {\cf low == high}.
34983498
For \color and \point-like types, the computations are
34993499
performed component-by-component (separately for $x$, $y$, and $z$).
35003500
\apiend
35013501

3502-
\apiitem{float {\ce smoothstep} (float edge0, float edge1, float x) \\
3503-
\emph{type} {\ce smoothstep} (\emph{type} edge0, \emph{type} edge1, \emph{type} x)}
3502+
\apiitem{float {\ce smoothstep} (float low, float high, float x) \\
3503+
\emph{type} {\ce smoothstep} (\emph{type} low, \emph{type} high, \emph{type} x)}
35043504
\indexapi{smoothstep()}
3505-
Returns 0 if $x \le {\mathit edge0}$, and 1 if $x \ge {\mathit edge1}$,
3505+
Returns 0 if $x < {\mathit low}$, and 1 if $x \ge {\mathit high}$,
35063506
and performs a smooth Hermite
3507-
interpolation between 0 and 1 when ${\mathit edge0} < x < {\mathit edge1}$.
3507+
interpolation between 0 and 1 when ${\mathit low} < x < {\mathit high}$.
35083508
This is useful in cases where you would want a thresholding function
35093509
with a smooth transition.
35103510

@@ -3513,17 +3513,16 @@ \section{Pattern generation}
35133513
performed component-by-component.
35143514
\apiend
35153515

3516-
\apiitem{float {\ce smooth_linearstep} (float edge0, float edge1, float x, float eps) \\
3517-
\emph{type} {\ce smooth_linearstep} (\emph{type} edge0, \emph{type} edge1, \emph{type} x, \emph{type} eps)}
3516+
\apiitem{float {\ce smooth_linearstep} (float low, float high, float x, float eps) \\
3517+
\emph{type} {\ce smooth_linearstep} (\emph{type} low, \emph{type} high, \emph{type} x, \emph{type} eps)}
35183518
\indexapi{smooth_linearstep()}
3519-
This function is strictly linear between ${\mathit edge0}+{\mathit eps}$ and ${\mathit edge1}-{\mathit eps}$
3520-
but smoothly ramps to 0 between ${\mathit edge0}-{\mathit eps}$ and ${\mathit edge0}+{\mathit eps}$
3521-
and smoothly ramps to 1 between ${\mathit edge1}-{\mathit eps}$ and ${\mathit edge1}+{\mathit eps}$.
3522-
It is 0 when $x \le {\mathit edge0}-{\mathit eps}$, and 1 if $x \ge {\mathit edge1}+{\mathit eps}$,
3523-
and performs a linear
3524-
interpolation between 0 and 1 when ${\mathit edge0} < x < {\mathit edge1}$.
3525-
For \color and \point-like types, the computations are
3526-
performed component-by-component.
3519+
This function returns 0 if $x < {\mathit low}-{\mathit eps}$, and 1 if
3520+
$x \ge {\mathit high}+{\mathit eps}$, is strictly linear between
3521+
${\mathit low}+{\mathit eps}$ and ${\mathit high}-{\mathit eps}$ but smoothly
3522+
ramps to 0 between ${\mathit low}-{\mathit eps}$ and ${\mathit low}+{\mathit eps}$
3523+
and smoothly ramps to 1 between ${\mathit high}-{\mathit eps}$ and
3524+
${\mathit high}+{\mathit eps}$. For \color and \point-like types, the
3525+
computations are performed component-by-component.
35273526
\apiend
35283527

35293528

src/doc/stdlib.md

+14-16
Original file line numberDiff line numberDiff line change
@@ -458,36 +458,34 @@ the computations are performed component-by-component (separately for `x`,
458458
performed component-by-component (separately for $x$, $y$, and $z$).
459459

460460

461-
`float` **`linearstep`** `(float edge0, float edge1, float x)` <br> *`type`* **`linearstep`** (*`type`* `edge0`, *`type`* `edge1`, *`type`* `x`)
461+
`float` **`linearstep`** `(float low, float high, float x)` <br> *`type`* **`linearstep`** (*`type`* `low`, *`type`* `high`, *`type`* `x`)
462462

463-
: Returns 0 if `x` $\le$ `edge0`, and 1 if `x` $\ge$ `edge1`, and performs a
464-
linear interpolation between 0 and 1 when `edge0` $<$ `x` $<$ `edge1`.
465-
This is equivalent to `step(edge0, x)` when `edge0 == edge1`. For `color`
463+
: Returns 0 if `x` $<$ `low`, and 1 if `x` $\ge$ `high`, and performs a
464+
linear interpolation between 0 and 1 when `low` $<$ `x` $<$ `high`.
465+
This is equivalent to `step(low, x)` when `low == high`. For `color`
466466
and `point`-like types, the computations are performed
467467
component-by-component (separately for $x$, $y$, and $z$).
468468

469469

470-
`float` **`smoothstep`** `(float edge0, float edge1, float x)` <br> *`type`* **`smoothstep`** (*`type`* `edge0`, *`type`* `edge1`, *`type`* `x`)
470+
`float` **`smoothstep`** `(float low, float high, float x)` <br> *`type`* **`smoothstep`** (*`type`* `low`, *`type`* `high`, *`type`* `x`)
471471

472-
: Returns 0 if `x` $\le$ `edge0`, and 1 if `x` $\ge$ `edge1`, and performs a
473-
smooth Hermite interpolation between 0 and 1 when `edge0` $<$ `x` $<$
474-
`edge1`. This is useful in cases where you would want a thresholding
472+
: Returns 0 if `x` $<$ `low`, and 1 if `x` $\ge$ `high`, and performs a
473+
smooth Hermite interpolation between 0 and 1 when `low` $<$ `x` $<$
474+
`high`. This is useful in cases where you would want a thresholding
475475
function with a smooth transition.
476476

477477
The *`type`* may be any of of `float`, `color`, `point`, `vector`, or
478478
`normal`. For `color` and `point`-like types, the computations are
479479
performed component-by-component.
480480

481481

482-
`float` **`smooth_linearstep`** `(float edge0, float edge1, float x, float eps)` <br> *`type`* **`smooth_linearstep`** (*`type`* `edge0`, *`type`* `edge1`, *`type`* `x`, *`type`* eps)
482+
`float` **`smooth_linearstep`** `(float low, float high, float x, float eps)` <br> *`type`* **`smooth_linearstep`** (*`type`* `low`, *`type`* `high`, *`type`* `x`, *`type`* eps)
483483

484-
: This function is strictly linear between `edge0 + eps` and `edge1 - eps`
485-
but smoothly ramps to 0 between `edge0 - eps` and `edge0 + eps`
486-
and smoothly ramps to 1 between `edge1 - eps` and `edge1 + eps`.
487-
It is 0 when `x` $\le$ `edge0-eps,` and 1 if `x` $\ge$ `edge1 + eps`,
488-
and performs a linear interpolation between 0 and 1 when
489-
`edge0` < x < `edge1`. For `color` and `point`-like types, the
490-
computations are performed component-by-component.
484+
: This function returns 0 if `x` $<$ `low-eps,` and 1 if `x` $\ge$ `high + eps`,
485+
is strictly linear between `low + eps` and `high - eps`, but smoothly
486+
ramps to 0 between `low - eps` and `low + eps` and smoothly ramps to 1
487+
between `high - eps` and `high + eps`. For `color` and `point`-like types,
488+
the computations are performed component-by-component.
491489

492490

493491
%## Noise functions

src/shaders/stdosl.h

+35-35
Original file line numberDiff line numberDiff line change
@@ -319,73 +319,73 @@ point step (point edge, point x) BUILTIN;
319319
vector step (vector edge, vector x) BUILTIN;
320320
normal step (normal edge, normal x) BUILTIN;
321321
float step (float edge, float x) BUILTIN;
322-
float smoothstep (float edge0, float edge1, float x) BUILTIN;
322+
float smoothstep (float low, float high, float x) BUILTIN;
323323

324-
color smoothstep (color edge0, color edge1, color x)
324+
color smoothstep (color low, color high, color x)
325325
{
326-
return color (smoothstep(edge0[0], edge1[0], x[0]),
327-
smoothstep(edge0[1], edge1[1], x[1]),
328-
smoothstep(edge0[2], edge1[2], x[2]));
326+
return color (smoothstep(low[0], high[0], x[0]),
327+
smoothstep(low[1], high[1], x[1]),
328+
smoothstep(low[2], high[2], x[2]));
329329
}
330-
vector smoothstep (vector edge0, vector edge1, vector x)
330+
vector smoothstep (vector low, vector high, vector x)
331331
{
332-
return vector (smoothstep(edge0[0], edge1[0], x[0]),
333-
smoothstep(edge0[1], edge1[1], x[1]),
334-
smoothstep(edge0[2], edge1[2], x[2]));
332+
return vector (smoothstep(low[0], high[0], x[0]),
333+
smoothstep(low[1], high[1], x[1]),
334+
smoothstep(low[2], high[2], x[2]));
335335
}
336336

337-
float linearstep (float edge0, float edge1, float x) {
337+
float linearstep (float low, float high, float x) {
338338
float result;
339-
if (edge0 != edge1) {
340-
float xclamped = clamp (x, edge0, edge1);
341-
result = (xclamped - edge0) / (edge1 - edge0);
339+
if (low != high) {
340+
float xclamped = clamp (x, low, high);
341+
result = (xclamped - low) / (high - low);
342342
} else { // special case: edges coincide
343-
result = step (edge0, x);
343+
result = step (low, x);
344344
}
345345
return result;
346346
}
347-
color linearstep (color edge0, color edge1, color x)
347+
color linearstep (color low, color high, color x)
348348
{
349-
return color (linearstep(edge0[0], edge1[0], x[0]),
350-
linearstep(edge0[1], edge1[1], x[1]),
351-
linearstep(edge0[2], edge1[2], x[2]));
349+
return color (linearstep(low[0], high[0], x[0]),
350+
linearstep(low[1], high[1], x[1]),
351+
linearstep(low[2], high[2], x[2]));
352352
}
353-
vector linearstep (vector edge0, vector edge1, vector x)
353+
vector linearstep (vector low, vector high, vector x)
354354
{
355-
return vector (linearstep(edge0[0], edge1[0], x[0]),
356-
linearstep(edge0[1], edge1[1], x[1]),
357-
linearstep(edge0[2], edge1[2], x[2]));
355+
return vector (linearstep(low[0], high[0], x[0]),
356+
linearstep(low[1], high[1], x[1]),
357+
linearstep(low[2], high[2], x[2]));
358358
}
359359

360-
float smooth_linearstep (float edge0, float edge1, float x_, float eps_) {
360+
float smooth_linearstep (float low, float high, float x_, float eps_) {
361361
float result;
362-
if (edge0 != edge1) {
362+
if (low != high) {
363363
float rampup (float x, float r) { return 0.5/r * x*x; }
364-
float width_inv = 1.0 / (edge1 - edge0);
364+
float width_inv = 1.0 / (high - low);
365365
float eps = eps_ * width_inv;
366-
float x = (x_ - edge0) * width_inv;
366+
float x = (x_ - low) * width_inv;
367367
if (x <= -eps) result = 0;
368368
else if (x >= eps && x <= 1.0-eps) result = x;
369369
else if (x >= 1.0+eps) result = 1;
370370
else if (x < eps) result = rampup (x+eps, 2.0*eps);
371371
else /* if (x < 1.0+eps) */ result = 1.0 - rampup (1.0+eps - x, 2.0*eps);
372372
} else {
373-
result = step (edge0, x_);
373+
result = step (low, x_);
374374
}
375375
return result;
376376
}
377377

378-
color smooth_linearstep (color edge0, color edge1, color x, color eps)
378+
color smooth_linearstep (color low, color high, color x, color eps)
379379
{
380-
return color (smooth_linearstep(edge0[0], edge1[0], x[0], eps[0]),
381-
smooth_linearstep(edge0[1], edge1[1], x[1], eps[1]),
382-
smooth_linearstep(edge0[2], edge1[2], x[2], eps[2]));
380+
return color (smooth_linearstep(low[0], high[0], x[0], eps[0]),
381+
smooth_linearstep(low[1], high[1], x[1], eps[1]),
382+
smooth_linearstep(low[2], high[2], x[2], eps[2]));
383383
}
384-
vector smooth_linearstep (vector edge0, vector edge1, vector x, vector eps)
384+
vector smooth_linearstep (vector low, vector high, vector x, vector eps)
385385
{
386-
return vector (smooth_linearstep(edge0[0], edge1[0], x[0], eps[0]),
387-
smooth_linearstep(edge0[1], edge1[1], x[1], eps[1]),
388-
smooth_linearstep(edge0[2], edge1[2], x[2], eps[2]));
386+
return vector (smooth_linearstep(low[0], high[0], x[0], eps[0]),
387+
smooth_linearstep(low[1], high[1], x[1], eps[1]),
388+
smooth_linearstep(low[2], high[2], x[2], eps[2]));
389389
}
390390

391391
float aastep (float edge, float s, float dedge, float ds) {

0 commit comments

Comments
 (0)