SUBSIM Radio Room Forums

SUBSIM Radio Room Forums (https://www.subsim.com/radioroom/index.php)
-   SH5 Mods Workshop (https://www.subsim.com/radioroom/forumdisplay.php?f=249)
-   -   GR2 Editor/Viewer/Extractor/Importer (https://www.subsim.com/radioroom/showthread.php?t=188290)

TheDarkWraith 09-29-11 05:10 PM

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.

http://www.subsim.com/radioroom/pict...pictureid=5515

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

THE_MASK 09-29-11 05:16 PM

Speechless :rock:

Echolot 09-29-11 05:47 PM

TheDarkWraith :rock:

Privateer :rock:

Subsim community :rock:

Great.

:sunny:

Madox58 09-29-11 07:31 PM

Very Nice Mate!
:salute:

I'm sure some of the information I have will help alot.

Sailor Steve 09-29-11 08:34 PM

Supercalifragilisticexpialidocious! :rock:

Not that I understand any of it, but I can see that it's awesome!

TheDarkWraith 09-29-11 09:39 PM

First texture render (lighting disabled):

http://www.subsim.com/radioroom/pict...pictureid=4940

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 :shifty: I obviously don't have my pointers straight :DL By looking at this graphically I can see that I'm not reading this part of the file correctly.

TheDarkWraith 09-29-11 09:57 PM

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:

http://www.subsim.com/radioroom/pict...pictureid=4941

Back to the Granny Viewer we go!

Anvart 09-30-11 01:25 AM

Quote:

Originally Posted by TheDarkWraith (Post 1757906)
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... :haha:
Looks tempting ...
Good luck. :up:

TheDarkWraith 09-30-11 01:48 AM

Well I'm miffed :shifty: 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 :hmmm:

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)? :06: Some units have all 3 of these maps defined for a mesh and I'm currently only using the diffuse one.

Rongel 09-30-11 02:54 AM

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)? :06: 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!

:DL:DL:DL:DL:DL:DL:DL:DL:DL:DL:DL:DL:DL:woot:

I really hope that you guys will break some locks that SH 5 has, and open the game to new possibilities!

skwasjer 09-30-11 10:19 AM

Quote:

Originally Posted by TheDarkWraith (Post 1758009)
Well I'm miffed :shifty: 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 :hmmm:

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)? :06: 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! :har:

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.

TheDarkWraith 09-30-11 10:46 AM

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 :shifty:

skwasjer 09-30-11 10:54 AM

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...

TheDarkWraith 09-30-11 10:56 AM

I think I have an incorrect map assigned for subset 2. Subset 1 renders fine:

http://www.subsim.com/radioroom/pict...pictureid=4946

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 09-30-11 11:11 AM

ok, I think I found the problem:

http://www.subsim.com/radioroom/pict...pictureid=4947

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.


All times are GMT -5. The time now is 07:10 PM.

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.