137 lines
		
	
	
		
			4.1 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
		
		
			
		
	
	
			137 lines
		
	
	
		
			4.1 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| 
								 | 
							
								const fs = require('fs');
							 | 
						||
| 
								 | 
							
								const Recast = require("../haxerecast/recastjs/recast");
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Get mesh path and NavMesh config
							 | 
						||
| 
								 | 
							
								const recast_settings = process.argv[3];
							 | 
						||
| 
								 | 
							
								const path_mesh = './' + process.argv[2] + '.obj'
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Read OBJ file and build NavMesh
							 | 
						||
| 
								 | 
							
								readObjFile(path_mesh, (error, vertices, vertexLength, indices, indexLength) => {
							 | 
						||
| 
								 | 
							
									if (error) {
							 | 
						||
| 
								 | 
							
										console.error('Error:', error);
							 | 
						||
| 
								 | 
							
									} else {
							 | 
						||
| 
								 | 
							
										buildNavMesh(vertices, vertexLength, indices, indexLength);
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								});
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Parse OBJ file
							 | 
						||
| 
								 | 
							
								function readObjFile(objFilePath, callback) {
							 | 
						||
| 
								 | 
							
								  try {
							 | 
						||
| 
								 | 
							
									// Read the OBJ file
							 | 
						||
| 
								 | 
							
									const objFileContent = fs.readFileSync(objFilePath, 'utf-8');
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// Process the OBJ content
							 | 
						||
| 
								 | 
							
									const vertices = [];
							 | 
						||
| 
								 | 
							
									const indices = [];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									vertices.length
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									const lines = objFileContent.split('\n');
							 | 
						||
| 
								 | 
							
									lines.forEach((line) => {
							 | 
						||
| 
								 | 
							
									  const parts = line.trim().split(/\s+/);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									  if (parts[0] === 'v') {
							 | 
						||
| 
								 | 
							
										// Vertex data
							 | 
						||
| 
								 | 
							
										const x = parseFloat(parts[1]);
							 | 
						||
| 
								 | 
							
										const y = parseFloat(parts[2]);
							 | 
						||
| 
								 | 
							
										const z = parseFloat(parts[3]);
							 | 
						||
| 
								 | 
							
										vertices.push(x, y, z);
							 | 
						||
| 
								 | 
							
									  } else if (parts[0] === 'f') {
							 | 
						||
| 
								 | 
							
										// Face data
							 | 
						||
| 
								 | 
							
										const faceIndices = parts.slice(1).map((vertex) => parseInt(vertex.split('/')[0]) - 1);
							 | 
						||
| 
								 | 
							
										indices.push(...faceIndices);
							 | 
						||
| 
								 | 
							
									  }
							 | 
						||
| 
								 | 
							
									});
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// Call the callback with the result
							 | 
						||
| 
								 | 
							
									callback(null, vertices, vertices.length, indices, indices.length);
							 | 
						||
| 
								 | 
							
								  } catch (error) {
							 | 
						||
| 
								 | 
							
									callback(error);
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function buildNavMesh (vertices, vertexLength, indices, indexLength) {
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
									recastSettings = JSON.parse(recast_settings);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									Recast().then(function(Recast) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										// Copy recast config settings
							 | 
						||
| 
								 | 
							
										var recastConfig = new Recast.rcConfig();
							 | 
						||
| 
								 | 
							
										recastConfig.width = recastSettings.width;
							 | 
						||
| 
								 | 
							
										recastConfig.height = recastSettings.height;
							 | 
						||
| 
								 | 
							
										if(recastSettings.tiledMesh) {
							 | 
						||
| 
								 | 
							
											recastConfig.tileSize = recastSettings.tileSize;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										else {
							 | 
						||
| 
								 | 
							
											recastConfig.tileSize = 0;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										recastConfig.borderSize = recastSettings.borderSize;
							 | 
						||
| 
								 | 
							
										recastConfig.cs = recastSettings.cellSize;
							 | 
						||
| 
								 | 
							
										recastConfig.ch = recastSettings.cellHeight;
							 | 
						||
| 
								 | 
							
										recastConfig.walkableSlopeAngle = recastSettings.walkableSlopeAngle;
							 | 
						||
| 
								 | 
							
										recastConfig.walkableHeight = recastSettings.walkableHeight;
							 | 
						||
| 
								 | 
							
										recastConfig.walkableClimb = recastSettings.walkableClimb;
							 | 
						||
| 
								 | 
							
										recastConfig.walkableRadius = recastSettings.walkableRadius;
							 | 
						||
| 
								 | 
							
										recastConfig.maxEdgeLen = recastSettings.maxEdgeLen;
							 | 
						||
| 
								 | 
							
										recastConfig.maxSimplificationError = recastSettings.maxSimplificationError;
							 | 
						||
| 
								 | 
							
										recastConfig.minRegionArea = recastSettings.minRegionArea;
							 | 
						||
| 
								 | 
							
										recastConfig.mergeRegionArea = recastSettings.mergeRegionArea;
							 | 
						||
| 
								 | 
							
										recastConfig.maxVertsPerPoly = recastSettings.maxVertsPerPoly;
							 | 
						||
| 
								 | 
							
										recastConfig.detailSampleDist = recastSettings.detailSampleDist;
							 | 
						||
| 
								 | 
							
										recastConfig.detailSampleMaxError = recastSettings.detailSampleMaxError;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										// Init NavMesh
							 | 
						||
| 
								 | 
							
										var navNesh = new Recast.NavMesh();
							 | 
						||
| 
								 | 
							
										// Build NavMesh
							 | 
						||
| 
								 | 
							
										navNesh.build(vertices, vertexLength, indices, indexLength, recastConfig);
							 | 
						||
| 
								 | 
							
										// Create debug NavMesh for visualization
							 | 
						||
| 
								 | 
							
										var debugNavMesh = navNesh.getDebugNavMesh();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										var trianglesCount = debugNavMesh.getTriangleCount();
							 | 
						||
| 
								 | 
							
										triangelVertices = []
							 | 
						||
| 
								 | 
							
										triangleFaces = []
							 | 
						||
| 
								 | 
							
										// Loop through triangles
							 | 
						||
| 
								 | 
							
										for(let runTriangle = 0; runTriangle < trianglesCount; runTriangle++) {
							 | 
						||
| 
								 | 
							
											var triangle = debugNavMesh.getTriangle(runTriangle);
							 | 
						||
| 
								 | 
							
											// Get triangle vertices
							 | 
						||
| 
								 | 
							
											var points = [triangle.getPoint(0),
							 | 
						||
| 
								 | 
							
														 triangle.getPoint(1),
							 | 
						||
| 
								 | 
							
														 triangle.getPoint(2)];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											// Get vertex positon
							 | 
						||
| 
								 | 
							
											for(var i in points) {
							 | 
						||
| 
								 | 
							
												// y, z interchanged
							 | 
						||
| 
								 | 
							
												triangelVertices.push([points[i].x, points[i].z, points[i].y]);
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
											// Get triangle indices
							 | 
						||
| 
								 | 
							
											var face = [3 * runTriangle + 1, 
							 | 
						||
| 
								 | 
							
														3 * runTriangle + 2, 
							 | 
						||
| 
								 | 
							
														3 * runTriangle + 3];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											
							 | 
						||
| 
								 | 
							
											triangleFaces.push(face);
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										// Get OBJ format of triangles
							 | 
						||
| 
								 | 
							
										var navMeshObj = saveGeometryToObj(triangelVertices, triangleFaces);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										// Write to OBJ file
							 | 
						||
| 
								 | 
							
										fs.writeFile(path_mesh, navMeshObj, function (err) {
							 | 
						||
| 
								 | 
							
											if (err) throw err;
							 | 
						||
| 
								 | 
							
										});
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									});
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function saveGeometryToObj (vertices, faces) {
							 | 
						||
| 
								 | 
							
									var buffer = '';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									//Write Vertices
							 | 
						||
| 
								 | 
							
									for (var i in vertices) buffer += 'v ' + (vertices[i][0]) + ' ' + vertices[i][1] + ' ' + vertices[i][2] + '\n';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									//Write Faces
							 | 
						||
| 
								 | 
							
									for (var i in faces) buffer += 'f ' + (faces[i][0]) + ' ' + faces[i][1] + ' ' + faces[i][2] + '\n';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									return buffer;
							 | 
						||
| 
								 | 
							
								}
							 |