I have a custom script that modifies an object's normals in order to make it behave like a retroreflective material. The script worked fine in Max 2023, but ever since updating to Max 2024 it hasn't worked. I've ruled out any network or folder permissions issues. I've also tried it on multiple systems with the same results. Any help would be much appreciated!
Here is the script:
plugin simpleMeshMod Retroreflector
name:"Retroreflector"
classID:#(0x6ce99f6f, 0x315dd71d)
usePBValidity:off
(
local compilerParams =
(
compilerParams = dotNetObject "System.CodeDom.Compiler.CompilerParameters" #(
getDir #maxRoot + "\\bin\\assemblies\\Autodesk.Max.Wrappers.dll",
getDir #maxRoot + "\\Autodesk.Max.dll"
)
compilerParams.CompilerOptions = "/optimize+"
compilerParams.GenerateInMemory = true
compilerParams
)
local compilerResults = (dotNetObject "Microsoft.CSharp.CSharpCodeProvider").CompileAssemblyFromSource compilerParams #("
using System;
using Autodesk.Max;
using System.Runtime.InteropServices;
using Wrappers = Autodesk.Max.Wrappers;
class MeshNormals {
public static void SetNormalsConvergencePt(IntPtr mesh_pointer, IntPtr point3_pointer) {
var mesh = (IMesh)Wrappers.CustomMarshalerMesh.GetInstance(string.Empty).MarshalNativeToManaged(mesh_pointer);
var pt = (IPoint3)Wrappers.CustomMarshalerPoint3.GetInstance(string.Empty).MarshalNativeToManaged(point3_pointer);
if (mesh.SpecifiedNormals == null)
mesh.SpecifyNormals();
using (var normals = mesh.SpecifiedNormals) {
normals.SetParent(mesh);
if (mesh.GetFlag((uint)mesh.NormalsBuilt) == 0)
normals.CheckNormals();
for (int face = 0; face < mesh.NumFaces; face++) {
for (int faceCorner = 0; faceCorner < 3; faceCorner++) {
var vtxPos = mesh.Verts[(int)mesh.Faces[face].V[faceCorner]];
normals.SetNormal(face, faceCorner, pt.Subtract(vtxPos));
}
}
}
}
}"
)
local meshNormals = compilerResults.CompiledAssembly.CreateInstance "MeshNormals"
parameters main rollout:params ( centerObj type:#node useNodeTmValidity:on useNodeOsValidity:on ui:pbCenterObj; _dummy type:#maxObjectTab tabSizeVariable:on)
rollout params "Parameters" ( pickButton pbCenterObj "Pick Object" autoDisplay:on; )
on modifyMesh do if isValidNode centerObj do
meshNormals.SetNormalsConvergencePt mesh (centerObj.pos * inverse owningNode.objectTransform)
on postDisplay obj do
(
if classof obj == Editable_Poly do
(
deleteModifier obj (obj.numModifiers)
local ca = obj.custAttributes["A Simple Normal Modifier"]
if ca != undefined do
(
obj.custAttributes.delete ca
)
)
)
on attachedToNode node do if isValidNode node do
append this._dummy (NodeTransformMonitor node:node)
)
When I try to run it in 2024 I get this error (file paths modified for security):
-- Error occurred in anonymous codeblock; filename: C:\Users\...\Maxscripts\Retroreflector.ms; position: 2071; line: 48
-- MAXScript Scripted plugin local init Exception:
-- Runtime error: .NET runtime exception: Could not load file or assembly 'file:///C:\Users\...\AppData\Local\Temp\bijqyraz.dll' or one of its dependencies. The system cannot find the file specified.
-- MAXScript callstack:
-- thread data: threadID:77924
Editing someone else's script is unethical and not a good practice; it's better to try to contact the author.
I appreciate you looking out for authors, but this is my script. I am not a programer but pieced it together with help from ChatGPT and Reddit while trying to learn maxscript. I never did REALLY learn it though, so now I'm having no luck troubleshooting the issues in Max 2024. ChatGPT just goes in circles. Reddit hasn't been able to help yet. None of my research has turned up anything.
All of my testing suggests something in Max changed between versions that's causing the problem. The script works in 2023 on multiple systems, but throws the same error in 2024 on multiple systems. So I'm hoping someone here can help me pinpoint what's causing the problem.
@hockey1237 wrote:pieced it together with help from ChatGPT and Reddit while trying to learn maxscript.
I rather suggest you start reading the 3dsmax scripting manual first and go through the examples, as we all did..
From what I can see from the code, you want to set the object's normals so that they all face a specific point. In terms of Reflection the idea is clear, but it will change the entire lighting of the object. For me this is a very questionable decision. I would solve the problem at the shader level, not at the geometry level.
plugin simpleMeshMod LookAtNormals
name:"LookAtNormals"
classID:#(0x2A882515, 0x744F49CB)
(
fn create_IMeshNormalsAssembly =
(
local source = @"
using System;
using System.Runtime.InteropServices;
using Autodesk.Max;
using Wrappers = Autodesk.Max.Wrappers;
class IMeshNormals
{
public static void SetNormalsConvergencePt(IntPtr mesh_pointer, IntPtr point3_pointer)
{
var mesh = (IMesh)Wrappers.CustomMarshalerMesh.GetInstance(string.Empty).MarshalNativeToManaged(mesh_pointer);
var pivot = (IPoint3)Wrappers.CustomMarshalerPoint3.GetInstance(string.Empty).MarshalNativeToManaged(point3_pointer);
if (mesh.SpecifiedNormals == null) mesh.SpecifyNormals();
using (var normals = mesh.SpecifiedNormals)
{
normals.SetParent(mesh);
if (mesh.GetFlag((uint)mesh.NormalsBuilt) == 0) normals.CheckNormals();
for (int face = 0; face < mesh.NumFaces; face++)
{
for (int faceCorner = 0; faceCorner < 3; faceCorner++)
{
var vtxPos = mesh.Verts[(int)mesh.Faces[face].V[faceCorner]];
var vtxNorm = pivot.Subtract(vtxPos).FNormalize;
normals.SetNormal(face, faceCorner, vtxNorm);
}
}
}
}
}"
local csharpProvider = dotnetobject "Microsoft.CSharp.CSharpCodeProvider"
local compilerParams = dotnetobject "System.CodeDom.Compiler.CompilerParameters"
compilerParams.ReferencedAssemblies.AddRange #("System.dll", getDir #assemblies + @"\Autodesk.Max.Wrappers.dll", getDir #maxRoot + @"\Autodesk.Max.dll")
compilerParams.GenerateInMemory = true
local compilerResults = csharpProvider.CompileAssemblyFromSource compilerParams #(source)
if (compilerResults.Errors.Count > 0) then
(
errs = stringstream ""
for i = 0 to (compilerResults.Errors.Count-1) do
(
err = compilerResults.Errors.Item[i]
format "Error:% Line:% Column:% %\n" err.ErrorNumber err.Line err.Column err.ErrorText to:errs
)
MessageBox (errs as string) title: "Errors encountered while compiling C# code"
format "%\n" errs
undefined
)
else
(
local _assembly = compilerResults.CompiledAssembly
_assembly.CreateInstance "IMeshNormals"
)
)
local _IMeshNormals = create_IMeshNormalsAssembly()
parameters main rollout:params
(
target type:#node useNodeTmValidity:on ui:ui_target
object type:#maxobject readonly:on
)
rollout params "Parameters"
(
pickButton ui_target "Pick Object" autoDisplay:on
)
on modifyMesh do if isValidNode target do
(
_IMeshNormals.SetNormalsConvergencePt mesh (target.pos * inverse owningNode.objectTransform)
)
on attachedToNode node do if isValidNode node do
(
object = NodeTransformMonitor node:node
)
on update do
(
if isValidNode owningNode do object = NodeTransformMonitor node:owningNode
)
)
/* TEST SCENE: *************************
delete objects
gc()
t = teapot name:"OBJECT" wirecolor:orange
p = point name:"TARGET" wirecolor:green
addmodifier t (LookAtNormals target:p)
****************************************/
So some projects came up that forced me to put this on the backburner, but I'm jumping back in this week. After some digging, the issue I'm having appears to be the result of Max changing from .NET 4 to .NET 6 in 2024, which the original script is not compatible with. I did some testing, some research, worked with my IT team, and upgraded to the latest version of ChatGPT and came up with the below, which required downloading a few DLLs and has some debugging efforts built in (username swapped out because, the internet):
plugin simpleMeshMod Retroreflector24
name:"Retroreflector24"
classID:#(0x6ce99f6f, 0x315dd71e)
usePBValidity:off
(
fn compileAndLoadAssembly =
(
try
(
-- Define the references to required DLLs
local references = #(
getDir #maxRoot + "\\bin\\assemblies\\Autodesk.Max.Wrappers.dll",
getDir #maxRoot + "\\Autodesk.Max.dll",
"C:\\Users\\[Username]\\DLLs\\Microsoft.CodeAnalysis.dll",
"C:\\Users\\[Username]\\DLLs\\Microsoft.CodeAnalysis.CSharp.dll",
"C:\\Users\\[Username]\\DLLs\\System.Collections.Immutable.dll",
"C:\\Users\\[Username]\\DLLs\\System.Reflection.Metadata.dll"
)
-- Print paths to ensure they are correct
for ref in references do
(
print ("Reference path: " + ref)
)
-- Define the C# code
local csharpCode = "
using System;
using Autodesk.Max;
using System.Runtime.InteropServices;
using Wrappers = Autodesk.Max.Wrappers;
public class MeshNormals {
public static void SetNormalsConvergencePt(IntPtr mesh_pointer, IntPtr point3_pointer) {
var mesh = (IMesh)Wrappers.CustomMarshalerMesh.GetInstance(string.Empty).MarshalNativeToManaged(mesh_pointer);
var pt = (IPoint3)Wrappers.CustomMarshalerPoint3.GetInstance(string.Empty).MarshalNativeToManaged(mesh_pointer);
if (mesh.SpecifiedNormals == null)
mesh.SpecifyNormals();
using (var normals = mesh.SpecifiedNormals) {
normals.SetParent(mesh);
if (mesh.GetFlag((uint)mesh.NormalsBuilt) == 0)
normals.CheckNormals();
for (int face = 0; face < mesh.NumFaces; face++) {
for (int faceCorner = 0; faceCorner < 3; faceCorner++) {
var vtxPos = mesh.Verts[(int)mesh.Faces[face].V[faceCorner]];
normals.SetNormal(face, faceCorner, pt.Subtract(vtxPos));
}
}
}
}
}
"
-- Create the SyntaxTree and Compilation objects
print "Creating SyntaxTree..."
local syntaxTree = (dotNetClass "Microsoft.CodeAnalysis.CSharp.CSharpSyntaxTree").ParseText csharpCode
print "Creating References..."
local referencesArray = for ref in references collect (dotNetClass "Microsoft.CodeAnalysis.MetadataReference").CreateFromFile ref
print "Creating Compilation..."
local compilation = (dotNetClass "Microsoft.CodeAnalysis.CSharp.CSharpCompilation").Create "MeshNormalsAssembly"
compilation = compilation.WithOptions ((dotNetClass "Microsoft.CodeAnalysis.CSharp.CSharpCompilationOptions").Create (dotNetClass "Microsoft.CodeAnalysis.OutputKind").DynamicallyLinkedLibrary)
compilation = compilation.AddReferences referencesArray
compilation = compilation.AddSyntaxTrees #(syntaxTree)
-- Emit the compiled assembly to a temporary file
print "Emitting Assembly..."
local tempDllPath = getDir #temp + "\\MeshNormals.dll"
local emitResult = compilation.Emit tempDllPath
if not emitResult.Success then
(
for diag in emitResult.Diagnostics do
(
format "Diagnostic: %\n" (diag.ToString())
)
throw "Compilation failed. See diagnostics for details."
)
-- Load the emitted assembly and create an instance of MeshNormals
print "Loading Assembly..."
local assembly = (dotNetClass "System.Reflection.Assembly").LoadFrom tempDllPath
local meshNormals = assembly.CreateInstance "MeshNormals"
print "Assembly Loaded Successfully"
return meshNormals
)
catch e
(
if isKindOf e dotNetObject then
(
format "Error: %\n" (e.ToString())
format "Exception Type: %\n" (e.GetType()).ToString()
format "Exception Message: %\n" e.Message
format "Exception Stack Trace: %\n" e.StackTrace
)
else
(
format "Error: %\n" (e as string)
)
return undefined
)
)
-- Compile and load the assembly
print "Compiling and Loading Assembly..."
local meshNormals = compileAndLoadAssembly()
-- Check if the assembly was loaded successfully
if meshNormals == undefined then
(
format "Failed to load the compiled assembly.\n"
return
)
-- Define the parameters and rollout
parameters main rollout:params (
centerObj type:#node useNodeTmValidity:on useNodeOsValidity:on ui:pbCenterObj;
_dummy type:#maxObjectTab tabSizeVariable:on
)
rollout params "Parameters" (
pickButton pbCenterObj "Pick Object" autoDisplay:on;
)
-- Modify the mesh normals to converge at the specified point
on modifyMesh do if isValidNode centerObj do
if meshNormals != undefined do
meshNormals.SetNormalsConvergencePt mesh (centerObj.pos * inverse owningNode.objectTransform)
-- Clean up after display
on postDisplay obj do
(
if classof obj == Editable_Poly do
(
deleteModifier obj (obj.numModifiers)
local ca = obj.custAttributes["A Simple Normal Modifier"]
if ca != undefined do
(
obj.custAttributes.delete ca
)
)
)
-- Track node transformation
on attachedToNode node do if isValidNode node do
append this._dummy (NodeTransformMonitor node:node)
)
I'm not back to going in circles troubleshooting the issue, getting this error with the current code:
-- Error occurred in anonymous codeblock; filename: C:\Users\JSwanson\DLLs\Retroreflector-2024.ms; position: 4916; line: 110
-- Syntax error: at name, expected Plugin clause:
-- In line: print "
Can't find what you're looking for? Ask the community or share your knowledge.