 |
 |
|
 |
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
OK "POV-Ray community,"
Let's make a concerted effort to get some of those things out of your heads and
off of your hard drives and onto the forum during the next week.
Post something. It doesn't matter what it is.
Really. Just post it. Here.
A question.
"I saw X and always wondered how they did that."
"I always wanted to do Y, but never knew how."
"I tried to get Z to work, but never finished it."
"How does this work in source code?"
"How do I achieve this effect?"
"I saw this on the forum, and always wondered how they did that."
A simple scene.
A little coding or math trick.
A photo/diagram of something you've always wanted to make in POV-Ray.
And old scene that you've never posted. "I made this way back in 19XX"
I wish we had XYZ feature.
There's a bug that's always annoyed me.
They can do this with
Blender/Maya/Grasshopper/Shadertoy/Mathematica/MathMod/etc. so why can't we do
that with POV-Ray?
I did a web search for PDQ and I found ABC. Pretty cool, huh?
If you know some people who are on another website / forum / social media site -
extend the invitation to post . . . something.
Poke your old POV-Ray friends until they post something just to get you to stop
bothering them. :D
Add new topics to post about. "You forgot IJK..."
- BE
Post a reply to this message
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
All-SDL, Fully tileable, Full-color true Voronoi pigment. (grid-based)
Post a reply to this message
Attachments:
Download 'tileablevoronoi_torusoptimized_patch2.png' (425 KB)
Preview of image 'tileablevoronoi_torusoptimized_patch2.png'

|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
On 2026-03-20 19:21 (-4), Bald Eagle wrote:
>
> Post something. It doesn't matter what it is.
> Really. Just post it. Here.
Funny you should mention. I was just at a stopping point with this
experiment for improving my light bleeding code.
Post a reply to this message
Attachments:
Download 'relative_glow.pbi.png' (76 KB)
Preview of image 'relative_glow.pbi.png'

|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
"Attractors"
When surfing the Web looking for new and interesting pigment patterns that I
could implement, I came across some very cool looking stuff.
The idea is that a pattern is somehow modulated by its proximity to points or
even lines. Any attribute can be modified - size, shape, color, position, some
other more complicated thing like a parameter of the underlying pattern, etc.
I've experimented a little with this in the past, but didn't know that it was a
fully-developed "thing".
Here's a sinc function that modulates the size of 3 different object grids.
https://en.wikipedia.org/wiki/Sinc_function
Post a reply to this message
Attachments:
Download 'demo_attractorgrids.png' (346 KB)
Preview of image 'demo_attractorgrids.png'

