PDA

View Full Version : OBJ2Map [mesh-wise]



serthy
16th December 2012, 11:42
Hey

i wrote this simple thing to convert *.obj to *.map!

THIS IS USING ONLY MESHES!

it is like the VMF2Map-converter, but in instead of brushes, it is using meshes


<?php
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

ini_set( "memory_limit" , "500M" );

$path = "X:\\MODDING\\COD2\\map_source\\"; //output path
$name = "objfile"; //input filename
$scale = 1; //output scale
$snapToGrid = false; //this may distort the output!

echo "Converting $name.obj!\n";

$objString = file_get_contents( $name . ".obj" );
$obj = parse_OBJ( $objString );
$map = export_OBJ2MAP( $obj , $scale , $snapToGrid );

file_put_contents( "$path$name.map" , $map );

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

function parse_OBJ( $mapSourceString )
{
$obj = array();
$obj["faces"] = array();
$obj["verts"] = array();

$lines = explode( "\n" , $mapSourceString );

foreach( $lines as $line )
{
$temp = explode( " " , $line );
$val = $temp[0];

switch( $val )
{
case "#": //skip the unwanted elements like
case "usemtl": //bezier curves, splines, groubs, objects,
case "mtllib": //materials, vertexnormals, vertextestures etc
case "s": //to stay as easy as possible
case "vt":
case "vn":
case "o":
break;

case "v": //plain vertex: v xCoord yCoord zCoord weight
//strip only the 3 worldcoords
//keep the order to get the globalVertexIndex later on!
//this code ignores the lokalVertexIndex
$obj["verts"][] = array_slice( $temp , 1 , 3 );

break;

case "f": //plain face: f globalVertIndex1/globalVertParamIndex1/globalVertNormalIndex1
//this discribes 1 vertex with the globalVertexIndex of the siad vertex
//if the globalVertexIndex is negative it will use the lokalVertexIndex! (not used here)
$temp = array_slice( $temp , 1 , 3 );

//strip the elements and leave the globalVertexIndex
foreach( $temp as $key => $val )
{
$val = explode( "/" , $val );
$temp[$key] = $val[0];
}

$obj["faces"][] = $temp;

break;
}
}

return $obj;
}

function export_OBJ2MAP( $obj , $scale = 1 , $snapToGrid = false )
{
$map = "";
$map = "iwmap 4\n";
$map .= "{\n";
$map .= "\t\"classname\" \"worldspawn\"\n";

foreach( $obj["faces"] as $face )
{
$vertStrArray = array();

foreach( $face as $vertIndex )
{
$vertIndex = (int)$vertIndex - 1;

if( $vertIndex < 0 || !isset( $obj["verts"][$vertIndex] ) )
break;

$vert = $obj["verts"][$vertIndex];

$vertStr = "v ";

foreach( $vert as $coord )
{
$coord = (float)$coord * $scale;

if( $snapToGrid )
$coord = round( $coord );

$vertStr .= $coord;
$vertStr .= " ";
}

$vertStr .= "t -160 -160 -0.625 0.625\n";

$vertStrArray[] = $vertStr;
}

if( count( $vertStrArray ) != 3 ) //this code handles only trinagles!
continue; //so your *.obj file should consists out of them!

$faceStr = "";
$faceStr .= "\t{\n";
$faceStr .= "\t\tmesh\n";
$faceStr .= "\t\t{\n";
$faceStr .= "\t\t\tcaulk\n";
$faceStr .= "\t\t\tlightmap_grey\n";
$faceStr .= "\t\t\t2 2 16 8\n";
$faceStr .= "\t\t\t(\n";
$faceStr .= "\t\t\t\t$vertStrArray[0]"; //play with the indexes here
$faceStr .= "\t\t\t\t$vertStrArray[1]"; //there must be 3 uniques (0,1,2)
$faceStr .= "\t\t\t)\n";
$faceStr .= "\t\t\t(\n";
$faceStr .= "\t\t\t\t$vertStrArray[2]"; //and one duplicate > quad to triangle!
$faceStr .= "\t\t\t\t$vertStrArray[2]"; //this is the best for me right now
$faceStr .= "\t\t\t)\n";
$faceStr .= "\t\t}\n";
$faceStr .= "\t}\n";

$map .= $faceStr;
}

$map .= "}\n";

return $map;
}

usage: VMF2Map (http://killtube.org/showthread.php?1003-VMF2Map)


cheers Serthy

kung foo man
16th December 2012, 18:44
Hey, nice work :)

Just tried it, but from inside its invisible. Is it only for decoration?

91

serthy
16th December 2012, 19:06
in Radiant:
select all [i]
flip normals [shift + i]

the texturing is not working at all, also in fact that this is using triangles (and the *.map requires at least 2x2 vertices, so the fourth is just a copie of another) there is no way (for me right now) to point out the normals, textures, lightmaps. you cant also connect every plane to the next, since *.map uses 2 types of vertices (red & pink ones)

to flip the normals you have to switch the Y and Z coordinate for every vertex of that mesh (in *.map)

