MNMesh ComputeRenderNormal gives Access Violation

MNMesh ComputeRenderNormal gives Access Violation

duncan_rowland
Explorer Explorer
1,600 Views
17 Replies
Message 1 of 18

MNMesh ComputeRenderNormal gives Access Violation

duncan_rowland
Explorer
Explorer

Hi,
   I having trouble computing render normals on an MNMesh.

  For example:

   If I make a 1x1 plane (i.e. 1 face, 2 tris), convert it to an Editable Poly, and run the following,
   the DebugPrint looks ok to me (below), but I get an access violation,
   (and other, more complex polys are similar).

   Strangely, if I zoom the viewport in and out before running the script, no violation...

Many thanks in advance, -Duncan.

 

def_visible_primitive(ComputeRenderNormal, "ComputeRenderNormal");
...

INode* node = static_cast<MAXNode*>(arg_list[0])->to_node();
const ObjectState* object_state = &node->EvalWorldState(MAXScript_time());
Object* object = object_state->obj;
PolyObject* poly_object = dynamic_cast<PolyObject*>(object);
MNMesh* mnmesh = &poly_object->GetMesh();
mnmesh->CheckAllData();
mnmesh->MNDebugPrint();
mnmesh->ComputeRenderNormal(0,0); <-- Access Violation 😞

 

MNMesh Debug Output: 4 verts, 4 edges, 1 faces
2024/08/01 10:26:20 [19564] : 68656ms : Vertex 0:
2024/08/01 10:26:20 [19564] : 68657ms : ( -23.065, -21.422, 0.000)
2024/08/01 10:26:20 [19564] : 68657ms : Edges: (
2024/08/01 10:26:20 [19564] : 68657ms : 0
2024/08/01 10:26:20 [19564] : 68657ms : 3
2024/08/01 10:26:20 [19564] : 68657ms : )
2024/08/01 10:26:20 [19564] : 68657ms : Faces: (
2024/08/01 10:26:20 [19564] : 68657ms : 0
2024/08/01 10:26:20 [19564] : 68657ms : )
2024/08/01 10:26:20 [19564] : 68658ms :
2024/08/01 10:26:20 [19564] : 68658ms : Vertex 1:
2024/08/01 10:26:20 [19564] : 68658ms : ( 23.065, -21.422, 0.000)
2024/08/01 10:26:20 [19564] : 68658ms : Edges: (
2024/08/01 10:26:20 [19564] : 68658ms : 2
2024/08/01 10:26:20 [19564] : 68658ms : 3
2024/08/01 10:26:20 [19564] : 68658ms : )
2024/08/01 10:26:20 [19564] : 68658ms : Faces: (
2024/08/01 10:26:20 [19564] : 68658ms : 0
2024/08/01 10:26:20 [19564] : 68659ms : )
2024/08/01 10:26:20 [19564] : 68659ms :
2024/08/01 10:26:20 [19564] : 68659ms : Vertex 2:
2024/08/01 10:26:20 [19564] : 68659ms : ( -23.065, 21.422, 0.000)
2024/08/01 10:26:20 [19564] : 68659ms : Edges: (
2024/08/01 10:26:20 [19564] : 68659ms : 0
2024/08/01 10:26:20 [19564] : 68659ms : 1
2024/08/01 10:26:20 [19564] : 68659ms : )
2024/08/01 10:26:20 [19564] : 68659ms : Faces: (
2024/08/01 10:26:20 [19564] : 68659ms : 0
2024/08/01 10:26:20 [19564] : 68660ms : )
2024/08/01 10:26:20 [19564] : 68660ms :
2024/08/01 10:26:20 [19564] : 68660ms : Vertex 3:
2024/08/01 10:26:20 [19564] : 68660ms : ( 23.065, 21.422, 0.000)
2024/08/01 10:26:20 [19564] : 68660ms : Edges: (
2024/08/01 10:26:20 [19564] : 68660ms : 1
2024/08/01 10:26:20 [19564] : 68660ms : 2
2024/08/01 10:26:20 [19564] : 68660ms : )
2024/08/01 10:26:20 [19564] : 68660ms : Faces: (
2024/08/01 10:26:20 [19564] : 68660ms : 0
2024/08/01 10:26:20 [19564] : 68661ms : )
2024/08/01 10:26:20 [19564] : 68661ms :
2024/08/01 10:26:20 [19564] : 68661ms : Edge 0:
2024/08/01 10:26:20 [19564] : 68661ms : verts (2 0), face 0
2024/08/01 10:26:20 [19564] : 68661ms :
2024/08/01 10:26:20 [19564] : 68661ms : Edge 1:
2024/08/01 10:26:20 [19564] : 68661ms : verts (3 2), face 0
2024/08/01 10:26:20 [19564] : 68661ms :
2024/08/01 10:26:20 [19564] : 68661ms : Edge 2:
2024/08/01 10:26:20 [19564] : 68661ms : verts (1 3), face 0
2024/08/01 10:26:20 [19564] : 68662ms :
2024/08/01 10:26:20 [19564] : 68662ms : Edge 3:
2024/08/01 10:26:20 [19564] : 68662ms : verts (0 1), face 0
2024/08/01 10:26:20 [19564] : 68662ms :
2024/08/01 10:26:20 [19564] : 68662ms : Face 0:
2024/08/01 10:26:20 [19564] : 68662ms : verts (
2024/08/01 10:26:20 [19564] : 68662ms : 2
2024/08/01 10:26:20 [19564] : 68662ms : 0
2024/08/01 10:26:20 [19564] : 68662ms : 1
2024/08/01 10:26:20 [19564] : 68662ms : 3
2024/08/01 10:26:20 [19564] : 68662ms : ) edges (
2024/08/01 10:26:20 [19564] : 68663ms : 0v
2024/08/01 10:26:20 [19564] : 68663ms : 3v
2024/08/01 10:26:20 [19564] : 68663ms : 2v
2024/08/01 10:26:20 [19564] : 68663ms : 1v
2024/08/01 10:26:20 [19564] : 68663ms : )
2024/08/01 10:26:20 [19564] : 68663ms : Map 1:
2024/08/01 10:26:20 [19564] : 68663ms : MNMap Debug Output: 4 verts, 1 faces
2024/08/01 10:26:20 [19564] : 68663ms : UVVert 0: 0.000000, 0.000000, 0.000000
2024/08/01 10:26:20 [19564] : 68663ms : UVVert 1: 1.000000, 0.000000, 0.000000
2024/08/01 10:26:20 [19564] : 68663ms : UVVert 2: 0.000000, 1.000000, 0.000000
2024/08/01 10:26:20 [19564] : 68663ms : UVVert 3: 1.000000, 1.000000, 0.000000
2024/08/01 10:26:20 [19564] : 68663ms : Face 0:
2024/08/01 10:26:20 [19564] : 68664ms : 2
2024/08/01 10:26:20 [19564] : 68664ms : 0
2024/08/01 10:26:20 [19564] : 68664ms : 1
2024/08/01 10:26:20 [19564] : 68664ms : 3
2024/08/01 10:26:20 [19564] : 68664ms :
2024/08/01 10:26:20 [19564] : 68664ms :
2024/08/01 10:26:20 [19564] : 68664ms :
Exception thrown at 0x00007FFCE5DD64DB (MNMath.dll) in 3dsmax.exe: 0xC0000005: Access violation reading location 0x0000000000000008.

