In perspective mode, if the camera is inside the negative cube, it
will not be rendered. You can see that in GUI too by zooming in/out.
ciao,
Torsten.
On 11/4/2022 7:05 AM, Torsten Paul wrote:
In perspective mode, if the camera is inside the negative cube, it
will not be rendered. You can see that in GUI too by zooming in/out.
Huh. I knew about the "don't put the camera in the negative object"
rule, but hadn't realized that it only applies to perspective mode.
Is there a simple explanation for why perspective mode has that
restriction and orthogonal mode doesn't?
Probably because you don't need clipping planes for an orthogonal view but
you do for perspective.
On Fri, 4 Nov 2022 at 17:04, Jordan Brown openscad@jordan.maileater.net
wrote:
On 11/4/2022 7:05 AM, Torsten Paul wrote:
In perspective mode, if the camera is inside the negative cube, it
will not be rendered. You can see that in GUI too by zooming in/out.
Huh. I knew about the "don't put the camera in the negative object" rule,
but hadn't realized that it only applies to perspective mode.
Is there a simple explanation for why perspective mode has that
restriction and orthogonal mode doesn't?
OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org
On 11/4/2022 10:13 AM, nop head wrote:
Probably because you don't need clipping planes for an orthogonal view
but you do for perspective.
I have never truly understood the need for clipping planes... and
after doing a bit of research, I still don't.
Most sources say only what they do, without saying why you want
them. The one source I found that said "why", a computer graphics
textbook, gave reasons that I didn't really understand.
In my copious free time I'll track down where they are applied in
OpenSCAD and disable them, and see what the effects are like.
You need near and far clipping planes for BOTH orthographic and perspective
camera modes, and it is not possible to disable them.
They are builtin to the way the "camera" is modeled in OpenGL.
Those limits are used to determine the overall "scale" or precision of the
depth buffer.
See here https://www.khronos.org/opengl/wiki/Depth_Buffer_Precision for a
much more thorough explanation of how the clipping planes contribute to
depth buffer precision.
The crucial difference between ortho and perspective is that a perspective
view has a focal point. (diagram of a perspective view frustum
https://en.wikipedia.org/wiki/Viewing_frustum#/media/File:ViewFrustum.svg)
You can't render things behind the focal point (zNear < 0), because the
image of those things would be flipped upside down and backwards.
Furthermore you can't set your near clipping plane exactly at the focal
point (zNear = 0), because that is a mathematical singularity, where you
have to divide by zero and your depth buffer ceases to have any precision
or meaning.
In orthographic mode, there is no focal point and the viewing frustum is a
cuboid
https://en.wikipedia.org/wiki/Viewing_frustum#/media/File:Orthographic_view_frustum.png
That means you can set the "near" clipping plane to a negative value with
no adverse effects, and so we do in fact set (zNear = -zFar)
On Fri, Nov 4, 2022 at 12:30 PM Jordan Brown openscad@jordan.maileater.net
wrote:
On 11/4/2022 10:13 AM, nop head wrote:
Probably because you don't need clipping planes for an orthogonal view but
you do for perspective.
I have never truly understood the need for clipping planes... and after
doing a bit of research, I still don't.
Most sources say only what they do, without saying why you want them.
The one source I found that said "why", a computer graphics textbook, gave
reasons that I didn't really understand.
In my copious free time I'll track down where they are applied in OpenSCAD
and disable them, and see what the effects are like.
OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org
On 11/5/2022 6:52 AM, Hans L wrote:
The crucial difference between ortho and perspective is that a
perspective view has a focal point. (diagram of a perspective view
frustum
https://en.wikipedia.org/wiki/Viewing_frustum#/media/File:ViewFrustum.svg)
You can't render things behind the focal point (zNear < 0), because
the image of those things would be flipped upside down and backwards.
Furthermore you can't set your near clipping plane exactly at the
focal point (zNear = 0), because that is a mathematical
singularity, where you have to divide by zero and your depth buffer
ceases to have any precision or meaning.
In orthographic mode, there is no focal point and the viewing frustum
is a cuboid
https://en.wikipedia.org/wiki/Viewing_frustum#/media/File:Orthographic_view_frustum.png
That means you can set the "near" clipping plane to a negative value
with no adverse effects, and so we do in fact set (zNear = -zFar)
Ah, now I understand the "camera inside the negative space" restriction,
and why it doesn't apply to orthographic mode. Thanks!
But that also revealed another ... interesting ... behavior.
Part of the trickery surrounding preview mode is that negative objects
are "real" and play a critical role in preview. I haven't been able to
really internalize what's going on, but I think that roughly a negative
object is an "invisibility cloak" that projects an image of what's on
the other side on its near side, thus hiding the objects in-between.
In perspective mode, once the negative object is in front of the near
plane (perhaps behind the camera, perhaps not), we are "under" the
invisibility cloak and it no longer works.
I kind of understood that before.
But the tidbit that you've added is that for orthogonal mode, the near
clipping plane is far behind the camera.
That's great for negative objects, because they are "shown"; the
invisibility cloak works.
But it's not nearly so great for positive objects - because objects both
in front of and behind the camera are shown. (Or, I suppose, another
way to look at it is that the camera is always infinitely far away from
the model; the camera can never be in the model.)
I visualized this using an animation (included below). First, watch it
in perspective mode. It creates a line of blue cubes and a line of red
cubes, then flies between them. When it reaches the middle of the line,
it turns left to face a blue cube.
That all looks straightforward in perspective mode. Now put it in
orthogonal mode. While it makes an interesting dance of cubes, it
doesn't look even a little bit the same, and you end up facing a red
cube. (Really, you're still facing that blue cube, but it's showing you
the outside face of the red cube.)
As a side note, one of the reasons that I used an animation for this is
that I already had some "fly through" logic, that let me think in terms
of where the camera is rather than the more model-centric view that the
UI usually presents. I was finding it quite hard to get the camera to
do what I wanted using the manual controls. That in turn makes me
wonder about maybe including a "first person shooter" mode, where the
mouse and keyboard move the camera, rather than moving the module.
Somebody on IRC was asking about that a couple of weeks ago.
Here's the program. I'm using FPS=10 and steps=100. Note that because
of the repetitive pattern, some combinations lead to frame rate
illusions where it can look like you are moving backwards through the cubes.
flythrough=true;
size = 5;
ysep = 50;
xsep = 20;
for(x=[-500:xsep:500]) translate([x,0,0]) {
color("red") translate([0,-ysep/2,0]) cube(size, center=true);
color("blue") translate([0,ysep/2,0]) cube(size, center=true);
}
route = [
[ 0, [-700, 0, 0], [0, 90]],
[ 1, [0, 0, 0], [0, 90]],
[ 2, [0, 0, 0], [90, 90]],
[ 1, [0, 0, 0], [90, 90]],
];
// Given a [rho, theta] or [rho, theta, phi], transform to
// an [x,y] or [x,y,z].
function torect(p) =
len(p) == 3 ? torect3(p) : torect2(p);
function torect2(p) = [
p[0] * cos(p[1]),
p[0] * sin(p[1])
];
function torect3(p) = [
p[0] * cos(p[1]) * sin(p[2]),
p[0] * sin(p[1]) * sin(p[2]),
p[0] * cos(p[2])
];
// Given a value and a table of value/position pairs, interpolate a
// position for that value.
// It seems like lookup() should do this sort of vector interpolation
// on its own, but it doesn't seem to.
function xyzinterp(v, table) =
let (x= [for (i=[0:len(table)-1]) [table[i][0], table[i][1][0]]])
let (y= [for (i=[0:len(table)-1]) [table[i][0], table[i][1][1]]])
let (z= [for (i=[0:len(table)-1]) [table[i][0], table[i][1][2]]])
[lookup(v, x), lookup(v, y), lookup(v,z)];
function routesum(a, start, end) = start > end ? 0 : a[start][0] + routesum(a, start+1, end);
r2 = [ for (i = [0:len(route)-1]) [ routesum(route, 0, i), route[i][1], route[i][2] ] ];
t_start = 0;
t_end = r2[len(r2)-1][0];
positions = [ for (e = r2) [ e[0], e[1] ]];
directions = [ for (e = r2) [ e[0], e[2] ]];
pos = xyzinterp($t*(t_end-t_start)+t_start, positions);
dir = xyzinterp($t*(t_end-t_start)+t_start, directions);
$vpd = flythrough ? 140 : $vpd;
$vpt = flythrough ? pos + torect([$vpd, dir[0], dir[1]]) : $vpt;
$vpr = flythrough ? [180-dir[1], 0, (dir[0]+270)%360] : $vpr;
This is why l render nearly all my 3D differences for previews. Not only is
there the camera problem but also the negative objects can clash with other
surfaces and cause z fighting.
It does give a one off time hit but I minimize the scope of the difference
and union un rendered bits that don't need to be included in the difference.
Also having the entire scene being made of positive objects speeds up the
frame rate when panning. Less of an issue with the vbo rendering
On Sat, 5 Nov 2022, 19:58 Jordan Brown, openscad@jordan.maileater.net
wrote:
On 11/5/2022 6:52 AM, Hans L wrote:
The crucial difference between ortho and perspective is that a perspective
view has a focal point. (diagram of a perspective view frustum
https://en.wikipedia.org/wiki/Viewing_frustum#/media/File:ViewFrustum.svg)
You can't render things behind the focal point (zNear < 0), because the
image of those things would be flipped upside down and backwards.
Furthermore you can't set your near clipping plane exactly at the focal
point (zNear = 0), because that is a mathematical singularity, where you
have to divide by zero and your depth buffer ceases to have any precision
or meaning.
In orthographic mode, there is no focal point and the viewing frustum is
a cuboid
https://en.wikipedia.org/wiki/Viewing_frustum#/media/File:Orthographic_view_frustum.png
That means you can set the "near" clipping plane to a negative value with
no adverse effects, and so we do in fact set (zNear = -zFar)
Ah, now I understand the "camera inside the negative space" restriction,
and why it doesn't apply to orthographic mode. Thanks!
But that also revealed another ... interesting ... behavior.
Part of the trickery surrounding preview mode is that negative objects are
"real" and play a critical role in preview. I haven't been able to really
internalize what's going on, but I think that roughly a negative object is
an "invisibility cloak" that projects an image of what's on the other side
on its near side, thus hiding the objects in-between.
In perspective mode, once the negative object is in front of the near
plane (perhaps behind the camera, perhaps not), we are "under" the
invisibility cloak and it no longer works.
I kind of understood that before.
But the tidbit that you've added is that for orthogonal mode, the near
clipping plane is far behind the camera.
That's great for negative objects, because they are "shown"; the
invisibility cloak works.
But it's not nearly so great for positive objects - because objects both
in front of and behind the camera are shown. (Or, I suppose, another way
to look at it is that the camera is always infinitely far away from the
model; the camera can never be in the model.)
I visualized this using an animation (included below). First, watch it in
perspective mode. It creates a line of blue cubes and a line of red cubes,
then flies between them. When it reaches the middle of the line, it turns
left to face a blue cube.
That all looks straightforward in perspective mode. Now put it in
orthogonal mode. While it makes an interesting dance of cubes, it doesn't
look even a little bit the same, and you end up facing a red cube.
(Really, you're still facing that blue cube, but it's showing you the
outside face of the red cube.)
As a side note, one of the reasons that I used an animation for this is
that I already had some "fly through" logic, that let me think in terms of
where the camera is rather than the more model-centric view that the UI
usually presents. I was finding it quite hard to get the camera to do what
I wanted using the manual controls. That in turn makes me wonder about
maybe including a "first person shooter" mode, where the mouse and keyboard
move the camera, rather than moving the module. Somebody on IRC was asking
about that a couple of weeks ago.
Here's the program. I'm using FPS=10 and steps=100. Note that because of
the repetitive pattern, some combinations lead to frame rate illusions
where it can look like you are moving backwards through the cubes.
flythrough=true;
size = 5;
ysep = 50;
xsep = 20;
for(x=[-500:xsep:500]) translate([x,0,0]) {
color("red") translate([0,-ysep/2,0]) cube(size, center=true);
color("blue") translate([0,ysep/2,0]) cube(size, center=true);
}
route = [
[ 0, [-700, 0, 0], [0, 90]],
[ 1, [0, 0, 0], [0, 90]],
[ 2, [0, 0, 0], [90, 90]],
[ 1, [0, 0, 0], [90, 90]],
];
// Given a [rho, theta] or [rho, theta, phi], transform to
// an [x,y] or [x,y,z].
function torect(p) =
len(p) == 3 ? torect3(p) : torect2(p);
function torect2(p) = [
p[0] * cos(p[1]),
p[0] * sin(p[1])
];
function torect3(p) = [
p[0] * cos(p[1]) * sin(p[2]),
p[0] * sin(p[1]) * sin(p[2]),
p[0] * cos(p[2])
];
// Given a value and a table of value/position pairs, interpolate a
// position for that value.
// It seems like lookup() should do this sort of vector interpolation
// on its own, but it doesn't seem to.
function xyzinterp(v, table) =
let (x= [for (i=[0:len(table)-1]) [table[i][0], table[i][1][0]]])
let (y= [for (i=[0:len(table)-1]) [table[i][0], table[i][1][1]]])
let (z= [for (i=[0:len(table)-1]) [table[i][0], table[i][1][2]]])
[lookup(v, x), lookup(v, y), lookup(v,z)];
function routesum(a, start, end) = start > end ? 0 : a[start][0] + routesum(a, start+1, end);
r2 = [ for (i = [0:len(route)-1]) [ routesum(route, 0, i), route[i][1], route[i][2] ] ];
t_start = 0;
t_end = r2[len(r2)-1][0];
positions = [ for (e = r2) [ e[0], e[1] ]];
directions = [ for (e = r2) [ e[0], e[2] ]];
pos = xyzinterp($t*(t_end-t_start)+t_start, positions);
dir = xyzinterp($t*(t_end-t_start)+t_start, directions);
$vpd = flythrough ? 140 : $vpd;
$vpt = flythrough ? pos + torect([$vpd, dir[0], dir[1]]) : $vpt;
$vpr = flythrough ? [180-dir[1], 0, (dir[0]+270)%360] : $vpr;
OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org