Analyzing Viewport Lighting [3DS Max 2014]


#21

I don’t know what can cause the flickering on your end, but I don’t think is .Net related. The script just sends a standard Windows message. Perhaps is video card or driver related, I can’t tell.
You could try with windows.postMessage() instead of sendmessage().
Or try sending just the messages to enable/disable the redraw and see if they work.


#22

you can really use the orbit tool while running the script?

I also tried to send the same message to ViewportControlPanel but then i couldnt even select the orbit tool anymore…
My earlier script has the same problem that I have to select the object to start the render to texture script.
If I only could find a way to do it in the background or to render to texture without selecting the object everything would work out.
The new “All prepared” option in the render to texture rollout was a hope but I dont know how to select in the script.


clearListener()
global nodeName = "right_perfect"
global DotNetForm
-- Check variable and close window if it exists
try DotNetForm.close() catch()
(    
    unregisterRedrawViewsCallback printTime
    global obj = getnodebyname nodeName
    -- Create a form
    global DotNetForm = DotNetObject "System.Windows.Forms.Form"
    DotNetForm.Size = (DotNetObject "Drawing.Size" 200 80)
    
    global ViewPanelHwnd = 0
    fn GetViewportsPanelHWND = ( for j in (windows.getchildrenhwnd #max) where j[4] == "ViewPanel" do exit with j[1] )
    ViewPanelHwnd = GetViewportsPanelHWND()
    
    global ViewPanelHwnd2 = 0
    fn GetViewportsPanelHWND2 = ( for j in (windows.getchildrenhwnd #max) where j[4] == "RollupPanel" do exit with j[1] )
    ViewPanelHwnd2 = GetViewportsPanelHWND2()
    
    -- create bakemap to use later
    global monitor = bitmap 14 14 color:green
    display monitor
    -- set render environment background to black
    execute "backgroundcolor = color 0 0 0"
    if (obj != undefined AND obj.name == nodeName) then (        
        local bakeMap = diffusemap()
        bakeMap.outputSzX = 16
        bakeMap.outputSzY = 16
        bakeMap.fileType = ".png"
        bakeMap.filterOn = false
        bakeMap.shadowsOn = on
        bakeMap.lightingon = on
        bakeMap.targetMapSlotName = "Diffuse"
        bakeMap.enabled = true
        obj.INodeBakeProperties.addBakeElement bakeMap
        obj.INodeBakeProperties.bakeEnabled = on
        obj.INodeBakeProperties.flags = 1
        obj.INodeBakeProperties.bakeChannel = 1
         obj.INodeBakeProperties.nDilations = 0
    )
    local myBitmap = render rendertype:#bakeSelected vfb:off progressBar:false outputSize:[16,16]
    
    fn renderFrame = (
        if (obj != undefined AND obj.name == nodeName) then (
            faceValues = #()
            selectedbefore = getCurrentSelection()
            
            windows.sendmessage ViewPanelHwnd 11 0 0    -- redraw off
            windows.sendmessage ViewPanelHwnd2 11 0 0    -- redraw off
            select obj
            myBitmap = render rendertype:#bakeSelected vfb:off progressBar:false outputSize:[16,16]

            if (selectedbefore != undefined) then ( select selectedbefore )
            windows.sendmessage ViewPanelHwnd 11 1 0    -- redraw on
            windows.sendmessage ViewPanelHwnd2 11 1 0    -- redraw off
            
            -- this is the first row which has only 6 fields
            thisRow = getPixels myBitmap [1,2] 6
            for color in thisRow do ( append faceValues color.r )
            for row=3 to 16 do (
            thisRow = getPixels myBitmap [1,row] 14 
                for color in thisRow do (
                    append faceValues color.r
                )    
            )
            for y = 1 to 14 do (
                for x = 1 to 14 do (
                    index = (y*x)
                    if index <= 188 then (
                        colorValue = faceValues[index] 
                        thisColor = color colorValue colorValue colorValue
                        -- append colors thisColor
                        colors = #(thisColor)
                        setPixels monitor [(x-1),(y-1)] colors
                    )
                )
            )
            close myBitmap
            -- copy myBitmap monitor
            display monitor 
            -- return faceValues
        )
    )
    
    local theTimer = dotNetObject "System.Windows.Forms.Timer"
    fn printTime = (
        values = renderFrame()
    )
    
    fn stopEverything = (
   unregisterRedrawViewsCallback printTime        
    )
    fn exitProgram = (
   unregisterRedrawViewsCallback printTime
        if (obj != undefined AND obj.name == nodeName) then (
              obj.iNodeBakeProperties.removeAllBakeElements()
        )
        free myBitmap
        undisplay monitor
    )

    -- Create a button
    local DotNetButton = DotNetObject "System.Windows.Forms.Button"
    DotNetButton.Text = "start"
    DotNetButton.Location = (DotNetObject "Drawing.Point" 10 10)

    -- Create another button
    local DotNetButton2 = DotNetObject "System.Windows.Forms.Button"
    DotNetButton2.Text = "stop"
    DotNetButton2.Location = (DotNetObject "Drawing.Point" 100 10)

    -- The "Click" event calls this function (see below)
    fn OnButtonClick s e =(
        if (s.Text == "start") then (
            registerRedrawViewsCallback printTime
        ) else (
            unregisterRedrawViewsCallback printTime
            stopEverything()
        )
    )

    -- Setup an event handler for both buttons
    dotNet.addEventHandler DotNetButton "Click" OnButtonClick
    dotNet.addEventHandler DotNetButton2 "Click" OnButtonClick
    dotNet.addEventHandler DotNetForm "Closing" exitProgram
   
    -- Add the buttons to the form
    DotNetForm.Controls.AddRange #(DotNetButton, DotNetButton2)
    DotNetForm.TopMost = true
    
    -- Show the form   
    DotNetForm.Show()
)

this somehow works but If i add or remove a light while it is running it is crashing .
when adding a light it first crashes if I leave the mouse button so while dragging the light into the scene everything still works even with two lights but as soon as i move my finger up (on mouse up event) I get an application error and max crashes


#23

I can use Max normally including any viewport navigation command, add/remove lights, modify the box, add/remove faces etc. and everything updates in real time, with no flickering, not even in the controls. Additionally, I can animate and play the animation while the tools is enabled and the values updates while playing.

The CPU usage keeps at 0 and the FPS does not slow down, which is surprising for a script that captures 100 images per second. I would expect at least a little drop in performance, but nothing changes on my end.

Using the render() function does cast a lot of notifications so I don’t think it is suitable for this task,

Using the Max .Net API should do it better. Here is all you need to implement it:


(
    gbl = (dotnetclass "Autodesk.Max.GlobalInterface").Instance
    ip  = gbl.COREInterface
    
    viewHwnd = dotnetobject "system.intptr" ip.ActiveViewExp.Hwnd
    viewExp = ip.GetViewExp viewHwnd
    GraphicsWindow = viewExp.Gw
    
    dib = GraphicsWindow.DIB
)

Grab each viewport hwnd and the just get the bitmap of them and find the pixels values. From my last script you can remove all the stuff to switch the active viewport and the redraw messages. With this, you should see no flickering at all. Don’t forget to dispose the returning bitmap once you don’t need it.


#24

cool thanks,
Ufff, I dont really know how to implement the code, did you write it or did you find it somewhere?
I tried to look at the dib data from the code like this but only got black screen:


gbl = (dotnetclass "Autodesk.Max.GlobalInterface").Instance
ip  = gbl.COREInterface

viewHwnd = dotnetobject "system.intptr" ip.ActiveViewExp.Hwnd
viewExp = ip.GetViewExp viewHwnd
GraphicsWindow = viewExp.Gw

dib = GraphicsWindow.DIB

testbmp = bitmap 1920 1024 
copy dib testbmp 
display testbmp


#25

I wrote the code. The bitmap you get is a .Net bitmap so it won’t display with the MXS display() function. You can either copy it to the clipboard (using .Net) and then getting the clipboard image from MXS and display it or use a .Net control to see it.


(
    gbl = (dotnetclass "Autodesk.Max.GlobalInterface").Instance
    ip  = gbl.COREInterface

    viewHwnd = dotnetobject "system.intptr" ip.ActiveViewExp.Hwnd
    viewExp = ip.GetViewExp viewHwnd
    GraphicsWindow = viewExp.Gw

    dib = GraphicsWindow.DIB
    
    rollout RO_VIEWER ""
    (
        dotNetControl dnc_img "PictureBox" pos:[8,8] width:dib.width height:dib.height
        
        on RO_VIEWER open do dnc_img.image = dib
    )
    
    createdialog RO_VIEWER width:(dib.width+16) height:(dib.height+16)
)


#26

okay I did the following to see all properties of gbl.COREInterface


local props = getPropNames gbl:COREInterface
print props 

but there is nothing else than ActiveViewExp in the list
I dont get how to grab a Viewport handle mh, if I find it I will report it here
___ EDIT
I can somehow get the top view with the following, but I have no idea how to get the other views.
Do you know how to do it?


gbl = (dotnetclass "Autodesk.Max.GlobalInterface").Instance
ip  = gbl.COREInterface    
viewHwnd = dotnetobject "system.intptr" ip.MAXHWnd  -- this here returns the top view, I dont know why.


#27

link


#28

Thanks! I could somehow manage to get them like this now by try and error


clearListener()
gbl = (dotnetclass "Autodesk.Max.GlobalInterface").Instance
ip  = gbl.COREInterface
fn GetLeftCamHWND = ( for j in (windows.getchildrenhwnd #max) where j[5] == "camera_left" do exit with j[1] )
fn GetRightCamHWND = ( for j in (windows.getchildrenhwnd #max) where j[5] == "camera_right" do exit with j[1] )
camLeft = GetLeftCamHWND()
camRight = GetRightCamHWND()

viewHwnd = dotnetobject "system.intptr" camLeft    
viewExp = ip.GetViewExp viewHwnd
GraphicsWindow = viewExp.Gw

dib = GraphicsWindow.DIB
rollout RO_VIEWER ""
(
    dotNetControl dnc_img "PictureBox" pos:[8,8] width:dib.width height:dib.height

    on RO_VIEWER open do dnc_img.image = dib
)
createdialog RO_VIEWER width:(dib.width+16) height:(dib.height+16)


#29

Unfortunately not all SDK is implemented in the .Net API, although it gets better in later Max versions. But in Max 2014 many things do not work.

There are several methods and properties implemented in different interfaces, but I couldn’t get most of them to work.

GetCOREInterface7()->getViewport()

Was deprecated in Max 2013 and getViewExp() doesn’t seem to work in Max 2014.

Here is something I could get to work if you want to stick to the SDK, but there might be other ways.


(

    gbl = (dotnetclass "Autodesk.Max.GlobalInterface").Instance
    ip  = gbl.COREInterface
    
    fn GetCameraViewExp name: =
    (
        viewPanel = gbl.ViewPanelManager
        activePanel = viewPanel.ActiveViewPanel
        numViewports = activePanel.NumberOfViewports
        
        for j = 1 to numViewports do
        (
            ViewExp = activePanel.GetViewExpByIndex (j-1)
            ViewType = ViewExp.ViewType.ToString()
            if ViewType == "Camera" do
            (
                if ViewExp.ViewCamera.Name == name do return ViewExp
            )
        )
        return undefined
    )
    
    GetCameraViewExp name:"camera_left"
    
)


#30

Here is a working code using the .net API. You still need to debug and improve it.

The Logarithmic Exposure Control seems to work consistently in viewport and render, but not all the others, so this solution is a partial workaround for what you need. If you switch to another Exposure algorithm, it might not give the values you need.

A better solution would be to implement the Exposure algorithm in the code, or perhaps you can adjust the exposure externally and use something different. After all, it is just a color curve.


(
    global GW_DisplayFacesColors
    local data_front = #()
    local data_back  = #()
    local data_type  = 1
    local showSamples = false

    fn GW_DisplayFacesColors =
    (
        for j in data_front do
        (
            val = case data_type of
            (
                1: j[2] as point3
                2: int j[2].h
                3: int j[2].s
                4: int j[2].v
            )
            gw.text j[1] (val as string) color:red
            if showSamples do for k in j[3] do gw.Marker k #asterisk color:red
        )

        for j in data_back do
        (
            val = case data_type of
            (
                1: j[2] as point3
                2: int j[2].h
                3: int j[2].s
                4: int j[2].v
            )
            gw.text j[1] (val as string) color:black
            if showSamples do for k in j[3] do gw.Marker k #asterisk color:black
        )
        gw.enlargeUpdateRect #whole
    )
    
    
    try destroydialog ::RO_DISPLAY_FACES_COLORS catch()

    rollout RO_DISPLAY_FACES_COLORS "Faces Colors" width:172 height:172
    (
        button       bt_vp1          "Set Font View"      pos:[ 8, 8] width:72 height:32
        button       bt_vp2          "Set Back View"      pos:[88, 8] width:72 height:32
        spinner      sp_sampleDist   "Samples Distance"   pos:[ 8,48] range:[0,100,50] fieldwidth:56
        checkbox     chk_showSamples "Show Smaple Points" pos:[ 8,72]

        radioButtons rdo1 "Display:" pos:[8, 96] labels:#("RGB","H","S","B") columns:4
        checkbutton  btn1 "Enable"   pos:[8,136] width:154 height:28
        timer        clock interval:20 active:false

        local GetFaceVerts = polyop.getfaceverts
        local GetfaceNormal = polyop.getfaceNormal
        local GetFaceCenter = polyop.getFaceCenter
        local GetVert = polyop.getvert
        
        local node
        local vp_front = undefined
        local vp_back  = undefined
        local gw_front = undefined
        local gw_back  = undefined

        local gbl = (dotnetclass "Autodesk.Max.GlobalInterface").Instance
        local ip  = gbl.COREInterface
        
        local identityTM = gbl.IdentityTM.Create()
        
        fn ConvertMatrix tm =
        (
            r1 = tm.GetRow 0
            r2 = tm.GetRow 1
            r3 = tm.GetRow 2
            
            return (matrix3 [r1.x, r1.y, r1.z] [r2.x, r2.y, r2.z] [r3.x, r3.y, r3.z] [0,0,0])
        )
        
        fn CalculateFacesColors viewGW viewTM =
        (
            dib = viewGW.DIB
            
            tm = viewTM.AffineTM
            viewTM = ConvertMatrix tm
            viewGW.transform = identityTM
            
            result = for f = 1 to node.numfaces collect
            (
                faceNormal = normalize (GetfaceNormal node f)

                if (faceNormal*viewTM).z > 0 then
                (
                    faceCenter = GetFaceCenter node f
                    fverts = GetFaceVerts node f

                    numverts = fverts.count
                    faceColor = black
                    
                    samplePoints = #()

                    for j in fverts do
                    (
                        d = distance faceCenter (GetVert node j)
                        n = normalize (faceCenter - (GetVert node j))
                        
                        d = sp_sampleDist.value * d / 100.0
                            
                        pt = faceCenter + (d*n)
                        pt = gbl.Point3.Create pt.x pt.y pt.z
                            
                        px = gbl.Point3.Create 0 0 0
                        viewGW.TransPoint pt px
                        
                        if px.x > 0 and px.x < dib.width and px.y > 0 and px.y < dib.height do
                        (
                            pcolor = dib.GetPixel px.x px.y
                            if pcolor != undefined then
                            (
                                faceColor.r += pcolor.r
                                faceColor.g += pcolor.g
                                faceColor.b += pcolor.b
                            )else(
                                numverts -= 1
                            )
                        )
                        
                        append samplePoints [pt.x, pt.y, pt.z]
                        
                        px.Dispose()
                        pt.Dispose()
                    )

                    faceColor.r = int (faceColor.r/numverts)
                    faceColor.g = int (faceColor.g/numverts)
                    faceColor.b = int (faceColor.b/numverts)
                    
                    #(faceCenter, faceColor, samplePoints)
                )else(
                    dontcollect
                )
            )
            
            tm.Dispose()
            dib.Dispose()
            
            return result
        )
        
        fn GetDisplayData =
        (
            data_front = CalculateFacesColors gw_front vp_front 
            data_back  = CalculateFacesColors gw_back vp_back
        )
        
        fn GetViewExp =
        (
            viewHwnd = dotnetobject "system.intptr" ip.ActiveViewExp.Hwnd
            return ip.GetViewExp viewHwnd
        )

        on clock tick do
        (
            GetDisplayData()
        )

        on RO_DISPLAY_FACES_COLORS close do
        (
            unregisterRedrawViewsCallback GW_DisplayFacesColors
            completeredraw()
        )

        on btn1 changed arg do
        (
            if vp_front == undefined or vp_back == undefined do
            (
                btn1.checked = false
                return messagebox "Select Front and Back Views"
            )

            unregisterRedrawViewsCallback GW_DisplayFacesColors
            if arg then
            (
                if selection.count == 1 and iskindof selection[1] editable_poly then
                (
                    node = selection[1]
                    clock.tick()
                    clock.active = true
                    registerRedrawViewsCallback GW_DisplayFacesColors
                )else(
                    node = undefined
                    btn1.checked = false
                    clock.active = false
                    messagebox "Select an object"
                )
            )else(
                clock.active = false
            )
            completeredraw()
        )

        on rdo1 changed arg do
        (
            data_type = arg
            completeredraw()
        )

        on bt_vp1 pressed do
        (
            vp_front = GetViewExp()
            gw_front = vp_front.Gw
            bt_vp1.text = viewport.activeViewport as string
        )

        on bt_vp2 pressed do
        (
            vp_back = GetViewExp()
            gw_back = vp_back.Gw
            bt_vp2.text = viewport.activeViewport as string
        )
        
        on chk_showSamples changed arg do
        (
            showSamples = arg
            GetDisplayData()
            completeredraw()
        )
        
        on sp_sampleDist changed arg do
        (
            GetDisplayData()
            completeredraw()
        )

    )

    createdialog RO_DISPLAY_FACES_COLORS
)


#31

Merry Christmas everyone!
With the incredible help here I could find a solution with a very small UV map and texture baking -> analyzing which allows me to interact with the viewport, rotate & and move the objects,
getting the default light which changes on the object while rotating around it and so on .
this is the sketch:


clearListener()
global nodeName = "right_perfect"
global obj = getnodebyname nodeName
    
global DotNetForm
-- Check variable and close window if it exists
try DotNetForm.close() catch()
(    
    -- Create a form
    global DotNetForm = DotNetObject "System.Windows.Forms.Form"
    DotNetForm.Size = (DotNetObject "Drawing.Size" 200 80)
    
    global ViewPanelHwnd = 0
    fn GetViewportsPanelHWND = ( for j in (windows.getchildrenhwnd #max) where j[4] == "ViewPanel" do exit with j[1] )
    ViewPanelHwnd = GetViewportsPanelHWND()
    
    global ViewPanelHwnd2 = 0
    fn GetViewportsPanelHWND2 = ( for j in (windows.getchildrenhwnd #max) where j[4] == "RollupPanel" do exit with j[1] )
    ViewPanelHwnd2 = GetViewportsPanelHWND2()
    
    
    global monitor = bitmap 14 14 color:green
    display monitor
    
    -- set render environment background to black
    execute "backgroundcolor = color 0 0 0"
    
    -- create bakemap to use later
    if (obj != undefined AND obj.name == nodeName) then (        
        local bakeMap = diffusemap()
        bakeMap.outputSzX = 16
        bakeMap.outputSzY = 16
        bakeMap.fileType = ".png"
        bakeMap.filterOn = false
        bakeMap.shadowsOn = on
        bakeMap.lightingon = on
        bakeMap.targetMapSlotName = "Diffuse"
        bakeMap.enabled = true
        obj.INodeBakeProperties.addBakeElement bakeMap
        obj.INodeBakeProperties.bakeEnabled = on
        obj.INodeBakeProperties.flags = 1
        obj.INodeBakeProperties.bakeChannel = 1
         obj.INodeBakeProperties.nDilations = 0
    )
    local myBitmap = render rendertype:#bakeSelected vfb:off progressBar:false outputSize:[16,16]
    
    fn renderFrame = (
        if (obj != undefined AND obj.name == nodeName) then (
            faceValues = #()
            selectedbefore = getCurrentSelection()
            
            windows.sendmessage ViewPanelHwnd 11 0 0    -- redraw off
            windows.sendmessage ViewPanelHwnd2 11 0 0    -- redraw off
            select obj
            myBitmap = render rendertype:#bakeSelected vfb:off progressBar:false outputSize:[16,16]
            
            if (selectedbefore != undefined) then ( select selectedbefore )
            windows.sendmessage ViewPanelHwnd 11 1 0    -- redraw on
            windows.sendmessage ViewPanelHwnd2 11 1 0    -- redraw off
            
            -- this is the first row which has only 6 fields
            thisRow = getPixels myBitmap [1,2] 6
            for color in thisRow do ( append faceValues color.r )
            for row=3 to 16 do (
            thisRow = getPixels myBitmap [1,row] 14 
                for color in thisRow do (
                    append faceValues color.r
                )    
            )
            for y = 1 to 14 do (
                for x = 1 to 14 do (
                    index = (y*x)
                    if index <= 188 then (
                        colorValue = faceValues[index] 
                        thisColor = color colorValue colorValue colorValue
                        -- append colors thisColor
                        colors = #(thisColor)
                        setPixels monitor [(x-1),(y-1)] colors
                    )
                )
            )
            close myBitmap
            -- copy myBitmap monitor
            display monitor 
        )
    )
    global dnc_control, mouseButtonStates, lButton, mButton, rButton
    global mouseState
    global numObjects = objects.count -- to store last object count before mouse clicking to check if object is created later
    
    fn printTime = (
        mouseButtonStates = dnc_control.MouseButtons.value__
        theButtonStr = ""
        if (dotnet.CompareEnums mouseButtonStates lButton) then ( 
            --theButtonStr += "Left " 
            mouseState = "clicked";
            if (objects.count > numObjects) then (
                -- print "create object"
            ) else (
                values = renderFrame()
            )
        ) else (
            mouseState = "not clicked"
            values = renderFrame()
            numObjects = objects.count
        )
        --print mouseState
    )

    fn stopEverything = (
        unregisterRedrawViewsCallback printTime
        print("stop")
    )
    fn exitProgram = (
        unregisterRedrawViewsCallback printTime
        print("exit")
        if (obj != undefined AND obj.name == nodeName) then (
              obj.iNodeBakeProperties.removeAllBakeElements()
        )
        free myBitmap
        undisplay monitor
    )

    -- Create a button
    local DotNetButton = DotNetObject "System.Windows.Forms.Button"
    DotNetButton.Text = "start"
    DotNetButton.Location = (DotNetObject "Drawing.Point" 10 10)
    -- Create another button
    local DotNetButton2 = DotNetObject "System.Windows.Forms.Button"
    DotNetButton2.Text = "stop"
    DotNetButton2.Location = (DotNetObject "Drawing.Point" 100 10)

    -- The "Click" event calls this function (see below)
    fn OnButtonClick s e =(
        if (s.Text == "start") then (
            print("start everything")
            registerRedrawViewsCallback printTime
            dnc_control = dotNetClass "Control"
            mouseButtons = dnc_control.MouseButtons
            lButton = mouseButtons.Left.value__
            --theTimer.start()
        ) else (
            unregisterRedrawViewsCallback printTime
            print("stop everything")
            stopEverything()
            
        )
    )
    -- Setup an event handler for both buttons
    dotNet.addEventHandler DotNetButton "Click" OnButtonClick
    dotNet.addEventHandler DotNetButton2 "Click" OnButtonClick
    dotNet.addEventHandler DotNetForm "Closing" exitProgram

    -- Add the buttons to the form
    DotNetForm.Controls.AddRange #(DotNetButton, DotNetButton2)
    DotNetForm.TopMost = true
    
    -- Show the form
    DotNetForm.Show()
)


the last problem to solve is to check avoid rendering while objects are created I could manage to do it for lights like this


 global numObjects = objects.count -- to store last object count before mouse clicking to check if object is created later
    
    fn printTime = (
        mouseButtonStates = dnc_control.MouseButtons.value__
        theButtonStr = ""
        if (dotnet.CompareEnums mouseButtonStates lButton) then ( 
            --theButtonStr += "Left " 
            mouseState = "clicked";
            if (objects.count > numObjects) then (
                -- print "create object"
            ) else (
                values = renderFrame()
            )
        ) else (
            mouseState = "not clicked"
            values = renderFrame()
            numObjects = objects.count
        )
        --print mouseState
    )

But if i Create a box it does not work because the box creation process is not finished after leaving the mouse.
Does anyone know a property or a way how to find out if a object is in the process of being created?

Thanks so much for the help so far. I hope perhaps the collection of scripts can be helpful to others too.
best wishes!


#32

One little thing is still not working perhaps someone can help me out.
When I create a light while the script is running on every viewport change callback 3ds Max crash as soon as I leave the mouse button…
It seems this happens because leaving the mouse button after dragging in a target spot leads Max to deselect the target/ reselect the light base only. I think if the light creation selecting parts are executed it crashes with the asynchron rendering progress which depends on the selection.

If there just would be a solution to bake a texture be script without selecting it. Everything would be so easy…
__
EDIT :
this is what happens if I leave the left mouse after creating this target spot. I dont understand why the script crashes.


fn printTime = (       
   mouseButtonStates = dnc_control.MouseButtons.value__        
   theButtonStr = ""      
   if (dotnet.CompareEnums mouseButtonStates lButton) then (               
      mouseState = "clicked";            
      if (objects.count > numObjects) then (                     
         -- values = renderFrame()          <<<<<<<<< if i uncomment this i get the ERROR 
      ) else (                
         values = renderFrame()         
      )       
    ) else (            
      mouseState = "not clicked"            
      values = renderFrame()            
      numObjects = objects.count        
   )   
)


#33

Hello, I am trying to improve the script based on the svg renderer with max script tutorial because this script proposed by @PolyTools3D is working almost perfectly for simple real-time rendering kind of tasks. Now I wonder if there is a way to add very simplistic shadows either raytraced or if there’s something simpler like a shadow map also that . Can someone help me to implement it into the script . What would be a good starting point? I would also pay a little for help because I am too much of a novice and I think it might be quite easy for an expert to add simple shadows to the scene . Now I hope for help : ) good night and greetings from Hamburg

EDIT:
this is the tutorial :
https://help.autodesk.com/view/3DSMAX/2016/ENU/?guid=__files_GUID_14B02950_26DF_498C_A88A_CD87DC84473C_htm

this i my script so far: ( the code function is not working good… )
clearListener()
(
– Generals
global myNodeName = “kopfmodell”
– face mapping position in uv map from left top to hardware order
global faceMap = #(159, 154, 153, 60, 134, 59, 79, 19, 43, 94, 56, 7, 12, 20, 40, 27, 65, 82, 121, 176, 1, 77, 90, 30, 91, 89, 78, 81, 85, 57, 76, 31, 44, 13, 11, 10, 83, 49, 50, 64, 93, 87, 88, 5, 4, 3, 6, 92, 75, 66, 34, 22, 58, 24, 23, 33, 21, 80, 41, 28, 39, 26, 47, 61, 9, 46, 32, 45, 2, 8, 14, 16, 15, 35, 36, 51, 73, 69, 72, 67, 74, 52, 37, 62, 18, 17, 86, 84, 63, 48, 150, 101, 106, 114, 38, 68, 70, 42, 25, 71, 29, 55, 54, 53, 185, 183, 172, 175, 179, 151, 170, 125, 138, 107, 173, 113, 137, 188, 144, 158, 187, 181, 182, 99, 98, 97, 100, 186, 95, 171, 184, 124, 152, 118, 117, 127, 115, 174, 135, 122, 133, 120, 105, 104, 177, 143, 126, 139, 96, 102, 108, 110, 109, 129, 130, 145, 169, 160, 128, 116, 168, 146, 131, 156, 112, 111, 180, 178, 157, 142, 141, 155, 103, 140, 132, 162, 164, 136, 119, 165, 123, 149, 148, 147, 167, 163, 166, 161);
– face mpping face ids to hardware order of leds
global faceMap2 = #(132,162,164,136,119,165,123,149,148,147,167,163,166,161,168,146,131,156,112,111,180,178,157,142,141,155,103,140,126,139,96,102,108,110,109,129,130,145,169,160,128,116,152,118,117,127,115,174,135,122,133,120,105,104,177,143,144,158,187,181,182,99,98,97,100,186,95,171,184,124,185,183,172,175,179,151,170,125,138,107,173,113,137,188,150,101,106,114,38,68,70,42,25,71,29,55,54,53,73,69,72,67,74,52,37,62,18,17,86,84,63,48,47,61,9,46,32,45,2,8,14,16,15,35,36,51,75,66,34,22,58,24,23,33,21,80,41,28,39,26,11,10,83,49,50,64,93,87,88,5,4,3,6,92,1,77,90,30,91,89,78,81,85,57,76,31,44,13,79,19,43,94,56,7,12,20,40,27,65,82,121,176,159,154,153,60,134,59);
global mappedOutput = #();
for i=1 to 188 do (
if i == 2 then (
append mappedOutput (254 as integer)
) else (
append mappedOutput (0 as integer)
)
)
global mappedOutputTest = #();
for i=1 to 188 do (
if i == 1 then (
append mappedOutputTest (254 as integer)
) else (
append mappedOutputTest (i as integer)
)
)
– prepare serial port
global serialEnabled = true
fn setupSerialPort = (
if serialEnabled then (
global serialPortName = “COM49”
global serialBaudRate = 230400
global port = dotNetObject “System.IO.Ports.SerialPort”
port.portname = serialPortName
port.baudrate = serialBaudRate
port.parity = port.parity.even
–port.databits = 8
–port.stopbits = port.stopbits.one
–port.readtimeout = 500

–port.writetimeout = 100

		port.Open()
		--sleep(1)
		--port.Write("q\r")
		sleep(1)
		--port.Write("livemodedebug\r")
		type = dotNetClass "System.byte[]"
		res = dotnet.ValueToDotNetObject mappedOutputTest type		
		if serialEnabled then (
			--port.Write res 0 188
			--port.Write("\r")
			for i=0 to 187 do (
				--port.write res i 1
				--sleep(0.01)
				--	ComPort.Write(mappedOutput[i])
				--writeSerialPort((mappedOutput[i] as byte))
			)
		)

		port.Close()
	)
)

setupSerialPort()
fn openSerialPort = (
	if port != undefined AND serialEnabled then (
		port.Open()
		sleep(1)
		isOpen = getProperty port #IsOpen
		print ("Open port " + (serialPortName as string) + " isOpen: " + (isOpen as string))
	)
)
fn closeSerialPort = (
	if port != undefined AND serialEnabled then (
		port.Close()
		sleep(1)
		isOpen = getProperty port #IsOpen
		print ("Close port " + (serialPortName as string) + " isOpen: " + (isOpen as string))
	)
)
fn writeSerialPort data = (
	isOpen = getProperty port #IsOpen
	if port != undefined AND serialEnabled AND isOpen then (
		
		port.Write(data)
	)
)

try destroydialog ::RO_DISPLAY_FACES_COLORS catch()

rollout RO_DISPLAY_FACES_COLORS "Faces Colors" width:172 height:250
(
    colorPicker  cp1  "Material Color:" pos:[8, 8] height:16 color:white
    radioButtons rdo1 "Display:"        pos:[8,32] labels:#("RGB","H","S","B") columns:4
	label lab1 "Live Mode - Serial Transfer"
	checkbutton btnStartStop "Start" pos:[8,100] width:154 height:28
	
	timer        clock interval:50 active:false
    global GW_DisplayFacesColors
	
	
	local node = getNodeByName (myNodeName as string)
    local GetfaceNormal = polyop.getfaceNormal
    local GetFaceCenter = polyop.getFaceCenter

    fn CalculateFacesColors obj =
    (
		mappedOutput = #();
		
        viewTM = viewport.getTM()
        viewTM.row4 = [0,0,0]
        viewPos = (inverse (viewport.getTM())).row4

        fillColor = cp1.color

        for faceIndex = 1 to obj.numfaces do (
            faceNormal = normalize (GetfaceNormal obj faceIndex)
            value = 0
            --if (faceNormal*viewTM).z > 0 then
			if true then 
            (
                faceCenter = GetFaceCenter obj faceINdex
                viewVector = normalize (viewPos - faceCenter)
                faceColor = black
                
                for k in lights where classof k != targetobject do
                (
                    lightDir = normalize (k.pos - faceCenter)
                    
                    diffuse = amax ((dot lightDir faceNormal)*k.multiplier) 0
                    faceColor += fillColor * k.color * diffuse
                )
                
                value = amin (int faceColor.r) 255
            )
			if value == 255 then value = 254
			mappedOutput[faceMap2[faceIndex]] = value
			--mappedOutput[fmp2[faceIndex]] = value
        )
    )
    
    fn GW_DisplayFacesColors =
    (
		--CalculateFacesColors(node)
		type = dotNetClass "System.byte[]"
		res = dotnet.ValueToDotNetObject mappedOutput type		
		if serialEnabled then (
			port.write res 0 188
			for i=0 to 187 do (
				--port.write res i 1
			--	ComPort.Write(mappedOutput[i])
				--writeSerialPort((mappedOutput[i] as byte))
			)
		)
    )
	
	on clock tick do
    (
       GW_DisplayFacesColors()
	)

	fn exitProgram = (
		print "Exit program"
		clock.active = false
		writeSerialPort("q\r\n") -- serial command to enter menu 
		closeSerialPort()
		unregisterRedrawViewsCallback GW_DisplayFacesColors
		completeredraw()
	)
	
    on RO_DISPLAY_FACES_COLORS open do
    (
        --unregisterRedrawViewsCallback GW_DisplayFacesColors
        completeredraw()
    )

    on RO_DISPLAY_FACES_COLORS close do
    (
		exitProgram()
        unregisterRedrawViewsCallback GW_DisplayFacesColors
        completeredraw()
    )
    
	on btnStartStop changed arg do
	(
		unregisterRedrawViewsCallback GW_DisplayFacesColors
		if arg then -- start program
        (
			openSerialPort()
			--writeSerialPort("q\r") -- serial command to enter menu 
			--writeSerialPort("livemode\r") -- serial command to enter live mode
			
			clock.active = true
			if lights.count == 0 then
			(
				node = undefined
				btnStartStop.checked = false
				messagebox "There must be at least one light source in the scene"
			) else (
				--node.wirecolor = cp1.color
				if classof node.mat == standardmaterial do node.mat.diffuse = cp1.color
				--registerRedrawViewsCallback GW_DisplayFacesColors
			)		
			
		) else (
			exitProgram()
		)
		if btnStartStop.checked then (
			btnStartStop.Text = "Stop"
		) else (
			btnStartStop.Text = "Start"
		)
		completeredraw()
	)
    
    on rdo1 changed arg do completeredraw()
    
    on cp1 changed arg do
    (
        if node != undefined do
        (
            node.wirecolor = arg
            if classof node.mat == standardmaterial do node.mat.diffuse = arg
        )
        completeredraw()
    )

)
createdialog RO_DISPLAY_FACES_COLORS

)

`


#34

nobody?