[surface3d] display scaling depends on grid resolution?
Add a description
Pd 0.55.0, GEM 0.94.git v0.94-651-g199e8d21, Ubuntu 22.04
I find myself perplexed about the display scaling of surface3d.
In the attached patch, I'm generating control points in a loop -- for testing purposes, just in a simple grid. The grid points always interpolate linearly between -3.0 and 3.0, but the object's display is always smaller than this.
Even more strangely, the size depends on the number of divisions in the grid: 5x5 seems to scale the coordinates by exactly half, 6x6 is slightly larger, 7x7 larger, with each step incrementing by a smaller amount, so that there is probably some sort of asymptote but I haven't quantified that.
I haven't been able to divine the reason for this behavior.
In any case, I would just like the object to display the size that I'm requesting, by whatever combination of coordinates and scaling are necessary -- to do that properly, I would need to understand the relationship between coordinates, grid size and actual display. Can you offer some insight?
5x5 display:
10x10 display:
The patch
thanks github :-\
#N canvas 326 27 828 747 12;
#X declare -lib Gem -path Gem;
#X obj 43 78 gemhead;
#X floatatom 436 79 5 4 15 0 - - - 0;
#X obj 436 29 loadbang;
#X msg 436 54 5;
#X obj 436 128 value num;
#N canvas 475 342 450 300 idx2gem 0;
#X obj 47 35 inlet;
#X obj 254 114 value num;
#X obj 95 165 expr ($f1 / ($f2-1) - 0.5) * 6;
#X obj 95 190 outlet;
#X obj 47 60 t f f b, f 30;
#X obj 47 228 outlet;
#X connect 0 0 4 0;
#X connect 1 0 2 1;
#X connect 2 0 3 0;
#X connect 4 0 5 0;
#X connect 4 1 2 0;
#X connect 4 2 1 0;
#X restore 283 212 pd idx2gem;
#N canvas 470 51 450 528 loop-indices 0;
#X obj 36 37 inlet;
#X obj 36 96 value num;
#X obj 36 146 f, f 11;
#X obj 129 146 + 1;
#X msg 110 96 0;
#X obj 36 250 value num;
#X obj 36 300 f, f 11;
#X obj 129 300 + 1;
#X msg 111 250 0;
#X obj 36 171 t b f f, f 11;
#X obj 36 225 t b b, f 11;
#X obj 36 121 until;
#X obj 36 275 until;
#X obj 264 377 outlet;
#X obj 36 377 outlet;
#X obj 36 71 t b b, f 11;
#X obj 36 325 t f f, f 11;
#X connect 0 0 15 0;
#X connect 1 0 11 0;
#X connect 2 0 9 0;
#X connect 3 0 2 1;
#X connect 4 0 2 1;
#X connect 5 0 12 0;
#X connect 6 0 16 0;
#X connect 7 0 6 1;
#X connect 8 0 6 1;
#X connect 9 0 10 0;
#X connect 9 1 13 0;
#X connect 9 2 3 0;
#X connect 10 0 5 0;
#X connect 10 1 8 0;
#X connect 11 0 2 0;
#X connect 12 0 6 0;
#X connect 15 0 1 0;
#X connect 15 1 4 0;
#X connect 16 0 14 0;
#X connect 16 1 7 0;
#X restore 192 161 pd loop-indices;
#N canvas 475 342 450 300 idx2gem 0;
#X obj 47 35 inlet;
#X obj 254 114 value num;
#X obj 95 165 expr ($f1 / ($f2-1) - 0.5) * 6;
#X obj 95 190 outlet;
#X obj 47 60 t f f b, f 30;
#X obj 47 228 outlet;
#X connect 0 0 4 0;
#X connect 1 0 2 1;
#X connect 2 0 3 0;
#X connect 4 0 5 0;
#X connect 4 1 2 0;
#X connect 4 2 1 0;
#X restore 192 212 pd idx2gem;
#X obj 43 446 surface3d;
#X obj 376 128 s size;
#X obj 249 348 r size;
#X obj 192 266 pack f f f f, f 23;
#X msg 74 304 normal \$1;
#X obj 74 279 tgl 20 0 empty empty empty 0 -10 0 12 #fcfcfc #000000 #000000 0 1;
#N canvas 475 342 450 300 printctl 0;
#X obj 39 41 inlet;
#X obj 39 120 f;
#X obj 39 145 t f f;
#X msg 93 120 0;
#X obj 39 198 outlet;
#X obj 94 41 inlet;
#X connect 0 0 1 0;
#X connect 1 0 2 0;
#X connect 2 0 4 0;
#X connect 2 1 3 0;
#X connect 3 0 1 1;
#X connect 5 0 1 1;
#X restore 479 323 pd printctl;
#X obj 553 273 bng 20 250 50 0 empty empty empty 0 -10 0 12 #fcfcfc #000000 #000000;
#X msg 553 298 1;
#X obj 440 348 spigot;
#X obj 440 373 print;
#X obj 545 199 gemhead 2;
#X msg 192 291 set \$1 \$2 \$3 \$4 0;
#X obj 545 224 square 3;
#X obj 43 237 color 0.1 0.1 0.5;
#X text 620 209 size reference: should be this big, f 19;
#X text 586 268 bang to print the control points once, f 15;
#X obj 43 507 color 0.3 0.7 0.3;
#X obj 43 540 translateXYZ -1.5 -1.5 0;
#X obj 43 565 circle 0.1;
#X obj 43 624 circle 0.1;
#X obj 43 599 translateXYZ 3 0 0;
#X obj 239 565 circle 0.1;
#X obj 239 540 translateXYZ 0 3 0;
#X obj 239 624 circle 0.1;
#X obj 239 599 translateXYZ -3 0 0;
#X text 192 459 see? it really is drawing exactly 1.5 \, when my control points range -3 .. +3 ???, f 24;
#X text 84 325 no effect;
#X obj 611 77 gemwin;
#X msg 587 29 create \, 1;
#X msg 671 29 0 \, destroy;
#X obj 43 38 declare -lib Gem -path Gem;
#X obj 43 103 t a b b, f 43;
#X msg 134 376 draw line;
#X msg 249 373 res \$1 \$1 \, grid \$1 \$1;
#X connect 0 0 40 0;
#X connect 1 0 4 0;
#X connect 1 0 9 0;
#X connect 2 0 3 0;
#X connect 3 0 1 0;
#X connect 5 0 11 1;
#X connect 5 1 11 3;
#X connect 6 0 7 0;
#X connect 6 1 5 0;
#X connect 7 0 11 0;
#X connect 7 1 11 2;
#X connect 8 0 25 0;
#X connect 10 0 42 0;
#X connect 11 0 20 0;
#X connect 12 0 8 0;
#X connect 13 0 12 0;
#X connect 14 0 17 1;
#X connect 15 0 16 0;
#X connect 16 0 14 1;
#X connect 17 0 18 0;
#X connect 19 0 21 0;
#X connect 20 0 17 0;
#X connect 20 0 8 0;
#X connect 22 0 8 0;
#X connect 25 0 26 0;
#X connect 26 0 27 0;
#X connect 27 0 29 0;
#X connect 28 0 31 0;
#X connect 29 0 28 0;
#X connect 30 0 33 0;
#X connect 31 0 30 0;
#X connect 33 0 32 0;
#X connect 37 0 36 0;
#X connect 38 0 36 0;
#X connect 40 0 22 0;
#X connect 40 1 6 0;
#X connect 40 2 14 0;
#X connect 41 0 8 0;
#X connect 42 0 8 0;
According to the helpfile : "The surface3d object renders a curve at the current position with current color or texture. The shape of the curve is controlled from a matrix. The curve go throw all control points (between point 1 to res-1)" It did not go from point 0 to "resolution", because of the curved interpolation. So it behave like advertised. (Well it may be a bad design, but I have no idea how to do better).
p.s : tips : you can zip a Pd patch to attach it in a comment.
With apologies, but I can't quite make sense of this answer.
It's perhaps my own lack of familiarity with 3D graphics, but "The curve go through [sic] all control points (between point 1 to res-1)" ... I don't know how to interpret this at all.
With a bit more experimentation (but sticking with square grids), I see that:
- If res(n, n) == grid(n, n), then the shape maintains its integrity as I would expect, but the rendered size varies with (x, y).
- If res(n, n) < grid(n, n), then the shape maintains its integrity, but shrinks and moves towards the lower left corner.
- If res(n, n) > grid(n, n), then there is some curious modulo behavior with the control point coordinates, where they seem to wrap around according to some pattern.
I'm not saying that the design needs to change -- what I am saying is that the relationship between res, grid and the rendering of the eventual coordinates is not at all easy to understand based on the documentation. There is something in there that is obvious to you as the developer, but, nobody else understands it.
I would be satisfied with some formula to calculate [scaleXYZ] factors given n control points on the two axes.
sorry for my bad explanation. let's try to make an understandable documentation. Let me explain the way it works from the beginning : Res X Y is the resolution of the control surface. Grid X Y is the resolution of the surface that will be display. The grid will be interpolated to create a smooth surface, a bit like tabread4 is interpolating a table when you want to read in between control point. Grid X Y should be > Res X Y in order to have the soothing effect of the interpolation. The problem is on the border of the grid. The interpolation need 2 points on every direction to create this smooth interpolation. (it's just like tabread4~ : it can't interpolate the border of the table). If you use a grid of resolution 5 (only speaking in 1 direction), you will have 4 intervals. And the 1st and last will not be display. So, the size of the surface is : (n-3)/(n-1). Scale the curve with a factor (n-1)/(n-3) is probably what you want. an other easy workaround is the create additional points on the border : 0, 0, 0.5, 1, 1 to display a curve from 0, 0.5, 1. but the interpolation will not be uniform. If you need something uniform, you need to add points like this : -0.5, 0, 0.5, 1, 1.5 in order to display points uniformly from 0 to 1. in a generic way : -1/n, 0, 1/n, 2/n ... n-1:n, n, (n+1)/n But if you need something uniform it's easier to use [mesh_square]...
I hope it answer your question, feel free to ask for more, and adjust the help file if needed.
Ah OK, that explains it very well. Thanks for taking the time!
(n-3)/(n-1), where n = 5, = 2/4 = 1/2 and that matches exactly the scaling I was seeing.
I'll put it on the to-do list to add an example or two to the help patch, but I won't be able to do it quickly.