0 Likes
1,601 Views
17 Replies
Replies (17)
Message 2 of 18

denisT.MaxDoctor
Advisor
Advisor

I recall some problems with ComputeRenderNormal, but I've always wanted all normals, so I use buildRenderNormals...

I am sure ComputeRenderNormal also works, but you need to invalidate something in the MNMesh as usual 🙂.

Message 3 of 18

denisT.MaxDoctor
Advisor
Advisor

I could be wrong, but as I can guess the ComputeRenderNormal was designed for "manual" (soft) rendering. This method has been out of use for a long time and you can't find it in the SDK examples now. Its functioning is related to GraphicsWindow, and in the modern world, it implies some form of caching. You need to force the node containing the MNMesh to cache something, which is what happens when you zoom a viewport.

Message 4 of 18

denisT.MaxDoctor
Advisor
Advisor

Also, ComputeRenderNormal implies that you are working with triangular faces, which can cause more headaches at the polygon level. In general, I advise working with built render vertex normals or using the Mesh instead.

Message 5 of 18

duncan_rowland
Explorer
Explorer

Thank you for replying,
I'm working with a PolyObject (a TriObject works fine). The PolyObject works when I zoom in-and-out so it does seem to have cached what it needs like you say.

For reference, buildRenderNormals also causes a similar violation unless I call buildNormals first.

If it's a case of causing the cached data to be generated, is there a ref you can post on how I'd add that to my code?
Thanks again, -Duncan.

INode* node = static_cast<MAXNode*>(arg_list[0])->to_node();
const ObjectState* object_state = &node->EvalWorldState(MAXScript_time());
Object* object = object_state->obj;
PolyObject* poly_object = dynamic_cast<PolyObject*>(object);
MNMesh* mnmesh = &poly_object->GetMesh();
mnmesh->ComputeRenderNormal(0,0);

0 Likes
Message 6 of 18

klvnk
Collaborator
Collaborator

have you tried the Editable Mesh version ? e.g. does it also throw an exception ? 

Message 7 of 18

duncan_rowland
Explorer
Explorer

Yes, exactly, the "mesh" version works fine when passed an Editable Mesh:

