diff --git a/.vscode/launch.json b/.vscode/launch.json index f3698e2..c2d0505 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -1,6 +1,7 @@ { "version": "0.2.0", "configurations": [ + { "name": "Listen for XDebug", "type": "php", @@ -11,7 +12,7 @@ "name": "Launch currently open script", "type": "php", "request": "launch", - "program": "${workspaceFolder}/examples/configBatch.php", + "program": "${workspaceFolder}/examples/loadObjDemo.php", "cwd": "${workspaceFolder}", "port": 9055 } diff --git a/examples/loadObjDemo.php b/examples/loadObjDemo.php new file mode 100644 index 0000000..5d309b6 --- /dev/null +++ b/examples/loadObjDemo.php @@ -0,0 +1,13 @@ +toPly(LoardObj::TYPE_BINARY); + +?> diff --git a/src/core/LoardObj.php b/src/core/LoardObj.php index 0d7c754..31f7fc2 100644 --- a/src/core/LoardObj.php +++ b/src/core/LoardObj.php @@ -2,82 +2,61 @@ namespace Blobt\Luxcore\core; -class Base +class LoardObj { - const TYPE_TXT = 'txt'; - const TYPE_BINARY = 'binary'; + const TYPE_TXT = 'ascii 1.0'; + const TYPE_BINARY = 'binary_little_endian 1.0'; const OPEN = true; const CLOSE = false; - - - /** * @var string $objFile obj文件路径 */ public $objFile; /** - * @var string $plyFile ply文件路径 - */ - public $plyFile = []; - - /** - * @var string $format ply文件储存格式 - */ - public $format = self::TYPE_TXT; - - /** - * @var bool $flipYZ 是 + * @var array 储存obj模型数据 */ - public $flipYZ; + public $objData = []; /** - * @var array $vertexs 顶点坐标数组 + * @var array 储存ply模型数据 */ - public $vertexs = []; + public $plyData = []; - /** - * @var array $textureUV 纹理坐标数组 - */ - public $textureUV = []; - /** - * @var array $normals 顶点法线数组 - */ - public $normals = []; - - /** - * @var array $faces 面片数组 - */ - public $mesh = []; - - /** * @param string $objFile 传入obj文件 * @param bool $flipYZ 是否翻转Z轴Y轴 */ - public function __construct(string $objFile,bool $flipYZ = self::OPEN) - { - $this->file = $objFile; - $this->flipYZ = $flipYZ; + public function __construct( string $objFile, bool $flipYZ = self::OPEN ) + { + $this->objFile = $objFile; + $this->readObj(); + if( $flipYZ ) $this->flipYZ(); } - public function toPly() + /** + * @param string $format 储存 ply模型 的格式 + */ + public function toPly( string $format = self::TYPE_BINARY) { - return $this->plyFile; + $this->createPly(); + return $this->writePly($format); } + /** - * + * 读取OBJ模型数据,并拆分模型 */ - public function readObj() + private function readObj() { $handle = null; - $line = true; + $line = null; + $keyName = null; if( !file_exists($this->objFile) ) @@ -86,54 +65,202 @@ class Base } else { - $handle = fopen($this->file,'r'); + $handle = fopen($this->objFile,'r'); } - + if( !$handle ) { throw new \Exception("File ".$this->objFile." open failed"); } else { - fseek($handle, 0); - while( !feof($handle) ) // 读取所有的 顶点坐标、UV坐标、顶点法线,并存入到相应的数组 + while( !feof($handle) ) // 读取所有的 顶点坐标、UV坐标、顶点法线、面片,并存入到相应的数组 { $line = fgets( $handle ); $line = ltrim( $line ); - if( $line[0] == '#' ) continue; - - switch( explode(' ', $line)[0] ) + $line = explode(' ', $line); + switch( $line[0] ) { case 'v': - $this->vertexs[] = $line; + array_shift($line); // 将 v 开头的数据行 存入顶点数组 + $this->objData['v'][] = $line; + break; case 'vn': - $this->normals[] = $line; + array_shift($line); // 将 vn 开头的数据行 存入顶点法线数组 + $this->objData['vn'][] = $line; + break; case 'vt': - $this->textureUV[] = $line; + array_shift($line); // 将 vt 开头的数据行 存入 UV坐标数组 + $this->objData['vt'][] = $line; + break; + + case 'o': + array_shift($line); // 将 o 开头的行(object名) 作为一个键名(按照 ‘o’ 关键字拆分OBJ模型) + $line = implode("_", $line); + $keyName = $line; + break; + + case 'f': + array_shift($line); // 将 f 开头的行 存入 ['meshs'][$keyName] 指向的数组 + $this->objData['meshs'][$keyName][] = $line; + + default: + ; // 丢弃无用的 数据行 } } + } + + } - fseek($handle, 0); - while( !feof($handle) ) // 读取 顶点坐标、UV坐标、顶点法线,并存入到相应的数组 - { - $line = fgets( $handle ); - $line = ltrim( $line ); - if( $line[0] == '#' ) continue; - if ( explode(' ', $line)[0] == 'o' ) - } + + /** + * 翻转模型的YZ轴向 + */ + private function flipYZ() + { + foreach( $this->objData['v'] as $key => $value) + { + $this->objData['v'][$key] = []; + $this->objData['v'][$key][] = $value[0]; + $this->objData['v'][$key][] = $value[2]; + $this->objData['v'][$key][] = $value[1]; } + } + + + + + /** + * 利用已经拆分的 obj 模型数据,生成多个 ply 模型,并将这些模型储存在 plyData 数组中 + */ + private function createPly() + { + + foreach( $this->objData['meshs'] as $meshs_key => $meshs_value ) + { + var_dump($this->objData); + $ply = []; + $vCount = 0; + $fCount = 0; + + foreach( $meshs_value as $face_value ) // 生成顶点和面数据 + { + $face_value = implode('/', $face_value); + $face_value = explode('/', $face_value); + $lineFace = []; + $v = []; + $vt = []; + $vn = []; + foreach( $face_value as $v_key => $v_value ) + { + switch( ($v_key+1) % 3 ) + { + case 1: + $v = $this->objData['v'][$v_value-1]; + break; + + case 2: + $vt = array_splice($this->objData['vt'][$v_value-1],2); + break; + + case 0; + $vn = $this->objData['vn'][$v_value-1]; + $ply['vertex'][$vCount] = implode(' ',$v).' '.implode(' ',$vn).' '.implode(' ',$vt); + $lineFace[] = $vCount; + $vCount++; + break; + + default: + ; + } + } + $ply['face'][$fCount] = implode(' ',$lineFace); + $fCount++; + } + $ply['header'][] = 'ply'; // 生成头部数据 + $ply['header'][] = "format "; + $ply['header'][] = "comment Created by reaiyunju, source file: ''"; + $ply['header'][] = "element vertex ".$vCount; + $ply['header'][] = "property float x"; + $ply['header'][] = "property float y"; + $ply['header'][] = "property float z"; + $ply['header'][] = "property float nx"; + $ply['header'][] = "property float ny"; + $ply['header'][] = "property float nz"; + $ply['header'][] = "property float s"; + $ply['header'][] = "property float t"; + $ply['header'][] = "element face ".count($ply['face']); + $ply['header'][] = "property list uchar uint vertex_indices"; + $ply['header'][] = "end_header"; + + $this->plyData[$meshs_key] = $ply; // 在 数组plyData 中添加一个 $key 所指名称的ply模型 + } + } + /** + * 将 $plyData 数组中的ply模型 写入硬盘 + */ + private function writePly(string $format) + { + $plyFile = []; + $handle = null; + foreach( $this->plyData as $key => $value ) + { + $plyFile[] = $key."ply"; + $handle = fopen( $key."ply",'w+'); + + foreach( $value['header'] as $h_key => $h_value) // 写入头部数据 + { + if( $h_key == 1 ) $data = $h_value.$format."\n"; + else $data = $h_value."\n"; + fwrite($handle,$data); + } + + foreach( $value['vertex'] as $v_value ) // 写入顶点数据 + { + if( $format == self::TYPE_BINARY ) // 二进制格试写入 + { + foreach( explode(' ', $v_value) as $v ) + { + $data .= pack('f',$v); + } + fwrite($handle,$data); + } + else + { + $data = $v_value."\n"; // 文本格试写入 + fwrite($handle,$data); + } + } + foreach( $value['face'] as $f_value ) // 写入面片数据 + { + if( $format == self::TYPE_BINARY ) // 二进制格试写入 + { + foreach( explode(' ', $f_value) as $v ) + { + $data .= pack('f',$v); + } + fwrite($handle,$data); + } + else + { + $data = $f_value."\n"; // 文本格试写入 + fwrite($handle,$data); + } + } + } + return $plyFile; } }