here is the *.OBJ file format reference.. 92 if someone is interested in it lol :cool:

kung foo man
16th December 2012, 20:07
Hey, here is what i needed to do also:

Select all: I
Click some Texture
Open Surface inspector (press S) then [Fit]-button
Selection -> Rotate -> Rotate Y
Selection -> Scale 100,100,100

Then it looks usable :D

93

serthy
17th December 2012, 12:38
fixed rotation
added paths

<?php
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

ini_set( "memory_limit" , "500M" );

$name = "testmap"; //input filename
$scale = 35; //output scale
$snapToGrid = true; //this may distort the output!
$texture = "case"; //default texture
$version = "cod2"; //game version

switch( $version )
{
case "cod5":
$path = "G:\\Modding\\spiele\\cod5\\map_source\\SERTHYWARS\ \";
break;
case "cod2":
$path = "X:\\MODDING\\COD2\\map_source\\";
break;
default:
$path = "X:\\MODDING\\COD2\\map_source\\";
break;
}

echo "Converting $name.obj!\n";

$objString = file_get_contents( $name . ".obj" );
$obj = parse_OBJ( $objString );
$map = export_OBJ2MAP( $obj , $scale , $snapToGrid , $texture , $version );

file_put_contents( "$path$name.map" , $map );

echo "Converting done!\n";

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

function parse_OBJ( $mapSourceString )
{
$obj = array();
$obj["faces"] = array();
$obj["verts"] = array();

$lines = explode( "\n" , $mapSourceString );

foreach( $lines as $line )
{
$temp = explode( " " , $line );
$val = $temp[0];

switch( $val )
{
case "#": //skip the unwanted elements like
case "usemtl": //bezier curves, splines, groubs, objects,
case "mtllib": //materials, vertexnormals, vertextestures etc
case "s": //to stay as easy as possible
case "vt":
case "vn":
case "o":
break;

case "v": //plain vertex: v xCoord yCoord zCoord weight
//strip only the 3 worldcoords
//keep the order to get the globalVertexIndex later on!
//this code ignores the lokalVertexIndex
$obj["verts"][] = array_slice( $temp , 1 , 3 );

break;

case "f": //plain face: f globalVertIndex1/globalVertParamIndex1/globalVertNormalIndex1
//this discribes 1 vertex with the globalVertexIndex of the siad vertex
//if the globalVertexIndex is negative it will use the lokalVertexIndex! (not used here)
$temp = array_slice( $temp , 1 , 3 );

//strip the elements and leave the globalVertexIndex
foreach( $temp as $key => $val )
{
$val = explode( "/" , $val );
$temp[$key] = $val[0];
}

$obj["faces"][] = $temp;

break;
}
}

return $obj;
}

function export_OBJ2MAP( $obj , $scale = 1 , $snapToGrid = true , $texture = "case" , $version = "cod2" )
{
$map = "";
$map .= "iwmap 4\n";

if( $version == "cod5" || $version == "cod4" )
{
$map .= "\"000_Global\" flags active\n";
$map .= "\"The Map\" flags\n";
}

$map .= "{\n";
$map .= "\t\"classname\" \"worldspawn\"\n";

foreach( $obj["faces"] as $face )
{
$vertStrArray = array();

foreach( $face as $vertIndex )
{
$vertIndex = (int)$vertIndex - 1;

if( $vertIndex < 0 || !isset( $obj["verts"][$vertIndex] ) || count( $obj["verts"][$vertIndex] ) != 3 )
break;

$vert = $obj["verts"][$vertIndex];

for( $c = 0 ; $c < 3 ; $c++ )
{
$coord = (float)$vert[$c] * $scale;

if( $snapToGrid )
$coord = round( $coord );

$vert[$c] = $coord;
}

$vertStrArray[] = "v $vert[0] $vert[2] $vert[1] t -1600 -1600 -0.625 0.625\n";
}

if( count( $vertStrArray ) != 3 ) //this code handles only trinagles!
continue; //so your *.obj file should consists out of them!

$faceStr = "";
$faceStr .= "\t{\n";
$faceStr .= "\t\tmesh\n";
$faceStr .= "\t\t{\n";
$faceStr .= "\t\t\ttoolFlags splitGeo;\n";
$faceStr .= "\t\t\t$texture\n";
$faceStr .= "\t\t\tlightmap_gray\n";
$faceStr .= "\t\t\t2 2 16 8\n";
$faceStr .= "\t\t\t(\n";
$faceStr .= "\t\t\t\t$vertStrArray[0]"; //play with the indexes here
$faceStr .= "\t\t\t\t$vertStrArray[0]"; //there must be 3 uniques (0,1,2)
$faceStr .= "\t\t\t)\n";
$faceStr .= "\t\t\t(\n";
$faceStr .= "\t\t\t\t$vertStrArray[1]"; //and one duplicate > quad to triangle!
$faceStr .= "\t\t\t\t$vertStrArray[2]"; //this is the best for me right now
$faceStr .= "\t\t\t)\n";
$faceStr .= "\t\t}\n";
$faceStr .= "\t}\n";

$map .= $faceStr;
}

$map .= "}\n";

return $map;
}