INode* node = static_cast<MAXNode*>(arg_list[0])->to_node();
const ObjectState* object_state = &node->EvalWorldState(MAXScript_time());
Object* object = object_state->obj;
TriObject* tri_object = dynamic_cast<TriObject*>(object); //<--Changed to TriObject
Mesh* mesh = &tri_object->GetMesh(); //<--Changed to Mesh
mesh->ComputeRenderNormal(0, 0);


The "poly" version causes an access violation when passed an Editable Poly
(unless  you "zoom in-and-out a bit" first).

INode* node = static_cast<MAXNode*>(arg_list[0])->to_node();
const ObjectState* object_state = &node->EvalWorldState(MAXScript_time());
Object* object = object_state->obj;
PolyObject* poly_object = dynamic_cast<PolyObject*>(object); //<--Changed to PolyObject
MNMesh* mnmesh = &poly_object->GetMesh(); //<--Changed to MNMesh
mnmesh->ComputeRenderNormal(0, 0); //<-- Access Violation Here

 

0 Likes
Message 8 of 18

klvnk
Collaborator
Collaborator

have you tried calling mnmesh->CheckNormals(TRUE) before the call to ComputeRenderNormal ?

Message 9 of 18

denisT.MaxDoctor
Advisor
Advisor

I did ... 🙂 doesn't help

Message 10 of 18

duncan_rowland
Explorer
Explorer

Thanks for the help. For interest, I have some further information that may help.

If I make the normals explicit, then the poly code works.

e.g.

Make a Plane

Convert to Editable Poly

Add Edit Normals modifier

Select All Normals

Make Explicit

If I then either select and pass the modifier, or collapse and pass the object to the function, all works.

0 Likes
Message 11 of 18

duncan_rowland
Explorer
Explorer

An update on making the normals explicit. I now suspect this isn't actually the problem, it's just that the Edit Normals modifier is causing a 'redraw' (i.e. cacheing whatever is needed like zooming in-and-out).

0 Likes
Message 12 of 18

denisT.MaxDoctor
Advisor
Advisor

@duncan_rowland wrote:

An update on making the normals explicit. I now suspect this isn't actually the problem, it's just that the Edit Normals modifier is causing a 'redraw' (i.e. cacheing whatever is needed like zooming in-and-out).


that's more likely... 

 

however, I am still puzzled and want to find a #software solution to cache/allocate/init poly render normals like #zoom does.

0 Likes
Message 13 of 18

duncan_rowland
Explorer
Explorer

Yes, I don't have a method that works 100% of the time, some programatic solution is needed. If you find one, do let me know! :0)
What I'm actually trying to do is check the polys for inverted normals. i.e. compare each normal with its associated face and check they're more or less in the same direction. I have a maxscript that does this, but it's very slow for high polys. If these's a better way to get these vertex normals I'm all ears!

Thanks again, -Duncan.

0 Likes
Message 14 of 18

denisT.MaxDoctor
Advisor
Advisor

@duncan_rowland wrote:


What I'm actually trying to do is check the polys for inverted normals. i.e. compare each normal with its associated face and check they're more or less in the same direction. 

 


Take a look at MeshDelta::PropagateFacing (meshdelta.h)

Message 15 of 18

klvnk
Collaborator
Collaborator

why do you specifically need to use ComputeRenderNormal for this ?

 

can't you use something like....

MNNormalSpec* mnspecnormals = mesh->GetSpecifiedNormals();
if(mnspecnormals)
{
  // use MNNormalSpec functionality to get the face normals
  // ....
}
else
{
    for(int f=0; f < numfaces;++f)
    {
         Point3 fnormal = mesh->GetFaceNormal(f, TRUE);
       //..... 
    }
}

 

0 Likes
Message 16 of 18

denisT.MaxDoctor
Advisor
Advisor

@klvnk wrote:

why do you specifically need to use ComputeRenderNormal for this ?

 


The "computed render normals", as I see it, are not "specified". A special buffer is used for them, and they should be updated whenever you change the geometry/topology (instead of the specified normals, which you have to rebuild yourself).
If you only want to use some specific normals (faces), computed normals can be much faster. The only problem is that there is no official way to force them to be updated.

 

denisTMaxDoctor_0-1723748856317.png

 

0 Likes
Message 17 of 18

klvnk
Collaborator
Collaborator

The only problem is that there is no official way to force them to be updated.

 

forcing the update will cost the same time as computing them yourself, you can maintain your own buffer if need be and force your own update on what ever criteria that suits it's how most modifiers handle this kind of stuff using the NotifyInputChanged function

 

@klvnk - this post has been edited due to Community Rules & Etiquette violation.

0 Likes
Message 18 of 18

denisT.MaxDoctor
Advisor
Advisor

It’s not the same as manually update normals. It seems like these computed normals need only allocated memory. What normals should be recomputed are specified by user.

0 Likes