void CqTransform::ConcatCurrentTransform( TqFloat time, const CqMatrix& matTrans ) { TqFloat det = matTrans.Determinant(); bool flip = ( !matTrans.fIdentity() && det < 0 ); SqTransformation ct; ct.m_matTransform = matTrans; ct.m_Handedness = (flip)? !m_Handedness : m_Handedness; // If we are actually in a motion block, and we already describe a moving transform, // concatenate this transform with the existing one at that time slot, // ConcatTimeSlot will take care of making sure that the matrix is initially set to the // static matrix, as long as we ensure that the default is kept up to date. if ( QGetRenderContext() ->pconCurrent() ->fMotionBlock() ) { ConcatTimeSlot( time, ct ); m_IsMoving = true; } else // else, if we are moving, apply this transform at all time slots, otherwise apply to static matrix. { if( m_IsMoving ) ConcatAllTimeSlots( ct ); else { m_StaticMatrix = m_StaticMatrix * matTrans; m_Handedness = (flip)? !m_Handedness : m_Handedness; ct.m_Handedness = m_Handedness; SetDefaultObject( ct ); } } }
void CqTransform::SetCurrentTransform( TqFloat time, const CqMatrix& matTrans ) { TqFloat det = matTrans.Determinant(); bool flip = ( !matTrans.fIdentity() && det < 0 ); SqTransformation ct; ct.m_matTransform = matTrans; ct.m_Handedness = !flip; if ( QGetRenderContext() ->pconCurrent() ->fMotionBlock() ) { AddTimeSlot( time, ct ); m_IsMoving = true; } else { if( m_IsMoving ) { AddTimeSlot( time, ct ); } else { m_StaticMatrix = matTrans; m_Handedness = (flip)? !m_Handedness : m_Handedness; //m_Handedness = flip; ct.m_Handedness = flip; SetDefaultObject( ct ); } } }
void CqTransform::SetTransform( TqFloat time, const CqMatrix& matTrans ) { TqFloat det = matTrans.Determinant(); bool flip = ( !matTrans.fIdentity() && det < 0 ); CqMatrix matCtoW; QGetRenderContext()->matSpaceToSpace("world", "camera", NULL, NULL, QGetRenderContext()->Time(), matCtoW); TqFloat camdet = matCtoW.Determinant(); bool camhand = ( !matCtoW.fIdentity() && camdet < 0 ); if ( QGetRenderContext() ->pconCurrent() ->fMotionBlock() ) { SqTransformation ct; ct.m_Handedness = (flip)? !camhand : camhand; ct.m_matTransform = matTrans; AddTimeSlot( time, ct ); m_IsMoving = true; } else { // If not in a motion block, but we are moving, apply the transform to all keys. if( m_IsMoving ) { CqMatrix mat0 = matObjectToWorld(Time(0)); SqTransformation ct; ct.m_Handedness = (flip)? !camhand : camhand; bool hand0 = ct.m_Handedness; ct.m_matTransform = matTrans; AddTimeSlot( Time(0), ct ); TqInt i; for(i=1; i<cTimes(); i++) { CqMatrix matOffset = mat0 * matObjectToWorld(Time(i)).Inverse(); ct.m_matTransform = matOffset * matTrans; bool flip2 = ( matOffset.Determinant() < 0 ); ct.m_Handedness = (flip2)? !hand0 : hand0; AddTimeSlot( Time(i), ct); } } else { m_StaticMatrix = matTrans; m_Handedness = (flip)? !camhand : camhand; } } }
/** \brief Create a view from imageNum of the provided file. * * \param file - file from which to read the image data. * \param imageNum - subimage number for this view in the input file * \param currToWorld - current -> world transformation matrix. */ CqShadowView(const boost::shared_ptr<IqTiledTexInputFile>& file, TqInt imageNum, const CqMatrix& currToWorld) : m_currToLight(), m_currToRaster(), m_currToRasterVec(), m_viewDirec(), m_pixels(file, imageNum) { // TODO refactor with CqShadowSampler, also refactor this function, // since it's a bit unweildly... if(!file) AQSIS_THROW_XQERROR(XqInternal, EqE_NoFile, "Cannot construct shadow map from NULL file handle"); const CqTexFileHeader& header = file->header(imageNum); if(header.channelList().sharedChannelType() != Channel_Float32) AQSIS_THROW_XQERROR(XqBadTexture, EqE_BadFile, "Shadow maps must hold 32-bit floating point data"); // Get matrix which transforms the sample points to the light // camera coordinates. const CqMatrix* worldToLight = header.findPtr<Attr::WorldToCameraMatrix>(); if(!worldToLight) { AQSIS_THROW_XQERROR(XqBadTexture, EqE_BadFile, "No world -> camera matrix found in file \"" << file->fileName() << "\""); } m_currToLight = (*worldToLight) * currToWorld; // Get matrix which transforms the sample points to texture coordinates. const CqMatrix* worldToLightScreen = header.findPtr<Attr::WorldToScreenMatrix>(); if(!worldToLightScreen) { AQSIS_THROW_XQERROR(XqBadTexture, EqE_BadFile, "No world -> screen matrix found in file \"" << file->fileName() << "\""); } m_currToRaster = (*worldToLightScreen) * currToWorld; // worldToLightScreen transforms world coordinates to "screen" coordinates, // ie, onto the 2D box [-1,1]x[-1,1]. We instead want texture coordinates, // which correspond to the box [0,width]x[0,height]. In // addition, the direction of increase of the y-axis should be // swapped, since texture coordinates define the origin to be in // the top left of the texture rather than the bottom right. m_currToRaster.Translate(CqVector3D(1,-1,0)); m_currToRaster.Scale(0.5f, -0.5f, 1); // Transform the light origin to "current" space to use // when checking the visibility of a point. m_lightPos = m_currToLight.Inverse()*CqVector3D(0,0,0); // Transform the normal (0,0,1) in light space into a normal in // "current" space. The appropriate matrix is the inverse of the // cam -> light normal transformation, which itself is the inverse // transpose of currToLightVec. CqMatrix currToLightVec = m_currToLight; currToLightVec[3][0] = 0; currToLightVec[3][1] = 0; currToLightVec[3][2] = 0; m_viewDirec = currToLightVec.Transpose()*CqVector3D(0,0,1); m_viewDirec.Unit(); }
void CqZInputFile::readHeader(std::istream& inStream, CqTexFileHeader& header) { const char zFileMagicNum[] = "Aqsis ZFile"; const TqInt magicNumSize = sizeof(zFileMagicNum)-1; const TqInt versionNumSize = sizeof(AQSIS_VERSION_STR)-1; std::vector<char> buf(max(magicNumSize, versionNumSize)); // Read in magic number inStream.read(&buf[0], magicNumSize); if(!std::equal(buf.begin(), buf.begin() + magicNumSize, zFileMagicNum) || inStream.gcount() != magicNumSize) { AQSIS_THROW_XQERROR(XqBadTexture, EqE_BadFile, "Magic number missmatch in zfile"); } // Read in Aqsis version. We require this to match the current aqsis version. inStream.read(&buf[0], versionNumSize); if(!std::equal(buf.begin(), buf.begin() + versionNumSize, AQSIS_VERSION_STR) || inStream.gcount() != versionNumSize) { AQSIS_THROW_XQERROR(XqBadTexture, EqE_Version, "zfile was created with a different aqsis version"); } // Read in map width TqUint width = 0; inStream.read(reinterpret_cast<char*>(&width), sizeof(width)); if(inStream.gcount() != sizeof(width)) AQSIS_THROW_XQERROR(XqBadTexture, EqE_BadFile, "cannot read width from aqsis z-file"); // Read in map height TqUint height = 0; inStream.read(reinterpret_cast<char*>(&height), sizeof(height)); if(inStream.gcount() != sizeof(height)) AQSIS_THROW_XQERROR(XqBadTexture, EqE_BadFile, "cannot read height from aqsis z-file"); // Read world to camera transformation matrix CqMatrix worldToCamera; worldToCamera.SetfIdentity(false); inStream.read(reinterpret_cast<char*>(worldToCamera.pElements()), 16*sizeof(TqFloat)); if(inStream.gcount() != 16*sizeof(TqFloat)) AQSIS_THROW_XQERROR(XqBadTexture,EqE_BadFile, "could not read world to camera matrix from aqsis z-file"); // Read world to screen transformation matrix CqMatrix worldToScreen; worldToScreen.SetfIdentity(false); inStream.read(reinterpret_cast<char*>(worldToScreen.pElements()), 16*sizeof(TqFloat)); if(inStream.gcount() != 16*sizeof(TqFloat)) AQSIS_THROW_XQERROR(XqBadTexture, EqE_BadFile, "could not read world to screen matrix from aqsis z-file"); // Save the read header attributes into the file header. header.setWidth(width); header.setHeight(height); header.set<Attr::WorldToScreenMatrix>(worldToScreen); header.set<Attr::WorldToCameraMatrix>(worldToCamera); // Complete the header with some other attributes implied by the file format header.set<Attr::TextureFormat>(TextureFormat_Shadow); header.channelList().addChannel(SqChannelInfo("z", Channel_Float32)); }
/** \brief Create a view from imageNum of the provided file. * * \param file - file from which to read the image data. * \param imageNum - subimage number for this view in the input file * \param currToWorld - current -> world transformation matrix. */ CqOccView(const boost::shared_ptr<IqTiledTexInputFile>& file, TqInt imageNum, const CqMatrix& currToWorld) : m_currToLight(), m_currToRaster(), m_currToRasterVec(), m_negViewDirec(), m_pixels(file, imageNum) { // TODO refactor with CqShadowSampler, also refactor this function, // since it's a bit unweildly... if(!file) AQSIS_THROW_XQERROR(XqInternal, EqE_NoFile, "Cannot construct shadow map from NULL file handle"); const CqTexFileHeader& header = file->header(imageNum); if(header.channelList().sharedChannelType() != Channel_Float32) AQSIS_THROW_XQERROR(XqBadTexture, EqE_BadFile, "Shadow maps must hold 32-bit floating point data"); // Get matrix which transforms the sample points to the light // camera coordinates. const CqMatrix* worldToLight = header.findPtr<Attr::WorldToCameraMatrix>(); if(!worldToLight) { AQSIS_THROW_XQERROR(XqBadTexture, EqE_BadFile, "No world -> camera matrix found in file \"" << file->fileName() << "\""); } m_currToLight = (*worldToLight) * currToWorld; // Get matrix which transforms the sample points to texture coordinates. const CqMatrix* worldToLightScreen = header.findPtr<Attr::WorldToScreenMatrix>(); if(!worldToLightScreen) { AQSIS_THROW_XQERROR(XqBadTexture, EqE_BadFile, "No world -> screen matrix found in file \"" << file->fileName() << "\""); } m_currToRaster = (*worldToLightScreen) * currToWorld; // worldToLightScreen transforms world coordinates to "screen" coordinates, // ie, onto the 2D box [-1,1]x[-1,1]. We instead want texture coordinates, // which correspond to the box [0,width]x[0,height]. In // addition, the direction of increase of the y-axis should be // swapped, since texture coordinates define the origin to be in // the top left of the texture rather than the bottom right. m_currToRaster.Translate(CqVector3D(1,-1,0)); m_currToRaster.Scale(0.5f*header.width(), -0.5f*header.height(), 1); // This extra translation is by half a pixel width - it moves the // raster coordinates m_currToRaster.Translate(CqVector3D(-0.5,-0.5,0)); // Convert current -> texture transformation into a vector // transform rather than a point transform. // TODO: Put this stuff into the CqMatrix class? m_currToRasterVec = m_currToRaster; m_currToRasterVec[3][0] = 0; m_currToRasterVec[3][1] = 0; m_currToRasterVec[3][2] = 0; // This only really makes sense when the matrix is affine rather // than projective, ie, the last column is (0,0,0,h) // // TODO: Investigate whether this is really correct. // assert(m_currToRasterVec[0][3] == 0); // assert(m_currToRasterVec[1][3] == 0); // assert(m_currToRasterVec[2][3] == 0); m_currToRasterVec[0][3] = 0; m_currToRasterVec[1][3] = 0; m_currToRasterVec[2][3] = 0; // Transform the normal (0,0,1) in light space into a normal in // "current" space. The appropriate matrix is the inverse of the // cam -> light normal transformation, which itself is the inverse // transpose of currToLightVec. CqMatrix currToLightVec = m_currToLight; currToLightVec[3][0] = 0; currToLightVec[3][1] = 0; currToLightVec[3][2] = 0; m_negViewDirec = currToLightVec.Transpose()*CqVector3D(0,0,-1); m_negViewDirec.Unit(); }