First 3Ds Max 2008 Scene Explorer extention
Last Wednesday, I got the the copy of 3Ds Max 2008. And today, I play around the new features of it, mainly focus on the scene explorer.
Overview
Wow, I have to say Scene Explorer is a must-have tool for modern modeller who frequently need to handel large scale scenes. Simplily speaking,
u can manipulate the all kind of properties of the objects (they provide u API to extent the scene explorer) in a over-view windows, doing search for specific condition, checking the models with different display mode, load/save different scene explorer for convinience and so on.
In this evolutionary version of Max, autodesk provides programmer a C++/CLI writtern dll as the entry point for extenting the scene explorer. As the C++/CLI can use the functionality of .net and take care of the backwards compatibilty, I guess it is the best choice for 3Ds Max.
Extension step-by-step:
1, install the 3DsMaxprojectWizard shipped with the 3Ds Max SDK.
2, create a GUP (General Utility Plugin) project
3, change the project properties to support CLR.
4, add a C++/CLI class. (e.g. U want to extent the columns in the display list of scene explorer)
5, override the GetValue /SetValue of the abstact class inherited.
6, Register the new class object in the GUP plugin.
7, basically, that's it, enjoy.
Codes
SizeProperty.h
2#ifndef SIZEPROPERTY_H
3#define SIZEPROPERTY_H
4
5#pragma unmanaged
6#include "nativeInclude.h"
7
8#pragma managed
9// Declare references to .NET assemblies. Notice that it doesn't matter if
10// an assembly is originally written in C++/CLI or C#, we use it same way.
11// The only difference from an external point of view is that C++/CLI may be
12// aware of native types.
13
14// SceneExplorer.dll is a 3ds Max .NET assembly written in C++/CLI.
15#using <SceneExplorer.dll>
16// ExplorerFramework is a 3ds Max .NET assembly written in C#.
17#using <ExplorerFramework.dll>
18// Microsoft .NET Framework assembly.
19#using <System.dll>
20
21namespace SceneExplorerExtension
22{
23 public ref class Size
24 {
25 public :
26 Size(float n_value);
27 ~Size();
28
29 virtual System::String^ ToString() override;
30
31 private:
32 float value;
33 };
34
35 public ref class SizeProperty : SceneExplorer::INodePropertyDescriptor<Size^>
36 {
37 public:
38
39 // Factory method, builds the property with descriptors
40 static System::ComponentModel::PropertyDescriptor^ Create();
41
42 // Registers this property with the Scene Explorer's registry
43 static void RegisterProperty();
44
45 ~SizeProperty();
46
47 protected:
48 // implement the accessor operations
49 virtual System::Object^ DoINodeGetValue(INode *node) override;
50 virtual void DoINodeSetValue(INode* node, Size^ value) override;
51
52 private:
53 // Client code should use the factory method instead.
54 SizeProperty(void);
55
56 // This would be more efficient as a static constant, but we're trying to
57 // avoid the crash on DLL unload issue.
58 // For a managed class to have a native type as a data member, the native
59 // data member must be a reference or a pointer.
60 MSTR* mUserPropertyKey;
61 };
62}
63
64#endif //SIZEPROPERTY_H
SizeProperty.cpp
2// AUTHOR: Eric Feng
3// DATE: 2007-10-20
4//***************************************************************************/
5#include "SizeProperty.h"
6
7using namespace SceneExplorer;
8
9namespace SceneExplorerExtension
10{
11 Size::Size(float n_value)
12 {
13 value = n_value;
14 }
15
16 Size::~Size()
17 {
18 }
19
20 System::String^ Size::ToString()
21 {
22 if(value > 100.0f)
23 {
24 return "Huge";
25 }
26 else if(value <=100 && value > 50)
27 {
28 return "Medium";
29 }
30 else if(value > 0&& value <= 50)
31 {
32 return "Small";
33 }
34 else
35 {
36 return "Invalid";
37 }
38 }
39
40 SizeProperty::SizeProperty() :
41 INodePropertyDescriptor("Radius Size"),
42 mUserPropertyKey(new MSTR("Radius Size"))
43 {
44 }
45
46 SizeProperty::~SizeProperty()
47 {
48 delete mUserPropertyKey;
49 mUserPropertyKey = nullptr;
50 }
51
52 System::Object^ SizeProperty::DoINodeGetValue(INode *node)
53 {
54 ObjectState os = node->EvalWorldState(0);
55 if (!os.obj)
56 return nullptr;
57 if (!os.obj->CanConvertToType(triObjectClassID))
58 return nullptr;
59
60 TriObject *tobj = (TriObject *) os.obj->ConvertToType (0, triObjectClassID);
61 Mesh & mesh = tobj->GetMesh();
62 Box3 bbox = mesh.getBoundingBox(&(node->GetNodeTM(0)));
63 float radius = bbox.Width().Length()/2;
64 return gcnew Size(radius);
65 }
66
67 void SizeProperty::DoINodeSetValue(INode* node, Size^ value)
68 {
69 //node->SetUserPropFloat(*mUserPropertyKey, value);
70
71 }
72
73 void SizeProperty::RegisterProperty()
74 {
75 // Create a SizeProperty and register it with the Scene Explorer's
76 // property registry. It will be available from the Column Chooser.
77 NodePropertyRegistry::GetInstance()->AddProperty(Create());
78 }
79
80 System::ComponentModel::PropertyDescriptor^ SizeProperty::Create()
81 {
82 // create a SizeProperty decorated with the UndoablePropertyDecorator
83 // to support undo and redo for edits in the scene explorer.
84 return UndoablePropertyDecorator::Create( gcnew SizeProperty() );
85 }
86
87
88}
Screen shot:
Radius size is the custom column for scene explorer, which illustrate the radius size of the each object inside.
Conclusion
There are lots of new functions in scene explorer waiting for us to dig into, e.g. the custom search functions, the custom editor for column value,the UI of scene explorer, commands. And this article is to show the new features and what scene explorer is able to do, which give programmer a new world to explore.