|
@ -2,56 +2,28 @@ |
|
|
|
|
|
|
|
|
namespace Blobt\Luxcore\core; |
|
|
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 OPEN = true; |
|
|
const CLOSE = false; |
|
|
const CLOSE = false; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
* @var string $objFile obj文件路径 |
|
|
* @var string $objFile obj文件路径 |
|
|
*/ |
|
|
*/ |
|
|
public $objFile; |
|
|
public $objFile; |
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
* @var string $plyFile ply文件路径 |
|
|
|
|
|
*/ |
|
|
|
|
|
public $plyFile = []; |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* @var string $format ply文件储存格式 |
|
|
|
|
|
*/ |
|
|
|
|
|
public $format = self::TYPE_TXT; |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* @var bool $flipYZ 是 |
|
|
|
|
|
*/ |
|
|
|
|
|
public $flipYZ; |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* @var array $vertexs 顶点坐标数组 |
|
|
|
|
|
*/ |
|
|
|
|
|
public $vertexs = []; |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* @var array $textureUV 纹理坐标数组 |
|
|
|
|
|
|
|
|
* @var array 储存obj模型数据 |
|
|
*/ |
|
|
*/ |
|
|
public $textureUV = []; |
|
|
|
|
|
|
|
|
public $objData = []; |
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
* @var array $normals 顶点法线数组 |
|
|
|
|
|
|
|
|
* @var array 储存ply模型数据 |
|
|
*/ |
|
|
*/ |
|
|
public $normals = []; |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* @var array $faces 面片数组 |
|
|
|
|
|
*/ |
|
|
|
|
|
public $mesh = []; |
|
|
|
|
|
|
|
|
public $plyData = []; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -60,24 +32,31 @@ class Base |
|
|
* @param string $objFile 传入obj文件 |
|
|
* @param string $objFile 传入obj文件 |
|
|
* @param bool $flipYZ 是否翻转Z轴Y轴 |
|
|
* @param bool $flipYZ 是否翻转Z轴Y轴 |
|
|
*/ |
|
|
*/ |
|
|
public function __construct(string $objFile,bool $flipYZ = self::OPEN) |
|
|
|
|
|
|
|
|
public function __construct( string $objFile, bool $flipYZ = self::OPEN ) |
|
|
{ |
|
|
{ |
|
|
$this->file = $objFile; |
|
|
|
|
|
$this->flipYZ = $flipYZ; |
|
|
|
|
|
|
|
|
$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; |
|
|
$handle = null; |
|
|
$line = true; |
|
|
|
|
|
|
|
|
$line = null; |
|
|
|
|
|
$keyName = null; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if( !file_exists($this->objFile) ) |
|
|
if( !file_exists($this->objFile) ) |
|
@ -86,7 +65,7 @@ class Base |
|
|
} |
|
|
} |
|
|
else |
|
|
else |
|
|
{ |
|
|
{ |
|
|
$handle = fopen($this->file,'r'); |
|
|
|
|
|
|
|
|
$handle = fopen($this->objFile,'r'); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -96,44 +75,192 @@ class Base |
|
|
} |
|
|
} |
|
|
else |
|
|
else |
|
|
{ |
|
|
{ |
|
|
|
|
|
|
|
|
fseek($handle, 0); |
|
|
fseek($handle, 0); |
|
|
while( !feof($handle) ) // 读取所有的 顶点坐标、UV坐标、顶点法线,并存入到相应的数组
|
|
|
|
|
|
|
|
|
while( !feof($handle) ) // 读取所有的 顶点坐标、UV坐标、顶点法线、面片,并存入到相应的数组
|
|
|
{ |
|
|
{ |
|
|
$line = fgets( $handle ); |
|
|
$line = fgets( $handle ); |
|
|
$line = ltrim( $line ); |
|
|
$line = ltrim( $line ); |
|
|
if( $line[0] == '#' ) continue; |
|
|
|
|
|
|
|
|
|
|
|
switch( explode(' ', $line)[0] ) |
|
|
|
|
|
|
|
|
$line = explode(' ', $line); |
|
|
|
|
|
switch( $line[0] ) |
|
|
{ |
|
|
{ |
|
|
case 'v': |
|
|
case 'v': |
|
|
$this->vertexs[] = $line; |
|
|
|
|
|
|
|
|
array_shift($line); // 将 v 开头的数据行 存入顶点数组
|
|
|
|
|
|
$this->objData['v'][] = $line; |
|
|
|
|
|
break; |
|
|
|
|
|
|
|
|
case 'vn': |
|
|
case 'vn': |
|
|
$this->normals[] = $line; |
|
|
|
|
|
|
|
|
array_shift($line); // 将 vn 开头的数据行 存入顶点法线数组
|
|
|
|
|
|
$this->objData['vn'][] = $line; |
|
|
|
|
|
break; |
|
|
|
|
|
|
|
|
case 'vt': |
|
|
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坐标、顶点法线,并存入到相应的数组
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* 翻转模型的YZ轴向 |
|
|
|
|
|
*/ |
|
|
|
|
|
private function flipYZ() |
|
|
{ |
|
|
{ |
|
|
$line = fgets( $handle ); |
|
|
|
|
|
$line = ltrim( $line ); |
|
|
|
|
|
if( $line[0] == '#' ) continue; |
|
|
|
|
|
|
|
|
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]; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if ( explode(' ', $line)[0] == 'o' ) |
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* 利用已经拆分的 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; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
} |
|
|
} |