to get the best & rly fast texture results:
set $version to cod5
convert
open it in codwawRadiant
select all [i]
invert meshes [shift+i]
hit a texture
bring up the surface inspector [s]
hit [LMAP]

kung foo man
17th December 2012, 14:27
Hm, whats the difference to cod2-radiant?

serthy
17th December 2012, 15:05
1. waw CAP
2. cod2 LMAP
3. waw FIT
4. waw LMAP (best results)
5. waw NATURAL

Samantha Carter
2nd April 2024, 20:59
Hello, with the help of a ChatGPT 3.5, I fixed Serthy's OBJ2Map so now it uses the material names of your meshes from OBJ.


<?php
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

ini_set( "memory_limit" , "500M" );

$name = "my_obj"; //input filename
$scale = 1; //output scale
$snapToGrid = false; //this may distort the output!
$texture = "case"; //default texture
$version = "cod2"; //game version

switch( $version )
{
case "cod5":
$path = "D:/";
break;
case "cod2":
$path = "D:/";
break;
default:
$path = "D:/";
break;
}

echo "Converting $name.obj!\n";

$objString = file_get_contents( $name . ".obj" );
$obj = parse_OBJ( $objString );
$map = export_OBJ2MAP( $obj , $scale , $snapToGrid , $texture , $version );

file_put_contents( "$path$name.map" , $map );

echo "Converting done!\n";

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

function parse_OBJ($mapSourceString)
{
$obj = array();
$obj["faces"] = array();
$obj["verts"] = array();
$obj["materials"] = array(); // Store materials as associative array

$lines = explode("\n", $mapSourceString);

$currentMaterial = null;

foreach ($lines as $line) {
$temp = explode(" ", $line);
$val = $temp[0];

switch ($val) {
case "#":
break;
case "usemtl":
// Extract material name and store it
if (isset($temp[1])) {
$currentMaterial = trim($temp[1]);
}
break;
case "mtllib":
case "s":
case "vt":
case "vn":
case "o":
break;

case "v":
$obj["verts"][] = array_slice($temp, 1, 3);
break;

case "f":
$temp = array_slice($temp, 1, 3);

foreach ($temp as $key => $val) {
$val = explode("/", $val);
$temp[$key] = $val[0];
}

$materialName = $currentMaterial !== null ? $currentMaterial : "defaultMaterial";
$obj["faces"][] = array("indices" => $temp, "material" => $materialName);
break;
}
}

return $obj;
}

function export_OBJ2MAP($obj, $scale = 1, $snapToGrid = true, $version = "cod2")
{
$map = "";
$map .= "iwmap 4\n";

if ($version == "cod5" || $version == "cod4") {
$map .= "\"000_Global\" flags active\n";
$map .= "\"The Map\" flags\n";
}

$map .= "{\n";
$map .= "\t\"classname\" \"worldspawn\"\n";

foreach ($obj["faces"] as $face) {
$vertStrArray = array();

foreach ($face["indices"] as $vertIndex) {
$vertIndex = (int)$vertIndex - 1;

if ($vertIndex < 0 || !isset($obj["verts"][$vertIndex]) || count($obj["verts"][$vertIndex]) != 3)
break;

$vert = $obj["verts"][$vertIndex];

for ($c = 0; $c < 3; $c++) {
$coord = (float)$vert[$c] * $scale;

if ($snapToGrid)
$coord = round($coord);

$vert[$c] = $coord;
}

$vertStrArray[] = "v $vert[0] $vert[2] $vert[1] t -1600 -1600 -0.625 0.625\n";
}

if (count($vertStrArray) != 3) //this code handles only triangles!
continue; //so your *.obj file should consist only of them!

$materialName = $face["material"];

$faceStr = "";
$faceStr .= "\t{\n";
$faceStr .= "\t\tmesh\n";
$faceStr .= "\t\t{\n";
$faceStr .= "\t\t\ttoolFlags splitGeo;\n";
$faceStr .= "\t\t\t$materialName\n"; // Use the material name associated with the face
$faceStr .= "\t\t\tlightmap_gray\n";
$faceStr .= "\t\t\t2 2 16 8\n";
$faceStr .= "\t\t\t(\n";
$faceStr .= "\t\t\t\t$vertStrArray[0]"; //play with the indexes here
$faceStr .= "\t\t\t\t$vertStrArray[0]"; //there must be 3 uniques (0,1,2)
$faceStr .= "\t\t\t)\n";
$faceStr .= "\t\t\t(\n";
$faceStr .= "\t\t\t\t$vertStrArray[1]"; //and one duplicate > quad to triangle!
$faceStr .= "\t\t\t\t$vertStrArray[2]"; //this is the best for me right now
$faceStr .= "\t\t\t)\n";
$faceStr .= "\t\t}\n";
$faceStr .= "\t}\n";

$map .= $faceStr;
}

$map .= "}\n";

return $map;
}