peter_spy Posted July 29, 2021 Report Share Posted July 29, 2021 (edited) @HMart you should be able to have detail textures with certain material keywords. You can do this by e.g. stacking normalmaps with addnormals, or by using gl blend modes. I'm using something a la detail noise texture in Rage, since one of the gl blend modes seems to work like Overlay mode in photoshop: Edit: sorry, you can't really make detail normalmaps with addnormals, since this is image programs territory and there is no option to tile the second normalmap there. It's quite confusing, because there's a scale keyword for image stage, which is responsible for tiling, and there's a scale image program function, which acts as a multiplier for image RGBA values. Two completely different things. Edited July 29, 2021 by peter_spy Quote Misc. assets for TDM | Artstation stuff Link to comment Share on other sites More sharing options...
MirceaKitsune Posted July 29, 2021 Report Share Posted July 29, 2021 (edited) @HMart So the engine should support this I understand? However we don't have any such textures by default, do we? Note that I'm not suggesting adding extra textures for this purpose: We already have good terrain images for most use cases, only suggesting a shader to blend multiple ones based on surface direction to obtain more realistic detail. Edited July 29, 2021 by MirceaKitsune Quote Mods: Builder Blocks minigame | Keypad | Disguises Link to comment Share on other sites More sharing options...
jonri Posted July 29, 2021 Report Share Posted July 29, 2021 On 7/28/2021 at 4:20 PM, MirceaKitsune said: Meaning terrain materials that alternate between images based on the surface normals, blending one image horizontally and another vertically for more realism The term for this is called triplanar mapping. Before getting your hopes up, the answer is no, TDM does not have this capability. That said, I once did an experiment some time ago, I achieved some degree of success but there were some major drawbacks: Spoiler Other than the trees, this terrain is a single mesh with one material applied to it: The features: Using an RGB splatmap, I could paint 3 different textures onto the ground. A 4th texture would automatically be used for vertical areas using triplanar mapping. Where different textures meet, instead of linearly blending them together, they are blended based on heightmap. Lacking actual heightmap data for the textures in use here, I substituted a grayscale map of the texture and still got good results. Why you shouldn't do this: Custom shaders are fun to toy around with, but they're likely to get broken in future releases. There was another thread for discussion of this here. This isn't great for performance, it's a heavy material that will get run on large portions of your screen. All the magic happens by modulating the diffuse texture. You can't have normal or specular maps. 1 Quote Link to comment Share on other sites More sharing options...
MirceaKitsune Posted July 29, 2021 Report Share Posted July 29, 2021 Thanks @jonri that clarifies it better. Yeah triplanar mapping is a common and great way of doing it. I figured it might still be possible by manually painting a grayscale blend image, but with terrain patches that you need to constantly adjust and move around that isn't really an option. And if it breaks the normal or specular map it's a big no-no, each terrain shader should still have its own active on its own portion of the surface. Wonder what could be done for our engine to support even a simple version of this system. Quote Mods: Builder Blocks minigame | Keypad | Disguises Link to comment Share on other sites More sharing options...
jonri Posted July 29, 2021 Report Share Posted July 29, 2021 33 minutes ago, MirceaKitsune said: Thanks @jonri that clarifies it better. Yeah triplanar mapping is a common and great way of doing it. I figured it might still be possible by manually painting a grayscale blend image, but with terrain patches that you need to constantly adjust and move around that isn't really an option. And if it breaks the normal or specular map it's a big no-no, each terrain shader should still have its own active on its own portion of the surface. Wonder what could be done for our engine to support even a simple version of this system. @MirceaKitsuneto be clear, you can still use vertex color blending to blend two materials and that shouldn't break the other maps, it was just my experimental approach to terrain that did that. And you are correct, it wouldn't be something you could attempt with patches, you'd want to build it all in a 3d modeler. Quote Link to comment Share on other sites More sharing options...
AluminumHaste Posted July 30, 2021 Report Share Posted July 30, 2021 That triplanar technique is really cool https://catlikecoding.com/unity/tutorials/advanced-rendering/triplanar-mapping/ Quote I always assumed I'd taste like boot leather. Link to comment Share on other sites More sharing options...
Geep Posted August 3, 2021 Report Share Posted August 3, 2021 Could someone point me to the sound shader and/or ogg file that has the sound of a fly circling over a chamberpot? I know I've seen this in FMs in the past, but can't seem find it. Quote Link to comment Share on other sites More sharing options...
Dragofer Posted August 3, 2021 Report Share Posted August 3, 2021 19 minutes ago, Geep said: Could someone point me to the sound shader and/or ogg file that has the sound of a fly circling over a chamberpot? I know I've seen this in FMs in the past, but can't seem find it. I've got such a speaker underneath the northwestern external stairs on the ship in Perilous Refuge - can't checl that myself atm. 1 Quote FM: One Step Too Far | FM: Down by the Riverside | FM: Perilous Refuge Co-FM: The Painter's Wife | Co-FM: Written in Stone | Co-FM: Seeking Lady Leicester Dragofer's Stuff | Dragofer's Scripting | A to Z Scripting Guide | Dark Ambient Music & Sound Repository Link to comment Share on other sites More sharing options...
Geep Posted August 3, 2021 Report Share Posted August 3, 2021 I had searched for "fly" when I shoulda searched for "flies". All good. Quote Link to comment Share on other sites More sharing options...
Jedi_Wannabe Posted August 9, 2021 Report Share Posted August 9, 2021 (edited) Need some help. Nearing the end of my list of fixes, and this sprang up at random, thankfully I caught it by chance. I've got an issue with some locked doors and corresponding keys. At first they worked perfect, but now the key(s) won't unlock the door(s). Here's the set up. I've got a room with three doors into it. Two of them are locked. There is a key outside the room on a guard, and one inside the room hidden somewhere. Attached is a screenshot of the properties of the keys (top row) and the doors they correspond to (bottom row.) I should note, initially I started with just one key outside the room, placed on the guard. While it technically worked, beta feedback dictated a second key to be found inside the room. No problem, the first time I implemented it and dmapped it worked exactly as intended, with my new second key unlocking both doors, and vice versa for the key on the guard. So I moved on and didn't think about it for months. But randomly I noticed they don't do shit no more! I swear I haven't changed the spawnargs since I got it working the way I wanted, but clearly something is wrong and now I'm perplexed. Thanks, -Jedi Edited August 9, 2021 by Jedi_Wannabe Quote As my father used to say, "A grenade a day, keeps the enemy at bay!" My one FM so far: Paying the Bills: 0 - Moving Day Link to comment Share on other sites More sharing options...
Dragofer Posted August 9, 2021 Report Share Posted August 9, 2021 There's an excess comma at the end of the key name in the "used_by" spawnarg. Maybe that's what tripped up the door script for both keys. Also, it might be worth making the 2 keys stackable with inv_stackable 1, since they're identical. Might need to change the used_by spawnargs to point to the inv_names in that case. 1 Quote FM: One Step Too Far | FM: Down by the Riverside | FM: Perilous Refuge Co-FM: The Painter's Wife | Co-FM: Written in Stone | Co-FM: Seeking Lady Leicester Dragofer's Stuff | Dragofer's Scripting | A to Z Scripting Guide | Dark Ambient Music & Sound Repository Link to comment Share on other sites More sharing options...
Jedi_Wannabe Posted August 9, 2021 Report Share Posted August 9, 2021 Well I can't explain the existence of the comma haha, but it's absence cleared up my problem. They stack by default, even without the inv_stackable 1 spawnarg. Unless they break again I'm just gonna leave it lol. Thanks for the help @Dragofer! 1 Quote As my father used to say, "A grenade a day, keeps the enemy at bay!" My one FM so far: Paying the Bills: 0 - Moving Day Link to comment Share on other sites More sharing options...
Geep Posted August 10, 2021 Report Share Posted August 10, 2021 (edited) Another sound issue. Primarily for conjectural performance reasons, I was trying to replace large area speakers with info_location ambience instead, using the same looping sound shaders (e.g., city_sounds_varied). But it appears that if the sound shader has multiple sound files, only 1 ever gets played & looped. Sucks. Since this is not mission-critical, I'll probably revert the build, unless someone has an easy fix. Update: Got a mix of smaller speakers and info_locations that are working good enough for me, so moving on. (BTW, the manifestation with city_sounds_varied as a location ambient seems to be that a random ogg is played the first time, but then it loops forevermore on the first ogg in the list. So back to a speaker, with "random 1" "s_looping 0" for that one.) Edited August 11, 2021 by Geep update Quote Link to comment Share on other sites More sharing options...
OrbWeaver Posted August 11, 2021 Report Share Posted August 11, 2021 Yes, if a sound shader is looping then it will only ever loop on one sound file. Otherwise how would it know when to switch from one to another, and how would it do so without a jarring interruption of the sound? In theory it would be possible to implement fading between multiple sounds in a single looping shader, but it would require additional work on the engine and extra fields in the shader to control things like how many seconds it should play each file for, and how often it should switch to another one. But I'm not sure this would be a very important feature, because the expectation is that if you want a load of random things in a single looping ambient, you just bake them in to the looping sound file using your audio editor. I very much doubt you will get any performance benefit from combining multiple location speakers into a single ambient. Playing sounds isn't the performance-affecting element in a game engine. Quote DarkRadiant homepage ⋄ DarkRadiant user guide ⋄ OrbWeaver's Dark Ambients ⋄ Blender export scripts Link to comment Share on other sites More sharing options...
Geep Posted August 11, 2021 Report Share Posted August 11, 2021 @OrbWeaver With a speaker, there's already a "random" keyword that does the magic, with expectation that each constituent ogg file (which when playing will play in its entirety) begins and ends with silence, so flows OK. I'm just observing that it would be nice if location-based ambience had this capability likewise. A bit of a lift to have to go to the audio editor to compose a pseudo-random track, at least for me. What you are describing is more elaborate than what I considered, with fades between constituent ogg files and control over duration of each. As for performance, some forum posts reported that large-extent speakers (not multiple) were a problem, and should be replaced by location zones. Having just gone through that exercise, maybe there's a couple fps to be had... but there's more visportals to support locationseparators, so that contributes too. Not a controlled experiment. Quote Link to comment Share on other sites More sharing options...
Geep Posted August 11, 2021 Report Share Posted August 11, 2021 Hmmm, I see that I misstated what "random" (paired with "wait") were doing. Real story is https://wiki.thedarkmod.com/index.php?title=Sounds:_Background_and_Local. So the playing of constituent ogg files can overlap. I imagine this is simultaneous co-equal playing rather than fades between constituents. Quote Link to comment Share on other sites More sharing options...
OrbWeaver Posted August 11, 2021 Report Share Posted August 11, 2021 1 hour ago, Geep said: With a speaker, there's already a "random" keyword that does the magic, with expectation that each constituent ogg file (which when playing will play in its entirety) begins and ends with silence, so flows OK. As far as I know, random only applies to sound shaders which are triggered repeatedly. I've never heard of s_looping do anything other than loop a single sound forever; if it has gained the capability to also switch between random sounds, that is news to me. Quote DarkRadiant homepage ⋄ DarkRadiant user guide ⋄ OrbWeaver's Dark Ambients ⋄ Blender export scripts Link to comment Share on other sites More sharing options...
Geep Posted August 12, 2021 Report Share Posted August 12, 2021 "s_looping" is not involved. It's "wait" (when applied to a speaker) that specifies a time interval to repeatedly, automatically start up one of the ogg files. "random" provides variation to that time interval. "nodup" to prevent the same ogg file from being played twice in a row. Probably not a built-in way to do what I was originally bloviating about: repeatedly pick an ogg, play it by itself from beginning to end, pick another, repeat forever. Quote Link to comment Share on other sites More sharing options...
Dragofer Posted August 17, 2021 Report Share Posted August 17, 2021 I'm wondering if there's a way to set spawnargs on heads of AIs: Normally for anything that's def_attached, you can use "set x on y", where x is the name of the spawnarg and y is the name of the attachment (name_attach). So i.e. "set light_radius on flame" "120 120 120" on candle holders changes the radius of the def_attached light entity ("name_attach" "flame"). This is important because in DR it's not possible to select or apply spawnargs to def_attached entities directly. Problem is, it seems heads are attached differently. You use def_head instead of def_attach, and there seems to be no name_attach given to the head (only "head_bodyname" "head" and "head_jointname" "head"). This doesn't work: "set model on head" "head_skeleton_skull" These "set x on y" spawnargs seem to be parsed in Entity.cpp from line 12886. Maybe we should add separate handling for "set x on head"? Spoiler // tels: parse all "set .." spawnargs const idKeyValue *kv_set = from->MatchPrefix( "set ", NULL ); while ( kv_set ) { // "set FOO on BAR" "0.5 0.5 0" // means set "_color" "0.5 0.5 0" on the entity attached to the attachment point // named "BAR" (defined with "name_attach" "BAR" on the original entity) // Get the value // example: "0.5 0.5 0" idStr SpawnargValue(kv_set->GetValue()); // "set FOO on BAR" idStr SetAttName(kv_set->GetKey()); // "set FOO on BAR" => "FOO on BAR" SetAttName = SetAttName.Right( kv_set->GetKey().Length() - 4 ); // "FOO on BAR" idStr SpawnargName(SetAttName); // find position of first ' ' int PosSpace = SetAttName.Find( ' ', 0, -1); if (PosSpace == -1) { gameLocal.Warning( "%s of class %s: Spawnarg '%s' (value '%s') w/o attachment name. Applying to to all attachments.", from->GetString("name", "[unknown]"), from->GetString("classname", "[unknown]"), kv_set->GetKey().c_str(), kv_set->GetValue().c_str() ); //kv_set = from->MatchPrefix( "set ", kv_set ); //continue; // pretend "set _color" "0.1 0.2 0.3" means "set _color on BAR" where BAR is the // current attachement. So it applies to all of them. // SpawnargName is already right SetAttName = AttNameValue; } else { // "FOO on BAR" => "FOO" SpawnargName = SpawnargName.Left( PosSpace ); // "FOO on BAR" => "BAR" SetAttName = SetAttName.Right( SetAttName.Length() - (PosSpace + 4) ); } // gameLocal.Printf("SetAttName '%s'\n", SetAttName.c_str()); // gameLocal.Printf("AttNameValue '%s'\n", AttNameValue.c_str()); // gameLocal.Printf("SpawnargName '%s'\n", SpawnargName.c_str()); // does this spawnarg apply to the newly spawned entity? if (SetAttName == AttNameValue) { // it matches, so this spawnarg must be applied directly to this entity //gameLocal.Printf("Match: Setting '%s' to '%s'\n", SpawnargName.c_str(), SpawnargValue.c_str() ); args.Set( SpawnargName, SpawnargValue ); } else { // pass along the original "set ..." spawnarg, it might apply to an // def_attached entity of the newly spawned one //gameLocal.Printf("No match: Passing along '%s' ('%s')\n", kv_set->GetKey().c_str(), SpawnargValue.c_str() ); args.Set( kv_set->GetKey(), SpawnargValue ); } kv_set = from->MatchPrefix( "set ", kv_set ); // end while ( kv_set ) } What I want to use this for is to set "model_xray" on heads so that they get replaced with a skull when seen through an xray screen. This would be much more convenient than having to create a new head entity just to change a couple spawnargs. Edit: might be better to modify idActor::SetupHead() in Actor.cpp since that's where def_head is handled, while the code I pasted from Entity.cpp only handles spawnargs for def_attach entities before spawning them. Spoiler void idActor::SetupHead() { idStr headModelDefName = spawnArgs.GetString( "def_head", "" ); if (!headModelDefName.IsEmpty()) { // We look if the head model is defined as a key to have a specific offset. // If that is not the case, then we use the default value, if it exists, // otherwise there is no offset at all. mHeadModelOffset = spawnArgs.GetVector(headModelDefName, "0 0 0"); // greebo: Regardless what happens, the offsetHeadModel vector always gets added to the offset mHeadModelOffset += spawnArgs.GetVector("offsetHeadModel", "0 0 0"); idStr jointName = spawnArgs.GetString( "head_joint" ); jointHandle_t joint = animator.GetJointHandle( jointName ); if ( joint == INVALID_JOINT ) { gameLocal.Error( "Joint '%s' not found for 'head_joint' on '%s'", jointName.c_str(), name.c_str() ); } // set the damage joint to be part of the head damage group (if possible) jointHandle_t damageJoint = joint; for (int i = 0; i < damageGroups.Num(); i++ ) { if ( damageGroups[ i ] == "head" ) { damageJoint = static_cast<jointHandle_t>( i ); break; } } // Setup the default spawnargs for all heads idDict args; const idDeclEntityDef* def = gameLocal.FindEntityDef(headModelDefName, false); if (def == NULL) { gameLocal.Warning("Could not find head entityDef %s!", headModelDefName.c_str()); // Try to fallback on the default head entityDef def = gameLocal.FindEntityDef(TDM_HEAD_ENTITYDEF, false); } if (def != NULL) { // Make a copy of the default spawnargs args = def->dict; } else { gameLocal.Warning("Could not find head entityDef %s or %s!", headModelDefName.c_str(), TDM_HEAD_ENTITYDEF); } // Copy any sounds in case we have frame commands on the head for (const idKeyValue* kv = spawnArgs.MatchPrefix("snd_", NULL); kv != NULL; kv = spawnArgs.MatchPrefix("snd_", kv)) { args.Set(kv->GetKey(), kv->GetValue()); } // Spawn the head entity idEntity* ent = gameLocal.SpawnEntityType(idAFAttachment::Type, &args); idAFAttachment* headEnt = static_cast<idAFAttachment*>(ent); headEnt->SetName( name + "_head" ); // Retrieve the actual model from the head entityDef idStr headModel = args.GetString("model"); if (headModel.IsEmpty()) { gameLocal.Warning("No 'model' spawnarg on head entityDef: %s", headModelDefName.c_str()); } headEnt->SetBody( this, headModel, damageJoint ); headEnt->SetCombatModel(); // Store the head locally head = headEnt; DM_LOG(LC_AI, LT_DEBUG)LOGSTRING("SETBODY: Actor %s : damage joint %d for attached head is part of damage group %s\r", name.c_str(), (int) damageJoint, GetDamageGroup( damageJoint ) ); // Add the head as attachment idVec3 origin; idMat3 axis; CAttachInfo& attach = m_Attachments.Alloc(); attach.channel = animator.GetChannelForJoint( joint ); animator.GetJointTransform( joint, gameLocal.time, origin, axis ); origin = renderEntity.origin + ( origin + modelOffset + mHeadModelOffset ) * renderEntity.axis; attach.ent = headEnt; attach.posName = jointName; // grayman #2603 headEnt->SetOrigin( origin ); headEnt->SetAxis( renderEntity.axis ); headEnt->BindToJoint( this, joint, true ); // greebo: Setup the frob-peer relationship between head and body m_FrobPeers.AddUnique(headEnt->name); } } Quote FM: One Step Too Far | FM: Down by the Riverside | FM: Perilous Refuge Co-FM: The Painter's Wife | Co-FM: Written in Stone | Co-FM: Seeking Lady Leicester Dragofer's Stuff | Dragofer's Scripting | A to Z Scripting Guide | Dark Ambient Music & Sound Repository Link to comment Share on other sites More sharing options...
Dragofer Posted August 17, 2021 Report Share Posted August 17, 2021 I've added support for "set x on head" spawnargs for AI heads, adding a simplifed version of the general method from idEntity::ParseAttachmentSpawnargs() to idActor::SetupHead(). Rev 9557 2 Quote FM: One Step Too Far | FM: Down by the Riverside | FM: Perilous Refuge Co-FM: The Painter's Wife | Co-FM: Written in Stone | Co-FM: Seeking Lady Leicester Dragofer's Stuff | Dragofer's Scripting | A to Z Scripting Guide | Dark Ambient Music & Sound Repository Link to comment Share on other sites More sharing options...
Geep Posted August 17, 2021 Report Share Posted August 17, 2021 Scripting question. For script variables that are at file level (not within a function and not part of a script object), are their values automatically handled correctly during game Save/Load? Or does the script author need to do something explicit? Quote Link to comment Share on other sites More sharing options...
Dragofer Posted August 17, 2021 Report Share Posted August 17, 2021 32 minutes ago, Geep said: Scripting question. For script variables that are at file level (not within a function and not part of a script object), are their values automatically handled correctly during game Save/Load? Or does the script author need to do something explicit? Yes to question 1, I've used such variables for the new secret tracking system and encountered no problems when testing loading and saving. 1 Quote FM: One Step Too Far | FM: Down by the Riverside | FM: Perilous Refuge Co-FM: The Painter's Wife | Co-FM: Written in Stone | Co-FM: Seeking Lady Leicester Dragofer's Stuff | Dragofer's Scripting | A to Z Scripting Guide | Dark Ambient Music & Sound Repository Link to comment Share on other sites More sharing options...
DeTeEff Posted August 20, 2021 Report Share Posted August 20, 2021 Since this is the newbie question thread, here's one that I feel really should fit; (I believe I should know this, but no, I do not ) You probably think I'm nuts but is there any simple way to see/know exactly where every material definition and skins and such are stored? I would like to "Hey, I like this model I found in DR, but I would like to tinker with it (add a new skin to it or change the graphics in some way). I wonder where the material definition and graphical textures are stored..." My solution this far has been: extract every single pk4-folder and search through them one by one and open the text files I believe contain the stuff I need and after 30 minutes my head hurts and I want to kill everything within 50 meters... It would be golden to be able to enter the Skin name, from the model inspector in DR, somewhere and get a pointer to which folder the material files/data is stored... Quote Link to comment Share on other sites More sharing options...
Geep Posted August 20, 2021 Report Share Posted August 20, 2021 With a copy of a TDM distribution where you have expanded all the pk4s, you can search from the directory root with a tool that does full-text search across file. With Windows, I use TextPad to do this... look for Search/Find in Files. You can specify what string to look for and in what files, e.g., "*.def". It's not perfect, but usually gets the job done. To apply it to FMs, you'd have to expand those pk4s too. 1 Quote Link to comment Share on other sites More sharing options...
Geep Posted August 20, 2021 Report Share Posted August 20, 2021 I might add, if what you are searching for is not within a file, but within a filename, then you can use the built-in File Explorer search box in the upper right corner. Navigate to the tree of interest and enter the search term (e.g., rug*.dds) . This will also work for compressed directories, but you have to first rename them from .pk4 to .zip for Windows to understand. 1 Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.