SUBSIM: The Web's #1 resource for all submarine & naval simulations since 1997 |
09-29-11, 05:10 PM | #1 |
Black Magic
|
GR2 Editor/Viewer/Extractor/Importer
For approximately the last 8 months I've been gathering information on the GR2 format. I've found info from the net and from this one magical place on the net dealing with QuArK. This one magical place has been a major source of the information I've attained about the GR2 format. Another huge source of information was the GrannyViewer app from RAD games (the 'maker' of the granny format - a free app from them). That app tells you everything that is contained in the GR2 file - the trick is figuring where the info displayed resides in the GR2 file. I used that app extensively in the making of this app. Last, but not least, Privateer provided the last missing piece to the puzzle when he released his GR2 template for the 010 editor. I couldn't figure out how to read the very beginning of the file and that template provided information that allowed me to figure it out.
The pointers contained in section 0 of the GR2 file will tell you everything you need to know to do what I've done. The screenshot above shows NSS_Uboat7a (with hull mesh turned off to show rooms). All waypoints are shown also. Since I have all this data and I know how to interpret it correctly I can do basically anything with it. An extractor will be coded in to allow you to extract meshes from the GR2 file into OBJ format (might even code it for Microsoft's X format also). I hope to also figure out how to import new items into the GR2 file via the app. Now I know someone is going to say "We have the goblin editor and Granny viewer to see GR2 files graphically. Why reinvent the wheel?" And that would be a good and valid question. Here's why: - If I can display the information I read from the file graphically and it renders correctly then I'm reading the file correctly. Most important. - To do things that either of them can't do (picking, moving bones, rotating meshes, etc.) For anyone that's curious: - developed using Visual Studio 2008 C# - currently uses DirectX fixed-function pipeline (I plan on converting it to the programmable pipeline [aka shaders] once everything is working). I use the fixed-function pipeline because it's easier to code initially. Goal is to get everything working then go back and polish. - uses DirectX 9.0c for rendering (no OpenGL or anything like that) current version v1.1.459.1: https://www.mediafire.com/?0c360d3g4jx3qah NOTE: CURRENT VERSION IS IN ALPHA STATE. ENSURE TO BACKUP YOUR WORK BEFORE SAVING WITH APP! In hopes of getting some open-source type thing going on here is the C# AntiGranny code file (old and outdated but still full of useful info). Since there was no participation in my open-source adventure I will not be updating the source code below anymore: http://www.gamefront.com/files/20890...10_15_2011_zip Last edited by TheDarkWraith; 08-23-14 at 04:33 PM. |
09-29-11, 05:16 PM | #2 |
Ace of the deep .
|
Speechless
|
09-29-11, 05:47 PM | #3 |
Seasoned Skipper
Join Date: Mar 2010
Location: Berlin, Germany
Posts: 718
Downloads: 567
Uploads: 0
|
TheDarkWraith
Privateer Subsim community Great. |
09-29-11, 07:31 PM | #4 |
Stowaway
Posts: n/a
Downloads:
Uploads:
|
Very Nice Mate!
I'm sure some of the information I have will help alot. |
09-29-11, 08:34 PM | #5 |
Eternal Patrol
|
Supercalifragilisticexpialidocious!
Not that I understand any of it, but I can see that it's awesome!
__________________
“Never do anything you can't take back.” —Rocky Russo |
09-29-11, 09:39 PM | #6 |
Black Magic
|
First texture render (lighting disabled):
As you can see I have more work to do on it. Not bad for first render with textures though! The textures and how they are defined in the GR2 file are somewhat confusing. You have a pointer that can point to the actual material or it could point to another pointer that can point to another pointer......so on and so forth I obviously don't have my pointers straight By looking at this graphically I can see that I'm not reading this part of the file correctly. |
09-29-11, 09:57 PM | #7 |
Black Magic
|
The problem above is due to multiple textures defined per a mesh subset. I'm not reading those correctly. When I try a simple item like the CMD_small_boat it renders fine:
Back to the Granny Viewer we go! Last edited by TheDarkWraith; 09-29-11 at 10:42 PM. |
09-30-11, 01:25 AM | #8 | |
Admiral
Join Date: Jan 2006
Location: Russia ®
Posts: 2,492
Downloads: 122
Uploads: 1
|
Quote:
Looks tempting ... Good luck.
__________________
Alex ® Moses said: "Don't create yourself an idol"... Last edited by Anvart; 09-30-11 at 04:48 AM. |
|
09-30-11, 01:48 AM | #9 |
Black Magic
|
Well I'm miffed According to granny viewer all my ducks are in a row regarding textures, vertices, texture coordinates, etc. for the King George gr2 file. But the hull still renders incorrectly. Now one thing I have noticed is that on some units where the hull is rendered incorrectly if I place the camera inside the hull (inside the ship) and look at the hull it's rendered correctly (with culling set to none). Puzzling
Another thing that maybe someone knows the answer to: how does one correctly render the other maps beside the diffuse map (self-illumination and bump)? Some units have all 3 of these maps defined for a mesh and I'm currently only using the diffuse one. |
09-30-11, 02:54 AM | #10 | |
Grey Wolf
Join Date: Jan 2009
Location: Finland
Posts: 859
Downloads: 174
Uploads: 0
|
Quote:
Anyway, awesome work! I really hope that you guys will break some locks that SH 5 has, and open the game to new possibilities! |
|
09-30-11, 10:19 AM | #11 | |
The Old Man
Join Date: Apr 2007
Location: Netherlands
Posts: 1,547
Downloads: 26
Uploads: 3
|
Quote:
2. Shaders and correct use of index/vertex buffers... Here's S3D's shaders (diffuse, specular and ambient occlusion, no bump)... You know, that dumbmaking tool that did similar things to what you are making now for SH5! Code:
//-------------------------------------------------------------------------------------- // Global variables //-------------------------------------------------------------------------------------- int g_nNumLights; // Vertex shader globals float4x4 worldViewProjection; // World * View * Projection matrix float3 g_LightParams[3]; //x - type, y - Att2, z - Range float3 g_LightSpotParams[3]; //x = cos(Phi/2), y = cos(theta/2), z = 1 / (cos(theta/2) - cos(Phi/2)) float4 g_LightDiffuse[3]; // Light's diffuse color float4 g_LightSpecular[3]; // Light's specular color float3 g_LightPos[3]; // Light's position in world space float3 g_LightDir[3]; // Light's direction in world space //float4 g_fogParam; // Shared globals float3 g_CameraPosition; float3 g_MaterialParams; // x - specular power, y - specular strength // Pixel shader globals float4 g_MaterialAmbientColor; //float3 g_fogColor; float g_bUseSpecFromDiffuse; float4 g_UseMaps; // x - use AO map, y - use spec map, z - use bump map float2 g_BrightnessContrast = float2(0.05f, 0.05f); // x - brightness, y - contrast float4 g_SelectionColor; // Color used to indicate selection. // Wireframe color float4 g_WireframeColor; texture g_DiffuseTexture; // Color texture for mesh texture g_SelfIllumTexture; // Color texture for mesh float appTime; // App's time in seconds float4x4 worldMatrix; // World matrix for object //-------------------------------------------------------------------------------------- // Texture samplers //-------------------------------------------------------------------------------------- sampler DiffuseMap = sampler_state { Texture = <g_DiffuseTexture>; MipFilter = LINEAR; MinFilter = LINEAR; MagFilter = LINEAR; }; sampler LightMap = sampler_state { Texture = <g_SelfIllumTexture>; MipFilter = LINEAR; MinFilter = LINEAR; MagFilter = LINEAR; }; //-------------------------------------------------------------------------------------- // Vertex shader output structure //-------------------------------------------------------------------------------------- struct VS_OUTPUT { float4 ProjPos : POSITION; // vertex position float4 Texs : TEXCOORD0; // vertex texture coords //float Fog : TEXCOORD1; float3 Normal : TEXCOORD2; float3 EyeVertex : TEXCOORD3; float3 Diffuse : COLOR0; // vertex diffuse color float3 Specular : COLOR1; // vertex specular color }; //-------------------------------------------------------------------------------------- // This shader computes standard transform and lighting //-------------------------------------------------------------------------------------- VS_OUTPUT RenderSceneVS( float4 vPos : POSITION, float3 vNormal : NORMAL, float2 vTex0 : TEXCOORD0, float2 vTex1 : TEXCOORD1, uniform bool bWireFrame ) { VS_OUTPUT Out; Out.ProjPos = mul(vPos, worldViewProjection); Out.Texs = float4(vTex0, vTex1); // Out.Fog = 0; Out.Normal = vNormal; Out.EyeVertex = normalize(vPos.xyz - g_CameraPosition); Out.Diffuse = 0; Out.Specular = 0; if (bWireFrame) { Out.Diffuse = float4(1, 1, 1, 1); // Full... return Out; } float3 refl = reflect(Out.EyeVertex, vNormal); float dist; for (int i=0; i < g_nNumLights; i++) { float3 lightPos = mul(g_LightPos[i], transpose(worldMatrix)); dist = distance(lightPos, vPos.xyz); float3 VertexLightDir = normalize(lightPos - vPos.xyz); float LightAtt = 1 / (1 + dist * dist * g_LightParams[i].y); float LightInfluence = LightAtt * saturate(dot(vNormal, VertexLightDir)); float specFactor = LightAtt * saturate(dot(refl, VertexLightDir)); float spot = 1; if (g_LightParams[i].x > 1.1f) //that means we have a spot light { float cosa = dot(VertexLightDir, g_LightDir[i]); if (cosa < g_LightSpotParams[i].x) { spot = 0; } else { if (cosa < g_LightSpotParams[i].y) spot = (cosa - g_LightSpotParams[i].x) * g_LightSpotParams[i].z; } } Out.Diffuse += g_LightDiffuse[i] * LightInfluence * spot; Out.Specular += g_LightSpecular[i] * pow(specFactor, g_MaterialParams.x) * spot; } dist = distance(g_CameraPosition, vPos.xyz); //Out.Fog = saturate((dist - g_fogParam.x) * g_fogParam.z); return Out; } //-------------------------------------------------------------------------------------- // Pixel shader output structure //-------------------------------------------------------------------------------------- struct PS_OUTPUT { float4 RGBColor : COLOR0; // Pixel color }; //-------------------------------------------------------------------------------------- // This shader outputs the pixel's color by modulating the texture's // color with diffuse material color //-------------------------------------------------------------------------------------- float4 RenderScenePS( VS_OUTPUT In, uniform bool bWireFrame ) : COLOR { if (bWireFrame) { return g_WireframeColor; } float4 BaseColor = tex2D(DiffuseMap, In.Texs.xy); float4 SelfIllum = tex2D(LightMap, In.Texs.zw); // float specMask = lerp(1, BaseColor.w, g_bUseSpecFromDiffuse); float specMask = tex2D(LightMap, In.Texs.xy).w; specMask = lerp(specMask, BaseColor.w, g_bUseSpecFromDiffuse); if (g_UseMaps.x == 0) SelfIllum = float4(0.75f, 0.75f, 0.75f, 1); if (g_UseMaps.w == 0) { BaseColor = g_SelectionColor; BaseColor.w = g_MaterialAmbientColor.w; } else { BaseColor.xyz = BaseColor.xyz * g_SelectionColor.xyz; } //else if (g_UseMaps.y == 0) // BaseColor.xyz = (BaseColor.xyz + g_BrightnessContrast.x) * (1.0 + g_BrightnessContrast.y)/1.0; if (g_UseMaps.y == 0) specMask = 0; //BaseColor.w = saturate(BaseColor.w + g_bUseSpecFromDiffuse); float3 VNormal = normalize(In.Normal); float3 refl = reflect(In.EyeVertex, VNormal); float3 DiffuseColor = In.Diffuse; float3 SpecularColor = In.Specular; for (int i=0; i < g_nNumLights; i++) { float LightInfluence = saturate(dot(VNormal, g_LightDir[i].xyz)); float specFactor = saturate(dot(refl, g_LightDir[i].xyz)); DiffuseColor += LightInfluence * g_LightDiffuse[i]; SpecularColor += g_MaterialParams.y * pow(specFactor, g_MaterialParams.x * (specMask+0.01)) * g_LightSpecular[i]; } //return float4(BaseColor.xyz * (DiffuseColor + g_MaterialAmbientColor.xyz), 1); //return float4(SpecularColor, 1); float4 Color; Color.xyz = BaseColor.xyz * SelfIllum.xyz * (DiffuseColor + g_MaterialAmbientColor.xyz) + SpecularColor * SelfIllum.x * specMask; Color.w = BaseColor.w; //Color.xyz = lerp(Color.xyz, g_fogColor, In.Fog); Color.xyz = (Color.xyz + g_BrightnessContrast.x) * (1.0 + g_BrightnessContrast.y)/1.0; return Color; } //-------------------------------------------------------------------------------------- // Renders scene to render target //-------------------------------------------------------------------------------------- technique RenderScene { pass P0 { VertexShader = compile vs_2_0 RenderSceneVS(false); PixelShader = compile ps_2_0 RenderScenePS(false); } } //-------------------------------------------------------------------------------------- // Renders scene to render target, using wireframe mode //-------------------------------------------------------------------------------------- technique RenderSceneWireframe { pass P0 { FillMode = Wireframe; CullMode = CCW; ZWriteEnable = false; ZFunc = Less; //CullMode = None; VertexShader = compile vs_2_0 RenderSceneVS(true); PixelShader = compile ps_2_0 RenderScenePS(true); } } //-------------------------------------------------------------------------------------- // Renders scene to render target, using point mode //-------------------------------------------------------------------------------------- technique RenderSceneVertices { pass P0 { FillMode = Point; CullMode = CCW; ZWriteEnable = false; ZFunc = Less; VertexShader = compile vs_2_0 RenderSceneVS(true); PixelShader = compile ps_2_0 RenderScenePS(true); } } //-------------------------------------------------------------------------------------- // Renders scene to render target, using wireframe mode //-------------------------------------------------------------------------------------- technique RenderSceneSolidWireframe { pass P0 { FillMode = Solid; CullMode = CCW; ZWriteEnable = true; ZFunc = LessEqual; VertexShader = compile vs_2_0 RenderSceneVS(false); PixelShader = compile ps_2_0 RenderScenePS(false); } pass P1 { FillMode = Wireframe; CullMode = CCW; ZWriteEnable = false; ZFunc = Less; PixelShader = compile ps_2_0 RenderScenePS(true); } } //-------------------------------------------------------------------------------------- // Renders scene to render target, using point mode //-------------------------------------------------------------------------------------- technique RenderSceneSolidVertices { pass P0 { FillMode = Solid; CullMode = CCW; ZWriteEnable = true; ZFunc = LessEqual; VertexShader = compile vs_2_0 RenderSceneVS(false); PixelShader = compile ps_2_0 RenderScenePS(false); } pass P1 { FillMode = Point; CullMode = CCW; ZWriteEnable = false; ZFunc = Less; PixelShader = compile ps_2_0 RenderScenePS(true); } }
__________________
SH5 mods: Speech Recognition for SH5 | Digital UI Clock Tutorials: [TEC] Import/export 3D models to/from game using S3D [TEC] How to work with the model viewer in S3D - VIDEO |
|
09-30-11, 10:46 AM | #12 |
Black Magic
|
Don't think it's a matrix problem. The bone associated with the King GeorgeV hull is positioned at world center (0,0,0) with no rotations so for all intensive purposes the world matrix is Matrix.Identity.
The index buffer and vertex buffer for the mesh match what the granny viewer shows. The texture coordinates for the verticies in the vertex buffer also match what granny viewer shows. The normals for the verticies in the vertex buffer also match what granny viewer shows. Everything renders correctly geometry wise and everything except the hull renders correctly texture wise. The hull mesh has two subsets and I've noticed that anything with more than 1 subset in the mesh doesn't render correctly texture wise. I'm currently using the fixed-function pipeline for rendering. I'll convert to programmable pipeline (shaders) after I get everything working correctly. This hull rendering problem is really starting to annoy me |
09-30-11, 10:54 AM | #13 |
The Old Man
Join Date: Apr 2007
Location: Netherlands
Posts: 1,547
Downloads: 26
Uploads: 3
|
If you've got a 'small' world/view matrix error (or related, RH/LH system mixup), the entire unit still renders correctly (at least, might) but the uv-map thus can be offset. All I'm saying, it's a common and classic mistake, and you are not the first to make it. [edit] and PS, it's exactly why flipping the culling from CW to CCW or vice versa sort of fixes it (obviously it's not fixed, since it renders inside out). This generally means a matrix error (just a single 'sign' - somewhere, usually, the identity)
Of course it can have other causes, like not using map channels correctly, loading uv table incorrectly... but my first comment is something worth looking into because I've seen this error many times...
__________________
SH5 mods: Speech Recognition for SH5 | Digital UI Clock Tutorials: [TEC] Import/export 3D models to/from game using S3D [TEC] How to work with the model viewer in S3D - VIDEO |
09-30-11, 10:56 AM | #14 |
Black Magic
|
I think I have an incorrect map assigned for subset 2. Subset 1 renders fine:
I'm going to try forcing subset 2 to use subset 1's map EDIT: same result. The inside of the hull of the King George renders incorrectly also so it's not a matter of triangle verticies flipped. |
09-30-11, 11:11 AM | #15 |
Black Magic
|
ok, I think I found the problem:
If a mesh has multiple subsets then of course it has maps assigned to each subset. When I read the maps assigned to a mesh with multiple subsets from the GR2 file I need to reverse the order of them. Another strange quirk of the GR2 format. |
|
|