|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
One of the reasons that I started this thread was to try and spur people into
action, and get people who are scattered over the vast interweb to contribute
here in the official POV-Ray newsgroup. Not Facebook, Meta, X, Telegram,
Instagram, YouTube, Discord, etc.
I have too many of my own projects to keep up with - I don't have the time and
attention to multiply posting and answer-searching over a dozen other venues.
Also, since I don't have the time to pursue every new thing that I come across
or need to do as part of a 5-step development, I figured I'd start posting bits
and pieces, so that others might be inspired to pick something up, investigate
it further, and maybe carry it across the finish line.
Some things I "complete" just to demonstrate proof-of-concept.
"No, it's not 'impossible'."
Other things I create from spur-of-the moment necessity, and just continue using
as a matter of practicality.
All of those things could surely be "better", more efficient, and more elegant.
They could also be refactored into durable "production code" with future-proof
structuring of the code and data structures, comments, references, and notes on
future, unfinished improvements.
Perhaps if there is interest - the fruits of this thread could be periodically
packaged into a semantic-versioned archive (zip, 7z, tar.gz) that would help
people expand on the official distribution.
- BE
Post a reply to this message
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
One of the things that I have sustained an active interest in over the past
several years is the creation of procedural patterns.
Doing this in SDL to create pigment {function {}} patterns can be challenging
due to the scalar-only nature of the function parser / virtual machine.
During experimentation with infinitely tiling a plane or filling space, it
became readily apparent that the stock modulo function - mod (N, M) - did not
remain consistent across the -value|0|+value transition.
So I crafted my own. And then another. And then another.
So which one was "right"? Apparently this is one of those situation-dependent
functions like pow (0, 0).
So I did some investigating and there are a number of different ways to perform
modular arithmetic so that the result has the specific characteristics that you
need in your given situation. And here's an important note: you may need to use
different behaviours in different parts of your equations.
I discovered that my custom-rolled fmod () function usually worked for what I
needed, but when applied in a blanket manner was inappropriate for certain parts
of my patterns. So I use fmod () some places, and stock mod () in others.
Here's a small starting library. I'm sure there are more variations.
// MODULO_LIB.inc
// Behavioral Modulo Library for POV-Ray SDL
// Guarded, scalar-only, function-safe
#ifndef (MODULO_LIB_INC)
#declare MODULO_LIB_INC = yes;
// --- HARD MODULO ---
#declare MOD_HARD_BASIC = function (V, P) { mod(V, P) };
// --- ABSOLUTE MODULO ---
#declare MOD_ABS_BASIC = function (V, P) { mod(abs(V), P) };
// --- PHASE-CORRECTED ABS MODULO ---
#declare MOD_ABS_PHASE = function (V, P)
{ select(V, 1 - mod(abs(V), P), mod(abs(V), P)) };
// --- CENTERED MODULO ---
#declare MOD_CENTER_BASIC = function (V, P)
{ mod(V + P/2, P) - P/2 };
// --- TRIANGLE MODULO ---
#declare MOD_TRI_BASIC = function (V, P)
{ abs(mod(V, 2*P) - P) };
// --- SMOOTH MODULO ---
#declare MOD_SMOOTH_BASIC = function (V, P)
{ P * (0.5 - 0.5*cos(2*pi*V/P)) };
#declare MOD_SMOOTH_SIGNED = function (V, P)
{ V - P * sin(2*pi*V/P)/(2*pi) };
// --- NESTED MODULO ---
#declare MOD_NEST_BASIC = function (V, A, B)
{ mod(mod(V, A), B) };
#declare MOD_NEST_ABS = function (V, A, B)
{ mod(mod(abs(V), A), B) };
#declare MOD_NEST_PHASE = function (V, A, B)
{ select(V, B - mod(mod(abs(V), A), B), mod(mod(abs(V), A), B)) };
// --- LOGIC MODULO ---
#declare MOD_LOGIC_PARITY = function (V, P)
{ mod(floor(abs(V)/P), 2) };
#declare MOD_LOGIC_QUANTIZED = function (V, P, S)
//{ round(mod(V, P)/S)*S };
{ int(mod(V, P)/S)*S };
// --- WINDOWED / CLAMPED ---
#declare MOD_LOGIC_WINDOW = function (V, P)
{ select(V, mod(abs(V), P), 0) };
#declare MOD_LOGIC_CLAMP = function (V, P, C)
{ min(mod(V, P), C) };
// --- METRIC HELPERS ---
#declare MOD_METRIC_RADIAL = function (R, P)
{ mod(R, P) };
#declare MOD_METRIC_ANGLE = function (A, P)
{ mod(A, P) };
#end
// *** end of file ***
Post a reply to this message
Attachments:
Download 'modulo_lib_full_demo.png' (53 KB)
Preview of image 'modulo_lib_full_demo.png'

