SUBSIM Radio Room Forums



SUBSIM: The Web's #1 resource for all submarine & naval simulations since 1997

Go Back   SUBSIM Radio Room Forums > Silent Hunter 3 - 4 - 5 > SH5 Mods Workshop
Forget password? Reset here

Reply
 
Thread Tools Display Modes
Old 09-29-11, 05:10 PM   #1
TheDarkWraith
Black Magic
 
Join Date: Jun 2007
Posts: 11,962
Downloads: 147
Uploads: 5


Default 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.
TheDarkWraith is offline   Reply With Quote
Old 09-29-11, 05:16 PM   #2
THE_MASK
Ace of the deep .
 
THE_MASK's Avatar
 
Join Date: Jan 2006
Posts: 9,225
Downloads: 901
Uploads: 73


Default

Speechless
THE_MASK is offline   Reply With Quote
Old 09-29-11, 05:47 PM   #3
Echolot
Seasoned Skipper
 
Join Date: Mar 2010
Location: Berlin, Germany
Posts: 718
Downloads: 567
Uploads: 0
TheDarkWraith

Privateer

Subsim community

Great.

Echolot is offline   Reply With Quote
Old 09-29-11, 07:31 PM   #4
Madox58
Stowaway
 
Posts: n/a
Downloads:
Uploads:
Default

Very Nice Mate!


I'm sure some of the information I have will help alot.
  Reply With Quote
Old 09-29-11, 08:34 PM   #5
Sailor Steve
Eternal Patrol
 
Sailor Steve's Avatar
 
Join Date: Nov 2002
Location: High in the mountains of Utah
Posts: 50,369
Downloads: 745
Uploads: 249


Default

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
Sailor Steve is offline   Reply With Quote
Old 09-29-11, 09:39 PM   #6
TheDarkWraith
Black Magic
 
Join Date: Jun 2007
Posts: 11,962
Downloads: 147
Uploads: 5


Default

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.
TheDarkWraith is offline   Reply With Quote
Old 09-29-11, 09:57 PM   #7
TheDarkWraith
Black Magic
 
Join Date: Jun 2007
Posts: 11,962
Downloads: 147
Uploads: 5


Default

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.
TheDarkWraith is offline   Reply With Quote
Old 09-30-11, 01:25 AM   #8
Anvart
Admiral
 
Join Date: Jan 2006
Location: Russia ®
Posts: 2,492
Downloads: 122
Uploads: 1
Quote:
Originally Posted by TheDarkWraith View Post
For approximately the last 8 months I've been gathering information on the GR2 format. I've found info from the net ...
At last, "a whipping boy" appeared...
Looks tempting ...
Good luck.
__________________
Alex ®


Moses said: "Don't create yourself an idol"...

Last edited by Anvart; 09-30-11 at 04:48 AM.
Anvart is offline   Reply With Quote
Old 09-30-11, 01:48 AM   #9
TheDarkWraith
Black Magic
 
Join Date: Jun 2007
Posts: 11,962
Downloads: 147
Uploads: 5


Default

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.
TheDarkWraith is offline   Reply With Quote
Old 09-30-11, 02:54 AM   #10
Rongel
Grey Wolf
 
Join Date: Jan 2009
Location: Finland
Posts: 859
Downloads: 174
Uploads: 0
Default

Quote:
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.
I've been figuring out myself how the textures are assigned to GR2 units, but don't know still. The O0_file is always in the ship folder, so I guessed other maps are embedded. But then I found in data/textures lots of ship textures, about 30 of them in total (ship_hull_N01, ship_hull_T01-T06, ship_T01 for example). I'm not sure if that helps but I guess they must be there for a reason.

Anyway, awesome work!



I really hope that you guys will break some locks that SH 5 has, and open the game to new possibilities!
Rongel is offline   Reply With Quote
Old 09-30-11, 10:19 AM   #11
skwasjer
The Old Man
 
Join Date: Apr 2007
Location: Netherlands
Posts: 1,547
Downloads: 26
Uploads: 3
Default

Quote:
Originally Posted by TheDarkWraith View Post
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.
1. Most definately a matrix problem
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);
 }
}
Now if you need more (technical) answers you'll have to be more specific.
skwasjer is offline   Reply With Quote
Old 09-30-11, 10:46 AM   #12
TheDarkWraith
Black Magic
 
Join Date: Jun 2007
Posts: 11,962
Downloads: 147
Uploads: 5


Default

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
TheDarkWraith is offline   Reply With Quote
Old 09-30-11, 10:54 AM   #13
skwasjer
The Old Man
 
Join Date: Apr 2007
Location: Netherlands
Posts: 1,547
Downloads: 26
Uploads: 3
Default

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...
skwasjer is offline   Reply With Quote
Old 09-30-11, 10:56 AM   #14
TheDarkWraith
Black Magic
 
Join Date: Jun 2007
Posts: 11,962
Downloads: 147
Uploads: 5


Default

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.
TheDarkWraith is offline   Reply With Quote
Old 09-30-11, 11:11 AM   #15
TheDarkWraith
Black Magic
 
Join Date: Jun 2007
Posts: 11,962
Downloads: 147
Uploads: 5


Default

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.
TheDarkWraith is offline   Reply With Quote
Reply

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT -5. The time now is 07:32 AM.


Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Copyright © 1995- 2024 Subsim®
"Subsim" is a registered trademark, all rights reserved.