- Site Map >
- Modding and Creation >
- Sims 3 Creation >
- Modding Discussion >
- Cracking Open Shaders_Win32.precomp? (for better shaders!)
- Site Map >
- Modding and Creation >
- Sims 3 Creation >
- Modding Discussion >
- Cracking Open Shaders_Win32.precomp? (for better shaders!)
Posts: 5,656
Thanks: 1035 in 5 Posts
Funnily enough every video game, no matter how recent or big-budget they may be, has issues like that if you look closely enough.
( Join my dumb Discord server if you're into the whole procrastination thing. But like, maybe tomorrow. )
Posts: 3,444
Thanks: 938 in 5 Posts
Funnily enough every video game, no matter how recent or big-budget they may be, has issues like that if you look closely enough. |
I'd say that there's usually a 'good' enough for graphics where all the bases are more or less covered and any advances usually are to sweat out the finer details.
The issue with TS3 is that while it still holds up well in some regards, it falls quite short in others (i.e. defective hair shine, skin shine, multi-floor lighting [broken since WA], shadow draw distance).
It's frustratingly close, yet so far.
Posts: 5,656
Thanks: 1035 in 5 Posts
And that's one of the things you will run into when modding any game. You can improve textures all you want, you can enhance models all you want, you could even inject new shader code to add realistic effects. But you can't do all three. Ever seen Quake or GTA San Andreas with RTX? It's a masterclass in advanced turd polishing.
Anyway - that's not to say I wouldn't be thrilled to see my custom 8K shadow maps render properly across lot boundaries et cetera et cetera. And let Lyralei have her silky smooth blanket of snow already!
( Join my dumb Discord server if you're into the whole procrastination thing. But like, maybe tomorrow. )
Posts: 3,444
Thanks: 938 in 5 Posts
I'd have to disagree with that, TS3 falls well short. Texture resolution, polygon budgets, (the lack of) postprocessing, primitive shaders and lighting with poor dynamic range.....anno 2020, TS3 looks flat, lifeless and blurry. Mods can take care of a fairly large part of the more visible limitations, but the fact is that the engine is showing its age. It's a decent-looking game for 2009 but I wouldn't say it holds up well. Especially not with the dreadful graphics you get out of the box. And that's one of the things you will run into when modding any game. You can improve textures all you want, you can enhance models all you want, you could even inject new shader code to add realistic effects. But you can't do all three. Ever seen Quake or GTA San Andreas with RTX? It's a masterclass in advanced turd polishing. |
I don't think anyone doubts the engine is showing its age, but the fact that some of the graphic engine's elements are broken or missing just requires you to take some large suspensions of disbelief, and really casts the game (which does have some beautiful moments and decently detailed models despite its mediocre art direction) in an unfair light.
And of course in the bigger picture, you aren't really playing TS3 because it's a top-of-the-line graphics engine. We play it because it's the only easily-moddable third-person open-world click-and-point life simulator out there There are plenty of gaming communities that stick to games with outdated graphics largely because of the gameplay.
Posts: 177
Thanks: 437 in 6 Posts
Posts: 231
Thanks: 1026 in 5 Posts
What's the link between shaders and objects? For example, what tells the game to apply ghost shader with certain settings to a ghost sim? |
That's what materials are for, a material is an instance of a shader with certain values set for each parameter.
For example; A simple shader can be made to display an object in a single solid color, this color can also be passed as a parameter instead of being hard-coded.
A material could then be created for a blue and a red color(or any other color), both will use the exact same shader code but they use different parameter values.
Posts: 433
Thanks: 792 in 6 Posts
Set the Visual Override of a Sim to the Alien one
World.ObjectSetVisualOverride(this.Target.ObjectId, eVisualOverrideTypes.Alien, null);
Set the Ghoststate of a Sim
World.ObjectSetGhostState(this.Target.ObjectId, 4u, (uint)target.SimDescription.AgeGenderSpecies);
4u is deathtype Electrocution while 0 would be a non ghosty appearance
Posts: 177
Thanks: 437 in 6 Posts
That's what materials are for, a material is an instance of a shader with certain values set for each parameter. |
So where the materials for ghost shader are set? Are those in the precomp file?
And Battery, I was asking the step that comes right after that; the part where the game says "since this object is an electrocution type ghost, I should set the diffuse to yellow".
Posts: 231
Thanks: 1026 in 5 Posts
So where the materials for ghost shader are set? Are those in the precomp file? And Battery, I was asking the step that comes right after that; the part where the game says "since this object is an electrocution type ghost, I should set the diffuse to yellow". |
You wouldn't find any materials in the precomp file, materials would be stored in .package files. Probably as MTNF or MATD chunks of some sort, those have parameters like how shiny an object should be or what textures they use.
The precomp file would contain the code telling your computer how to render a ghost, the material in some .package file would tell it what color to use and which extra effects to possible use.
As for where these materials are actually stored/set, I have no clue. My guess is it would have to be in one of the FullBuild*.package files and which specific version to use would be decided by the game code depending on how a sim died.
Posts: 3,860
Thanks: 8549 in 67 Posts
You wouldn't find any materials in the precomp file, materials would be stored in .package files. Probably as MTNF or MATD chunks of some sort, those have parameters like how shiny an object should be or what textures they use. The precomp file would contain the code telling your computer how to render a ghost, the material in some .package file would tell it what color to use and which extra effects to possible use. As for where these materials are actually stored/set, I have no clue. My guess is it would have to be in one of the FullBuild*.package files and which specific version to use would be decided by the game code depending on how a sim died. |
So, indeed, not everything is defined in the Precomp file. Some things like the vampire glowy eyes can be changed through editing the SWB. Now, one thing, you don't actually need the SWB cloner tool for this, that's only useful if you're making your own Script mod that happens to need an effect
Posts: 109
Posts: 3,860
Thanks: 8549 in 67 Posts
So, it's possible to, through hex editing, edit the bit where you see all the other options. (See: http://www.modthesims.info/showthread.php?p=5603975#post5603975 )
But then the next issue occurs and that's adding newly written shaders. Currently, you can only edit new ones with different default values. And honestly, that already is possible if you were to edit an object yourself, so that part feels almost pointless to make a tool out of.
Personally haven't really looked into it too much, but I might after I finish the current project i'm working on.
Posts: 3,860
Thanks: 8549 in 67 Posts
However, it still begs for the question of how we'd edit the very first bit of the precomp file, where the shaders are already pretty much cached and ready to be used in-game.
Shaders.zip (131.4 KB, 23 downloads) |
Posts: 3,860
Thanks: 8549 in 67 Posts
Here are some snippets, warning, because it's programmatically decompiled, the variables are pretty machine-like:
struct s22241 { int32_t f0; int32_t* f4; int32_t f8; int32_t f12; int32_t f16; }; void ShaderSet_GetParameterInfo(struct s8249* a1, struct s22241* a2, int32_t a3) { int32_t* eax4; int32_t eax5; int32_t eax6; int32_t eax7; int32_t eax8; eax4 = fun_105903f0(a1, a3); a2->f4 = eax4; eax5 = fun_10590410(a1, a3); a2->f0 = eax5; fun_10590470(a1, a3); __asm__("fstp dword [ebx+0x14]"); fun_105904b0(a1, a3); __asm__("fstp dword [ebx+0x18]"); fun_105904f0(a1, a3); __asm__("fstp dword [ebx+0x1c]"); eax6 = fun_10590560(a1, a3); a2->f8 = eax6; eax7 = fun_10590590(a1, a3); a2->f12 = eax7; eax8 = fun_10590530(a1, a3); a2->f16 = eax8; return; } int32_t* ShaderSet_GetParameterDefaultFloat(struct s8249* a1, int32_t a2) { int32_t* eax3; int32_t* eax4; eax3 = fun_105903f0(a1, a2); if (!reinterpret_cast<int1_t>(eax3 == 1)) { __asm__("fldz "); return eax3; } else { eax4 = fun_10590440(a1, a2); __asm__("fld dword [eax]"); return eax4; } } int32_t g10b4b4ac = 0; int32_t ShaderSet_GetParameterDefaultFloat2(struct s8249* a1, int32_t a2) { int32_t* eax3; int32_t v4; int32_t eax5; eax3 = fun_105903f0(a1, a2); if (eax3 == 2) { fun_10590440(a1, a2); __asm__("movss xmm0, [eax]"); __asm__("movss [esp+0x8], xmm0"); __asm__("movss xmm0, [eax+0x4]"); __asm__("movss [esp+0xc], xmm0"); return v4; } else { eax5 = g10b4b4ac; return eax5; } } struct s22242 { int32_t f0; int32_t f4; int32_t f8; }; int32_t g10b4b4b4 = 0; int32_t g10b4b4b8 = 0; int32_t g10b4b4bc = 0; void ShaderSet_GetParameterDefaultFloat3(struct s22242* a1, struct s8249* a2, int32_t a3) { int32_t* eax4; int32_t v5; int32_t v6; int32_t v7; int32_t ecx8; int32_t edx9; int32_t ecx10; eax4 = fun_105903f0(a2, a3); if (eax4 == 3) { fun_10590440(a2, a3); __asm__("movss xmm0, [eax]"); __asm__("movss [esp+0x8], xmm0"); __asm__("movss xmm0, [eax+0x4]"); __asm__("movss [esp+0xc], xmm0"); __asm__("movss xmm0, [eax+0x8]"); a1->f0 = v5; __asm__("movss [esp+0x10], xmm0"); a1->f4 = v6; a1->f8 = v7; return; } else { ecx8 = g10b4b4b4; edx9 = g10b4b4b8; a1->f0 = ecx8; ecx10 = g10b4b4bc; a1->f4 = edx9; a1->f8 = ecx10; return; } } struct s22243 { int32_t f0; int32_t f4; int32_t f8; int32_t f12; }; int32_t g10b4b4c0 = 0; int32_t g10b4b4c4 = 0; int32_t g10b4b4c8 = 0; int32_t g10b4b4cc = 0; void ShaderSet_GetParameterDefaultFloat4(struct s22243* a1, struct s8249* a2, int32_t a3) { int32_t* eax4; int32_t v5; int32_t v6; int32_t v7; int32_t v8; int32_t ecx9; int32_t edx10; int32_t ecx11; int32_t edx12; eax4 = fun_105903f0(a2, a3); if (eax4 == 4) { fun_10590440(a2, a3); __asm__("movss xmm0, [eax]"); __asm__("movss [esp+0x8], xmm0"); __asm__("movss xmm0, [eax+0x4]"); __asm__("movss [esp+0xc], xmm0"); __asm__("movss xmm0, [eax+0x8]"); __asm__("movss [esp+0x10], xmm0"); __asm__("movss xmm0, [eax+0xc]"); a1->f0 = v5; a1->f4 = v6; __asm__("movss [esp+0x14], xmm0"); a1->f8 = v7; a1->f12 = v8; return; } else { ecx9 = g10b4b4c0; edx10 = g10b4b4c4; a1->f0 = ecx9; ecx11 = g10b4b4c8; a1->f4 = edx10; edx12 = g10b4b4cc; a1->f8 = ecx11; a1->f12 = edx12; return; } } void** ShaderLibrary_GetShaderSetCount() { void** eax1; eax1 = g10c1fd14; return *reinterpret_cast<void***>(eax1 + 0x7c); } struct s22244 { void** f0; signed char[3] pad4; int32_t f4; int32_t f8; int32_t f12; }; void ShaderLibrary_GetShaderSets(struct s22244* a1, uint32_t a2) { void** ecx3; void** eax4; uint32_t v5; uint32_t ebp6; void** esi7; void** ebp8; uint32_t eax9; void** v10; struct s22244* ebx11; void** edx12; struct s8251* eax13; int32_t eax14; int32_t eax15; int32_t eax16; int32_t eax17; ecx3 = g10c1fd14; eax4 = *reinterpret_cast<void***>(ecx3 + 0x74); v5 = ebp6; esi7 = *reinterpret_cast<void***>(eax4); ebp8 = eax4; if (!esi7) { ebp8 = eax4 + 4; if (*reinterpret_cast<void***>(eax4 + 4) == esi7) { do { ebp8 = ebp8 + 4; } while (!*reinterpret_cast<void***>(ebp8)); } esi7 = *reinterpret_cast<void***>(ebp8); } eax9 = 0; v10 = *reinterpret_cast<void***>(eax4 + reinterpret_cast<unsigned char>(*reinterpret_cast<void***>(ecx3 + 0x78)) * 4); if (a2 > 0) { ebx11 = a1; do { if (esi7 == v10) break; if (*reinterpret_cast<void***>(esi7 + 4)) { edx12 = *reinterpret_cast<void***>(*reinterpret_cast<void***>(*reinterpret_cast<void***>(esi7 + 4)) + 12); eax13 = reinterpret_cast<struct s8251*>(edx12(0x3212e84)); if (eax13) { ebx11->f0 = *reinterpret_cast<void***>(esi7); eax14 = eax13->f0->f16; eax15 = reinterpret_cast<int32_t>(eax14(eax13, 0x3212e84)); ebx11->f4 = eax15; eax16 = fun_105905e0(eax13, 0x3212e84); ebx11->f8 = eax16; eax17 = fun_10590600(eax13, 0x3212e84); ebx11->f12 = eax17; ++ebx11; ++v5; } eax9 = v5; } esi7 = *reinterpret_cast<void***>(esi7 + 8); if (!esi7) { do { esi7 = *reinterpret_cast<void***>(ebp8 + 4); ebp8 = ebp8 + 4; } while (!esi7); } } while (eax9 < a2); } return; (Helper functions that are referenced here) int32_t* fun_105903f0(struct s8249* ecx, int32_t a2) { if (!ecx->f76) { return 0; } else { return *reinterpret_cast<int32_t**>(ecx->f76->f0 + ((a2 << 4) - a2) + 2); } } int32_t fun_10590410(struct s8249* ecx, int32_t a2) { if (!ecx->f76) { return 0; } else { return ecx->f76->f0[(a2 << 4) - a2] + ecx->f76->f16; } } int32_t* fun_10590470(struct s8249* ecx, int32_t a2) { int32_t* eax3; if (!ecx->f76) { __asm__("xorps xmm0, xmm0"); __asm__("movss [esp+0x4], xmm0"); __asm__("fld dword [esp+0x4]"); return eax3; } else { __asm__("movss xmm0, [eax+edx*4+0xc]"); __asm__("movss [esp+0x4], xmm0"); __asm__("fld dword [esp+0x4]"); return ecx->f76->f0; } } int32_t* fun_105904b0(struct s8249* ecx, int32_t a2) { int32_t* eax3; if (!ecx->f76) { __asm__("movss xmm0, [0x10b08b48]"); __asm__("movss [esp+0x4], xmm0"); __asm__("fld dword [esp+0x4]"); return eax3; } else { __asm__("movss xmm0, [eax+edx*4+0x10]"); __asm__("movss [esp+0x4], xmm0"); __asm__("fld dword [esp+0x4]"); return ecx->f76->f0; } } int32_t* fun_105904f0(struct s8249* ecx, int32_t a2) { int32_t* eax3; if (!ecx->f76) { __asm__("movss xmm0, [0x10a644ac]"); __asm__("movss [esp+0x4], xmm0"); __asm__("fld dword [esp+0x4]"); return eax3; } else { __asm__("movss xmm0, [eax+edx*4+0x14]"); __asm__("movss [esp+0x4], xmm0"); __asm__("fld dword [esp+0x4]"); return ecx->f76->f0; } } int32_t fun_10590590(struct s8249* ecx, int32_t a2) { if (!ecx->f76) { return 0x10a68fa0; } else { return (ecx->f76->f0 + ((a2 << 4) - a2))[10]; } } int32_t fun_10590560(struct s8249* ecx, int32_t a2) { if (!ecx->f76) { return 0x10a68fa0; } else { return (ecx->f76->f0 + ((a2 << 4) - a2))[6]; } } int32_t fun_10590530(struct s8249* ecx, int32_t a2) { if (!ecx->f76) { return 0x2ea8fb98; } else { return (ecx->f76->f0 + ((a2 << 4) - a2))[14]; } } struct s8249 { signed char[76] pad76; struct s8250* f76; }; int32_t* fun_10590440(struct s8249* ecx, int32_t a2) { if (!ecx->f76) { return 0; } else { return (ecx->f76->f0 + ((a2 << 4) - a2))[1] + ecx->f76->f16; } } int32_t fun_105905e0(struct s8251* ecx, int32_t a2) { if (!ecx->f76) { return 0x10a68fa0; } else { return ecx->f76->f48; } } int32_t fun_10590600(struct s8251* ecx, int32_t a2) { if (!ecx->f76) { return 0x10a68fa0; } else { return ecx->f76->f64; } } }
But overall it's relatively easy to read. I'm just not quite sure yet if this is just *progressing* the shader data or actually reading from the precomp file. And, where some functions with params are being called from, since they must be called from somewhere. Will update this post if I know!
Posts: 5,656
Thanks: 1035 in 5 Posts
( Join my dumb Discord server if you're into the whole procrastination thing. But like, maybe tomorrow. )
Posts: 3,860
Thanks: 8549 in 67 Posts
Reads like a shader alright. |
But I did want to say that I'm currently converting the .bt file, that is attached here, into a program that can at least make some easier sense of the whole hex code stuff. And hopefully making it possible to edit it eventually
Posts: 3,444
Thanks: 938 in 5 Posts
An example:
- The movie screen uses the Landmark shader, so it doesn't respond to any street lights.
- The Uni sign uses the Phong shader, so while it responds to light, it only responds if the center of the object is near the light source (see how if it's farther away, it doesn't respond at all).
- The bookstore rabbithole uses the Rabbithole shader, and as such, is the only object that properly and contexurally responds to light sources.
I wonder if it's possible to transfer this behaviour between shaders? It might even solve the issue of counters and other objects (which use the Phong shader) looking choppy under lights.
Posts: 3,860
Thanks: 8549 in 67 Posts
There is one thing I think would be worth looking into regarding shaders, which is possibly looking at how shaders respond to lights. An example: - The movie screen uses the Landmark shader, so it doesn't respond to any street lights. - The Uni sign uses the Phong shader, so while it responds to light, it only responds if the center of the object is near the light source (see how if it's farther away, it doesn't respond at all). - The bookstore rabbithole uses the Rabbithole shader, and as such, is the only object that properly and contexurally responds to light sources. I wonder if it's possible to transfer this behaviour between shaders? It might even solve the issue of counters and other objects (which use the Phong shader) looking choppy under lights. |
Posts: 3,444
Thanks: 938 in 5 Posts
Hopefully! I was talking on discord about this issue (Although not necessarily how shaders react on it but just how badly the lights have changed over the years from the first patch till today's patch). Because I remember the days where light *used* to travel to different levels on a wall. Which now isn't the case anymore. |
Definitely this! That was an effect that was broken in World Adventures when they first introduced basements.
Strangely enough, street lights outside the lot can still cast light correctly across several levels.
Posts: 64
Thanks: 70 in 3 Posts
Posts: 3,860
Thanks: 8549 in 67 Posts
Now that we have the reworked and improved lights mod by simsi45, i'm hoping the shader decompilation happens soon. |
Posts: 13
Thanks: 90 in 1 Posts
Still working on that program that makes us edit the Shaders! So we'll probably get that soon too I'll post the progress of that here soon as well, but time isn't exactly on my side as much because real life :p |
I really hope your program becomes a real thing! You're super talented :D
Posts: 10
The problem I ran into was that any modification to the precomp file causes the game to crash on startup. Even innocuous changes, like changing a letter in the ShaderSet's UI parameter name description. Since that's a description it shouldn't have any real effect on the game, and yet the game crashes on startup.
Similarly, if you try to replace the precomp file with an older version that EA shipped, the game crashes on startup.
My hunch is that there is a checksum being done on the precomp file. If it is changed in any way, the values don't match up, and game refuses to start.
Have you found a way around this problem?
Posts: 3,860
Thanks: 8549 in 67 Posts
I was also looking into cracking the shader precomp file. I wrote a tool that could parse it and pull out the shader names, parameters, etc... The problem I ran into was that any modification to the precomp file causes the game to crash on startup. Even innocuous changes, like changing a letter in the ShaderSet's UI parameter name description. Since that's a description it shouldn't have any real effect on the game, and yet the game crashes on startup. Similarly, if you try to replace the precomp file with an older version that EA shipped, the game crashes on startup. My hunch is that there is a checksum being done on the precomp file. If it is changed in any way, the values don't match up, and game refuses to start. Have you found a way around this problem? |
That was something I've noticed as well myself. So far, I think the shaders are cached somewhere. (TS3W.exe maybe?). All I've been able to do personally is tweak the parameters each shader comes with (Say, phong shader has a default of 20 on shininess IIRC, changing that to 30 won't crash the game)
So I don't think currently we've gotten to a state where we're able to *add* a new shader. Just editing parameters.
Now, I doubt this will do anything and I haven't tried it myself, but in ts4 forums, what one of the devs mentioned (or Guru rather) was to leave the precomp in the game files alone, but the 'new' one, you put in a package and then put it in your mods folder and the game should pick up on it then. I've personally seen this working with existing ini files that are outside of the game, and putting those in a package file seems to make some changes.
But that's as far as I got :/ I know some other dude did decode the shader precomp and turned it into a program, but according to him, it wasn't possible to get through and decompile the directx decompression bit (somewhere in the template file that's mentioned). or Recompile it or something along those lines.
So, it might well just be that the file we see in the game files is simply a checksum as you mentioned, and that adding it to a package and doing it that way might be a workaround of the issue
Lemme know if that works!
Posts: 10
Now, I doubt this will do anything and I haven't tried it myself, but in ts4 forums, what one of the devs mentioned (or Guru rather) was to leave the precomp in the game files alone, but the 'new' one, you put in a package and then put it in your mods folder and the game should pick up on it then. I've personally seen this working with existing ini files that are outside of the game, and putting those in a package file seems to make some changes. |
I spent some time trying to figure this out. Using ghidra to disassemble and decompile, I was able to find the code that parses the precomp file in TS3W.exe. I also found a call to stat64() just before the parsing. Debugging with IDA Pro, I was able to determine that the path to stat64() is the full path to Shaders_Win32.precomp in the game directory.
So far it isn't looking good for there being a way to override the file with a package in the mods folder. That said, all is not lost. I thought I understood how the game resolved the file location, but stepping through in the debugger I found that didn't actually work how I expected. So perhaps all I'm seeing is a failed check for a mod, resulting in loading the file from disk. I'll keep digging, but I'll have to find an alternative tool, IDA Pro doesn't seem to make looking at live memory easy and I think that's what I need to do if I'm going to figure out whether or not there's potential for overriding the file.
Who Posted
|