//-***************************************************************************** M44d getFinalMatrix( IObject &iObj ) { M44d xf; xf.makeIdentity(); IObject parent = iObj.getParent(); while ( parent ) { accumXform( xf, parent ); parent = parent.getParent(); } return xf; }
/// Guess position in 3D corresponding to a 2D click /// /// `clickPos` - 2D position in viewport, as from a mouse event. Imath::V3d View3D::guessClickPosition(const QPoint& clickPos) { // Get new point in the projected coordinate system using the click // position x,y and the z of a reference position. Take the reference point // of interest to be between the camera rotation center and the camera // position, as a rough guess of the depth the user is interested in. // // This works pretty well, except when there are noise points intervening // between the reference position and the user's actual point of interest. V3d refPos = 0.3*m_camera.position() + 0.7*m_camera.center(); M44d mat = m_camera.viewMatrix()*m_camera.projectionMatrix()*m_camera.viewportMatrix(); double refZ = (refPos * mat).z; V3d newPointProj(clickPos.x(), clickPos.y(), refZ); // Map projected point back into model coordinates return newPointProj * mat.inverse(); }
void ofxAlembic::IXform::updateWithTimeInternal(double time, Imath::M44f& transform) { ISampleSelector ss(time, ISampleSelector::kNearIndex); M44f mat; M44d m = m_xform.getSchema().getValue(ss).getMatrix(); double *src = m.getValue(); float *dst = mat.getValue(); for (int i = 0; i < 16; i++) dst[i] = src[i]; transform = mat * transform; for (int i = 0; i < 16; i++) { xform.local_matrix.getPtr()[i] = mat.getValue()[i]; xform.global_matrix.getPtr()[i] = transform.getValue()[i]; } }
void MatrixFieldMapping::updateTransform() { typedef MatrixCurve::SampleVec::const_iterator SampleIter; // Build the voxel to world space transforms --- M44d lsToVs; getLocalToVoxelMatrix(lsToVs); M44d vsToLs = lsToVs.inverse(); // Loop over all samples in lsToWs, append vsToLs and create new curve // Also handle the special case where lsToWs has no samples. In that // case m_vsToWsCurve still has to have one sample. const MatrixCurve::SampleVec &lsToWs = m_lsToWsCurve.samples(); m_vsToWsCurve.clear(); for (SampleIter i = lsToWs.begin(), end = lsToWs.end(); i != end; i++) { m_vsToWsCurve.addSample(i->first, vsToLs * i->second); } // See if the curve has more than just a single sample m_isTimeVarying = m_lsToWsCurve.numSamples() > 1; // Sample the time-varying transforms at time=0.0 m_lsToWs = m_lsToWsCurve.linear(0.0); m_wsToLs = m_lsToWs.inverse(); m_vsToWs = vsToLs * m_lsToWs; m_wsToVs = m_vsToWs.inverse(); // Precompute the voxel size V3d voxelOrigin, nextVoxel; m_vsToWs.multVecMatrix(V3d(0, 0, 0), voxelOrigin); m_vsToWs.multVecMatrix(V3d(1, 0, 0), nextVoxel); m_wsVoxelSize.x = (nextVoxel - voxelOrigin).length(); m_vsToWs.multVecMatrix(V3d(0, 1, 0), nextVoxel); m_wsVoxelSize.y = (nextVoxel - voxelOrigin).length(); m_vsToWs.multVecMatrix(V3d(0, 0, 1), nextVoxel); m_wsVoxelSize.z = (nextVoxel - voxelOrigin).length(); }
void FrustumFieldMapping::setTransforms(float t, const M44d &ssToWs, const M44d &csToWs) { if (m_defaultState) { clearCurves(); m_defaultState = false; } // Construct local-to-world transform from ssToWs M44d lsToSs, scale, translation; scale.setScale(V3d(2.0, 2.0, 1.0)); translation.setTranslation(V3d(-1.0, -1.0, 0.0)); lsToSs = scale * translation; M44d lpsToWs = lsToSs * ssToWs; // Add samples to Curves m_ssToWsCurve.addSample(t, ssToWs); m_lpsToWsCurve.addSample(t, lpsToWs); m_csToWsCurve.addSample(t, csToWs); // Compute near and far planes --- // Because the frustum may be skewed we can't just measure distance from // the apex of the frustum to the world-space center point of the frustum. // Instead, we transform into camera space and measure z depth there. V3d lsNearP(0.5, 0.5, 0.0), lsFarP(0.5, 0.5, 1.0); V3d wsNearP, wsFarP, csNearP, csFarP; lpsToWs.multVecMatrix(lsNearP, wsNearP); lpsToWs.multVecMatrix(lsFarP, wsFarP); M44d wsToCs = csToWs.inverse(); wsToCs.multVecMatrix(wsNearP, csNearP); wsToCs.multVecMatrix(wsFarP, csFarP); double near = -csNearP.z; double far = -csFarP.z; // Catch NaN here if (isnan(near) || isnan(far)) { throw BadPerspectiveMatrix("FrustumFieldMapping::setTransforms " "received bad screen-to-world matrix"); } m_nearCurve.addSample(t, near); m_farCurve.addSample(t, far); computeVoxelSize(); }
void FrustumFieldMapping::reset() { // Default camera to world --- M44d csToWs; csToWs.makeIdentity(); // Default screen to world --- double near = 1; double far = 2; double fovRadians = 45.0 * M_PI / 180.0; double invTan = 1.0 / std::tan(fovRadians / 2.0); double imageAspectRatio = 1.0; M44d perspective(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, (far) / (far - near), 1, 0, 0, (- far * near) / (far - near), 0); M44d fov; fov.setScale(V3d(invTan / imageAspectRatio, invTan, 1.0)); M44d flipZ; flipZ.setScale(V3d(1.0, 1.0, -1.0)); M44d csToSs = flipZ * perspective * fov; M44d standardSsToWs = csToSs.inverse() * csToWs; // Set default state --- clearCurves(); setTransforms(standardSsToWs, csToWs); m_defaultState = true; computeVoxelSize(); }
//-***************************************************************************** void xformOut() { OArchive archive( Alembic::AbcCoreOgawa::WriteArchive(), "Xform1.abc" ); OXform a( OObject( archive, kTop ), "a" ); OXform b( a, "b" ); OXform c( b, "c" ); OXform d( c, "d" ); OXform e( d, "e" ); OXform f( e, "f" ); OXform g( f, "g" ); XformOp transop( kTranslateOperation, kTranslateHint ); XformOp scaleop( kScaleOperation, kScaleHint ); XformOp matrixop( kMatrixOperation, kMatrixHint ); TESTING_ASSERT( a.getSchema().getNumSamples() == 0 ); OBox3dProperty childBounds = a.getSchema().getChildBoundsProperty(); XformSample asamp; for ( size_t i = 0; i < 20; ++i ) { asamp.addOp( transop, V3d( 12.0, i + 42.0, 20.0 ) ); if ( i >= 18 ) { childBounds.set( Abc::Box3d( V3d( -1.0, -1.0, -1.0 ), V3d( 1.0, 1.0, 1.0 ) ) ); } else { childBounds.set( Abc::Box3d() ); } a.getSchema().set( asamp ); } XformSample bsamp; for ( size_t i = 0 ; i < 20 ; ++i ) { bsamp.setInheritsXforms( (bool)(i&1) ); b.getSchema().set( bsamp ); } // for c we write nothing XformSample dsamp; dsamp.addOp( scaleop, V3d( 3.0, 6.0, 9.0 ) ); d.getSchema().set( dsamp ); XformSample esamp; M44d identmat; identmat.makeIdentity(); esamp.addOp( transop, V3d( 0.0, 0.0, 0.0 ) ); esamp.addOp( XformOp( kMatrixOperation, kMatrixHint ), identmat ); esamp.addOp( scaleop, V3d( 1.0, 1.0, 1.0 ) ); e.getSchema().set( esamp ); XformSample fsamp; fsamp.addOp( transop, V3d( 3.0, -4.0, 5.0 ) ); f.getSchema().set( fsamp ); // this will cause the Xform's values property to be an ArrayProperty, // since there will be 20 * 16 channels. XformSample gsamp; Abc::M44d gmatrix; gmatrix.makeIdentity(); for ( size_t i = 0 ; i < 20 ; ++i ) { gmatrix.x[0][1] = (double)i; gsamp.addOp( matrixop, gmatrix ); } g.getSchema().set( gsamp ); }
//-***************************************************************************** void someOpsXform() { std::string name = "someOpsXform.abc"; { OArchive archive( Alembic::AbcCoreOgawa::WriteArchive(), name ); OXform a( OObject( archive, kTop ), "a" ); OBox3dProperty bnds = CreateOArchiveBounds( archive ); XformOp transop( kTranslateOperation, kTranslateHint ); XformOp scaleop( kScaleOperation, kScaleHint ); XformSample asamp; // scale asamp.addOp( scaleop, V3d( 2.0, 1.0, 2.0 ) ); // Maya-like shear XformOp shearmatrixop( kMatrixOperation, kMayaShearHint ); M44d shearmat; shearmat.makeIdentity(); asamp.addOp( shearmatrixop, shearmat ); // rotate x axis XformOp rotop( kRotateOperation, kRotateHint ); asamp.addOp( rotop, V3d( 1.0, 0.0, 0.0 ), 1.57 ); // rotate y axis, angle will be animated asamp.addOp( rotop, V3d( 0.0, 1.0, 0.0 ), 0.125 ); // rotate z axis, use a different hint for fun XformOp rotorientop( kRotateOperation, kRotateOrientationHint ); asamp.addOp( rotorientop, V3d( 0.0, 0.0, 1.0 ), 0.1 ); // translate with animated y and z, different hint for fun XformOp transpivotop( kTranslateOperation, kRotatePivotPointHint ); asamp.addOp( transpivotop, V3d( 0.0, 0.0, 0.0 ) ); a.getSchema().set( asamp ); bnds.set( Box3d( V3d( -0.1, -0.1, -0.1 ), V3d( 0.1, 0.1, 0.1 ) ) ); for (size_t i = 1; i < 5 ; ++i) { asamp.addOp( scaleop, V3d( 2 * ( i + 1 ), 1.0, 2.0 ) ); shearmat.x[1][0] = (double)i; shearmat.x[2][0] = (double)( (int)i * -1.0 ); shearmat.x[2][1] = 0.0; asamp.addOp( shearmatrixop, shearmat ); asamp.addOp( rotop, V3d( 1.0, 0.0, 0.0 ), 1.57 ); asamp.addOp( rotop, V3d( 0.0, 1.0, 0.0 ), 0.125 * ( i + 1 ) ); asamp.addOp( rotorientop, V3d( 0.0, 0.0, 1.0 ), 0.1 * ( i + 1 ) ); asamp.addOp( transpivotop, V3d( 0.0, 3.0 * i, 4.0 * i ) ); a.getSchema().set( asamp ); double iVal = static_cast< double >( i ); bnds.set( Box3d( V3d( -iVal, -iVal, -iVal ), V3d( iVal, iVal, iVal ) ) ); } } { IArchive archive( Alembic::AbcCoreOgawa::ReadArchive(), name ); IXform a( IObject( archive, kTop ), "a" ); IBox3dProperty bnds = GetIArchiveBounds( archive ); XformSample asamp; a.getSchema().get( asamp ); TESTING_ASSERT( a.getSchema().getNumOps() == 6 ); TESTING_ASSERT( asamp[0].isScaleOp() ); TESTING_ASSERT( asamp[0].getHint() == kScaleHint ); TESTING_ASSERT( asamp[1].isMatrixOp() ); TESTING_ASSERT( asamp[1].getHint() == kMayaShearHint ); TESTING_ASSERT( asamp[2].isRotateOp() ); TESTING_ASSERT( asamp[2].getHint() == kRotateHint ); TESTING_ASSERT( asamp[3].getType() == kRotateOperation ); TESTING_ASSERT( asamp[3].getHint() == kRotateHint ); TESTING_ASSERT( asamp[4].getType() == kRotateOperation ); TESTING_ASSERT( asamp[4].getHint() == kRotateOrientationHint ); TESTING_ASSERT( asamp[5].getType() == kTranslateOperation ); TESTING_ASSERT( asamp[5].getHint() == kRotatePivotPointHint ); TESTING_ASSERT( asamp[0].isXAnimated() ); TESTING_ASSERT( !asamp[0].isYAnimated() ); TESTING_ASSERT( !asamp[0].isZAnimated() ); TESTING_ASSERT( !asamp[1].isChannelAnimated(0) ); // [0][0] TESTING_ASSERT( !asamp[1].isChannelAnimated(1) ); // [0][1] TESTING_ASSERT( !asamp[1].isChannelAnimated(2) ); // [0][2] TESTING_ASSERT( !asamp[1].isChannelAnimated(3) ); // [0][3] TESTING_ASSERT( asamp[1].isChannelAnimated(4) ); // [1][0] TESTING_ASSERT( !asamp[1].isChannelAnimated(5) ); // [1][1] TESTING_ASSERT( !asamp[1].isChannelAnimated(6) ); // [1][2] TESTING_ASSERT( !asamp[1].isChannelAnimated(7) ); // [1][3] TESTING_ASSERT( asamp[1].isChannelAnimated(8) ); // [2][0] TESTING_ASSERT( !asamp[1].isChannelAnimated(9) ); // [2][1] TESTING_ASSERT( !asamp[1].isChannelAnimated(10) ); // [2][2] TESTING_ASSERT( !asamp[1].isChannelAnimated(11) ); // [2][3] TESTING_ASSERT( !asamp[1].isChannelAnimated(12) ); // [3][0] TESTING_ASSERT( !asamp[1].isChannelAnimated(13) ); // [3][1] TESTING_ASSERT( !asamp[1].isChannelAnimated(14) ); // [3][2] TESTING_ASSERT( !asamp[1].isChannelAnimated(15) ); // [3][3] TESTING_ASSERT( !asamp[2].isXAnimated() ); TESTING_ASSERT( !asamp[2].isYAnimated() ); TESTING_ASSERT( !asamp[2].isZAnimated() ); TESTING_ASSERT( !asamp[2].isAngleAnimated() ); TESTING_ASSERT( !asamp[3].isXAnimated() ); TESTING_ASSERT( !asamp[3].isYAnimated() ); TESTING_ASSERT( !asamp[3].isZAnimated() ); TESTING_ASSERT( asamp[3].isAngleAnimated() ); TESTING_ASSERT( !asamp[4].isXAnimated() ); TESTING_ASSERT( !asamp[4].isYAnimated() ); TESTING_ASSERT( !asamp[4].isZAnimated() ); TESTING_ASSERT( asamp[4].isAngleAnimated() ); TESTING_ASSERT( !asamp[5].isXAnimated() ); TESTING_ASSERT( asamp[5].isYAnimated() ); TESTING_ASSERT( asamp[5].isZAnimated() ); // OK, now check the values came through M44d shearmat; shearmat.makeIdentity(); TESTING_ASSERT( asamp[0].getScale() == V3d( 2.0, 1.0, 2.0 ) ); TESTING_ASSERT( asamp[1].getMatrix() == shearmat ); TESTING_ASSERT( asamp[2].getAxis() == V3d( 1.0, 0.0, 0.0 ) ); TESTING_ASSERT( almostEqual( asamp[2].getAngle(), 1.57 ) ); TESTING_ASSERT( asamp[3].getAxis() == V3d( 0.0, 1.0, 0.0 ) ); TESTING_ASSERT( almostEqual( asamp[3].getAngle(), 0.125 ) ); TESTING_ASSERT( asamp[4].getAxis() == V3d( 0.0, 0.0, 1.0 ) ); TESTING_ASSERT( almostEqual( asamp[4].getAngle(), 0.1 ) ); TESTING_ASSERT( asamp[5].getTranslate() == V3d( 0.0, 0.0, 0.0 ) ); TESTING_ASSERT( bnds.getValue() == Box3d( V3d( -0.1, -0.1, -0.1 ), V3d( 0.1, 0.1, 0.1 ) ) ); for ( index_t i = 1; i < 5 ; ++i ) { a.getSchema().get( asamp, ISampleSelector( i ) ); TESTING_ASSERT( asamp[0].getScale() == V3d( 2 * ( i + 1 ), 1.0, 2.0 ) ); shearmat.x[1][0] = (double)i; shearmat.x[2][0] = (double)( (int)i * -1.0 ); shearmat.x[2][1] = 0.0; TESTING_ASSERT( asamp[1].getMatrix() == shearmat ); TESTING_ASSERT( asamp[2].getAxis() == V3d( 1.0, 0.0, 0.0 ) ); TESTING_ASSERT( almostEqual( asamp[2].getAngle(), 1.57 ) ); TESTING_ASSERT( asamp[3].getAxis() == V3d( 0.0, 1.0, 0.0 ) ); TESTING_ASSERT( almostEqual( asamp[3].getAngle(), 0.125 * ( i + 1 ) ) ); TESTING_ASSERT( asamp[4].getAxis() == V3d( 0.0, 0.0, 1.0 ) ); TESTING_ASSERT( almostEqual( asamp[4].getAngle(), 0.1 * ( i + 1 ) ) ); V3d tvec( 0.0, 3.0 * i, 4.0 * i ); TESTING_ASSERT( tvec.equalWithAbsError( asamp[5].getTranslate(), VAL_EPSILON ) ); Box3d b = bnds.getValue( ISampleSelector( i ) ); double iVal = static_cast< double >( i ); TESTING_ASSERT( b == Box3d( V3d( -iVal, -iVal, -iVal ), V3d( iVal, iVal, iVal ) ) ); } std::cout << "tested all xforms in " << name << std::endl; } }
void exportF3d::setF3dField(MFnFluid &fluidFn, const char *outputPath, const MDagPath &dagPath) { try { MStatus stat; unsigned int i, xres = 0, yres = 0, zres = 0; double xdim,ydim,zdim; // Get the resolution of the fluid container stat = fluidFn.getResolution(xres, yres, zres); stat = fluidFn.getDimensions(xdim, ydim, zdim); V3d size(xdim,ydim,zdim); const V3i res(xres, yres, zres); int psizeTot = fluidFn.gridSize(); /// get the transform and rotation MObject parentObj = fluidFn.parent(0, &stat); if (stat != MS::kSuccess) { MGlobal::displayError("Can't find fluid's parent node"); return; } MDagPath parentPath = dagPath; parentPath.pop(); MTransformationMatrix tmatFn(dagPath.inclusiveMatrix()); if (stat != MS::kSuccess) { MGlobal::displayError("Failed to get transformation matrix of fluid's parent node"); return; } MFnTransform fnXform(parentPath, &stat); if (stat != MS::kSuccess) { MGlobal::displayError("Can't create a MFnTransform from fluid's parent node"); return; } if (m_verbose) { fprintf(stderr, "cellnum: %dx%dx%d = %d\n", xres, yres, zres,psizeTot); } float *density(NULL), *temp(NULL), *fuel(NULL); float *pressure(NULL), *falloff(NULL); density = fluidFn.density( &stat ); if ( stat.error() ) m_density = false; temp = fluidFn.temperature( &stat ); if ( stat.error() ) m_temperature = false; fuel = fluidFn.fuel( &stat ); if ( stat.error() ) m_fuel = false; pressure= fluidFn.pressure( &stat ); if ( stat.error() ) m_pressure = false; falloff = fluidFn.falloff( &stat ); if ( stat.error() ) m_falloff = false; float *r,*g,*b; if (m_color) { stat = fluidFn.getColors(r,b,g); if ( stat.error() ) m_color = false; }else m_color = false; float *u,*v,*w; if (m_texture) { stat = fluidFn.getCoordinates(u,v,w); if ( stat.error() ) m_texture = false; }else m_texture = false; /// velocity info float *Xvel(NULL),*Yvel(NULL), *Zvel(NULL); if (m_vel) { stat = fluidFn.getVelocity( Xvel,Yvel,Zvel ); if ( stat.error() ) m_vel = false; } if (m_density == false && m_temperature==false && m_fuel==false && m_pressure==false && m_falloff==false && m_vel == false && m_color == false && m_texture==false) { MGlobal::displayError("No fluid attributes found for writing, please check fluids settings"); return; } /// Fields DenseFieldf::Ptr densityFld, tempFld, fuelFld, pressureFld, falloffFld; DenseField3f::Ptr CdFld, uvwFld; MACField3f::Ptr vMac; MPlug autoResizePlug = fluidFn.findPlug("autoResize", &stat); bool autoResize; autoResizePlug.getValue(autoResize); // maya's fluid transformation V3d dynamicOffset(0); M44d localToWorld; MatrixFieldMapping::Ptr mapping(new MatrixFieldMapping()); M44d fluid_mat(tmatFn.asMatrix().matrix); if(autoResize) { fluidFn.findPlug("dofx").getValue(dynamicOffset[0]); fluidFn.findPlug("dofy").getValue(dynamicOffset[1]); fluidFn.findPlug("dofz").getValue(dynamicOffset[2]); } Box3i extents; extents.max = res - V3i(1); extents.min = V3i(0); mapping->setExtents(extents); localToWorld.setScale(size); localToWorld *= M44d().setTranslation( -(size*0.5) ); localToWorld *= M44d().setTranslation( dynamicOffset ); localToWorld *= fluid_mat; mapping->setLocalToWorld(localToWorld); if (m_density){ densityFld = new DenseFieldf; densityFld->setSize(res); densityFld->setMapping(mapping); } if (m_fuel){ fuelFld = new DenseFieldf; fuelFld->setSize(res); fuelFld->setMapping(mapping); } if (m_temperature){ tempFld = new DenseFieldf; tempFld->setSize(res); tempFld->setMapping(mapping); } if (m_pressure){ pressureFld = new DenseFieldf; pressureFld->setSize(res); pressureFld->setMapping(mapping); } if (m_falloff){ falloffFld = new DenseFieldf; falloffFld->setSize(res); falloffFld->setMapping(mapping); } if (m_vel){ vMac = new MACField3f; vMac->setSize(res); vMac->setMapping(mapping); } if (m_color){ CdFld = new DenseField3f; CdFld->setSize(res); CdFld->setMapping(mapping); } if (m_texture){ uvwFld = new DenseField3f; uvwFld->setSize(res); uvwFld->setMapping(mapping); } size_t iX, iY, iZ; for( iZ = 0; iZ < zres; iZ++ ) { for( iX = 0; iX < xres; iX++ ) { for( iY = 0; iY < yres ; iY++ ) { /// data is in x major but we are writting in z major order i = fluidFn.index( iX, iY, iZ); if ( m_density ) densityFld->lvalue(iX, iY, iZ) = density[i]; if ( m_temperature ) tempFld->lvalue(iX, iY, iZ) = temp[i]; if ( m_fuel ) fuelFld->lvalue(iX, iY, iZ) = fuel[i]; if ( m_pressure ) pressureFld->lvalue(iX, iY, iZ) = pressure[i]; if ( m_falloff ) falloffFld->lvalue(iX, iY, iZ) = falloff[i]; if (m_color) CdFld->lvalue(iX, iY, iZ) = V3f(r[i], g[i], b[i]); if (m_texture) uvwFld->lvalue(iX, iY, iZ) = V3f(u[i], v[i], w[i]); } } } if (m_vel) { unsigned x,y,z; for(z=0;z<zres;++z) for(y=0;y<yres;++y) for(x=0;x<xres+1;++x) { vMac->u(x,y,z) = *Xvel++; } for(z=0;z<zres;++z) for(y=0;y<yres+1;++y) for(x=0;x<xres;++x) { vMac->v(x,y,z) = *Yvel++; } for(z=0;z<zres+1;++z) for(y=0;y<yres;++y) for(x=0;x<xres;++x) { vMac->w(x,y,z) = *Zvel++; } } Field3DOutputFile out; if (!out.create(outputPath)) { MGlobal::displayError("Couldn't create file: "+ MString(outputPath)); return; } string fieldname("maya"); if (m_density){ out.writeScalarLayer<float>(fieldname, "density", densityFld); } if (m_fuel) { out.writeScalarLayer<float>(fieldname,"fuel", fuelFld); } if (m_temperature){ out.writeScalarLayer<float>(fieldname,"temperature", tempFld); } if (m_color) { out.writeVectorLayer<float>(fieldname,"Cd", CdFld); } if (m_vel) out.writeVectorLayer<float>(fieldname,"v_mac", vMac); out.close(); } catch(const std::exception &e) { MGlobal::displayError( MString(e.what()) ); return; } }