예제 #1
0
bool TurretShape::getWorldNodeTransform(S32 node, MatrixF& mat)
{
   MatrixF nodeMat;
   if (!getNodeTransform(node, nodeMat))
      return false;

   nodeMat.affineInverse();
   mat = nodeMat;
   return true;
}
예제 #2
0
void AITurretShape::getAimTransform(MatrixF& mat)
{
   if (mDataBlock && mDataBlock->aimNode != -1)
   {
      if (getNodeTransform(mDataBlock->aimNode, mat))
      {
         return;
      }
   }

   mat = mObjToWorld;
}
예제 #3
0
void AITurretShape::_renderScanner( ObjectRenderInst *ri, SceneRenderState *state, BaseMatInstance *overrideMat )
{
   GFXStateBlockDesc desc;
   desc.setBlend(false, GFXBlendSrcAlpha, GFXBlendInvSrcAlpha);
   desc.setZReadWrite(false,true);
   desc.fillMode = GFXFillWireframe;

   // Render the scan box
   GFX->getDrawUtil()->drawCube(desc, mTransformedScanBox.getExtents(), mTransformedScanBox.getCenter(), ColorI(255, 0, 0));

   // Render a line from the scan node to the max scan distance
   MatrixF nodeMat;
   if (getNodeTransform(mDataBlock->scanNode, nodeMat))
   {
      Point3F start;
      nodeMat.getColumn(3, &start);

      Point3F end(0.0f, mScanDistance, 0.0f);
      nodeMat.mulP(end);

      GFX->getDrawUtil()->drawLine(start, end, ColorI(255, 255, 0));
   }
}
예제 #4
0
Exporter::Result Exporter::exportMesh(NiNodeRef &ninode, INode *node, TimeValue t)
{
	ObjectState os = node->EvalWorldState(t);

	bool local = !mFlattenHierarchy;

	TriObject *tri = (TriObject *)os.obj->ConvertToType(t, Class_ID(TRIOBJ_CLASS_ID, 0));
	if (!tri)
		return Skip;

	Mesh *copymesh = NULL;
	Mesh *mesh = &tri->GetMesh();

	Matrix3 mtx(true), rtx(true);
	if (Exporter::mCollapseTransforms)
	{
		mtx = GetNodeLocalTM(node, t);
		mtx.NoTrans();
		Quat q(mtx);
		q.MakeMatrix(rtx);
		mesh = copymesh = new Mesh(*mesh);
		{
			int n = mesh->getNumVerts();
			for ( unsigned int i = 0; i < n; ++i ) {
				Point3& vert = mesh->getVert(i);
				vert = mtx * vert;
			}
			mesh->checkNormals(TRUE);
#if VERSION_3DSMAX > ((5000<<16)+(15<<8)+0) // Version 6+
			MeshNormalSpec *specNorms = mesh->GetSpecifiedNormals ();
			if (NULL != specNorms) {
				specNorms->CheckNormals();
				for ( unsigned int i = 0; i < specNorms->GetNumNormals(); ++i ) {
					Point3& norm = specNorms->Normal(i);
					norm = (rtx * norm).Normalize();
				}
			}
#endif
		}
	}
	// Note that calling setVCDisplayData will clear things like normals so we set this up first
	vector<Color4> vertColors;
	if (mVertexColors)
	{
		bool hasvc = false;
		if (mesh->mapSupport(MAP_ALPHA))
		{
			mesh->setVCDisplayData(MAP_ALPHA);         int n = mesh->getNumVertCol();
			if (n > vertColors.size())
				vertColors.assign(n, Color4(1.0f, 1.0f, 1.0f, 1.0f));
			VertColor *vertCol = mesh->vertColArray;
			if (vertCol) {
				for (int i=0; i<n; ++i) {
					VertColor c = vertCol[ i ];
					float a = (c.x + c.y + c.z) / 3.0f;
					vertColors[i].a = a;
					hasvc |= (a != 1.0f);
				}
			}
		}
		if (mesh->mapSupport(0))
		{
			mesh->setVCDisplayData(0);
			VertColor *vertCol = mesh->vertColArray;
			int n = mesh->getNumVertCol();
			if (n > vertColors.size())
				vertColors.assign(n, Color4(1.0f, 1.0f, 1.0f, 1.0f));
			if (vertCol) {
				for (int i=0; i<n; ++i) {
					VertColor col = vertCol[ i ];
					vertColors[i] = Color4(col.x, col.y, col.z, vertColors[i].a);
					hasvc |= (col.x != 1.0f || col.y != 1.0f || col.z != 1.0f);
				}
			}
		}
		if (!hasvc) vertColors.clear();
	}

#if VERSION_3DSMAX <= ((5000<<16)+(15<<8)+0) // Version 5
	mesh->checkNormals(TRUE);
#else
	MeshNormalSpec *specNorms = mesh->GetSpecifiedNormals ();
	if (NULL != specNorms) {
		specNorms->CheckNormals();
		if (specNorms->GetNumNormals() == 0)
			mesh->checkNormals(TRUE);
	} else {
		mesh->checkNormals(TRUE);
	}
#endif

	Result result = Ok;

	Modifier* geomMorpherMod = GetMorpherModifier(node);
	bool noSplit = FALSE;
//	bool noSplit = (NULL != geomMorpherMod);

	while (1)
	{
		FaceGroups grps;
		if (!splitMesh(node, *mesh, grps, t, vertColors, noSplit))
		{
			result = Error;
			break;
		}
		bool exportStrips = mTriStrips && (Exporter::mNifVersionInt > VER_4_2_2_0);

		Matrix44 tm = Matrix44::IDENTITY;
		if ( mExportExtraNodes || (mExportType != NIF_WO_ANIM && isNodeKeyed(node) ) ) {
			tm = TOMATRIX4(getObjectTransform(node, t, false) * Inverse(getNodeTransform(node, t, false)));
		} else {
			Matrix33 rot; Vector3 trans;
			objectTransform(rot, trans, node, t, local);
			tm = Matrix44(trans, rot, 1.0f);
		}
		tm = TOMATRIX4(Inverse(mtx)) * tm;

		TSTR basename = node->NodeName();
		TSTR format = (!basename.isNull() && grps.size() > 1) ? "%s:%d" : "%s";

		int i=1;
		FaceGroups::iterator grp;
		for (grp=grps.begin(); grp!=grps.end(); ++grp, ++i)
		{
			string name = FormatString(format, basename.data(), i);
			NiTriBasedGeomRef shape = makeMesh(ninode, getMaterial(node, grp->first), grp->second, exportStrips);
			if (shape == NULL)
			{
				result = Error;
				break;
			}

			if (node->IsHidden())
				shape->SetVisibility(false);

			shape->SetName(name);
			shape->SetLocalTransform(tm);

			if (Exporter::mZeroTransforms) {
				shape->ApplyTransforms();
			}

			makeSkin(shape, node, grp->second, t);

			if (geomMorpherMod) {
				vector<Vector3> verts = shape->GetData()->GetVertices();
				exportGeomMorpherControl(geomMorpherMod, verts, shape->GetData()->GetVertexIndices(), shape);
				shape->GetData()->SetConsistencyFlags(CT_VOLATILE);
			}

		}

		break;
	}

	if (tri != os.obj)
		tri->DeleteMe();

	if (copymesh)
		delete copymesh;

	return result;
}
예제 #5
0
/**
 * This method will export the argument node and traverse
 * into its child nodes to export them.
 */
