4

I am writing a mesh editor where I have manipulators with the help of which I change the vertices of the mesh. The task is to render the manipulators with constant dimensions, which would not change when changing the camera and viewport parameters. The projection matrix is perspective. I will be grateful for ideas how to implement the invariant scale geometry.

innochenti
  • 1,093
  • 2
  • 8
  • 23

1 Answers1

5

If I got it right you want to render some markers (for example vertex drag editation area) with the same visual size for any depth they are rendered to.

There are 2 approaches for this:

  1. scale with depth

    compute perpendicular distance to camera view (simple dot product) and scale the marker size so it has the same visual size invariant on the depth.

    So if P0 is your camera position and Z is your camera view direction unit vector (usually Z axis). Then for any position P compute the scale like this:

    depth = dot(P-P0,Z)
    

    Now the scale depends on wanted visual size0 at some specified depth0. Now using triangle similarity we want:

    size/dept = size0/depth0
    size = size0*depth/depth0
    

    so render your marker with size or scale depth/depth0. In case of using scaling you need to scale around your target position P otherwise your marker would shift to the sides (so translate, scale, translate back).

  2. compute screen position and use non perspective rendering

    so you transform target coordinates the same way as the graphic pipeline does until you got the screen x,y position. Remember it and in pass that will render your markers just use that instead of real position. For this rendering pass either use some constant depth (distance from camera) or use non perspective view matrix.

For more info see Understanding 4x4 homogenous transform matrices

[Edit1] pixel size

you need to use FOVx,FOVy projection angles and view/screen resolution (xs,ys) for that. That means if depth is znear and coordinate is at half of the angle then the projected coordinate will go to edge of screen:

tan(FOVx/2) = (xs/2)*pixelx/znear
tan(FOVy/2) = (ys/2)*pixely/znear
---------------------------------
pixelx = 2*znear*tan(FOVx/2)/xs
pixely = 2*znear*tan(FOVy/2)/ys

Where pixelx,pixely is size (per axis) representing single pixel visually at depth znear. In case booth sizes are the same (so pixel is square) you have all you need. In case they are not equal (pixel is not square) then you need to render markers in screen axis aligned coordinates so approach #2 is more suitable for such case.

So if you chose depth0=znear then you can set size0 as n*pixelx and/or n*pixely to get the visual size of n pixels. Or use any dept0 and rewrite the computation to:

pixelx = 2*depth0*tan(FOVx/2)/xs
pixely = 2*depth0*tan(FOVy/2)/ys

Just to be complete:

size0x = size_in_pixels*(2*depth0*tan(FOVx/2)/xs)
size0y = size_in_pixels*(2*depth0*tan(FOVy/2)/ys)
-------------------------------------------------
sizex = size_in_pixels*(2*depth0*tan(FOVx/2)/xs)*(depth/depth0)
sizey = size_in_pixels*(2*depth0*tan(FOVy/2)/ys)*(depth/depth0)
---------------------------------------------------------------
sizex = size_in_pixels*(2*tan(FOVx/2)/xs)*(depth)
sizey = size_in_pixels*(2*tan(FOVy/2)/ys)*(depth)
---------------------------------------------------------------
sizex = size_in_pixels*2*depth*tan(FOVx/2)/xs
sizey = size_in_pixels*2*depth*tan(FOVy/2)/ys
Spektre
  • 49,595
  • 11
  • 110
  • 380
  • thank you! works like a charm. what do you think is the best way to name the topic? – innochenti Jun 06 '17 at 10:39
  • what do you think is the best way of automatic calculation of depth0? – innochenti Jun 06 '17 at 12:43
  • @innochenti it does not really matter what `depth0` you chose as it is just numerical scaling constant ... I usually select something between `znear` and `zfar` of perspective projection frustrum – Spektre Jun 06 '17 at 17:51
  • agree. but it would be better somehow to connect this constant with "pixel size" of manipulator – innochenti Jun 07 '17 at 05:59
  • is it possible to calculate depth0 based on pixelSize? I want something like depth0 = f(pixelSize); and use depth/depth0 for scaling – innochenti Jun 08 '17 at 12:19
  • @innochenti yes it is possible but I see no point of doing it ... what is wrong with seting `size` directly in pixels like in [edit1] ? I added the full equation there. As you can see depth0 is not there anymore as it is just numerical constant integrated in the FOV angles ... – Spektre Jun 09 '17 at 07:45
  • currently I do sceneNode->setTransform(dot(center(bbox)-eye,forward)/depth0); – innochenti Jun 09 '17 at 13:44
  • I want to set depth0 based on pixelSize value – innochenti Jun 09 '17 at 13:44
  • and don't want to change transform above – innochenti Jun 09 '17 at 13:44