Exemple #1
0
PXR_NAMESPACE_OPEN_SCOPE


PxrUsdKatanaUsdInPrivateData::PxrUsdKatanaUsdInPrivateData(
        const UsdPrim& prim,
        PxrUsdKatanaUsdInArgsRefPtr usdInArgs,
        const PxrUsdKatanaUsdInPrivateData* parentData)
    : _prim(prim), _usdInArgs(usdInArgs), _extGb(0)
{
    // XXX: manually track instance and master path for possible
    //      relationship re-retargeting. This approach does not yet
    //      support nested instances -- which is expected to be handled
    //      via the forthcoming GetMasterWithContext.
    //
    if (prim.IsInstance())
    {
        if (prim.IsInMaster() && parentData)
        {
            SdfPath descendentPrimPath = 
                prim.GetPath().ReplacePrefix(
                    prim.GetPath().GetPrefixes()[0], 
                    SdfPath::ReflexiveRelativePath());

            _instancePath = parentData->GetInstancePath().AppendPath(
                descendentPrimPath);
        }
        else
        {
            _instancePath = prim.GetPath();
        }

        const UsdPrim& masterPrim = prim.GetMaster();            
        if (masterPrim)
        {
            _masterPath = masterPrim.GetPath();
        }
    }
    else if (parentData)
    {
        // Pass along instance and master paths to children.
        //
        if (!parentData->GetInstancePath().IsEmpty())
        {
            _instancePath = parentData->GetInstancePath();
        }

        if (!parentData->GetMasterPath().IsEmpty())
        {
            _masterPath = parentData->GetMasterPath();
        }
    }

    //
    // Apply session overrides for motion.
    //

    const std::string primPath = prim.GetPrimPath().GetString();
    const std::string isolatePath = usdInArgs->GetIsolatePath();
    const std::string sessionPath = usdInArgs->GetSessionLocationPath();
    FnKat::GroupAttribute sessionAttr = usdInArgs->GetSessionAttr();

    // XXX: If an isolatePath has been specified, it means the PxrUsdIn is
    // probably loading USD contents below the USD root. This can prevent
    // overrides from trickling down the hierarchy, e.g. the overrides for /A/B
    // won't get applied to children if the isolatePath is /A/B/C/D.
    //
    // So, if the usdInArgs suggest that an isolatePath has been specified and
    // we don't have any parentData, we'll need to check if there are overrides
    // for the prim and any of its parents.
    //
    std::vector<std::string> pathsToCheck;
    if (!parentData and !isolatePath.empty() and
        pystring::startswith(primPath, isolatePath+"/"))
    {
        std::vector<std::string> parentLocs;
        Foundry::Katana::Util::Path::GetLocationStack(parentLocs, primPath);
        std::reverse(std::begin(parentLocs), std::end(parentLocs));
        for (size_t i = 0; i < parentLocs.size(); ++i)
        {
            pathsToCheck.push_back(FnKat::DelimiterEncode(
                    sessionPath + parentLocs[i]));
        }
    }
    else
    {
        pathsToCheck.push_back(FnKat::DelimiterEncode(sessionPath + primPath));
    }

    //
    // If a session override is specified, use its value. If no override exists,
    // try asking the parent data for its value. Otherwise, fall back on the
    // usdInArgs value.
    //

    bool overrideFound;

    // Current time.
    //
    overrideFound = false;
    for (size_t i = 0; i < pathsToCheck.size(); ++i)
    {
        FnKat::FloatAttribute currentTimeAttr =
            sessionAttr.getChildByName(
                "overrides."+pathsToCheck[i]+".currentTime");
        if (currentTimeAttr.isValid())
        {
            _currentTime = currentTimeAttr.getValue();
            overrideFound = true;
            break;
        }
    }
    if (!overrideFound)
    {
        if (parentData)
        {
            _currentTime = parentData->GetCurrentTime();
        }
        else
        {
            _currentTime = usdInArgs->GetCurrentTime();
        }
    }

    // Shutter open.
    //
    overrideFound = false;
    for (size_t i = 0; i < pathsToCheck.size(); ++i)
    {
        FnKat::FloatAttribute shutterOpenAttr =
                sessionAttr.getChildByName(
                    "overrides."+pathsToCheck[i]+".shutterOpen");
        if (shutterOpenAttr.isValid())
        {
            _shutterOpen = shutterOpenAttr.getValue();
            overrideFound = true;
            break;
        }
    }
    if (!overrideFound)
    {
        if (parentData)
        {
            _shutterOpen = parentData->GetShutterOpen();
        }
        else
        {
            _shutterOpen = usdInArgs->GetShutterOpen();
        }
    }

    // Shutter close.
    //
    overrideFound = false;
    for (size_t i = 0; i < pathsToCheck.size(); ++i)
    {
        FnKat::FloatAttribute shutterCloseAttr =
                sessionAttr.getChildByName(
                    "overrides."+pathsToCheck[i]+".shutterClose");
        if (shutterCloseAttr.isValid())
        {
            _shutterClose = shutterCloseAttr.getValue();
            overrideFound = true;
            break;
        }
    }
    if (!overrideFound)
    {
        if (parentData)
        {
            _shutterClose = parentData->GetShutterClose();
        }
        else
        {
            _shutterClose = usdInArgs->GetShutterClose();
        }
    }

    // Motion sample times.
    //
    // Fallback logic is a little more complicated for motion sample times, as
    // they can vary per attribute, so store both the overridden and the
    // fallback motion sample times for use inside GetMotionSampleTimes.
    //
    for (size_t i = 0; i < pathsToCheck.size(); ++i)
    {
        FnKat::Attribute motionSampleTimesAttr =
                sessionAttr.getChildByName(
                    "overrides."+pathsToCheck[i]+".motionSampleTimes");
        if (motionSampleTimesAttr.isValid())
        {
            // Interpret an IntAttribute as "use usdInArgs defaults"
            //
            if (motionSampleTimesAttr.getType() == kFnKatAttributeTypeInt)
            {
                _motionSampleTimesOverride = usdInArgs->GetMotionSampleTimes();
                break;
            }
            // Interpret a FloatAttribute as an explicit value override
            //
            if (motionSampleTimesAttr.getType() == kFnKatAttributeTypeFloat)
            {
                const auto& sampleTimes = FnKat::FloatAttribute(
                        motionSampleTimesAttr).getNearestSample(0);
                if (!sampleTimes.empty())
                {
                    for (float sampleTime : sampleTimes)
                        _motionSampleTimesOverride.push_back(
                            (double)sampleTime);
                    break;
                }
            }
        }
    }
    if (parentData)
    {
        _motionSampleTimesFallback = parentData->GetMotionSampleTimes();
    }
    else
    {
        _motionSampleTimesFallback = usdInArgs->GetMotionSampleTimes();
    }
}
Exemple #2
0
void
PxrUsdKatanaReadPointInstancer(
        const UsdGeomPointInstancer& instancer,
        const PxrUsdKatanaUsdInPrivateData& data,
        PxrUsdKatanaAttrMap& instancerAttrMap,
        PxrUsdKatanaAttrMap& sourcesAttrMap,
        PxrUsdKatanaAttrMap& instancesAttrMap,
        PxrUsdKatanaAttrMap& inputAttrMap)
{
    const double currentTime = data.GetCurrentTime();

    PxrUsdKatanaReadXformable(instancer, data, instancerAttrMap);

    // Get primvars for setting later. Unfortunatley, the only way to get them
    // out of the attr map is to build it, which will cause its contents to be
    // cleared. We'll need to restore its contents before continuing.
    //
    FnKat::GroupAttribute instancerAttrs = instancerAttrMap.build();
    FnKat::GroupAttribute primvarAttrs =
            instancerAttrs.getChildByName("geometry.arbitrary");
    for (int64_t i = 0; i < instancerAttrs.getNumberOfChildren(); ++i)
    {
        instancerAttrMap.set(instancerAttrs.getChildName(i),
                instancerAttrs.getChildByIndex(i));
    }

    instancerAttrMap.set("type", FnKat::StringAttribute("usd point instancer"));

    const std::string fileName = data.GetUsdInArgs()->GetFileName();
    instancerAttrMap.set("info.usd.fileName", FnKat::StringAttribute(fileName));

    FnKat::GroupAttribute inputAttrs = inputAttrMap.build();

    const std::string katOutputPath = FnKat::StringAttribute(
            inputAttrs.getChildByName("outputLocationPath")).getValue("", false);
    if (katOutputPath.empty())
    {
        _LogAndSetError(instancerAttrMap, "No output location path specified");
        return;
    }

    //
    // Validate instancer data.
    //

    const std::string instancerPath = instancer.GetPath().GetString();

    UsdStageWeakPtr stage = instancer.GetPrim().GetStage();

    // Prototypes (required)
    //
    SdfPathVector protoPaths;
    instancer.GetPrototypesRel().GetTargets(&protoPaths);
    if (protoPaths.empty())
    {
        _LogAndSetError(instancerAttrMap, "Instancer has no prototypes");
        return;
    }

    _PathToPrimMap primCache;
    for (auto protoPath : protoPaths) {
        const UsdPrim &protoPrim = stage->GetPrimAtPath(protoPath);
        primCache[protoPath] = protoPrim;
    }

    // Indices (required)
    //
    VtIntArray protoIndices;
    if (!instancer.GetProtoIndicesAttr().Get(&protoIndices, currentTime))
    {
        _LogAndSetError(instancerAttrMap, "Instancer has no prototype indices");
        return;
    }
    const size_t numInstances = protoIndices.size();
    if (numInstances == 0)
    {
        _LogAndSetError(instancerAttrMap, "Instancer has no prototype indices");
        return;
    }
    for (auto protoIndex : protoIndices)
    {
        if (protoIndex < 0 || static_cast<size_t>(protoIndex) >= protoPaths.size())
        {
            _LogAndSetError(instancerAttrMap, TfStringPrintf(
                    "Out of range prototype index %d", protoIndex));
            return;
        }
    }

    // Mask (optional)
    //
    std::vector<bool> pruneMaskValues =
            instancer.ComputeMaskAtTime(currentTime);
    if (!pruneMaskValues.empty() and pruneMaskValues.size() != numInstances)
    {
        _LogAndSetError(instancerAttrMap,
                "Mismatch in length of indices and mask");
        return;
    }

    // Positions (required)
    //
    UsdAttribute positionsAttr = instancer.GetPositionsAttr();
    if (!positionsAttr.HasValue())
    {
        _LogAndSetError(instancerAttrMap, "Instancer has no positions");
        return;
    }

    //
    // Compute instance transform matrices.
    //

    const double timeCodesPerSecond = stage->GetTimeCodesPerSecond();

    // Gather frame-relative sample times and add them to the current time to
    // generate absolute sample times.
    //
    const std::vector<double> &motionSampleTimes =
        data.GetMotionSampleTimes(positionsAttr);
    const size_t sampleCount = motionSampleTimes.size();
    std::vector<UsdTimeCode> sampleTimes(sampleCount);
    for (size_t a = 0; a < sampleCount; ++a)
    {
        sampleTimes[a] = UsdTimeCode(currentTime + motionSampleTimes[a]);
    }

    // Get velocityScale from the opArgs.
    //
    float velocityScale = FnKat::FloatAttribute(
        inputAttrs.getChildByName("opArgs.velocityScale")).getValue(1.0f, false);

    // XXX Replace with UsdGeomPointInstancer::ComputeInstanceTransformsAtTime.
    //
    std::vector<std::vector<GfMatrix4d>> xformSamples(sampleCount);
    const size_t numXformSamples =
        _ComputeInstanceTransformsAtTime(xformSamples, instancer, sampleTimes,
            UsdTimeCode(currentTime), timeCodesPerSecond, numInstances,
            positionsAttr, velocityScale);
    if (numXformSamples == 0) {
        _LogAndSetError(instancerAttrMap, "Could not compute "
                                          "sample/topology-invarying instance "
                                          "transform matrix");
        return;
    }

    //
    // Compute prototype bounds.
    //

    bool aggregateBoundsValid = false;
    std::vector<double> aggregateBounds;

    // XXX Replace with UsdGeomPointInstancer::ComputeExtentAtTime.
    //
    VtVec3fArray aggregateExtent;
    if (_ComputeExtentAtTime(
            aggregateExtent, data.GetUsdInArgs(), xformSamples,
            motionSampleTimes, protoIndices, protoPaths, primCache,
            pruneMaskValues)) {
        aggregateBoundsValid = true;
        aggregateBounds.resize(6);
        aggregateBounds[0] = aggregateExtent[0][0]; // min x
        aggregateBounds[1] = aggregateExtent[1][0]; // max x
        aggregateBounds[2] = aggregateExtent[0][1]; // min y
        aggregateBounds[3] = aggregateExtent[1][1]; // max y
        aggregateBounds[4] = aggregateExtent[0][2]; // min z
        aggregateBounds[5] = aggregateExtent[1][2]; // max z
    }

    //
    // Build sources. Keep track of which instances use them.
    //

    FnGeolibServices::StaticSceneCreateOpArgsBuilder sourcesBldr(false);

    std::vector<int> instanceIndices;
    instanceIndices.reserve(numInstances);

    std::vector<std::string> instanceSources;
    instanceSources.reserve(protoPaths.size());

    std::map<std::string, int> instanceSourceIndexMap;

    std::vector<int> omitList;
    omitList.reserve(numInstances);

    std::map<SdfPath, std::string> protoPathsToKatPaths;

    for (size_t i = 0; i < numInstances; ++i)
    {
        int index = protoIndices[i];

        // Check to see if we are pruned.
        //
        bool isPruned = (!pruneMaskValues.empty() and
                         pruneMaskValues[i] == false);
        if (isPruned)
        {
            omitList.push_back(i);
        }

        const SdfPath &protoPath = protoPaths[index];

        // Compute the full (Katana) path to this prototype.
        //
        std::string fullProtoPath;
        std::map<SdfPath, std::string>::const_iterator pptkpIt =
                protoPathsToKatPaths.find(protoPath);
        if (pptkpIt != protoPathsToKatPaths.end())
        {
            fullProtoPath = pptkpIt->second;
        }
        else
        {
            _PathToPrimMap::const_iterator pcIt = primCache.find(protoPath);
            const UsdPrim &protoPrim = pcIt->second;
            if (!protoPrim) {
                continue;
            }

            // Determine where (what path) to start building the prototype prim
            // such that its material bindings will be preserved. This could be
            // the prototype path itself or an ancestor path.
            //
            SdfPathVector commonPrefixes;

            UsdRelationship materialBindingsRel =
                    UsdShadeMaterial::GetBindingRel(protoPrim);

            auto assetAPI = UsdModelAPI(protoPrim);
            std::string assetName;
            bool isReferencedModelPrim =
                    assetAPI.IsModel() and assetAPI.GetAssetName(&assetName);

            if (!materialBindingsRel or isReferencedModelPrim)
            {
                // The prim has no material bindings or is a referenced model
                // prim (meaning that materials are defined below it); start
                // building at the prototype path.
                //
                commonPrefixes.push_back(protoPath);
            }
            else
            {
                SdfPathVector materialPaths;
                materialBindingsRel.GetForwardedTargets(&materialPaths);
                for (auto materialPath : materialPaths)
                {
                    const SdfPath &commonPrefix =
                            protoPath.GetCommonPrefix(materialPath);
                    if (commonPrefix.GetString() == "/")
                    {
                        // XXX Unhandled case.
                        // The prototype prim and its material are not under the
                        // same parent; start building at the prototype path
                        // (although it is likely that bindings will be broken).
                        //
                        commonPrefixes.push_back(protoPath);
                    }
                    else
                    {
                        // Start building at the common ancestor between the
                        // prototype prim and its material.
                        //
                        commonPrefixes.push_back(commonPrefix);
                    }
                }
            }

            // XXX Unhandled case.
            // We'll use the first common ancestor even if there is more than
            // one (which shouldn't appen if the prototype prim and its bindings
            // are under the same parent).
            //
            SdfPath::RemoveDescendentPaths(&commonPrefixes);
            const std::string buildPath = commonPrefixes[0].GetString();

            // See if the path is a child of the point instancer. If so, we'll
            // match its hierarchy. If not, we'll put it under a 'prototypes'
            // group.
            //
            std::string relBuildPath;
            if (pystring::startswith(buildPath, instancerPath + "/"))
            {
                relBuildPath = pystring::replace(
                        buildPath, instancerPath + "/", "");
            }
            else
            {
                relBuildPath = "prototypes/" +
                        FnGeolibUtil::Path::GetLeafName(buildPath);
            }

            // Start generating the full path to the prototype.
            //
            fullProtoPath = katOutputPath + "/" + relBuildPath;

            // Make the common ancestor our instance source.
            //
            sourcesBldr.setAttrAtLocation(relBuildPath,
                    "type", FnKat::StringAttribute("instance source"));

            // Author a tracking attr.
            //
            sourcesBldr.setAttrAtLocation(relBuildPath,
                    "info.usd.sourceUsdPath",
                    FnKat::StringAttribute(buildPath));

            // Tell the BuildIntermediate op to start building at the common
            // ancestor.
            //
            sourcesBldr.setAttrAtLocation(relBuildPath,
                    "usdPrimPath", FnKat::StringAttribute(buildPath));
            sourcesBldr.setAttrAtLocation(relBuildPath,
                    "usdPrimName", FnKat::StringAttribute("geo"));

            if (protoPath.GetString() != buildPath)
            {
                // Finish generating the full path to the prototype.
                //
                fullProtoPath = fullProtoPath + "/geo" + pystring::replace(
                        protoPath.GetString(), buildPath, "");
            }

            // Create a mapping that will link the instance's index to its
            // prototype's full path.
            //
            instanceSourceIndexMap[fullProtoPath] = instanceSources.size();
            instanceSources.push_back(fullProtoPath);

            // Finally, store the full path in the map so we won't have to do
            // this work again.
            //
            protoPathsToKatPaths[protoPath] = fullProtoPath;
        }

        instanceIndices.push_back(instanceSourceIndexMap[fullProtoPath]);
    }

    //
    // Build instances.
    //

    FnGeolibServices::StaticSceneCreateOpArgsBuilder instancesBldr(false);

    instancesBldr.createEmptyLocation("instances", "instance array");

    instancesBldr.setAttrAtLocation("instances",
            "geometry.instanceSource",
                    FnKat::StringAttribute(instanceSources, 1));

    instancesBldr.setAttrAtLocation("instances",
            "geometry.instanceIndex",
                    FnKat::IntAttribute(&instanceIndices[0],
                            instanceIndices.size(), 1));

    FnKat::DoubleBuilder instanceMatrixBldr(16);
    for (size_t a = 0; a < numXformSamples; ++a) {

        double relSampleTime = motionSampleTimes[a];

        // Shove samples into the builder at the frame-relative sample time. If
        // motion is backwards, make sure to reverse time samples.
        std::vector<double> &matVec = instanceMatrixBldr.get(
            data.IsMotionBackward()
                ? PxrUsdKatanaUtils::ReverseTimeSample(relSampleTime)
                : relSampleTime);

        matVec.reserve(16 * numInstances);
        for (size_t i = 0; i < numInstances; ++i) {

            GfMatrix4d instanceXform = xformSamples[a][i];
            const double *matArray = instanceXform.GetArray();

            for (int j = 0; j < 16; ++j) {
                matVec.push_back(matArray[j]);
            }
        }
    }
    instancesBldr.setAttrAtLocation("instances",
            "geometry.instanceMatrix", instanceMatrixBldr.build());

    if (!omitList.empty())
    {
        instancesBldr.setAttrAtLocation("instances",
                "geometry.omitList",
                        FnKat::IntAttribute(&omitList[0], omitList.size(), 1));
    }

    instancesBldr.setAttrAtLocation("instances",
            "geometry.pointInstancerId",
                    FnKat::StringAttribute(katOutputPath));

    //
    // Transfer primvars.
    //

    FnKat::GroupBuilder instancerPrimvarsBldr;
    FnKat::GroupBuilder instancesPrimvarsBldr;
    for (int64_t i = 0; i < primvarAttrs.getNumberOfChildren(); ++i)
    {
        const std::string primvarName = primvarAttrs.getChildName(i);

        // Use "point" scope for the instancer.
        instancerPrimvarsBldr.set(primvarName, primvarAttrs.getChildByIndex(i));
        instancerPrimvarsBldr.set(primvarName + ".scope",
                FnKat::StringAttribute("point"));

        // User "primitive" scope for the instances.
        instancesPrimvarsBldr.set(primvarName, primvarAttrs.getChildByIndex(i));
        instancesPrimvarsBldr.set(primvarName + ".scope",
                FnKat::StringAttribute("primitive"));
    }
    instancerAttrMap.set("geometry.arbitrary", instancerPrimvarsBldr.build());
    instancesBldr.setAttrAtLocation("instances",
            "geometry.arbitrary", instancesPrimvarsBldr.build());

    //
    // Set the final aggregate bounds.
    //

    if (aggregateBoundsValid)
    {
        instancerAttrMap.set("bound", FnKat::DoubleAttribute(&aggregateBounds[0], 6, 2));
    }

    //
    // Set proxy attrs.
    //

    instancerAttrMap.set("proxies", PxrUsdKatanaUtils::GetViewerProxyAttr(data));

    //
    // Transfer builder results to our attr maps.
    //

    FnKat::GroupAttribute sourcesAttrs = sourcesBldr.build();
    for (int64_t i = 0; i < sourcesAttrs.getNumberOfChildren(); ++i)
    {
        sourcesAttrMap.set(
                sourcesAttrs.getChildName(i),
                sourcesAttrs.getChildByIndex(i));
    }

    FnKat::GroupAttribute instancesAttrs = instancesBldr.build();
    for (int64_t i = 0; i < instancesAttrs.getNumberOfChildren(); ++i)
    {
        instancesAttrMap.set(
                instancesAttrs.getChildName(i),
                instancesAttrs.getChildByIndex(i));
    }
}
int ImagineRender::queueDataUpdates(FnKat::GroupAttribute updateAttribute)
{
//	fprintf(stderr, "Queue updates...\n");
	
	m_liveRenderState.lock();
	if (!m_pRaytracer)
	{
		m_liveRenderState.unlock();
		return 0;
	}

	m_liveRenderState.unlock();

	unsigned int numItems = updateAttribute.getNumberOfChildren();

	for (unsigned int i = 0; i < numItems; i++)
	{
		FnKat::GroupAttribute dataUpdateItemAttribute = updateAttribute.getChildByIndex(i);

		if (!dataUpdateItemAttribute.isValid())
			continue;
		
//		fprintf(stderr, "\n\n%s\n\n", dataUpdateItemAttribute.getXML().c_str());

		FnKat::StringAttribute typeAttribute = dataUpdateItemAttribute.getChildByName("type");

		if (!typeAttribute.isValid())
			continue;

		FnKat::StringAttribute locationAttribute = dataUpdateItemAttribute.getChildByName("location");
		FnKat::GroupAttribute attributesAttribute = dataUpdateItemAttribute.getChildByName("attributes");
		
//		fprintf(stderr, "\n\n%s\n\n", attributesAttribute.getXML().c_str());
		
		bool partialUpdate = false;

		FnKat::StringAttribute partialUpdateAttribute = attributesAttribute.getChildByName("partialUpdate");
		if (partialUpdateAttribute.isValid() && partialUpdateAttribute.getValue("", false) == "True")
		{
			partialUpdate = true;
		}

		std::string type = typeAttribute.getValue("", false);
		std::string location = locationAttribute.getValue("", false);

		if (type == "camera" && location == m_renderCameraLocation)
		{
			KatanaUpdateItem newUpdate(KatanaUpdateItem::eTypeCamera, KatanaUpdateItem::eLocCamera, location);
			
			FnKat::GroupAttribute xformAttribute = attributesAttribute.getChildByName("xform");
			if (xformAttribute.isValid())
			{
				LiveRenderHelpers::setUpdateXFormFromAttribute(xformAttribute, newUpdate);
			}
			
			FnKat::GroupAttribute geometryAttribute = attributesAttribute.getChildByName("geometry");
			if (geometryAttribute.isValid())
			{
				FnKat::DoubleAttribute fovAttribute = geometryAttribute.getChildByName("fov");
				if (fovAttribute.isValid())
				{
					double fovValue = fovAttribute.getValue(70.0, false);
					newUpdate.extra.add("fov", (float)fovValue);
				}
				
				FnKat::DoubleAttribute nearClipAttribute = geometryAttribute.getChildByName("near");
				if (nearClipAttribute.isValid())
				{
					double nearClipValue = nearClipAttribute.getValue(0.1, false);
					newUpdate.extra.add("nearClip", (float)nearClipValue);
				}
			}
			
			m_liveRenderState.addUpdate(newUpdate);
		}
		else if (type == "geoMaterial")
		{
			FnKat::GroupAttribute materialAttribute = attributesAttribute.getChildByName("material");
			
			if (!materialAttribute.isValid())
				continue;
			
			FnKat::StringAttribute shaderAttribute = materialAttribute.getChildByName("imagineSurfaceShader");
			if (shaderAttribute.isValid())
			{
				// we have a none-network material
				
				FnKat::GroupAttribute shaderParams = materialAttribute.getChildByName("imagineSurfaceParams");
				// if all shader params are default, there won't be a group, so shaderParams will be invalid, but we can pass
				// this down anyway. So we don't need to check for the validity of shaderParams, as its possible non-existance
				// is okay.
				
				// extremely hacky for the moment...
				KatanaUpdateItem newUpdate(KatanaUpdateItem::eTypeObjectMaterial, KatanaUpdateItem::eLocObject, location);
				
				std::string shaderType = shaderAttribute.getValue("", false);
				
				Material* pNewMaterial = MaterialHelper::createNewMaterialStandAlone(shaderType, shaderParams);
				
				if (pNewMaterial)
				{
					newUpdate.pMaterial = pNewMaterial;
					
					m_liveRenderState.addUpdate(newUpdate);
				}
				
				continue;
			}
			
			FnKat::GroupAttribute nodesAttribute = materialAttribute.getChildByName("nodes");
			if (nodesAttribute.isValid())
			{
				MaterialHelper materialHelper(m_logger);
				// we have a network material
				
				Material* pNewMaterial = materialHelper.createNetworkMaterial(materialAttribute, false);
				if (pNewMaterial)
				{
					// extremely hacky for the moment...
					KatanaUpdateItem newUpdate(KatanaUpdateItem::eTypeObjectMaterial, KatanaUpdateItem::eLocObject, location);
					
					newUpdate.pMaterial = pNewMaterial;
					
					m_liveRenderState.addUpdate(newUpdate);
				}
			}
		}
		else if (type == "geo")
		{
			KatanaUpdateItem newUpdate(KatanaUpdateItem::eTypeObject, KatanaUpdateItem::eLocObject, location);
			
			bool changed = false;
			
			FnKat::GroupAttribute xformAttribute = attributesAttribute.getChildByName("xform");
			if (xformAttribute.isValid())
			{
				LiveRenderHelpers::setUpdateXFormFromAttribute(xformAttribute, newUpdate);
				changed = true;
			}
			
			FnKat::IntAttribute deletedAttribute = attributesAttribute.getChildByName("deleted");
			if (deletedAttribute.isValid())
			{
				int deletedValue = deletedAttribute.getValue(0, false);
				if (deletedValue == 1)
				{
					newUpdate.extra.add("deleted", true);
					changed = true;
				}
			}
			
			if (changed)
			{
				m_liveRenderState.addUpdate(newUpdate);
			}
		}
		else if (type == "light")
		{
//			fprintf(stderr, "\n\n%s\n\n", attributesAttribute.getXML().c_str());
			
			KatanaUpdateItem newUpdate(KatanaUpdateItem::eTypeLight, KatanaUpdateItem::eLocLight, location);
			
			FnKat::GroupAttribute xformAttribute = attributesAttribute.getChildByName("xform");
			if (xformAttribute.isValid())
			{
				LiveRenderHelpers::setUpdateXFormFromAttribute(xformAttribute, newUpdate);
			}
			
			FnKat::GroupAttribute materialAttribute = attributesAttribute.getChildByName("material");
			if (materialAttribute.isValid())
			{
				FnKat::GroupAttribute shaderParamsAttribute = materialAttribute.getChildByName("imagineLightParams");
				if (shaderParamsAttribute.isValid())
				{
					KatanaAttributeHelper helper(shaderParamsAttribute);
					
					float intensity = helper.getFloatParam("intensity", 1.0f);
					newUpdate.extra.add("intensity", intensity);
					
					float exposure = helper.getFloatParam("exposure", 1.0f);
					newUpdate.extra.add("exposure", exposure);
				}
			}
			
			FnKat::IntAttribute muteAttribute = attributesAttribute.getChildByName("mute");
			if (muteAttribute.isValid())
			{
				int muteValue = muteAttribute.getValue(0, false);
				newUpdate.extra.add("muted", (bool)muteValue);
			}
			
			m_liveRenderState.addUpdate(newUpdate);
		}
	}

	return 0;
}