|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
"Bald Eagle" <cre### [at] netscape net> wrote:
> "I tried to get Z to work, but never finished it."
Way back when - when I had lots more time to spend several (mostly)
uninterrupted hours working things out, I coded up an animation of the entire
solar system, which mostly astronomically correct. Plus the asteroid belt.
Everything started out at clock=0, and all the objects were in syzygy.
For all those other folks playing around with such things like orreries, the
important part is adjusting everything for it's specific Mean Anomaly.
January 1, 2000, at 12:00 Terrestrial Time (TT) or Julian Date 2451545.0
Mean anomaly formulation:
M(t) = M0 + 360 * (t - t0)/P
Where:
- M0 : mean anomaly at J2000
- t : POV-Ray clock (years)
- t0 : epoch (0 = J2000)
- P : orbital period (years)
#declare Epoch_J2000 = 0.0;
#declare Mercury_M0 = 174.79253;
#declare Venus_M0 = 50.37663;
#declare Earth_M0 = 357.51716;
#declare Mars_M0 = 19.39020;
#declare Jupiter_M0 = 19.66796;
#declare Saturn_M0 = 317.02070;
#declare Uranus_M0 = 142.28383;
#declare Neptune_M0 = 260.24710;
#declare Pluto_M0 = 14.53;
Moons don't orbit around the sun, and so they need to be adjusted for their
local barycentric framing.
#declare Luna_M0 = 115.3654;
#declare Io_M0 = 171.0168;
#declare Europa_M0 = 67.9876;
#declare Ganymede_M0 = 44.0648;
#declare Callisto_M0 = 259.7088;
#declare Titan_M0 = 186.5855;
#declare Rhea_M0 = 191.9137;
#declare Iapetus_M0 = 79.6900;
#declare Dione_M0 = 131.5349;
#declare Tethys_M0 = 215.1191;
#declare Enceladus_M0 = 268.0502;
#declare Miranda_M0 = 311.33;
#declare Ariel_M0 = 98.35;
#declare Umbriel_M0 = 355.67;
#declare Titania_M0 = 77.82;
#declare Oberon_M0 = 250.96;
#declare Triton_M0 = 328.92;
Post a reply to this message
|
 |
|  |
|  |
|
 |
|
 |
|  |
|  |
|
 |
