Notifications
Clear all

[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
                    )
                )
10 Replies

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?

1 Reply
(@serejah)
Joined: 11 months ago

Posts: 0

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)
	
)

2QbVPjxMks

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; }

Redoing this MXS in c # is even harder :c