[Closed] [C#] Vertex count in sight MXS to C#. Wrong MapScreenToView in C#
Hello everyone, I really need help. I’m trying to do a Vertex count in the camera vision C#, I have Mxs code, I did almost everything except for one function, which doesn’t work like Mxs, MapScreenToView function, I searched the entire Internet and the whole forum, but found nothing I would be very grateful if you could help me.
MapScreenToView C# and MXS return different values.
Mxs code
fn getObjectPoints obj bbox bias = (
if bbox
then (
local bb_points = #()
local bb_min = obj.min
local bb_max = obj.max
if bias > 0
then (
bias_coeff = bias as float / 200
x_margin = bias_coeff * (bb_max.x - bb_min.x)
y_margin = bias_coeff * (bb_max.y - bb_min.y)
z_margin = bias_coeff * (bb_max.z - bb_min.z)
margins = point3 x_margin y_margin z_margin
--print(margins)
bb_min = bb_min + margins
bb_max = bb_max - margins
)
append bb_points (Point3 bb_max.x bb_max.y bb_max.z) -- top-right-front corner
append bb_points (Point3 bb_max.x bb_min.y bb_max.z) -- top-right-back corner
append bb_points (Point3 bb_min.x bb_min.y bb_max.z) -- top-left-back corner
append bb_points (Point3 bb_min.x bb_max.y bb_max.z) -- top-left-front corner
append bb_points (Point3 bb_max.x bb_max.y bb_min.z) -- bottom-right-front corner
append bb_points (Point3 bb_max.x bb_min.y bb_min.z) -- bottom-right-back corner
append bb_points (Point3 bb_min.x bb_min.y bb_min.z) -- bottom-left-back corner
append bb_points (Point3 bb_min.x bb_max.y bb_min.z) -- bottom-left-front corner
bb_points
)
else (
local verts = #()
local mesh = snapshotasmesh obj
local count = mesh.numverts
for i = 1 to count do (
vert = getVert mesh i
append verts vert
)
verts
)
)
fn getVertsInViewport points cam = (
insideVerts = #()
outsideVerts = #()
theTM = inverse cam.objecttransform
screen_width = renderWidth
screen_height = renderHeight
for pnt in points do (
thePos = pnt * theTM
p2 = [0, 0]
p21 = [screen_width, screen_height]
screen_origin = mapScreenToView p2(thePos.z) p21
end_screen = mapScreenToView[screen_width, screen_height](thePos.z)[screen_width, screen_height]
world_size = screen_origin - end_screen
x_aspect = screen_width / (abs world_size.x)
y_aspect = screen_height / (abs world_size.y)
screen_coords = point2(x_aspect * (thePos.x - screen_origin.x))(-(y_aspect * (thePos.y - screen_origin.y)))
if screen_coords.x <= 0 or screen_coords.y <= 0 or screen_coords.x > screen_width or screen_coords.y > screen_height
then(
append outsideVerts thePos
)else (
append insideVerts thePos
)
)
insideVerts
)
geom_obj = maxOps.getNodeByHandle {node.Handle}
render_camera = GetAnimByHandle {camera_handle}
obj_bbox_points = getObjectPoints geom_obj true 40
obj_mesh_points = getObjectPoints geom_obj false 0
pre_check = getVertsInViewport obj_bbox_points render_camera
if pre_check.count == 0
then(
0
)
else (
if pre_check.count == 8
then(
obj_mesh_points.count
)
else (
result = getVertsInViewport obj_mesh_points render_camera
result.count
)
)
This is from ViewExp class
If you check sdk examples there’re plenty of examples how it is used.
Without c# code posted it is hard to help you in any way.
C# Code
public static IList<IPoint3> getObjectPoints(IObject obj, IINode node, bool bbox, float bias)
{
if (bbox)
{
List<IPoint3> bb_points = new List<IPoint3>();
//IINode node = obj.WorldSpaceObjectNode;
IBox3 bb_box = obj.GetLocalBoundBox(max_interface.Time, node, null);
IPoint3 bb_min = bb_box.Min;
IPoint3 bb_max = bb_box.Max;
if (bias > 0)
{
float bias_coeff = bias / 200;
IPoint3 margins = (bb_box.Max.Subtract(bb_box.Min)).MultiplyBy(bias_coeff);
if (DEBUG)
global.TheListener.EditStream.Printf($"new: x: {margins.X},x: {margins.Y},x: {margins.Z}\n");
bb_min = bb_min.Add(margins);
bb_max = bb_max.DecreaseBy(margins);
}
//Corners Instantiate
IPoint3 top_right_front = global.Point3.Create(bb_max.X, bb_max.Y, bb_max.Z);
IPoint3 top_right_back = global.Point3.Create(bb_max.X, bb_min.Y, bb_max.Z);
IPoint3 top_left_back = global.Point3.Create(bb_min.X, bb_min.Y, bb_max.Z);
IPoint3 top_left_front = global.Point3.Create(bb_min.X, bb_max.Y, bb_max.Z);
IPoint3 bottom_right_front = global.Point3.Create(bb_max.X, bb_max.Y, bb_min.Z);
IPoint3 bottom_right_back = global.Point3.Create(bb_max.X, bb_min.Y, bb_min.Z);
IPoint3 bottom_left_back = global.Point3.Create(bb_min.X, bb_min.Y, bb_min.Z);
IPoint3 bottom_left_front = global.Point3.Create(bb_min.X, bb_max.Y, bb_min.Z);
//End Corners Instantiate
//Start Add in List
bb_points.Add(top_right_front);
bb_points.Add(top_right_back);
bb_points.Add(top_left_back);
bb_points.Add(top_left_front);
bb_points.Add(bottom_right_front);
bb_points.Add(bottom_right_back);
bb_points.Add(bottom_left_back);
bb_points.Add(bottom_left_front);
//Greate :)
return bb_points;
}
else
{
List<IPoint3> verts = new List<IPoint3>();
ITriObject tri_obj = (ITriObject)obj.ConvertToType(max_interface.Time, global.TriObjectClassID);
IMesh mesh = tri_obj.Mesh;
int count_verts = mesh.NumVerts;
for (int i = 0; i < count_verts; i++)
{
IPoint3 vertObjectSpace = mesh.GetVert(i);
//IPoint3 vert = mesh.GetVert(i);
IMatrix3 tmObj2World = node.GetObjectTM(max_interface.Time, null);
IPoint3 vertWorldSpace = tmObj2World.PointTransform(vertObjectSpace);
verts.Add(vertWorldSpace);
}
bool debug = false;
if (debug)
return mesh.Verts;
else
return verts;
}
}
func where problem
public static int getVertsInViewport(IList<IPoint3> points, IINode cam, IINode node)
{
List<IPoint3> insideVerts = new List<IPoint3>();
List<IPoint3> outsideVerts = new List<IPoint3>();
IMatrix3 testTM = max_interface.ActiveViewExp.AffineTM;
IPoint3 point31 = testTM.PointTransform(cam.ObjOffsetPos);
if (DEBUG)
global.TheListener.EditStream.Printf("-___- - AffineTM - Lazy Debug - NAME: " + cam.Name + " X : " + point31.X + " Y : " + point31.Y + " Z : " + point31.Z + "\n");
int width = max_interface2.RendWidth;
int height = max_interface2.RendHeight;
foreach (IPoint3 pnt in points)
{
IMatrix3 tmObj2World = node.GetObjectTM(max_interface.Time, null);
IPoint3 pnt2 = tmObj2World.PointTransform(pnt);
if (DEBUG)
global.TheListener.EditStream.Printf("._. Work Please - pnt - X : " + pnt2.X + " Y : " + pnt2.Y + " Z : " + pnt2.Z + "\n");
//Win!!! Eeeee --- thePos = pnt * theTM ---
IPoint3 thePos = testTM.PointTransform(pnt2);
//End Win!!! Eeeee
if (DEBUG)
global.TheListener.EditStream.Printf("._. Work Please - thePos - X : " + thePos.X + " Y : " + thePos.Y + " Z : " + thePos.Z + "\n");
IIPoint2 point2 = global.IPoint2NS.Create(0, 0);
IIPoint2 point23 = global.IPoint2NS.Create(width, height);
if (DEBUG)
global.TheListener.EditStream.Printf($"Start point 0,0 X : {point2.X} , Y : {point2.Y}\n");
if (DEBUG)
global.TheListener.EditStream.Printf($"End point X : {point23.X} , Y : {point23.Y}\n");
IPoint3 points3 = max_interface2.ActiveViewExp.MapScreenToView(point2, thePos.Z);
IPoint3 point32 = max_interface2.ActiveViewExp.MapScreenToView(point23, thePos.Z);
if (DEBUG)
global.TheListener.EditStream.Printf("._. Work Please - points3 - X : " + points3.X + " Y : " + points3.Y + " Z : " + points3.Z + "\n");
if (DEBUG)
global.TheListener.EditStream.Printf("._. Work Please - point32 - X : " + point32.X + " Y : " + point32.Y + " Z : " + point32.Z + "\n");
IPoint3 world_size = points3.Subtract(point32);
if (DEBUG)
global.TheListener.EditStream.Printf("0.0 Work Please - world_size - X : " + world_size.X + " Y : " + world_size.Y + " Z : " + world_size.Z + "\n");
float x_aspect = width / (Math.Abs(world_size.X));
float y_aspect = height / (Math.Abs(world_size.Y));
if (DEBUG)
global.TheListener.EditStream.Printf("Aspects - Work Please - X : " + x_aspect + " Y : " + y_aspect + "\n");
IPoint2 screen_coords = global.Point2.Create((x_aspect / (thePos.X - points3.X)), (-(y_aspect * (thePos.Y - points3.Y))));
if (DEBUG)
global.TheListener.EditStream.Printf("?.? Work Please - screene_coords - X : " + screen_coords.X + " Y : " + screen_coords.Y + "\n");
if ((screen_coords.X <= 0) || (screen_coords.Y <= 0) || (screen_coords.X > width) || (screen_coords.Y > height))
{
outsideVerts.Add(thePos);
if (DEBUG)
global.TheListener.EditStream.Printf("!.! Please - out - X : " + thePos.X + " Y : " + thePos.Y + " Z : " + thePos.Z + "\n");
}
else
{
insideVerts.Add(thePos);
if (DEBUG)
global.TheListener.EditStream.Printf("#.# Please - in - X : " + thePos.X + " Y : " + thePos.Y + " Z : " + thePos.Z + "\n");
}
}
return insideVerts.Count;
}
And Main func
public static List<List<uint>> Vertex_in_sight(UIntPtr camera_handle)
{
List<List<uint>> response = new List<List<uint>>();
//List<IINode> all_nodes = SceneNodes.GetAllNodes(max_interface.RootNode);
IAnimatable camera = global.Animatable.GetAnimByHandle(camera_handle);
IINode camera_node = camera as IINode;
if (DEBUG)
global.TheListener.EditStream.Printf("Debug - NAME: " + camera_handle + " Camera :" + camera.NodeName + " Node : " + camera_node.Name + "\n");
foreach (IINode node in applicable_nodes)
{
IObject obj = node.EvalWorldState(max_interface.Time, false).Obj;
IBox3 bbox = obj.GetLocalBoundBox(max_interface.Time, node, null);
IList<IPoint3> obj_bbox_points = getObjectPoints(obj, node, true, 40);
IList<IPoint3> obj_mesh_points = getObjectPoints(obj, node, false, 0);
int pre_check = getVertsInViewport(obj_bbox_points, camera_node, node);
if (DEBUG)
{
foreach (IPoint3 point in obj_mesh_points)
global.TheListener.EditStream.Printf($"Node: {node.Name} x : {point.X} , y: {point.Y} , z: {point.Z}\n");
}
List<uint> pair = new List<uint>();
if (pre_check == 0)
{
pair.Add(node.Handle);
pair.Add(0);
response.Add(pair);
}
}
return response;
C# output
.. Work Please – scr_orig – X : -40,79334 Y : 18,42768 Z : -97,16466
.. Work Please – scr_end – X : 23,82977 Y : -30,03965 Z : -97,16466
0.0 Work Please – world_size – X : -64,62311 Y : 48,46733 Z : 0
Aspects – Work Please – X : 9,903578 Y : 9,903578
?.? Work Please – screene_coords – X : 0,1634302 Y : 407,9365
MXS output
._. screen_org = [-40.7933, 30.595, -97.1647] , end = [40.7933, -30.595, -97.1647]
“world_size: [-81.5867, 61.19, 0]”
x_asp = 7.84442 y_asp = 7.84442
“screen_coords [475.358, 418.564]”
Didn’t check your sources yet, but here’s the possible maxscript alternative that doesn’t need MapScreenToView
(
-- https://forums.cgsociety.org/t/converting-3d-coordinates-to-2d-with-maxscript/1259949/9
fn get2DPoint pos yTop:true =
(-- takes a point3 value as input
local sX = gw.getWinSizeX() as float -- Get WinSize X
local sY = gw.getWinSizeY() as float -- Get WinSize Y
local rPA = renderPixelAspect -- Get Render Pixel Aspect
local rX = RenderWidth as float -- Get Render Pixels X
local rY = RenderHeight as float -- Get Render Pixels Y
rY = rY * ( 1 / rPA ) -- Correct for aspect ratio
local rratio = ( sX / rX ) / (sY / rY) -- Get RatioF
if rratio >= 1. then ( -- If Ratio is bigger than 1 then
local ratio = sY / rY -- Use Y ratio for calculations
) else (
local ratio = sX / rX -- Else use X ratio for calculations
) -- end if
local xMin = ( sX - ( rX * ratio ) ) / 2 -- Get x minimum value
local yMin = ( sY - ( rY * ratio ) ) / 2 -- Get y minimum value
gw.setTransform (matrix3 1) -- Set gw View transform to zero
local p = gw.TransPoint ( pos ) -- Get 3D point in 2D screenspace
local x = ( p.x - xMin ) / ( sX - ( xMin * 2) ) -- Convert View space to Render space for X
local y = ( p.y - yMin ) / ( sY - ( yMin * 2 ) ) -- idem for Y
if not yTop then y = 1 - y -- if [0,0] should be at the top then set Ytop true
[x,y] -- return a floating point2 value
)
in_sight = (for i=1 to $.numverts collect
(
pt = get2DPoint (GetVert $ i); if pt.x < 0 or pt.x > 1 or pt.y < 0 or pt.y > 1 then dontCollect else i
)) as BitArray
format "% verts in sight\n" (setVertSelection $ in_sight).NumberSet
)
C# func
public static IPoint2 get2DPoint(IPoint3 pos, bool yTop)
{
//takes a point3 value as input
IGraphicsWindow gw = max_interface2.ActiveViewExp.Gw;
float sX = gw.WinSizeX; // Get WinSize X
float sY = gw.WinSizeY; // Get WinSize Y
float rPA = max_interface2.RendApect; // Get Render Pixel Aspect
float rX = max_interface2.RendWidth; // Get Render Pixels X
float rY = max_interface2.RendHeight; // Get Render Pixels Y
float ratio = 0;
rY = rY * (1 / rPA); // Correct for aspect ratio
float rratio = (sX / rX) / (sY / rY); // Get RatioF
if (rratio >= 1)
{ //If Ratio is bigger than 1 then
ratio = sY / rY; // Use Y ratio for calculations;
}
else
{
ratio = sX / rX; // Else use X ratio for calculations;
} // --end if
float xMin = (sX - (rX * ratio)) / 2; // Get x minimum value
float yMin = (sY - (rY * ratio)) / 2; // Get y minimum value
gw.Transform = global.Matrix3.Create(true);
IPoint3 p_out = global.Point3.Create();
gw.TransPoint(pos,p_out);
float x = (p_out.X - xMin) / (sX - (xMin * 2)); // Convert View space to Render space for X
float y = (p_out.Y - yMin) / (sY - (yMin * 2)); // idem for Y
if (DEBUG)
global.TheListener.EditStream.Printf($"Test : x: {x},y: {y}\n");
if (!yTop) y = 1 - y; // if [0, 0] should be at the top then set Ytop true
return global.Point2.Create(x,y);
}
C# main
int count = 0;
foreach (IPoint3 pos_m in obj_mesh_points)
{
IPoint2 pt = get2DPoint(pos_m, true);
if (pt.X < 0 || pt.X > 1 || pt.Y < 0 || pt.Y > 1)
{
global.TheListener.EditStream.Printf("0\n");
}
else
{
count++;
global.TheListener.EditStream.Printf("++\n");
}
if (DEBUG)
global.TheListener.EditStream.Printf($"count: {count}\n");
}
IT WORK!!! BUT there is one problem, it displays 1 Vertex at the box on the screenshot below.
you can probably check whether vert is in front of the camera
in mxs get2DPoint function
...
local x = ( p.x - xMin ) / ( sX - ( xMin * 2) ) -- Convert View space to Render space for X
local y = ( p.y - yMin ) / ( sY - ( yMin * 2 ) ) -- idem for Y
if not yTop then y = 1 - y -- if [0,0] should be at the top then set Ytop true
view_tm = viewport.GetTM()
dp = (dot( (pos - view_tm[4])) view_tm[3])
if dp < 0 then [-1,0] else [x,y]
)
I have a question.
dp = (dot( (pos - view_tm[4])) view_tm[3])
view_tm[4] and [3] it row/column or what?
yep, rows can be accessed like this
here’s another way to go
cam = cameras[1]
cam.fovType = 1
half_x_angle = cam.curfov / 2.0
cam.fovType = 2
half_y_angle = cam.curfov / 2.0
cam.fovType = 1
in coordsys cam
(
dir = -z_axis
bits = for i=1 to $.numverts collect
(
v = GetVert $ i
nv = normalize v
x_ang = acos (dot (normalize(nv * [1,0,1])) dir)
y_ang = acos (dot (normalize(nv * [0,1,1])) dir)
if x_ang <= half_x_angle and y_ang <= half_y_angle then i else dontCollect
)
setVertSelection $ (bits as BitArray)
)
It became even worse :c, now he sees 4 vertex at the box in front of the camera, and 294 out of 530 at the teapot, but at the box behind the camera all 8, although it should be 0
IMatrix3 view_tm = max_interface2.ActiveViewExp.AffineTM;
IPoint3 point3 = pos.Subtract(view_tm.GetColumn3(4));
IPoint3 point31 = view_tm.GetColumn3(3);
float dp = (point3.X * point31.X + point3.Y * point31.Y + point3.Z * point31.Z);
if (dp < 0) { x = -1; y = 0; }