 |
 |
|
 |
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
On 226-02-24 12:36 (-4), kurtz le pirate wrote:
>
> How this <color White=1> is interpreted and why does it turn red?
I just tried it with different versions of POV-Ray. It is red only with
POV-Ray 3.8 and the discontinued POV-Ray 3.7.1. It is white for all
versions 3.5 to 3.7.0.10.
This appears to be a bug that was introduced in POV-Ray 3.7.1.
Post a reply to this message
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
Cousin Ricky <ric### [at] yahoo com> wrote:
> On 226-02-24 12:36 (-4), kurtz le pirate wrote:
> >
> > How this <color White=1> is interpreted and why does it turn red?
>
> I just tried it with different versions of POV-Ray. It is red only with
> POV-Ray 3.8 and the discontinued POV-Ray 3.7.1. It is white for all
> versions 3.5 to 3.7.0.10.
>
> This appears to be a bug that was introduced in POV-Ray 3.7.1.
Nice work, Richard.
So what are you doing that I didn't?
Because as you can see above/below, I'm using 3.8
[after light_source]
White = <1.000, 1.000, 1.000, 0.000, 0.000>
"C:\Users\Mini\Documents\POV-Ray\v3.8-beta\scenes\_CodeScratchPad.pov" line 13:
Parse Warning: Expected pure RGB color expression,
unexpected filter and transmit components will have no effect.
Are you outputting the color value with vstr(), or performing a render using
that light source?
I'm just trying to understand where this all goes off the rails, and where to
look under the hood.
- BE
Post a reply to this message
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
On 2026-02-25 16:11 (-4), Bald Eagle wrote:
> Cousin Ricky <ric### [at] yahoo com> wrote:
>> On 226-02-24 12:36 (-4), kurtz le pirate wrote:
>>>
>>> How this <color White=1> is interpreted and why does it turn red?
>>
>> I just tried it with different versions of POV-Ray. It is red only with
>> POV-Ray 3.8 and the discontinued POV-Ray 3.7.1. It is white for all
>> versions 3.5 to 3.7.0.10.
>>
>> This appears to be a bug that was introduced in POV-Ray 3.7.1.
>
> Nice work, Richard.
> So what are you doing that I didn't?
> Because as you can see above/below, I'm using 3.8
I just opened a bug report on GitHub, issue #486.
https://github.com/POV-Ray/povray/issues/486
> [after light_source]
> White = <1.000, 1.000, 1.000, 0.000, 0.000>
> "C:\Users\Mini\Documents\POV-Ray\v3.8-beta\scenes\_CodeScratchPad.pov" line 13:
> Parse Warning: Expected pure RGB color expression,
> unexpected filter and transmit components will have no effect.
The warning about unexpected filter and transmit components indicates
that the bug did manifest, but without altering `White`. Did you create
an image output? Did you vstr() the expression `(White=1)`?
> Are you outputting the color value with vstr(), or performing a render using
> that light source?
Both. My source code is in the GitHub report.
Post a reply to this message
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
Cousin Ricky <ric### [at] yahoo com> wrote:
> The warning about unexpected filter and transmit components indicates
> that the bug did manifest, but without altering `White`. Did you create
> an image output? Did you vstr() the expression `(White=1)`?
As far as I can remember (it was early and I was on my way out the door to
work):
I vstr()'d the expression White,
then instantiated the light source (copy/pasted kurtz le pirate's exact code) ,
then vstr()'d the expression White again.
Which is now even weirder, because if White got changed to include filter and
transmit, then why didn't it show up with vstr? And why did it still have g&b
values of 1?
I'll check/post my actual code when I get home - but that won't be for another
5h.
- BE
Post a reply to this message
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
On 2026-02-25 17:09 (-4), Bald Eagle wrote:
>
> I vstr()'d the expression White,
>
> then instantiated the light source (copy/pasted kurtz le pirate's exact code) ,
>
> then vstr()'d the expression White again.
>
> Which is now even weirder, because if White got changed to include filter and
> transmit, then why didn't it show up with vstr? And why did it still have g&b
> values of 1?
>
> I'll check/post my actual code when I get home - but that won't be for another
> 5h.
The value of `White` never changes. It is the expression `(White=1)`
(which is a conditional in this context, not an assignment) that you
should vstr().
Post a reply to this message
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
Cousin Ricky <ric### [at] yahoo com> wrote:
> The value of `White` never changes. It is the expression `(White=1)`
> (which is a conditional in this context, not an assignment) that you
> should vstr().
Ah, yes. Very interesting.
So <1, 1, 1> gets promoted to rgbft <1, 1, 1, 0, 0>,
and 1 gets promoted to <1, 0, 0, 0, 0>
and then comparing element by element ones gets
<1, 1, 1, 0, 0>
<1, 0, 0, 0, 0>
---------------
<1, 0, 0, 1, 1>
Totally logical, yet totally unexpected!
- BE
Post a reply to this message
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
On 25/02/2026 12:45, Bald Eagle wrote:
> I'm thinking that the red must be coming from something else.
> Post the whole scene, a link, or at least more to work from?
the scene :
#version 3.8;
#include "colors"
global_settings {
assumed_gamma 1.0
max_trace_level 5
}
#default {
finish {
ambient 0.00
emission 0.40
diffuse 0.60
}
}
camera {
location <40,20,22>
up y
right x*image_width/image_height
look_at <0, a*0.60, 0>
angle 36
}
light_source {
<290, 384, 1350>
color White=1
}
plane {
y,0
pigment { White }
}
#declare a = 4;
box {
<-a, 0, -a>, <+a, 2*a, +a>
pigment { White }
}
With the warning :
Parse Warning: Expected pure RGB color expression, unexpected filter and
transmit components will have no effect.
--
kurtz le pirate
compagnie de la banquise
Post a reply to this message
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
On 2026-02-26 09:17 (-4), Bald Eagle wrote:
>
> So <1, 1, 1> gets promoted to rgbft <1, 1, 1, 0, 0>,
> and 1 gets promoted to <1, 0, 0, 0, 0>
>
> and then comparing element by element ones gets
>
> <1, 1, 1, 0, 0>
> <1, 0, 0, 0, 0>
> ---------------
> <1, 0, 0, 1, 1>
Good work!
The 1 should have been promoted to <1, 1, 1, 1, 1>. This would be
consistent with previous behavior and with other contexts where a scalar
appears in the same expression as a color or vector.
> Totally logical, yet totally unexpected!
Logic can give you wrong answers if a premise (in this case, the
promotion of the scalar) is wrong.
P.S. Not that it makes a difference here, but colors.inc defines `White`
as `rgb 1`, which means it does not need promotion. It already has the
value <1, 1, 1, 0, 0>.
Post a reply to this message
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
Cousin Ricky <ric### [at] yahoo com> wrote:
> The 1 should have been promoted to <1, 1, 1, 1, 1>.
Well, this is the danger with code, stems in general, and expectations.
"We would have _expected_ the 1 to be promoted to <1, 1, 1, 0, 0>."
But it did not.
> This would be
> consistent with previous behavior and with other contexts where a scalar
> appears in the same expression as a color or vector.
Right, which is what I was expecting, and what was throwing me off.
> > Totally logical, yet totally unexpected!
>
> Logic can give you wrong answers if a premise (in this case, the
> promotion of the scalar) is wrong.
>
> P.S. Not that it makes a difference here, but colors.inc defines `White`
> as `rgb 1`, which means it does not need promotion. It already has the
> value <1, 1, 1, 0, 0>.
But it DOES make a difference.
White is _rgb_ 1. NOT rgbft1.
That only happens on the fly when it needs to be compared to 1, which gets
promoted on the fly to rgbft.
That warning about f&t in the light source being ignored tells you it got
promoted, whereas a "normal" scene with rgb 1 would not issue such a warning.
This will take a lot of looking into to find out WHY it does what it does.
I'm just very thankful that no such thing took place when I was working out the
vector / scalar typing/differentiation!
- BE
Post a reply to this message
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
I wanted to dig in a bit deeper to discover why scalar 1 gets promoted to <1, 0,
0, 0, 0, 0> instead of <1, 1, 1, 1, 1>.
Something clever that I noticed in the response was using vdot (V, V) as a way
to "count" the number of components in the vector (assuming they are all 1).
I will have to play with this idea.
Is there a way to normalize all the components of a vector without knowing how
many components there are?
--------------------------------------------------------------
AI response:
results: the equality operator = produces a scalar (0/1). If that scalar is then
required to participate in a 5‑component colour/vector context higher up
the expression tree, the parser embeds the scalar into a 5‑component
a float across all components, but it does not apply to boolean results of
comparisons. [github.com], [math.hws.edu]
Equality is scalar
In POV‑Ray SDL, A = B is a comparison with a scalar truth value (1 for
one. Internally the expression evaluator carries results in a small fixed array
count is 1. [github.com]
Type/arity is decided by surrounding context
When that scalar result is used where a vector/colour is expected, the parser
promotes it to the needed arity. There are two different promotion paths in the
language implementation:
General operator promotion (float → N‑vector), described in the
reference manual: a lone float can be promoted to a vector of 2/3/4/5 components
by replicating the same value into all components (e.g., 5 → <5,5,5> when
a 3‑vector is needed). This rule applies when a float literal/expression
itself is being used as a vector. [math.hws.edu]
Embedding of boolean/scalar results into multi‑component registers that
occurs inside the expression parser for comparison/logical operations. For
these, the parser stores the truth value in component 0 and clears the
remainder, producing <1,0,0,0,0> if the surrounding context expects a
5‑component value (as happens in colour/5‑term vector contexts).
This is why you observe <1,0,0,0,0> instead of <1,1,1,1,1>. You can see the
relevant behavior in the expression parser implementation (comparison handling
and result packing) in parser_expressions.cpp. [github.com]
Colour (5‑term) contexts are common
colours are 5‑component vectors: rgbft), the arity is 5. The documentation
non‑colour scalar promoted into a colour context naturally becomes
something shaped like <value, 0, 0, 0, 0> when it comes from a boolean
comparison result. [povray.org], [museum.state.il.us]
applies when a numeric float is directly promoted to an N‑vector (e.g.,
scale 5 → scale <5,5,5>). That rule does not override how
boolean/comparison results are packaged internally by the parser. So:
1 used as a colour literal where replication is needed: <1,1,1,1,1> (general
promotion). [math.hws.edu]
( <1,1,1> = 1 ) used where a colour is required: comparison yields scalar 1
first → then embedded as <1,0,0,0,0> (boolean embedding). [github.com]
If you need a vector/colour mask of ones after a comparison, build it
explicitly, e.g.:
Text.#declare V = <1,1,1>;#declare M = (vdot(V, V) = 3 ? <1,1,1,1,1> :
<0,0,0,0,0>); // example of explicit replicationShow more lines
or use arithmetic to replicate the scalar result across components before the
colour context forces 5D:
Chart.js#declare B = (<1,1,1> = 1); // scalar 0/1#declare M = B *
<1,1,1,1,1>; // replicate into all 5 lanesShow more lines
(Here the multiplication forces general operator promotion on the float B to a
5‑vector, giving <B,B,B,B,B>.) [math.hws.edu]
handles = and point to the code paths that set only the first component on
3.8 alpha, or master). [github.com]
The relevant code in the parser
defines an epsilon‑based predicate to turn floats into boolean truth
values. You can see both patterns in the current file and its 3.7 predecessor:
// parser_expressions.cpp
#define FTRUE (f) ( (int) (fabs (f)>EPSILON))
This is used throughout the numeric/logic code paths whenever a boolean is
needed. [github.com]
Internally, results are stored as an EXPRESS (a fixed array of DBL) with a
float-parameter helper rejects multi‑term results by checking Terms>1:
DBL Parser::Parse_Float_Param ()
{
DBL Local;
EXPRESS Express;
int Terms;
bool old_allow_id = Allow_Identifier_In_Call;
Allow_Identifier_In_Call = false;
Parse_Paren_Begin ();
Parse_Express (Express,&Terms);
if (Terms>1)
{
Error ("Float expected but vector or color expression found.");
}
Local = Express [0];
Parse_Paren_End ();
Allow_Identifier_In_Call = old_allow_id;
return (Local);
}
This shows the (values, arity) representation: Express[0..Terms-1] is the
payload; the scalar case is Terms == 1. [github.com]
You can see the same scheme in the 3.7 code (express.cpp) as well.
[bugs.povray.org]
2) Places that set the arity
Whenever a vector-returning construct is parsed (e.g., a vector function call),
the parser explicitly writes multiple lanes into Express[...] and sets the
arity:
void Parser::Parse_Vector_Function_Call(EXPRESS Express, int *Terms)
{
// ... call into VM ...
for (param = 0; param < f->return_size; param++)
Express[param] = fnVMContext->GetLocal(param);
*Terms = f->return_size; // <-- explicit arity for vector returns
}
the expression parser. [bugs.povray.org]
3) Where comparisons land
The actual comparison operators (e.g., =, !=, <, <=, >=, >) are handled in the
numeric/relational part of the expression parser; the code keeps temporary
scalars like greater_val, less_val, equal_val for those results, which are then
written back to the expression register as a single component (arity 1). You can
see these locals declared in the numeric parser routine:
// inside Parser::Parse_Num_Factor(...) in 3.7
DBL greater_val, less_val, equal_val; // temps for relational/equality tests
Those comparisons convert to 0/1 using epsilon semantics (FTRUE), and then store
the result as a scalar in Express[0] with *Terms = 1. That is the key to the
Why we care: Once a comparison has yielded a scalar Express[0] ∈ {0,1}
with Terms=1, any later need for a vector/colour will trigger a promotion. Which
promotion path it takes determines whether you get <1,0,0,0,0> or <1,1,1,1,1>.
the end result depends on which one the parser chooses from context:
Float → N‑vector replication (operator promotion rule).
expects an N‑component vector and you give it a float, it replicates the
float into all components:
9 → <9,9,9,9> (for 4‑vectors), 5 → <5,5,5> (for
3‑vectors), etc. [math.hws.edu]
Lower‑arity vector → higher‑arity vector zero‑fill.
The same section also says that when promoting a vector of lower dimension to a
higher one, the remaining components are set to zero:
<7,6> → <7,6,0,0> if a 4‑vector is required. [math.hws.edu]
The comparison result takes path (2), not (1).
The equality (<1,1,1> = 1) is parsed/evaluated in the numeric/relational
pipeline. The boolean truth value is put into the expression register as a
1 and Express[0] = 1.0. When that value is later needed in a 5‑component
colour context (e.g., inside pigment { ... } where colours are rgbft
5‑vectors), POV‑Ray promotes a 1‑component vector to a
5‑component vector, which fills lanes 2..5 with zeros, giving <1,0,0,0,0>.
This matches exactly what you observed. [povray.org], [math.hws.edu]
By contrast, a literal 1 (a float) appearing directly in a colour context
5‑vector is expected and it starts from a true float, not from a
had in mind. [povray.org], [math.hws.edu]
Why does a comparison yield a 1‑lane vector instead of a float?
All numeric/logic sub‑expressions are computed into the EXPRESS register
(DBL Express[5]) plus an integer Terms.
Pure scalars and booleans both occupy Terms = 1 lane at that point.
the parser treats a Terms = 1 result as a vector of arity 1 if vector/colour
typing already dominates the surrounding context. From there, the
vector→vector arity promotion (zero‑fill) applies, not the
float→vector replication. [github.com], [bugs.povray.org]
So for (<1,1,1> = 1) you end up with:
Relational evaluation → Express[0] = 1.0, Terms = 1 (boolean true).
[bugs.povray.org]
Used in a colour (5‑vector) position → 1‑lane vector upcast to
5‑lane → <1,0,0,0,0>. [povray.org], [math.hws.edu]
How to get <1,1,1,1,1> from a boolean on purpose
If your intent is a mask of ones across all five colour lanes, force the
float→vector promotion (replication) explicitly by multiplying with a full
vector constant:
#declare B = (<1,1,1> = 1); // scalar 0/1 in Express[0]
#declare M = B * <1,1,1,1,1>; // forces float→vector replication
→ <B,B,B,B,B>
This uses general operator promotion (a float on the left in a vector arithmetic
expression) so POV‑Ray replicates B to each lane. [math.hws.edu]
#declare M = select(B, <0,0,0,0,0>, <1,1,1,1,1>);
Post a reply to this message
|
 |
|  |
|  |
|
 |
|
 |
|  |
|
 |