Home Technical Talk

Max Script help

Hello,

I've developed a very basic custom exporter for my 3D engine, that simply exports geometry, and also centers the object when it exports etc.

However, there a few basic things I need to do, and I'm not sure how to go about them.

I've had a gander through the MaxScript help, but can't find what I'm looking for, probably because I don't know where to look amongst the abundant help files.

Could anyone point me towards an open source OBJ exporter (which would contain most of what I need) or answer these basic questions?

First of all, how to retrieve the material names per polygon as per the OBJ exporter?

Two other things I need are basic custom attributes, and sprite exporting.

I'd like to be able to assign/retrieve values from individual polygons, such as polygons that might trigger an event when collided with, or certain properties per polygon, like a different surface friction on ice for example.

And then sprite exporting, which should be pretty basic. I can simply export the position of the object, but of course I need the corresponding material of the sprite, and also the size. Should the size variable be handling with Custom Attributes?

It would be great if someone could point me in the right direction, as I'm working all day every day at the moment on the gameplay and physics of my racing game, and I'd like to get this boring part wrapped up so I can have a nice easy workflow for exporting levels ;)

Cheers,
RumbleSushi

Replies

  • rumblesushi
    Options
    Offline / Send Message
    I still haven't worked out the most concise way of handling material names per polygon.

    For models which have multiple materials (just environments), I'd like to be able to simply assign polygons different materials, retrieve the material name to export, so my engine can assign the appropriate texture.

    The only thing I've been able to find is this
    local polyMat = (getMeditMaterial(getFaceMatID meshObj i)).name

    But really, I don't want to be working in the MeditMaterial list do I, as it can only hold 24 materials? What if the object in question has more than 24 materials?
  • renderhjs
    Options
    Offline / Send Message
    renderhjs sublime tool
    First of all, how to retrieve the material names per polygon as per the OBJ exporter?
    Max handles polygon specific material settings via MultiSub materials. Faces on the other hand can have material ID's (look in the editPoly or editMesh inspector for that). Those ID's are linked and make out the different materials per polygon.
    If you select faces in max and drag a material or texture to that face selection it actually creates a multi sub material for you even though you might not realize that at first.
    So what you need to do is to read out the face material ID's of the mesh or poly. Then read out the associated material ($.material) and each submaterial slot.
    I'd like to be able to assign/retrieve values from individual polygons, such as polygons that might trigger an event when collided with, or certain properties per polygon, like a different surface friction on ice for example.
    Propably best to write a custom floater or tool where you store custom properties with ArraySets (the #{1..16} ones for face selections). Upon exporting you then read out those associations the way you need it.
    Many game engines however handle collision meshes as its own object. For general purpose properties refer to the node properties you can store for every max object. Like when you right click properties on a object you should see a "user defined" tab. Those properties can be accessed in maxscript and stored like ini files (simple ASCI variable assignments). You could use that to store and read custom properties.
    And then sprite exporting, which should be pretty basic. I can simply export the position of the object, but of course I need the corresponding material of the sprite, and also the size
    Depends on what you consider to be sprites. There are some maxscripts out there that render sprites, others are billboard managers but it all depends on your definition of them and how you work with them in max. I often just use dummy objects for a x,y,z scale and rotation setup, and some node name of the ID to export.

    Maybe have a look into rollouts and the visual script editor to quickly wrap up interfaces. You might need to write some custom tools in max to assign the custom attributes you want for your engine. Its what most tech artists do anyway when working with custom frameworks or engines.
  • rumblesushi
    Options
    Offline / Send Message
    Aha, render. I anticipated you'd reply ;)

    You see, not only do I not know much about how materials are handled in max, I don't even know how multi materials are handled in most 3D engines, it's not something I've ever investigated. In my engine, I have one material per object, and that's it.

    But now I'm making a game, I obviously need multiple materials for the environment.

    I had seen those material IDs actually, and the ability to set ID's, but didn't know what to do with them other than get their value from the materials panel.

    Essentially what I'm going to do is have a global materials list per level. Each polygon is going to be fed a material name, which then gets pulled from this global list, and if the material doesn't exist, it gets created.

    So what would be the simplest method of simply fetching the material name when looping through the polys? Then simply inserting the material name, just like the OBJ exporter does.

    And yep, I know most games do use seperate geometry for collision detection, which is obviously a good idea generally.

    For me though, the environments are plenty low poly enough to simply use the normal geometry for collision detection, especially considering I've written my own blazing fast 3D collision routine.

    And I didn't know that, that I would need to write a tool to assign custom attributes. I imagined CA's would generate a pseudo dynamic class with a pop up window which could simply be assigned various properties per object or sub object. Thanks I'll have to investigate CA's further. For now though I just need to get this multi material working.

    By the way, what I mean by sprites is I think what you consider billboards yep (mainly for trees really, and items), and that's pretty much what I had in mind, just a dummy object with position and material name.

    Edit - I just had a play around with dragging different material to polygon selections and I noticed that if you have a stack of different UV unwraps and edit polys, with one edit poly on on the top of the stack to select any poly, dragging a material onto a selection applies the material to the entire model. Do you know a way round this other than converting the entire stack to editable poly? (The only reason I don't want to do this is I want to keep the line/sweep in the stack, in case I need to change shape/polycount etc).
  • renderhjs
    Options
    Offline / Send Message
    renderhjs sublime tool
    You see, not only do I not know much about how materials are handled in max, I don't even know how multi materials are handled in most 3D engines, it's not something I've ever investigated. In my engine, I have one material per object, and that's it.
    Many engines I know of rather prefer however single materials per mesh or even environment. Its way faster as you can batch render calls (less tetxture swaps or non ideally) but it might require sometimes a texture atlas.

    Its sloppy as a texture artist anyway to mix up different textures per model. The ideal workflow is always to model, unwrap (with other objects in 1 UV sheet) and then texture everything. So instead of having multiple materials per object it should be rather multiple objects per texture or material :)

    Collision:
    How about you just set a face ID of the collision faces to #2 instead of #1. Once exporting it should be a piece of cake to export another mesh based off the face ID's of #2.

    ...dragging different material to polygon selections...
    Edit poly modifier ?


    so do you have a script already to read out the Face Id's, vertecies and UV data?
  • rumblesushi
    Options
    Offline / Send Message
    Absolutely, the main reason I do it is performance, to keep the draw calls as low as possible. Not only do I have only 1 texture per model, I like to share textures between models too where possible, so polygons of varying materials don't get shuffled up in the render list, creating possibly a draw call every other polygon etc.

    And for environment, do you basically mean a single texture per environment object? And possibly single textures per modular pieces of environment etc?

    I'm still going to share materials per object generally, it's just that for a track in my driving game, with varying textures on the core track material, partly from baked AO in the diffuse etc, I really need to have multiple materials for that one model at least.

    All trackside objects etc are going to have 1 material per object, and also share them.

    Oh and yes that all works fine, it exports all the geometry, and centers the object too. I haven't implemented exporting multiple objects though.

    As per edit poly, yeah that's what's causing it not to work. If I have an edit poly modifier on the stack, and select a bunch of them, the material gets applied to the whole model. If I right click, convert to editable poly, and then drag the material to that very same selection, it works perfectly. Odd.

    Also, in regards to the collision, I'm not exactly sure what you mean, what's the purpose?
  • renderhjs
    Options
    Offline / Send Message
    renderhjs sublime tool
    And for environment, do you basically mean a single texture per environment object? And possibly single textures per modular pieces of environment etc?
    No no, ONE texture for ALL objects of the environment. So track parts, corners, trees, crowd,... anything within the environment in 1 big texture (like 1024). Thats a lot more efficient work and performance wise. That way you model first all the models you need for the track, unwrap them all together (with same texel ratio) and then tetxure them all together.
    That way the models and textures are more consistent and its very efficient for the engine. For cars and swap able or dynamic objects it might make more sense of course to have another group of textures or individual textures. But from my experience the key thing is to keep the amount of textures low and plan your objects and texture use in advance, because technology and engines are about limitations and planning.
    I'm still going to share materials per object generally, it's just that for a track in my driving game, with varying textures on the core track material, partly from baked AO in the diffuse etc, I really need to have multiple materials for that one model at least.
    I guess what I was trying to say before that what max does is a hack. The general way engines handle materials is usually per model or mesh that is looped through. Anything like a multi sub material I think in the end comes down to the same as having 2 meshes (stacked together) each with their own material. Thats not really efficient because it requires a lot more drawing calls as booth objects with their materials are close at the same position making the render sorting resulting into a long render batch list.
    Oh and yes that all works fine, it exports all the geometry, and centers the object too. I haven't implemented exporting multiple objects though.
    thast piece of cake, I always write something along the lines of:
    for obj in selection do(
    --if typeof obj == poly...
    --if typeof obj == dummy...
    )
    
    so it saves your selection as a set.
    As per edit poly, yeah that's what's causing it not to work. If I have an edit poly modifier on the stack, and select a bunch of them, the material gets applied to the whole model. If I right click, convert to editable poly, and then drag the material to that very same selection, it works perfectly. Odd.
    I think that:
    1. the editPoly modifier needs to be on top
    2. you need to select some faces first in the submode
    3. then drag the material or a bitmap to that face selection
    Also, in regards to the collision, I'm not exactly sure what you mean, what's the purpose?
    Well I am assuming that you don't need all faces of your level as collision geometry - that certainly would be a waste of performance.
    So I was thinking that you could mark the faces of the track mesh that you want to be part of the collision faces. So with that idea you would select them and assign a face ID in the editPoly modifier or base object. Upon exporting the model using maxscript you first export the rendering model or arrays (faces, vertecies, UV faces, UV vertecies) and after that loop through the collision marked faces and export another mesh or array set with just the face ID's.
    That way there would be no need to create 2 models like one for the geometry and another one for the collision mesh which might not need all the same faces as the geometry level one.
  • rumblesushi
    Options
    Offline / Send Message
    1024 for a whole level? Obviously that would be ideal to keep draw calls to an absolute minimum, but it seems unrealistic for most games.

    I can imagine something like a Mario Kart battle stage fitting on a 1024 total.

    But take even a PS2 game like Burnout 3, with pretty big tracks, a lot of texture variety, lots of different trackside objects and buildings, plus a fair bit of unique AO.

    There's obviously no way that's going to fit on a 1024, or even close.

    Another thing I have to factor in is that unlike most engines that use lightmaps, I'm going to bake the AO into the diffuse.

    Which is actually the main reason that I need multiple textures per track actually, as there are going to be quite a few "duplicates" of the core road texture, because of different AO generated from trees and buildings.

    In regards to the edit poly, that's precisely what I'm doing. An edit poly on top of a stack (containing other edit polys and UV unwraps), I select a bunch of polys, drag the material to that selection, and wham, it applies it to the whole model. When collapsing the stack to an editable poly, it works perfectly, assigning the material to just the selection. It's odd, but I might make another thread about that.

    Oh and about the collision, gotcha. That would definitely work, I'll bear that in mind for other games.

    For this driving game determining which polys are collidable is fairly simple. Because the entire core track and mountain side is going to be collidable, I can just assign the entire model (or the models I'll break it up into) as collision polygons, where as anything that's out of reach, such as most background objects won't be marked for collision, so they won't even get added to the nodes of the broadphase.

    I already have multiple objects working by the way, you're right, it is easy ;)
  • renderhjs
    Options
    Offline / Send Message
    renderhjs sublime tool
    then make it 2048, my point is don't waste performance on multiple textures!
    It also comes down to your skills as a texture artist- like sometimes its better to set a omni directional or just directional top light, so that all casted shadows on the track are turn symmetrical on the x/y axis. That way you can mirror or turn track tiles while their baked shadows still match at the borders. Also don't forget to cheat with UV's like tiling, scaling things up where you only need solid colors, scale things where you only need a slice of a looping element,... That can save a lot of texture space.

    You shouldn't uniquely bake or place UV's for every single object anyway - thats such a waste. Instead try to instantiate as much as possible. It saves a shit load of work and lets you actually polish and push your objects at a higher level because you don't have to give a shit about every variation.

    Another thing to keep in mind you most likely have not implemented or will implement mip mapping. Without mip mapping you don't need much or any padding between the UV shells. Just make everything super tight and you can squeeze out another 30% texture space ;)

    Btw. the texture for this game environment was 1024, obviously its very modular but it worked just fine. Only the bike with the helicopter and particles were another texture.
    http://www.polycount.com/forum/showthread.php?t=68016
    bike_rooftop_game_s09.jpg
  • rumblesushi
    Options
    Offline / Send Message
    Render, with big polygons - one draw call on a 2048+ texture runs slower than a 512 texture with 100 draw calls ;) Well, in AS3 at least. On GPU platforms like Unity I have no idea.

    Up to 100 draw calls, the difference in performance is almost non existent. 500+ is where you start to see a very significant drop in performance.

    I'll be able to keep the draw calls under 100 easily, and this is how.

    Different sections of the track you drive through, are all going to share the same texture. As long as objects with different textures aren't parallel to each other on the z axis, it's not going to "shuffle" the polygons in the render list, and it's not going to increase draw calls.

    Only if a solid row of buildings on the side of the track had a different texture to the road for example, would the polygons be shuffled. As long as you share texures per track segment, whole sections can be rendered all one in one call.

    For example, with no cars in view, the number of draw calls is going to be as low as 3 or 4, as there'll be around that many sections of track visible at a time, each with a different texture (probably a 512, or preferably a 256 by 512).

    With a car visible, the draw calls gets upped to 10 to 20 from the slight shuffling introduced from the car's polygons.

    Oh and of course I'm not having unique UVs for everything. I'm going to tile as much AO as I can basically. On a tree lined road for example, I'll bake one texture with some tree shadows etc, then tile that along the whole road. I'll take this approach section by section.

    It's impressive that you used a 1024 map for everything. However, your game is sort of 2.5D, so you don't get anywhere near as close to the textures, so both texture resolution and AO is less important than a driving game with a 3D view.

    My levels are going to be somewhere between Ridge Racer and Burnout in size, so unless I have really low texture resolution or almost no unique AO, doing an entire level on a 1024 isn't possible. A 2048 would be doable, but like I said, a few extra draw calls is still going to be faster than using a 2048 which loses some fill rate (only noticeable on big polys, ie environment).

    I'm planning on having around 12 seperate 512 textures, which is actually lower than the 16 in a 2048, and as long as I keep the draw calls under 100, is going to outperform a single, large texture solution.

    By the way I agree about mip mapping. I implemented it ages ago, but it's not worth it in Flash. You need too much padding and it uses more RAM, plus textures smaller than 512 with dt don't have any effect on fill rate.

    I definitely like the idea of a flush top down light with a normal of 0,-1,0 so as to create tileable, rotatable shadows etc. I'll have a play with that.

    What do you use to bake? Scanline or MR?

    Personally I like environments with a lot of unique AO/shadows like Burnout 3, it adds to the richness and immersiveness of an environment. Obviously that's not practical with web games though.

    Outrun 2 is a great example of a game with heavily tiled AO. Each section pretty much just has one road texture with some AO shadows tiled the whole way. And because of the overall styling and sheer arcadeyness, it looks good.

    Ironically, the entire physics/gameplay side of things is all in hand. Level design and texturing I'm finding more difficult because I simply have no experience. I wish I had an experienced level designer, but oh well, I like a challenge and it's all fun.
  • renderhjs
    Options
    Offline / Send Message
    renderhjs sublime tool
    well do whatever you want, I don't care anymore at this point.
  • rumblesushi
    Options
    Offline / Send Message
    Easy fella, I'm trying to give you some advice. When it comes to performance, I know exactly what I'm talking about, my engine is faster than any other 3D engine in Flash. I'm a novice at modelling/level design but if anyone should be giving performance advice, it's me.

    You're wrong to think that a 2048 map is going to outperform an environment broken up into 512 textures, as long as you can keep the draw calls low, to 100 or less.

    You're too focused on draw calls, but with drawTriangles, it's only one of 3 components. The other 2 being texture size and and polygon size, DT is at least as fill rate limited as it is draw call limited, and poly count limited.

    Rather than making sure the draw calls are nearer to 0 than 100 for example, rendering at lower resolution and upscaling has a far more significant effect on performance, especially for environments with big polys and redraw.
  • renderhjs
    Options
    Offline / Send Message
    renderhjs sublime tool
    just start a project thread if you want a discussion
Sign In or Register to comment.