Jump to content

TorqueFan

Members
  • Posts

    130
  • Joined

  • Last visited

Everything posted by TorqueFan

  1. Haha, you posted as I was typing this all up so it's getting posted anyways! Check it out if you get a chance though, using Torque's skinning system can be really powerful once you get it nailed down. In this example you could use a single texture for any number of materials with added color to the diffuse of each material. Additionally a single model for as many materials as necessary! Anyways, glad you guys got it sorted =) Gonna try for a quick rundown of how to handle material definitions for skinning in 3, 2, 1... Naming the Materials Let's try for a really simple scenario. We'll use one single image, called "shirt_d". For skins we'll re-use the same image and just add color to the diffuse. This looks like so: // default shirt(white shirt diffuse texture) singleton Material( Mat_PlayerShirt ) { mapTo = "White_PlayerShirt"; diffuseColor[0] = "1 1 1 1"; diffuseMap[0] = "shirt_d"; materialTag0 = "Player"; }; // Blue shirt singleton Material( Mat_Blue_PlayerShirt : Mat_PlayerShirt ) { mapTo = "Blue_PlayerShirt"; diffuseColor[0] = "0.58 0.81 1 1"; }; Okay so the Mat_Blue_PlayerShirt enherits from Mat_PlayerShirt, so we didn't even have to name the texture since we're just going to apply some color to the same diffuse! Another important thing about this example is that I did NOT use the standard naming convention of "base_PlayerShirt" for my default material. This was on purpose to illustrate that you have the freedom to name your "mapTo" material whatever you like. Just be sure that any materials that enherit from it are named properly and the name here is the same as the name of the material on your model. Here's what I mean: Your base default texture is named "Mat_PlayerShirt". The base default texture's "mapTo" field is "whatever_PlayerShirt". Use whatever 'base' prefix you want, OR use the default "base_PlayerShirt". The next texture you create will need to enherit from the base texture. Declare it like this: singleton Material( Mat_New_PlayerShirt : Mat_PlayerShirt ) Any of the textures you created as above in point 3 need to label their "mapTo" property precisely. In point 3 the material is named "Mat_New_PlayerShirt" so the "mapTo" field would be "New_PlayerShirt". The Object Datablock In order for all of that material preparation to pay off, the datablock that's loading up the model needs to declare its skins. For datablock types that support skinning, the field looks like this: datablock PlayerData(DefaultPlayerData) { ... availableSkins = "White Blue"; // example 1 availableSkins = "whatever New"; // example 2 availableSkins = "base New"; // default example ... }; So we only use the prefix of the "mapTo" field for each material we want to add to the datablock's skin list. Also important to note is the availableSkins field wants you to enter a tab-delimited list of prefix strings. So just be sure you enter it in like: whatever(TAB)Blue(TAB)Green
  2. Cool, yea IIRC you should be able to call setSkin() to choose a skin for the model displayed in the GuiObjectView using the stock code. Yes, of course I am willing to share my GuiObjectView code! I've been meaning to upload it as a resource for awhile so it's coming soon! Now, dealing with skinning in the first place is just a little bit tricky but it's not too bad once you learn the ins and outs of naming the materials. I'll post more detail specifically about skinning and proper material setup either a bit later tonight( if I get the time ) or tomorrow. It's worth going over here one solid time for any who may be reading as well. Stay tuned!
  3. @Bricktronic: I skimmed over my updated GuiObjectView code and stumbled on the 'stock' T3D console function for setting skins. Before we overkill this thing completely, try to use this: // Define the skin we want to apply to the main model in the control. %skinName = "disco_gideon"; // Inform the GuiObjectView control to update the skin to the defined skin. %thisGuiObjectView.setSkin(%skinName); That might be more along the lines of what you were looking for to begin with. Sorry, I've been running all my builds custom for quite some time and have a tendency to overlook "what was stock" sometimes. I believe, dealing with skins, what my resource achieves is it allows the model to have multiple skins at the same time. As in, if you have a model with multiple sub-meshes that each have their own material. Anyhow, as promised, I'm still polishing my updated resource.
  4. When I was constructing character creation GUI's I'm pretty sure that was something I ended up having to 'fix' in source. I mean, it's not broken, just needed the support plugged in so to speak. IIRC, the GuiObjectView class didn't originally support the rendering of different skins using 'mapTo'. Since you bring it up, 'mapTo' specifically rings a bell and jogs my memory...seems like I may have even had to change something higher up the enheritance chain. Man, I really need to tidy up my updated GuiObjectView class resource and get it out the door. That's a lot of script you're having to go through for something that can be handled with 'setSkinName' using my updated resource. I know it's not helpful to you in this moment, but I will make it a point to upload it very soon. People just need stuff like this! Give me a lil bit to clean up my code and get a little bit of a 'how to' typed up for the resource and it will fix any problems you've likely had with the GuiObjectView! P.S. Are you comfortable with replacing your GuiObjectView.h and .cpp files in source(maybe another file or so I'll have to check when getting the resource ready)? Sorry should have asked before offering out a resource that requires source updates. :roll:
  5. I just wanted to chime in here to thank @kent for his contribution and sharing with the community. Also thank you for bringing up this same question that has been on my mind for quite some time: For a number of reasons, I personally would prefer not to submit PR's to the T3D branches directly from my company's GitHub account. However, I strongly feel the need to share some of the small updates and corrections I stumble across while developing. So I can either A)make another GitHub account and create an entire fork for each small change then PR it - or B)Copy/Paste the code in a resource here on the forums. It's like if I go with A) it's pretty cumbersome - especially with the sort of scheduling I have to deal with. If I go with B) it seems much simpler although then I feel as if I am not being helpful if I don't go the extra mile and submit the PRs. lol. Anyways just some thoughts, and I'd be interested in hearing the SC's stance on this. I would prefer to use the proper etiquette when sharing.
  6. Without opening a great big can of worms...no, objects with collision meshes are not constantly doing collision checks while idling. All objects that could potentially collide against something else share one thing in common: they have to be moving to collide with something. This being the case, the moving object should be testing against things for collision - hence why we have the Player class searching for Triggers in its onContact() function. Unfortunately I don't have the time this morning to break down T3D's collision system, but I'll try to touch on the important parts: Objects that support collision will have a castRay() function in the class's source file, to be used when another object queries against it for collision. So if %objA is a rock with a collision and %objB is any other moving object - if %objB collides against %objA(the nonmoving rock) then %objA's castRay() code will be called to check for the collision. Players specifically will keep track of a collisionWorkingList of objects they are colliding with to help keep things in sync client/server. Off the top of my head I wanna say it was the physicsShape.cpp file where you could look for yourself and see what data is actually streamed and updated by a physics enabled object.IIRC the physics rep is only dealing with mass/buoyancy and things like that.
  7. That statement compares a single raycast vs. multiple raycasts occurring for a single collision determination. We are comparing a single raycast being cast(300ms) constantly vs. multiple raycasts occurring for a single collison determination only when the player hits the door's collision area. One way to look at it is like: Do you want the engine constantly idling in your driveway, or would you prefer to only start it up when you need to drive it?
  8. I found this information, which is the approach I would probably use: StaticShape solution by Konrad Kiss So you could add a collision shape in the model file that encompasses the area where you'd want the GUI popup to appear. The player hits that area, popup the GUI. If they confirm to open the door, setMeshHidden() on the collision shapes and animate the door. This looks like the most elegant solution, although I hadn't scripted any of it to test. Long ago I did something similar with a garage door and it did indeed animate/kill the collision.
  9. @flysouth : That's a very good question, but likewise there is good news in return. I just cracked open some of the source code to be sure we are on the right page and uncovered just a tad more detail about Triggers. mObjects The first thing to understand is the Trigger class itself keeps track of a list of objects within its bounds, called mObjects. The important thing for us to figure out is exactly how the list of objects is updated. Luckily the Trigger itself is not constantly performing searches within its entire area even when there are no players inside. There is a function in the trigger.cpp file that will get the information from the GameBase object that hits the Trigger. The relevant function is potentialEnterObject(GameBase* enter). One good thing about it is it already takes care of client/server side stuff! In trigger.cpp : void Trigger::potentialEnterObject(GameBase* enter) { ... } This means that the Player object determines when there is a collision with a Trigger or not. The best part?? The Player already performs this check by default right now, so every test you've ever run already had the Player object searching for Triggers while moving. This is found in the player.cpp file in the findContact() function. Here's the relevant bit: In player.cpp : void Player::findContact( bool *run, bool *jump, VectorF *contactNormal ) { ... if (objectMask & TriggerObjectType) { Trigger* pTrigger = static_cast<Trigger*>( obj ); pTrigger->potentialEnterObject(this); } ... } What this is doing is it is determining if the contact object is a Trigger or not. Then if it is it's 'getting ahold' of the Trigger object by creating a pointer. Lastly it uses that pointer to tell the Trigger object that there now is indeed a GameBase object that is within its bounds - a Player no less! The Trigger will test that object again( in the potentialEnterObject() ) function I posted above) and if it meets the criteria it will accept that there is a GameBase object within its bounds. Now that the Trigger object is equipped with a proper GameBase object to add to its mObjects list it can finally begin to execute any of its code. As you can see, the Trigger really does pretty much sit around idle and do nothing at all until there are GameBase objects within its bounds and on its list! I hope this helps further, tbh I learned a tad bit more about the contact code myself! Good luck, happy Torquing! Notes: Note that you still have to weigh for your game what's the biggest hit. The usefulness of one method or another will vary based on number of doors vs. number of players and so on. All of what I've described here is for the greater good of actually answering the question, "How best to do this?", although by now it should be clear that "best" is specific to the implementation. To truly get the answer I'd suggest giving either way a shot and profiling the results to find out exactly what's more efficient. Personally I usually design/develop classes and objects with multiplayer in mind at all times, so I tend to use approaches that can 'handle' high traffic scenarios.
  10. Okay that's a bit clearer, I see what you're up to now. You want that dynamic GUI dialog to automatically pop up. I took it to mean you wanted to walk up to the door, hit a button, and the door opens(no popup involved). Well in any event constantly firing a raycast out in front of the player detecting stuff will surely keep things 'ticking', although I'd still approach it just a tad differently to reduce any additional overhead. Consider that the player may be out in the wilds someplace, far away from any potential door to be opened, yet he continues to cast rays out looking for doors that couldn't possibly exist. Here I'll try to address your implementation to the best of my understanding: Triggers : From old documentation : So here we see that you can create your own trigger datablock, and instead define its tick frequency to whatever you want(i.e. 300ms that you currently use while raycasting). Alright, great, so you can use triggers at the same tick rate - how does that help?? Let's take a closer look at the Trigger class again. In the same link provided above, check out the function DefaultTrigger::onTickTrigger (near the bottom of the page, also referenced here.) What this field allows you to do is enter in a command that you want to be executed while objects are inside the trigger. So, not only can you have your raycast function be called by the trigger at the same rate, you can also have it only fire off the raycast search while the player is close enough to the door for it to matter. Meaning you can create a trigger area much larger than just a few feet across, say maybe 10 feet x 10 feet, and have that trigger call to your player's raycast function only while the player is within that range of the door. Now you have the same functionality you did before but it's a LOT more efficient. Now, to be completely clear about the Trigger class, it should be understood that the Trigger itself will continue to tick at the rate you set it to even if nothing is in the Trigger's area. However, and this is the important part; the Trigger class's onTick() source code will immediately return and won't execute any code unless the criteria you set for the Trigger are met. So it will continue to 'listen' but it won't execute the raycast search code unless the player object is within the bounds of the trigger. Disclaimer: As usual bear in mind of course there are many ways to approach any given problem(be it in source or in script). For what you've got going, this seemed fairly appropriate, although I can see other paths as well if it isn't optimal to your needs. Personally I've spent a good deal of time and planning avoiding as many triggers and schedules as possible, but in some cases you just have to use the available classes to the best of your ability or craft up new ones :lol:. Think it over, see if it helps, cheers! P.S. Another thing to consider is that you could avoid the raycast code altogether. If you are going through all of that just to get a GUI control to pop up you might as well place a small trigger area in front of the door. Then when a player hits it, the GUI control pops up indicating the player is close enough to open the door. If the gameplay is of a type where clicky GUI navigation is happening to interact with stuff, whether or not the center target reticle is 'looking at' the door shouldn't matter. If you are standing on the door square you can open the door. Food for thought =)
  11. @Azaezel : Ah okay, yea, I gotcha. That's actually close to what I was doing in script when I first put all this AI system together. I mean the way you guys are adding the triggers onAdd(). I can get all my signals firing if I add a trigger for each signal I want to fire, easy peasy. What I'm actually trying to achieve at this point is a tad more advanced. I'm moving that trigger based scripted system into source, and what I'd really like to see happen is have the client detect what's in range and THEN fire the signal. This way, although all of the potential objects may be registered to the event, only those in range of each client will actually fire the event. Tbh I'm fairly close to nailing it, of course I'd be glad to share when it's complete. @flysouth : Well, if you have a schedule running it's full-on running as often as you tell it to. With a trigger, it can just sit idle and do nothing until something is within its bounds. Of course, regardless of what you do there is going to be a 'listener' of some sort paying attention to what's going on to fire off the event. I must be too deep in my current implementation, I didn't completely address your question flysouth. I'd recommend you avoid triggers/scheduling altogether. What you should do is have your event(the moving of the door/collision) fire off after a successful raycast. So shoot a ray at the door from your player's eye and once it hits, fire off the event that handles the animation of the door/collision shape.
  12. Dude, you wouldn't by chance mind giving an example of that "tacking on triggers so if nobody is around" bit would you? I am in the middle of constructing a custom AI system in source and it's using signals. I was wondering what the best way to handle the 'tick' is? I'm trying to determine whether or not I should have a custom 'Manager' class handle all that in its 'tick' functions or if I should have the clients gather the local information to see if a signal should be triggered? From what I've managed to gather so far, it's looking kind of like both...the client gets the stuff in range and the custom Manager class could use that information to trigger those in range. @flysouth : Are you trying to keep all of this in script? I have grown partial to using the ScriptTickObject class for having stuff 'tick' in script. You could have the ScriptTickObject call whatever is dynamically being refreshed, but I'd be careful using this approach. The good thing about the ScriptTickObject is you can throttle back the speed it ticks so whatever script you're feeding into it doesn't get called a bajillion times a second. I'd recommend a bit of research around that class. Also IIRC to get the ScriptTickObject to 'start up' you have to 'turn it on' using a script function. Can't remember the syntax off the top of my head, but if you decide to use the ScriptTickObject and need help just ask. I have at least one good example of it on my hard drive someplace.
  13. Just to be clear, how exactly did you make the collision mesh a child of the door? Did you properly create and add the collision mesh in the model? @irei1as : That's an interesting approach. It's been awhile since I messed with moving collisions but IIRC isn't it possible to just animate collision shapes in the model itself? Seems like I was able to do that once, but it required using more than one collision shape. /shrug
  14. @JeffR - I finished with my new template, which is based off of this one. I gotta hand it to ya, I've looked at reducing down all of that initialization code for quite some time but never really pegged it. Certainly not in such an elegant implementation. Kudos! So yea, after really getting my hands dirty and building up a project(using this template as a base) I wanted to share a couple things that stood out to me during the process. Root Directory : I renamed the root game\ directory to app\. If you really think about it, T3D can and has been used to develop more than just games. Of course many of the included classes and code is specifically designed around making games, so this could just a matter of preference ;) But hey, think about it! Shaders Directory : Actually I just ended up leaving it alone entirely. It exists in the root directory alongside core\ and data\, so it's app\shaders\. After getting a better 'feel' for the new directory structure, I actually didn't find anything wrong with shaders\ having its own directory there. All of the modules rest in data\ and core\ deals with things necessary to initialize the engine. So the shaders\ directory still does sort of exist as a grey area and as such shouldn't be denied its own directory. Gui Directory : Personally I opted to keep the old gui\ name instead of the new UI\ one, for 2 reasons: Firstly, I am more familiar with looking for a directory named gui\ after using Torque for years(it just 'feels' like it should be called that lol). Some of my existing projects can easily be transferred over using the same directory name. File paths will of course always need to be changed for something like this, but in any event I've found the entire process of transferring over to the new module system easier with the gui\ directory name intact. So really just some directory naming stuff. Which is a good place to be in with such a large update to the script base. Good work man, I hope you'll consider the suggestions :D P.S. Oh, I almost forgot. I did end up splitting apart the client\ and server\ modules. In the root directory's main.cs I did this and it works well: if(!$Server::Dedicated) ModuleDatabase.LoadGroup( "Client" ); ModuleDatabase.LoadGroup( "Server" ); Of course this depends on your 'Client' module residing in the group called 'Client' and the 'Server' module residing in the group called 'Server'. Cheers!
  15. Luckily for you, the updateMove() function in player.cpp already does this for you: VectorF contactNormal(0,0,0); bool jumpSurface = false, runSurface = false; if ( !isMounted() ) findContact( &runSurface, &jumpSurface, &contactNormal ); if ( jumpSurface ) mJumpSurfaceNormal = contactNormal; This nets you a VectorF variable with the surface normal data for whatever your player is standing on. You can follow the trail to the findContact() and _findContact() functions in the same player.cpp file. Another approach that I often use is to get ahold of the normal data using a raycast. Raycasts will return the normal as part of the collision struct. This can even be done in script, although for something like updating player movement it's best kept here in the source. I give mention to this approach because, believe it or not, it is used already for footprints and footstep sounds.
  16. Not sure if it'd be valid for your implementation, but could you just grab the normal of the surface the player is standing on? Then you could adjust your player's mOrient value based off of that.
  17. I appreciate all of that info man, thanks. It's all pretty clear with your explanations, sweet! Yea, that shader initialization is a trip. If it DID all get merged into core\ at least developers could simply just remove any shaders they didn't use if that was the case. Any project specific shader code could sit comfortably in a module. Yea, it kinda is I guess. I was just wondering if onStart() and onExit() callbacks would still exist that's all. I noticed ya did still use onExit() so I'm assuming those callbacks may still be floating around. It's a trivial concern, as you've eluded to, in question 2 we've covered what really matters: the modules initialize everything with their functions! Toss my vote in the hat for doing that. There are a few reasons: 1) Because I am going to separate my client/server scripts into separate modules. lol. My main project I'm making 'modular' atm will require it, because all of my GUI stuff will belong in the client module. 2) I believe that long time users of Torque will find it easier to maintain familiarity with separate client/server modules. It just 'feels' comfortable to pop open whatever directory it may be and see client\ and server\ sitting there side by side. Torque-goers know that feeling! :D Really I believe what's important here is looking at how easy it is to approach Torque. Regardless of our module structure or initialization process, Torque is going to require that client/server architecture. Better sooner than later for newcomers to learn how that all works. Having a single 'clientServer' module could serve to conceal a bit the importance of that divide for those unfamiliar with the engine.
  18. Well, if you are going to only read the last post please try to fully grasp that single post you do read. :shock: In my posting, if anything, I've spoken in favor of moving some stuff that doesn't belong in core\ out of it. I only suggested shaders\ joining with gfxData\ since they are closely related anyhow. Preferably, yes, I'd imagine they would belong in a client module. If you look closely at my Question #3 above, you'll see I did state that the shaders aren't necessary for core initialization. Which I immediately followed up with #4, where I question if gfxData\ belongs in core to begin with. Really all of that serves to highlight how much of a grey area those are and it's easy to see how placement of those particular directories/files can be a bit of a chore. Due to the way this template completely revamps the initialization process, that's already been done. As an aside, though, there is a new module named 'clientServer' that handles all the initialization for Client AND Server. But it actually IS easier to make MP games with this template, because it's easy enough to go one way or the other following the initialization scripts @JeffR has assembled here. Heck, as a matter of fact, the more I delve into this New Base Template, the more it's starting to stick and it's working well. I've already started building modules and having them initialize using the new system! EDIT: The thought occurred to me that one could split the clientServer module and add shaders\ to the client module. That could be useful, but Jeff's got it all so tidy already it's kinda hard to bring one's self to mix it up. lol. The client and server scripts are separate and initialize from different functions. Good enough for me!
  19. @JeffR: It would appear I'm raising this thread from the dead! Necromancer extraordinaire! I have been designing a new Base Template for modular development, and I found this thread. Firstly I'd like to commend you for the work and effort that went into building this. Thanks man, this has been needed for awhile. Respect, I am particularly fond of the craftiness that went into bypassing all of the duplicate initialization code. I have some inquiries about your work. Firstly, I didn't see the onStart() and onExit() callbacks in the new main.cs files. This is really interesting, and left me curious: Question #1: Will the current "main loop" layout be deprecated in source? Obviously it's already been deprecated in the New Base Template, just wondering if the current functionality would still be available. (i.e. onStart() and onExit() overrides to initialize mods.) Question #2: Related to Question #1 - Would the current onStart() and onExit() callbacks just be redundant anyway because the module system is automagically initializing the modules? Unrelated to all of that, I wanted to ask about the postFX and shaders: Question #3: Would it be safe to move the shaders\ directory into core\? It just seems out of place since it's not really a 'module' in the data\ directory. It appears shaders aren't necessary for core\ initialization, though, which leads us to Question#4: Question #4: I noticed the core\gfxData\ directory holds game-specific stuffs. TerrainBlock, Clouds, ScatterSky, Water...are these necessary to include in core\ ? Suggestion for #3 and #4: I would merge all of that either way. Either place shaders\ into the gfxData\ directory or gfxData into the shaders\ one. Anyways man, yea thanks so much again for this template. I had put in a few pages worth of a changelog constructing a new template when I stumbled on your post. Would have saved me a good bit of time. lol. Oh, I almost forgot: Question #5: Could you point me in GitHub to relevant files that were altered in source regarding the shader file paths?
  20. @Timmy Oh, thank goodness. That's exactly what I was looking for, thanks so much! With a bit of luck, I can have this template tidied up and operable by tonight. I'm grateful Timmy!
  21. EDIT: Barking up the wrong tree, still searching for a way to configure new template. EDIT2: It appears the new directory alongside source/ might be able to just simply be included in the template. I am still doing some work on the template, but at this point my problem appears to be more of a "learn to build a new template with CMake" issue than a "learn to build with Torque" one. lol. :lol:
  22. I have created a new template for my projects in T3D. I created this new template mainly for organizational purposes, in preparation for modular development. Basically the template moves things around so that the root directory isn't so cluttered and only contains 'mod' folders that contain a main.cs file. Anyways, to fully complete this template I would like to have Torque respect my new directory structure when compiling the .exe. My root directory is no longer named 'game', and in addition I have a couple of directories that are equal to the root. Where can I tell Torque to build in the new directory? Normally, if you compile the project's .exe Torque will create the new folder 'game' and place the .exe inside it. I want to tell Torque to create a different folder name, basically. If possible, it would also be nice to have Torque create some other directories at this same time. Can anyone offer guidance? I use CMake to generate the project if that's important. To be clear, in the solution's Output Directory field for ALL_BUILD there are variables: $(SolutionDir)$(Platform)\$(Configuration)\ I need to know if there is a configuration file similar to torque.rc or torqueConfig.h where these variables are adjusted. For the project itself, it's easy enough to just input a new path...but I also want to create a new path in the same directory as root. Like where the 'source' folder is now I want to add a 'docs' folder.
  23. I've been using Torque's SimXMLDocument class extensively for quite some time. Once I tried it out awhile and pinned down exactly how to store/retrieve data, I started using it exclusively for data persistence. You can use code or script. You can index data and iterate said index. For multiplayer this adds a layer of security, as all .xml files are accessed exclusively through your custom script/code functions. Feels like a win/win. I hadn't profiled it(yet) to see how much of an impact it may have on server performance with the reads/writes. But then again, thus far the amount of data has been so minimal that it doesn't matter regardless. As things expand, though, will have to keep an eye on all the SimXMLDocuments being read/written and probably use a manager class to handle read/write requests. Just thinking out loud, but yea, SimXMLDocument has been working pretty well for me as a way to store data.
  24. TorqueFan

    Toon shading

    @Timmy - Nice, thanks. Will be converting a class I based off of ScatterSky soon, and if I run into trouble I'll post about it. The class did pass some new shader values around.
  25. I am envious of your understanding of the inner workings of T3D's code! LOL! I go about as far as to write custom rendering functions within object classes, but that's about it. Any of the more deeply embedded functions, such as those belonging to SceneManager or GFXDevice etc., I just depend on the engine to do work =D Yea, I hear ya, using the proper viewing frustum to begin with sure does seem like a good place to start. For someone like myself, with limited knowledge/understanding of the 'core' rendering code, I just seek greater knowledge around the subject. Considering all of the updates and changes taking place as of late(specifically around the core rendering code lol), I am taking the opportunity to glean as much wisdom as possible from the transition.
×
×
  • Create New...