"Bald Eagle" <cre### [at] netscape net> wrote:
> A little coding or math trick.
Writing functions for a pigment {function {}} pattern with a scalar-only
function parser / VM can be painful.
For every vector, I need to evaluate 3 separate functions for each component,
and then when I need to daisy-chain functions together, that multiplies at every
step.
So one of the things I have come up with that makes this a little easier is to
extract the component that I need from the vector, and use select () to choose
which equation I need to evaluate based on a nice little operation.
select is a nice little function that gives me a way to use different equations
given the sign of some variable.
The easy way to remember this is to write select (N, -1, 0, 1).
Depending on the sign of N, I get the sign as the result.
You can put whatever you want in place of the sign when actually using this
mnemonic in practice.
To choose what equation you want would require you to remember that the pattern
is x=-1, y=0, and z=+1
But that's one more thing to forget, so we can make use of the dot product to
generate those values for us from the cardinal axis values themselves.
In POV-Ray, during the parse phase,
======================
x = <1, 0, 0>
y = <0, 1, 0>
z = <0, 0, 1>
The dot product takes the respective components of each vector, multiplies them
together, and then adds all the quotients to give a scalar value.
V1.x * V2.x +
V1.y * V2.y +
V1.z * V2.z
-------------
= dot product (V1, V2)
With POV-Ray's x, y, and z vectors, we are only ever multiplying anything by 0
or 1.
So what we do is take vector <-1, 0, 1> and calculate the dot product of that
with x, y, or z.
with x, you get 1 * -1, and the rest are zeros. Sum = -1
with Y, you get 1 * 0, and the rest are zeros. Sum = 0
with z, you get 1 * 1, and the rest are zeros. Sum = 1
This makes it easy to write macros that can take a vector argument and return a
function from a macro or the scalar result of a function from select ().
That's handy when you need to write a bunch of functions for x AND y AND z.
Because you can write a macro to assemble the function based upon which vector
you need.
MyMacro (x)
So you can either use an array of x, y, and z, or manually specify in your code
which one you want, and your intent is unambiguous.
This seems trivial.
It also requires a little bit of work up front to create the functionality, but
it makes handling functions along 3 different axes a lot more easily managed,
especially when you have A LOT of them.
In the macro below, I can assemble functions for each axis by using select() to
grab that vector component from an array using dot notation. This is
interesting because we're operating in the parser, not the function VM, so we
can use both arrays and dot notation to _construct_ a function.
Those values will remain static - which is fine because those are the vector
components of the control points for the Bezier surface, and don't need to
dynamically change during render phase.
#macro MakeVFn_BezierPatch (_Array, _Component)
// Assembles formula for ONE VECTOR COMPONENT of a Bezier patch
// (need to run THREE TIMES: once each for x, y, and z)
#local Degree = dimension_size (_Array, 1)-1;
function (_U, _V) {
#for (j, 0, Degree)
#for (i, 0, Degree)
#local _P =
select (_Component, _Array [i][j].x, _Array [i][j].y, _Array
[i][j].z);
Bernstein(Degree, i, _V) * Bernstein(Degree, j, _U) * _P +
#end
#end
0} // terminates equation for sum of all Bernstein polynomials in the patch
#end
That's a little snippet from a mammoth .pov file, so below is a self-contained
script that you can read and play with. A different function is graphed along
each axis without having to specify each axis operation by hand.
------------------------------------------------------------------------------
// Scene file for demonstrating the use of the dot product for
// extracting the relevant vector component of a macro argument
// by converting it to an index value for direct use in select ()
// Bill "Bald Eagle" Walker 2026/03/21
// There are other ways to do this, but this highlights one of the
// MANY uses of the vector dot product.
#version version;
global_settings {assumed_gamma 1.0}
camera {
location <1/4, 1, -1/2>*15
right x*image_width/image_height
up y
look_at <0, 0, 0>
}
light_source {<40, 30, -50> rgb 1 shadowless}
sky_sphere {pigment {rgb 1}}
plane {y, 0 pigment {checker rgb 0.1 rgb 0.2} scale 2}
#declare E = 0.000001;
#declare Line = 0.05;
#declare Extent = 10;
#declare Step = 0.1;
#declare Vdot = function (Vx, Vy, Vz, Cx, Cy, Cz) {Vx*Cx + Vy*Cy + Vz*Cz}
#macro DotProduct (V1, V2)
#local V1x = V1.x;
#local V1y = V1.y;
#local V1z = V1.z;
#local V2x = V2.x;
#local V2y = V2.y;
#local V2z = V2.z;
Vdot (V1x, V1y, V1z, V2x, V2y, V2z)
#end
#declare even = function(x) {select(mod(x, 2), 0, 1, 0)}
#declare odd = function(x) {select(mod(x, 2), 1, 0, 1)}
#declare Cardinal = array {x, y, z}
#declare Selector = <-1, 0, 1>;
#local ZeroVector = <0, 0, 0>;
#declare FunctionX = function (N) {sqrt(N)}
#declare FunctionY = function (N) {abs(-odd(floor(N))+mod(N, 1))}
#declare FunctionZ = function (N) {sin (N)}
#declare V3 = function (N) {mod (N, 3)}
#declare AxisFunction = function (Switch, N) {
select (
Switch,
FunctionX (N),
FunctionY (N),
FunctionZ (N)
)
}
#for (Axis, 0, 2)
#local Vector = Cardinal [Axis];
//===============================================
#local Component = DotProduct (Vector, Selector);
//===============================================
#local Abscissa = Vector;
#local Ordinate = Cardinal [V3(Axis+1)];
union {
#for (i, 0, Extent, Step)
#local Value = AxisFunction (Component, i);
#local A = Abscissa * i;
#local O = Ordinate * Value;
#local Current = A + O + ZeroVector;
sphere {Current, Line}
#if (i > 0)
cylinder {Last, Current+E Line}
#end
#local Last = Current;
#end
pigment {rgb Vector}
}
#end
Post a reply to this message
Attachments:
Download 'axisselection.png' (55 KB)
Preview of image 'axisselection.png'

|
 |
|  |
|  |
|
 |
|
 |
|  |
|
 |