POV-Ray : Newsgroups : povray.general : parse vs. render stages, and best use of memory : Re: parse vs. render stages, and best use of memory Server Time
26 Jun 2024 12:16:08 EDT (-0400)
  Re: parse vs. render stages, and best use of memory  
From: clipka
Date: 28 Jan 2018 07:32:22
Message: <5a6dc2d6@news.povray.org>
Am 26.01.2018 um 22:22 schrieb Kenneth:

> A first basic question: Does pre-#declaring *anything* in POV-Ray (or any other
> programming language, for that matter) cause it to be evaluated only once and
> instantiated later (excepting isosurfaces and ....)?  It's quite difficult to
> set up a meaningful experiment to test this question, as there are just too many
> elements and permutations to consider.

Maybe it's worth first clearing up the term "evaluate".

That term is normally only used when talking about /expressions/, e.g.
`2*3+4` - more specifically, /constant/ expressions, i.e. expressions
that have no unspecified variables. For example, `2*3+x` can only be
evaluated if x is a concrete value. Such expressions may contain
functions, but again all parameters of such functions must be constant
expressions themselves, otherwise it cannot be evaluated.

You can describe and/or interpret geometric objects and textures as
functions, but not as constant expressions. So technically you cannot
"evaluate" them in the above sense, unless you want to know something
about the object or function for a given point in space (e.g. test
whether that particular point is inside or outside a given object, or
compute a given texture's colour for that particular point in space).

Thus objects and textures can only ever be "evaluated" during the render
phase (the functions `trace`, `inside` and `eval_pigment` are special
cases which I won't discuss here), and I suspect you probably mean
something else entirely.


Maybe what you mean is something I'd call "creating an instance" of, or
just "instantiating", an object: Reserving a block of memory as required
for a primitive of that particular type, and filling in the values
required later during the render stage. This may include a few
precomputed values, but for most primitives it is just the data
specified in the SDL code. (In contrast to most rendering engines,
POV-Ray does not first need to tesselate, i.e. create a mesh from, the
primitives.)

Such instantiation of an object /always/ happen during the parse stage,
namely in the following situations:

- Whenever you use any of the primitive keywords (`sphere`, `box`,
`mesh`, etc.), an object is instantiated from scratch as per the
parameters specified in the SDL code. This is also true for CSG compound
objects: They can be considered a special type of primitive that is
comprised of multiple elements which in turn are also primitives.

- Whenever you use the `object` keyword, an object is instantiated as a
copy of whatever you specify inside.

What happens to such an instance depends on the context:

- When used in a `#declare` or `#local` statement, the object instance
is stored in that variable.

- When used in a CSG statement, the object instance effectively becomes
incorporated into the CSG you're about to instantiate.

- When used in the scene itself, the object instance is inserted into
the scene.

Only objects inserted into the scene (either directly or by being part
of a CSG that is inserted into the scene) continue to "live" past the
end of the parse stage.

The same is essentially true for textures, pigments and interiors.

Whenever an object instance is inserted into the scene, some additional
instantiations may also happen. For instance, if a primitive does not
have an explicit texture, a texture will be instantiated as a copy of
either the containing CSG's texture or the default texture.


As a special case, some elements that are notorious for requiring lots
of memory (such as mesh or blob) are implemented in such a way that they
share the bulk (but not all) of their data across copied instances.

I'd have to take a deep look into the code to say which scene elements
do share portions of their data; the only thing I can say off the top of
my head is that there's still quite some room for improvement there.


> // the elements are pre-#declared here...
> #declare TEX = texture{pigment{gradient y} finish{ambient .1 diffuse .7}}
> #declare B = box{0,1}
> 
> #declare C = 1;
> #while(C <= 100000)
> object{B texture TEX translate 1.1*C*x}
> #declare C = C + 1;
> #end

(If I'm not mistaken you need curly braces around `TEX` when using it.)

> // ...versus NO pre-#declared elements
> #declare C = 1;
> #while(C <= 100000)
> box{0,1
>     texture{pigment{gradient y} finish{ambient .1 diffuse .7}}
>     translate 1.1*C*x
>    }
> #declare C = C + 1;
> #end
> 
> Is there a difference (of any kind) between using one vs. the other?

Yes: The version /with/ pre-declared elements actually takes up /more/
memory during parsing (namely the space required to hold the declared
element). On the upside, it will parse faster.


> To 'muddy the waters' a bit (or  maybe not?), add something simple like a random
> scale to the texture, in the first-example #while loop (just a typical
> 'conceptual' example of a change.) Does this cause the texture itself to be
> re-evaluated every time, and/or to require more memory?
> 
> #declare S = seed(123);
> #declare C = 1;
> #while(C <= 100000)
> object{B texture (TEX scale .5 + .5*rand(S)} translate 1.1*C*x}
> #declare C = C + 1;
> #end

No change in memory consumption there: Even without the transformation
of the texture a copy is currently created.


A while ago I had made an attempt to avoid copying of textures wherever
possible, but that turned out to be more complicated than expected, most
notably because when transforming an object the texture is also
implicitly transformed accordingly. Thus, at least portions of the
texture (namely any transformation information) have to be copied in
most cases anyway. So for now that endeavour has been shelved.


Post a reply to this message

Copyright 2003-2023 Persistence of Vision Raytracer Pty. Ltd.