Posted: Wed Feb 14, 2018 10:55 pm Post subject:
VXL To OBJ
Has anyone created a VXL to OBJ converter (VXLSE III at least the latest version doesn't actually save any texture info, also it looks way too smooth like a blur filter was used on it hundreds of times)?
Im currently working on a mod for a game called Original War (which i have maintained since 2005) called Original Conquer. The idea being to try and re-create Tiberian Sun in Original War (Its also a way for me to push the modding limits of Original War).
I made a OBJ to GMZ converter which works well. GMZ's are basically like SHP files except they also contain height information for each pixel (Which allows you to for example have a factory which produces vehicles that has holes in its roof/etc and have the vehicle rendered correctly inside the building. As well as having river water go upto units ankles). So i basically need to convert VXL to OBJ to then convert to GMZ.
Some Images and and Old Video of Original Conquer:
VXLSE is currently the only program that can convert vxl to obj. It can create textures tho, the options for it are hidden in the "Views" menu (the box next to the rotation buttons).
Also, yay its stucuk nice to see you're still modding _________________
VXLSE is currently the only program that can convert vxl to obj. It can create textures tho, the options for it are hidden in the "Views" menu (the box next to the rotation buttons).
Even if VXLSE III can create textures, looking at the preview it was blured to hell. Id prefer the normal viewport with cubes than a too blured model.
I`m currently writing code to load the VXL and HVA files. Using HVA Builders source code as a reference. The code in HVA Builder is crap (Though i am not sure how much i actually wrote, the raw VXL loading code may have come from VXLSE II... idk).
Mig Eater wrote:
Also, yay its stucuk nice to see you're still modding
I never really did any modding. I played around but i never released anything. I mainly just worked on tools for others to make mods with.
P.S HVA Files are easy to load (not actually tested the code ):
Code:
type
TStr16 = String[16];
TM3x4 = Array [0..2,0..3] of Single;
THVASection = Record
Name : TStr16;
Frames : Array of TM3x4;
end;
PHVASection = ^THVASection;
THVA = Class(TObject)
private
FSection : Array of THVASection;
function GetSection(Index : Integer) : PHVASection;
public
constructor Create(Stream : TStream);
destructor Destroy; override;
Btw, the HVA.pas code on VXLSE III is much better than HVA Builder's... and, likewise yours, it is object oriented as well.
not really alot of difference:
Code:
Procedure LoadHVA2(var HVAFile : THVA; var HVAOpen : Boolean; const Filename,Ext : string);
var
f : file;
x : integer;
TFilename : string;
begin
if HVAOpen then
ClearHVA(HVAFile);
TFilename := extractfiledir(Filename) + '\' + copy(Extractfilename(Filename),1,Length(Extractfilename(Filename))-Length('.hva')) + Ext;
HVAOpen := false;
if not FileExists(TFilename) then exit;
AssignFile(F,TFilename); // Open file
Reset(F,1); // Goto first byte?
For x := 0 to High(TransformMatrices) do
BlockRead(F,TransformMatrices[x],Sizeof(TTransformMatrix));
CloseFile(f);
If Header.N_Frames < 1 then
exit;
WestwoodToOpenGLCoordinates;
Result := True;
end;
The WestwoodToOpenGLCoordinates looks wrong. If WW coordinates are Direct X system then it should be X,-Z,Y. It makes no sense for the coordinates to be Z,X,Y in a Matrix and i see nothing in HVA Builder which does any conversion. _________________ Free Map Editor - Game Requirements - Stucuk.Net QUICK_EDIT
Also Known As: banshee_revora (Steam) Joined: 15 Aug 2002 Location: Brazil
Posted: Thu Feb 15, 2018 1:42 pm Post subject:
I don't think that the DirectX coordinate system is the only thing that affects the original coordinates of these units. Remember that it is an "2.5D isometric" game. The X coordinate in game is the Y of your screen. QUICK_EDIT
I don't think that the DirectX coordinate system is the only thing that affects the original coordinates of these units. Remember that it is an "2.5D isometric" game. The X coordinate in game is the Y of your screen.
An Isometric View isn't what VXLSE, HVA Builder, etc uses. For that you need to setup an Isometric Projection Matrix (Isometric looks different, its not just the angle, but also how it does the depth). But that has nothing to do with the actual matrix you use to rotate the model.
Basically you have a projection matrix, and then you have the model matrix.
Normally you have model matrix's in Left Hand or Right Hand coordinate systems. They are really the only choices. _________________ Free Map Editor - Game Requirements - Stucuk.Net QUICK_EDIT
Also Known As: banshee_revora (Steam) Joined: 15 Aug 2002 Location: Brazil
Posted: Thu Feb 15, 2018 4:31 pm Post subject:
It's not just a matter of what VXLSE III uses, but also how Westwood rendered their models, optimizing it for their games. Their coordinate system is weird and that function translates it to the one used by VXLSE III. It is that simple and it works. If you wanna use a different coordinate system, go ahead, take it out and make your own. QUICK_EDIT
Stage 1 is complete. I can now load VXL files! (With 0 Bloat)
Nod Buggy, note that colour wise i am using the Colour Index as if it was the RGB value (Since i haven't wrote code to load a palette) which is why the colours aren't right.
Note: The code is only designed to load the data. Not save. Its also designed to only store the individual voxels which exist. It doesn't store the empty voxels (As its designed for rendering in 3D not 2D slices).
P.S I used the following code to make it render a 2D view:
Code:
procedure MakeImage(VXL : TVXL; Bitmap : TBitmap);
var
Section : PVXLSection;
PixelZ : Array of Byte;
V : Integer;
Voxel : PVXLVoxel;
begin
Section := VXL.Section[0];
Voxel := Section.Data;
for V := 0 to Section.VoxelCount-1 do
begin
if Voxel.XYZ[2] >= PixelZ[Voxel.XYZ[0]*Section.Size[1]+Voxel.XYZ[1]] then
begin
PixelZ[Voxel.XYZ[0]*Section.Size[1]+Voxel.XYZ[1]] := Voxel.XYZ[2];
Bitmap.Canvas.Pixels[Voxel.XYZ[0],Voxel.XYZ[1]] := RGB(Voxel.Colour,Voxel.Colour,Voxel.Colour);
end;
Inc(Cardinal(Voxel),SizeOf(TVXLVoxel));
end;
SetLength(PixelZ,0);
end;
The PixelZ stores each pixels depth so that you can get the voxel with the highest Z value. Note that i never designed it for speed. You should never use Canvas.Pixels of a TBitmap but the Scanline instead (As tje Canvas.Pixels is very slow). _________________ Free Map Editor - Game Requirements - Stucuk.Net QUICK_EDIT
Voxel := Section.Data;
for V := 0 to Section.VoxelCount-1 do
begin
Bitmap.Canvas.Brush.Color := RGB(Voxel.Colour,Voxel.Colour,Voxel.Colour);
Bitmap.Canvas.FillRect(MakeRect(Voxel.XYZ[0]*2+Section.Size[2]-Voxel.XYZ[2],Voxel.XYZ[1]*2+Section.Size[2]-Voxel.XYZ[2]));
HVA Builder uses a different coordinate system than VXLSE III.
By the looks of it WW just used Z for height. Which would effectively mean you swap the Y and Z when you want it to be 3D (Or just apply a 90 degree rotation around the X axis).
So the comments about "WW to OpenGL" and visa versa are wrong (As its not converting it to OpenGL) as it should be X,Z,Y when going from WW to OpenGL not Y,Z,X (X should never be touched as its always right, its the Y and Z which are the ones to be switched)
Iv tried to use the normal values, but i don't see the point in using them. If i just use the individual cubes normals it should always look right (Since they have 6 faces)
Click Images To Enlarge
EDIT: using the cubes normals looks horrible. Changed the lights position and it improved a bit.
Iv made a basic OBJ export. It lacks Side Colours being defined and its not optimised at all (Its literally just a full dump of all sides, so there is duplicate vertex/texture/normal values in the OBJ).
I may need to disable multi-sampling when i convert the OBJ as its coming out a bit too smooth looking. Also may need to increase ambient lighting. _________________ Free Map Editor - Game Requirements - Stucuk.Net QUICK_EDIT
I'm not sure why you are going to obj then to gmz rather than just trying to write a convertor that goes straight to gmz. From your description gmz is some kind of raster format, so when not just render out the information you need for each frame using the voxel viewers output? Seems overkill to involve another format. QUICK_EDIT
I'm not sure why you are going to obj then to gmz rather than just trying to write a convertor that goes straight to gmz. From your description gmz is some kind of raster format, so when not just render out the information you need for each frame using the voxel viewers output? Seems overkill to involve another format.
Because i made OBJToGMZ app. Technically i could modify it to load VXL files but its simpler to just leave OBJToGMZ alone and write a OBJ exporter. Its a simple format to save to. When i am finished someone may want to have an OBJ of some VXL's.
Also Known As: banshee_revora (Steam) Joined: 15 Aug 2002 Location: Brazil
Posted: Wed Feb 21, 2018 11:44 pm Post subject:
stucuk wrote:
Banshee wrote:
HVA Builder uses a different coordinate system than VXLSE III.
By the looks of it WW just used Z for height. Which would effectively mean you swap the Y and Z when you want it to be 3D (Or just apply a 90 degree rotation around the X axis).
So the comments about "WW to OpenGL" and visa versa are wrong (As its not converting it to OpenGL) as it should be X,Z,Y when going from WW to OpenGL not Y,Z,X (X should never be touched as its always right, its the Y and Z which are the ones to be switched)
The only thing I can agree here is that the term "OpenGL" as OpenGL coordinates can be considered to be questionable here.
What I have before doing have is components on the user interface that was documented to be changing the X axis while it was changing the Y axis, as well as objects that claimed to change the Y axis changing Z... and the same applies to Z and X. It was a mess to understand and debug.
With that function WestwoodToOpenGL, I could assure that the coordinates X, Y and Z of the user interface would match the ones in my code.
I do not care how Westwood designs their objects and what kind of optimizations they apply to improve the performance of these objects on their game engine. What I care is how much I understand the code I am dealing with. And that function has helped me a lot. QUICK_EDIT
What I have before doing have is components on the user interface that was documented to be changing the X axis while it was changing the Y axis, as well as objects that claimed to change the Y axis changing Z... and the same applies to Z and X. It was a mess to understand and debug.
That would either be people wanting it to match a previous version (or another tool) or a conversion to Y being upwards. But there is no reason to do a full conversion like your doing with VXL's where you literally create a new array to store it all. A simpler way would just be to have everything go through some code which is labelled like the interface. Like where you have an object property like Property X : Integer read FY;
Banshee wrote:
I do not care how Westwood designs their objects and what kind of optimizations they apply to improve the performance of these objects on their game engine. What I care is how much I understand the code I am dealing with. And that function has helped me a lot.
It has nothing to do with optimisation or performance.
There is no reason why you need to do any converting to get it to work with OpenGL. You can just rotate the view.
My VXL loading code loads the file in the same way, with the X for loop on the inside. All i did was switch the Z and Y around as OpenGL uses Y as up/down (Unless you rotate the view) and it worked fine. There was no swapping X with anything.
The code i recently wrote is alot nicer and doesn't jump back and forth when reading the VXL file. It reads it sequentially. Its alot easier to understand (I had to scratch my head a few times when trying to read the code in Voxel.pas)
// MAIN HEADER
Stream.Seek(16,soFromCurrent); // Skip 16 Bytes
Stream.Read(PaletteCount,4); // Should always be 1 but just in case handle it.
Stream.Read(S,4);
SetLength(FSection,S);
// SECTION HEADERS
for S := 0 to High(FSection) do
begin
Stream.Read(FSection[S].Name[1],16);
Stream.Seek(4*3,soFromCurrent); // Skip 12 Bytes
end;
// SECTION HEADERS
// BODY
GetMem(BodyData,BodySize);
Stream.Read(BodyData^,BodySize); // We use it below once we know the Tail Header
// BODY
for S := 0 to High(FSection) do
begin
// TAIL HEADER
Stream.Read(Span[0],4*3); // Read the Spans 3 offsets (Start, End and Data)
Stream.Read(FSection[S].Det,4+SizeOf(TM3x4)+(3*4*2)+3+1); // Read Det, Transform, MinB, MaxB, Size and NormalType in one go
// TAIL HEADER
// VOXEL DATA (Reading BODYDATA)
With FSection[S] do
begin
GetMem(Data,Size[0]*Size[1]*Size[2]*Sizeof(TVXLVoxel)); //We make it the maximum size as we don't know how many voxels
VoxelCount := 0;
for Y := 0 to Size[1]-1 do
for X := 0 to Size[0]-1 do
begin
if (SpanStart^ > -1) and (SpanEnd^ > -1) then // I am not sure if checking SpanEnd is needed.
begin
Z := 0;
SpanDataD := Pointer(Cardinal(SpanData)+SpanStart^);
while (Z < Size[2]) do
begin
Inc(Z,SpanDataD^);
Inc(SpanDataD,1);
AddVoxels(SpanDataD,Z,X,Y,S);
end;
end;
Inc(Cardinal(SpanStart),4);
Inc(Cardinal(SpanEnd),4);
end;
// VOXEL DATA
ReallocMem(Data,VoxelCount*Sizeof(TVXLVoxel)); //Resize to the correct size now we have it.
end;
end;
FreeMem(BodyData);
end;
procedure TVXL.AddVoxels(var SpanData : PByte; var Z : Integer; const X,Y,S : Integer);
var
Count,
V : Integer;
D : PVXLVoxel;
begin
Count := SpanData^;
Inc(Cardinal(SpanData),1);
With FSection[S] do
begin
D := Pointer(Cardinal(Data)+(VoxelCount*SizeOf(TVXLVoxel)));
for V := 0 to Count-1 do
begin
if P2Byte(SpanData)^.Byte1 > 0 then // We only want non-empty ones! Technically should never be any which are 0
begin
D^.Colour := P2Byte(SpanData)^.Byte1;
D^.Normal := P2Byte(SpanData)^.Byte2;
D^.XYZ[0] := X;
D^.XYZ[1] := Y;
D^.XYZ[2] := Z;
Also Known As: banshee_revora (Steam) Joined: 15 Aug 2002 Location: Brazil
Posted: Thu Feb 22, 2018 3:10 pm Post subject:
stucuk wrote:
Banshee wrote:
What I have before doing have is components on the user interface that was documented to be changing the X axis while it was changing the Y axis, as well as objects that claimed to change the Y axis changing Z... and the same applies to Z and X. It was a mess to understand and debug.
That would either be people wanting it to match a previous version (or another tool) or a conversion to Y being upwards. But there is no reason to do a full conversion like your doing with VXL's where you literally create a new array to store it all. A simpler way would just be to have everything go through some code which is labelled like the interface. Like where you have an object property like Property X : Integer read FY;
Look, the ideal solution is to change the voxel loading code to match the user interface. There is no reason why we should have things like Property X : Integer read FY; in the code. It makes debugging much harder and forces you to protect the Voxel inner data, forcing conversions every time you access a pixel on it, slowing down the program.
On my workaround, I've simply did a quick conversion of the data when loading and saving voxels. The arrays created during the process were destroyed at the same procedure.
It is not as good as the ideal solution, but it is useful for those lazy people like me who never bothered to understand, step by step, how voxel loading/saving really happens . It is not a big deal performance wise, hardly noticed by the user, but it is not the best thing it could be done either. QUICK_EDIT
You can post new topics in this forum You can reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum You cannot attach files in this forum You can download files in this forum