BOOL OSGExp::nodeEnum(osg::Group* rootTransform, INode* node, osg::Group* parent)
{
	osg::ref_ptr<osg::Group> child = NULL;

	_nCurNode++;
	_ip->ProgressUpdate((int)((float)_nCurNode/_nTotalNodeCount*100.0f)); 

	// Stop traversing if the user pressed Cancel.
	if (_ip->GetCancel())
		return TRUE;


	// If node is hidden and we are not exporting hidden nodes then return.
	if(node->IsNodeHidden() && !_options->getExportHiddenNodes()){
		return TRUE;
   }

   // Capture a special group helper if one is returned.
   // Nodes such as LODs and Switches will have to apply
   // special flags to their immediate children and thus
   // cannot be traversed in the normal recursive flow.
//   osg::Group* specialGroup = NULL;


	// Only export if hole scene is to be exported or
	// this node is choosen to be exported.
	if(!_onlyExportSelected || node->Selected())
   {
		// The ObjectState is a 'thing' that flows down the pipeline containing
		// all information about the object. By calling EvalWorldState() we tell
		// max to evaluate the object at the end of the pipeline.
		// An object may start out as an sphere, but could be modified by an modifier
		// object, the EvalWorldState will apply all modifiers to the original object
		// and return the final geometry for the object.
		ObjectState os = node->EvalWorldState(_ip->GetTime());

      // Use temporary variables for cleaner code.
      Object* obj = os.obj;
      TimeValue timeValue = _ip->GetTime();


		// If this a group node then make a OSG group node and add it to
		// the parent node and traverse into the children.
		if(node->IsGroupHead() || obj->ClassID() == Class_ID(DUMMY_CLASS_ID,0))
      {
			// Do not export referenced groups.
			if(Util::isReferencedByHelperObjects(node, _helperIDs))
				return TRUE;
			osg::MatrixTransform* groupNode = new osg::MatrixTransform();
			// Set name of group node.
			groupNode->setName(std::string(node->GetName()));
			// Set static datavariance for better performance
			groupNode->setDataVariance(osg::Object::STATIC);

			// Are we exporting animations.
			if(_options->getExportAnimations()){
				addAnimation(node, timeValue, groupNode);
			}
			
			// Set NodeMask
			if(_options->getUseDefaultNodeMaskValue())
				groupNode->setNodeMask(_options->getDefaultNodeMaskValue());
			groupNode->setMatrix(getNodeTransform(node, timeValue));
			parent->addChild(groupNode);
			parent = groupNode;
			applyNodeMaskValue(node, timeValue, groupNode);
		}

		// If this is not a group node it could be a geomtry object,
		// a camera, a light, or some other class. Switch the class ID
		// to carry out a specific export.
		// Note, it is the obj member of ObjectState which
		// is the actual object we are exporting.
		else if(obj != NULL)
      {
         Class_ID cid = obj->ClassID();

			// We look at the super class ID to determine the type of the object.
			switch(obj->SuperClassID())
         {
				case GEOMOBJECT_CLASS_ID:
					if(!Util::isReferencedByHelperObjects(node, _helperIDs))
               {
						child = createGeomObject(rootTransform, node, obj, timeValue).get();
						parent->addChild(child.get());
					}
					break;
				case CAMERA_CLASS_ID:
					if(_options->getExportCameras())
               {
						child = createCameraObject(rootTransform, node, obj, timeValue).get();
						parent->addChild(child.get());
					}
					break;
				case LIGHT_CLASS_ID:
					if(_options->getExportLights())
               {
						child = createLightObject(rootTransform, node, obj, timeValue).get();
						parent->addChild(child.get());
					}
					break;
				case SHAPE_CLASS_ID:
					if(_options->getExportShapes() && !Util::isReferencedByHelperObject(node, OCCLUDER_CLASS_ID))
               {
						child = createShapeObject(rootTransform, node, obj, timeValue).get();
						parent->addChild(child.get());
					}
					break;
				case HELPER_CLASS_ID:
               {
                  bool notRefByHelpers = Util::isReferencedByHelperObjects(node, _helperIDs) == NULL;
                  bool exportHelpers = _options->getExportHelpers() == TRUE;

                  if(_options->getExportPointHelpers() && cid == Class_ID(POINTHELP_CLASS_ID,0)) 
                  {
                     child = createPointFromHelperObject(rootTransform, node, obj, timeValue).get();
                     parent->addChild(child.get());
                  }
                  if(exportHelpers && notRefByHelpers)
                  {
                     if(cid == OSGGROUP_CLASS_ID)
                     {
                        child = createGroupFromHelper(parent, node, obj, timeValue).get();
                     }
                     else if(cid == LOD_CLASS_ID)
                     {
                        child = createLODFromHelperObject(parent, node, obj, timeValue).get();
                     }
                     else if(cid == SWITCH_CLASS_ID)
                     {
                        child = createSwitchFromHelperObject(parent, node, obj, timeValue).get();
                     }
                     else if(cid == DOFTRANSFORM_CLASS_ID) 
                     {
                        child = createDOFFromHelper(parent, node, obj, timeValue).get();                  
                     }
		               else
                     {
			               rootTransform->addChild(createHelperObject(rootTransform, node, obj, timeValue).get());
		               }
                  }
               }
					break;
            default:
               break;
			}
		}
	}

   for(int c = 0; c < node->NumberOfChildren(); c++)
   {
	   if(_ip->GetCancel() || ! nodeEnum(rootTransform, node->GetChildNode(c),child.valid()?child.get():parent))
      {
		   // If user cancels export we return false.
		   return FALSE;
	   }
   }

	return TRUE;
}
예제 #6
0
/**
 * This method will be called from the max system when the user
 * has choosen to export to the OpenSceneGraph format.
 * This method is the entry point to the exporter plugin.
 */
int	OSGExp::DoExport(const TCHAR *name, ExpInterface *ei,
					 Interface *i, BOOL suppressPrompts, DWORD MAXOptions){

	// Only support "one at the time" exporting.
	if(isExporting){
		return FALSE;
	}
	isExporting = TRUE;

	// Grab the interface pointer and save it for later use.
	_ip = i;

	// Set export path in options class
	TCHAR p[300];
	TCHAR f[100];
	TCHAR e[10];
	BMMSplitFilename(name, p, f, e);
	_options->setExportPath(p);
	_options->setExportFilename(f);
	_options->setExportExtension(e);

	// Get filename to config file.
	TSTR cfgfilename = _ip->GetDir(APP_PLUGCFG_DIR);;
	cfgfilename += _T("\\OSGEXP.CFG");

	// Load options from config file
	_options->load(cfgfilename);

	// Should we only export selected nodes?
	_onlyExportSelected = (MAXOptions & SCENE_EXPORT_SELECTED) ? TRUE : FALSE;

	// Show option dialog to user and retrive any possible plugin choices.
	if(!suppressPrompts)
		if(!DialogBoxParam(hInstance, MAKEINTRESOURCE(IDD_EXPORTBOX), 
				           GetActiveWindow(), OptionsDlgProc,
						   (LPARAM)_options)){
			// If user closed or canceled export box then shutdown plugin.
			isExporting = FALSE;
			return TRUE;
		}

	// Write options to config file.
	_options->write(cfgfilename);

	// Create OSG root transform to hold the scene.
{	
	osg::ref_ptr<osg::MatrixTransform> rootTransform = new osg::MatrixTransform();
	//osg::MatrixTransform* rootTransform = new osg::MatrixTransform();
	rootTransform->setName(std::string(_ip->GetRootNode()->GetName()));
	// Set static datavariance for better performance
	rootTransform->setDataVariance(osg::Object::STATIC);
	// Set NodeMask
	if(_options->getUseDefaultNodeMaskValue())
		rootTransform->setNodeMask(_options->getDefaultNodeMaskValue());
	osg::Matrix rootMat = getNodeTransform(_ip->GetRootNode(), _ip->GetTime());
	rootTransform->setMatrix(rootMat);
    // Create root stateset for the lights.
	osg::ref_ptr<osg::StateSet> rootStateSet = new osg::StateSet();
	// Turn of lighting if set by the user.
	if(_options->getTurnOffLighting())
		rootStateSet->setMode(GL_LIGHTING,osg::StateAttribute::OVERRIDE|osg::StateAttribute::OFF);
	else
		rootStateSet->setMode(GL_LIGHTING,osg::StateAttribute::ON);
	//osg::StateSet* rootStateSet = new osg::StateSet();
    rootTransform->setStateSet(rootStateSet.get());


	// We will make two progress bars. The first one will show
	// the exporting of materials, wheras the second one will show
	// the exporting of nodes. To get the total number of nodes in the
	// scene graph we will accumulate the total node count while
	// preprocessing the scenegraph for materials.
	_nTotalNodeCount = 0;
	_nCurNode = 0;
	_nTotalMtlCount = _ip->GetSceneMtls()->Count();
	_nCurMtl = 0;

	// Starting up the material exporting progress bar.
	_ip->ProgressStart(_T("Exporting materials..."), TRUE, fn, NULL);
	// Export materials by preprocessing the scenegraph. 
	if(!preProcess(_ip->GetRootNode(), _ip->GetTime())){
		// If user cancels we stop progress bar and return.
		_ip->ProgressEnd();
		isExporting = FALSE;
		return TRUE;
	}
	// We're done exporting materials. Finish the progress bar.
	_ip->ProgressEnd();

	// Starting up the node exporting progress bar.
	_ip->ProgressStart(_T("Exporting scene..."), TRUE, fn, NULL);

	// Get number of children for the root node in the interface.
	int numChildren = _ip->GetRootNode()->NumberOfChildren();
	
	// Call our node enumerator.
	// The nodeEnum function will recurse into itself and 
	// export each object found in the scene.
	for (int idx=0; idx<numChildren; idx++) {
		if (_ip->GetCancel() || !nodeEnum(rootTransform.get(), _ip->GetRootNode()->GetChildNode(idx), rootTransform.get())){
			// If user cancels we stop progress bar and return
			_ip->ProgressEnd();
			isExporting = FALSE;
			return TRUE;
		}
	}
	// Finish exporting progress bar
	_ip->ProgressEnd();


	// If optimize scene graph
	unsigned int optimizeMask = 0;
	if(_options->getTriStripGeometry())
		optimizeMask |= osgUtil::Optimizer::TRISTRIP_GEOMETRY;
	if(_options->getMergeGeometry())
		optimizeMask |= osgUtil::Optimizer::MERGE_GEOMETRY;
	if(_options->getFlattenStaticTransform())
		optimizeMask |= osgUtil::Optimizer::FLATTEN_STATIC_TRANSFORMS;
	if(_options->getShareDuplicateStates())
		optimizeMask |= osgUtil::Optimizer::SHARE_DUPLICATE_STATE;
	if(_options->getSpatializeGroups())
		optimizeMask |= osgUtil::Optimizer::SPATIALIZE_GROUPS;
	if(optimizeMask){
		_ip->ProgressStart(_T("Optimizing scenegraph..."), FALSE, fn, NULL);
		_ip->ProgressUpdate(0.5f); 
		osgUtil::Optimizer optimizer;
		optimizer.optimize(rootTransform.get(), optimizeMask);
		_ip->ProgressEnd();
	}
	 
	// Save file to disk.
	if(_options->getSaveFile()){
		_ip->ProgressStart(_T("Writing file..."), FALSE, fn, NULL);
		_ip->ProgressUpdate(0.5f); 
		if(_options->getExportExtension().compare(".osg")==0 ||
		   _options->getExportExtension().compare(".OSG")==0 ||
		   _options->getExportExtension().compare(".ive")==0 ||
		   _options->getExportExtension().compare(".IVE")==0   ){

			std::string filename(name);

			// Exclude image data from ive file if this options has been choosen
			if(!_options->getIncludeImageDataInIveFile()){
				osgDB::ReaderWriter::Options* opt = new osgDB::ReaderWriter::Options("noTexturesInIVEFile");
				osgDB::Registry::instance()->setOptions(opt);
			}


#if defined(OPENSCENEGRAPH_MAJOR_VERSION) && OPENSCENEGRAPH_MAJOR_VERSION >= 2 && defined(OPENSCENEGRAPH_MINOR_VERSION) && OPENSCENEGRAPH_MINOR_VERSION >= 4
            osgDB::ReaderWriter::WriteResult res = 
               osgDB::Registry::instance()->writeNode(*rootTransform, filename, NULL);
#else
            osgDB::ReaderWriter::WriteResult res = 
               osgDB::Registry::instance()->writeNode(*rootTransform, filename);
#endif

			if(res.error() && _options->getShowErrMsg()){
				static TCHAR szBuffer[256];
				wsprintf(szBuffer,TEXT("Error writing file %s:\n%s"), 
					     TEXT(filename.c_str()),res.message());
				MessageBox (GetActiveWindow(), szBuffer, TEXT("Warning"),
					        MB_OK | MB_ICONWARNING) ;
			}

			if(!_options->getIncludeImageDataInIveFile()){
                // Turn readerwriter options off again.
				osgDB::ReaderWriter::Options* opt = new osgDB::ReaderWriter::Options();
				osgDB::Registry::instance()->setOptions(opt);
            }
		}
		else{
			if(_options->getShowErrMsg()){
				std::string error("Can not find plugin to save file: ");
				error.append(name);
				MessageBox (GetActiveWindow(), error.c_str() , TEXT("Warning"), MB_OK | MB_ICONWARNING) ;
			}
		}
		_ip->ProgressEnd();
	}

	// Show quick preview
	if(_options->getQuickView()){

		float fNear = 1.0f;
		float fFar = 1000.0f;

		// Get the active viewport and the win32 window within it.
		// The position and size will be retreive from this.
		ViewExp* viewExp = _ip->GetActiveViewport();
		float fov = viewExp->GetFOV();
		HWND hWnd = viewExp->getGW()->getHWnd();
		RECT sRect;
		BOOL ok = GetWindowRect(hWnd, &sRect);
		int width = 100;
		int height = 100;
		int x =100;
		int y =100;
		if(ok){
			x = sRect.left;
			y = sRect.top;
			width = sRect.right - sRect.left;
			height = sRect.bottom - sRect.top;
		}

		// Create previewer window and set size.
		Previewer previewer;
		previewer.setWindowSize(x, y, width, height);


		// The affine TM transforms from world coords to view coords
		// so we need the inverse of this matrix
		Matrix3 aTM, camTM, coordSysTM;
		Point3 viewDir, viewPos, lookAtPos, upVector;
		INode* camera;
		float dist = 100;

		Point3 upperLeft = viewExp->MapScreenToView(IPoint2(0, 0), fFar);
		Point3 lowerRight = viewExp->MapScreenToView(IPoint2(width, height), fFar);
		
		viewExp->GetAffineTM(aTM);
		coordSysTM = Inverse(aTM);	

		viewDir = coordSysTM.VectorTransform(Point3(0.0f, 0.0f, -1.0f));
		viewPos = coordSysTM.GetRow(3);
		lookAtPos = viewPos + viewDir;
		upVector.Set(0.0f, 0.0f, 1.0f);

		switch(viewExp->GetViewType()){
			case VIEW_ISO_USER:
			case VIEW_PERSP_USER:
				previewer.setProjectionMatrixAsFrustum(lowerRight.x, upperLeft.x,  upperLeft.y, lowerRight.y, fFar, -fFar);
				break;
			case VIEW_CAMERA:
				previewer.setProjectionMatrixAsFrustum(upperLeft.x, lowerRight.x, lowerRight.y, upperLeft.y, fFar, -fFar);
				camera = viewExp->GetViewCamera();
				camTM = camera->GetObjTMBeforeWSM(_ip->GetTime());
				viewDir = camTM.VectorTransform(Point3(0.0f, 0.0f, -1.0f));
				viewPos = camTM.GetRow(3);
				lookAtPos = viewPos + viewDir;
				break;
			case VIEW_LEFT:
			case VIEW_RIGHT:
			case VIEW_TOP:
			case VIEW_BOTTOM:
			case VIEW_FRONT:
			case VIEW_BACK:
				previewer.setProjectionMatrixAsOrtho(upperLeft.x, lowerRight.x, lowerRight.y, upperLeft.y, -fFar, fFar);
				//cam->setOrtho(upperLeft.x, lowerRight.x, lowerRight.y, upperLeft.y, -fFar, fFar);
				// Go far away from the viewing point in the negative viewing direction.
				viewPos = coordSysTM.PointTransform(Point3(0.0f, 0.0f, fFar));
				lookAtPos = viewPos + viewDir;
				// In top view the up vector on the camera is the positive y-axis.
				if(viewExp->GetViewType() == VIEW_TOP)
					upVector.Set(0.0f, 1.0f, 0.0f);
				// In bottom view the up vector on the camera is the negative y-axis.
				if(viewExp->GetViewType() == VIEW_BOTTOM)
					upVector.Set(0.0f, -1.0f, 0.0f);
				break;
		}
		// When we are done with the viewport we should release it.
		_ip->ReleaseViewport(viewExp);

		// Set scene data.
		previewer.setSceneData(rootTransform.get());

		// set the view - OpenGL look at
		previewer.setViewMatrixAsLookAt(osg::Vec3( viewPos.x, viewPos.y, viewPos.z),
										 osg::Vec3(lookAtPos.x, lookAtPos.y, lookAtPos.z),
										 osg::Vec3(upVector.x, upVector.y, upVector.z) );
 		previewer.run();

		isExporting = FALSE;
		return TRUE;
	}
}
	isExporting = FALSE;
	return TRUE;
}
예제 #7
0
void Exporter::nodeTransform(Matrix33 &rot, Vector3 &trans, INode *node, TimeValue t, bool local)
{
	Matrix3 tm = getNodeTransform(node, t, local);
	convertMatrix(rot, tm);
	trans.Set(tm.GetTrans().x, tm.GetTrans().y, tm.GetTrans().z);
}