private void ProcessBoneWeights() { // bake bone matrices if (_tempColorBuffer == null || _tempColorBuffer.Length != bones.Length * 4) { _tempColorBuffer = new Color[bones.Length * 4]; _tempMatrixBuffer = new Matrix4x4[bones.Length]; } for (int i = 0; i < bindPoses.Length; ++i) { Matrix4x4 bindPose = bindPoses[i]; Matrix4x4 boneMatrix = bones[i].localToWorldMatrix; Matrix4x4 outputMatrix = localTransformInverse * boneMatrix * bindPose; _tempMatrixBuffer[i] = outputMatrix; } VertexProcessorUtility.MatrixArrayToColorArray(_tempMatrixBuffer, _tempColorBuffer); boneMatrixTexture.SetPixels(_tempColorBuffer); boneMatrixTexture.Apply(); // set texture boneMaterial.SetTexture("_NeoFur_BoneMatrixTexture", boneMatrixTexture); }
protected override void OnProcess() { base.OnProcess(); physicsMaterial.SetTexture("_NeoFur_PhysicsPositionTexture", positionTexture); physicsMaterial.SetTexture("_NeoFur_PhysicsVelocityTexture", velocityTexture); physicsMaterial.SetTexture("_NeoFur_PhysicsGuideTexture", guideTextureResource.value); physicsMaterial.SetVector("_NeoFur_PhysicsGravityVector", Physics.gravity * processor.neoFurAsset.physParams.GravityInfluence); physicsMaterial.SetFloat("_NeoFur_SpringLengthStiffness", processor.neoFurAsset.physParams.SpringLengthStiffnessInUnityUnits * 10); physicsMaterial.SetFloat("_NeoFur_SpringAngleStiffness", processor.neoFurAsset.physParams.SpringLengthStiffnessInUnityUnits * 10); physicsMaterial.SetFloat("_NeoFur_SpringMultiplyer", processor.neoFurAsset.physParams.SpringDampeningMultiplier); physicsMaterial.SetFloat("_NeoFur_AirResistanceMultiplyer", processor.neoFurAsset.physParams.AirResistanceMultiplier); Vector4 constraints = new Vector4(processor.neoFurAsset.physParams.MinStretchDistanceMultiplier, processor.neoFurAsset.physParams.MaxStretchDistanceMultiplier, processor.neoFurAsset.physParams.MaxRotationFromNormal); physicsMaterial.SetVector("_NeoFur_MinMaxConstraints", constraints); RenderTexture positionSwap = RenderTexture.GetTemporary(positionTexture.width, positionTexture.height, positionTexture.depth, positionTexture.format); positionSwap.filterMode = FilterMode.Point; RenderTexture velocitySwap = RenderTexture.GetTemporary(velocityTexture.width, velocityTexture.height, velocityTexture.depth, velocityTexture.format); velocitySwap.filterMode = FilterMode.Point; //TODO: We could support multiple wind sources. Like how we support multiple radial forces FakeWind wind = processor.neoFurAsset.mFakeWind; if (wind != null) { Vector3 windVector = wind.GetDirection() * wind.GetForce(); physicsMaterial.SetVector("_NeoFur_WindVector", windVector); physicsMaterial.SetFloat("_NeoFur_WindGustFactor", wind.GetGustFactor()); physicsMaterial.SetFloat("_NeoFur_WindInfluence", processor.neoFurAsset.physParams.WindInfluence); Graphics.Blit(null, velocityTexture, physicsMaterial, windPassIndex); } if (radialForces.Count > 0) { physicsMaterial.SetFloat("_NeoFur_RadialForceInfluence", processor.neoFurAsset.physParams.RadialForceInfluence); foreach (var force in radialForces) { physicsMaterial.SetVector("_NeoFur_RadialForcePosition", force.Origin); physicsMaterial.SetFloat("_NeoFur_RadialForceRadius", force.Radius); physicsMaterial.SetFloat("_NeoFur_RadialForcePower", force.Strength); Graphics.Blit(null, velocityTexture, physicsMaterial, radialForcePassIndex); } } radialForces.Clear(); targetBufferCache2x[0] = positionSwap.colorBuffer; targetBufferCache2x[1] = velocitySwap.colorBuffer; Graphics.SetRenderTarget(targetBufferCache2x, positionSwap.depthBuffer); Graphics.Blit(null, physicsMaterial, simulatePassIndex); Graphics.SetRenderTarget(null); VertexProcessorUtility.CopyTexture(positionSwap, positionTexture); VertexProcessorUtility.CopyTexture(velocitySwap, velocityTexture); if (isDx9) { if (targetBufferCache3x == null) { targetBufferCache3x = new RenderBuffer[3]; } RenderTexture tangentSwap = RenderTexture.GetTemporary(processor.tangentTexture.width, processor.tangentTexture.height, processor.tangentTexture.depth, processor.tangentTexture.format); tangentSwap.filterMode = FilterMode.Point; targetBufferCache3x[0] = positionSwap.colorBuffer; targetBufferCache3x[1] = velocitySwap.colorBuffer; targetBufferCache3x[2] = tangentSwap.colorBuffer; Graphics.SetRenderTarget(targetBufferCache3x, positionSwap.depthBuffer); Graphics.Blit(null, physicsMaterial, applyPositionPassIndex); VertexProcessorUtility.CopyTexture(positionSwap, processor.positionTexture); VertexProcessorUtility.CopyTexture(velocitySwap, processor.normalTexture); VertexProcessorUtility.CopyTexture(tangentSwap, processor.tangentTexture); Graphics.SetRenderTarget(null); RenderTexture.ReleaseTemporary(tangentSwap); } Graphics.SetRenderTarget(null); RenderTexture.ReleaseTemporary(positionSwap); RenderTexture.ReleaseTemporary(velocitySwap); }
protected override void OnRebuild() { base.OnRebuild(); DestroyResources(); int width = processor.positionTexture.width; int height = processor.positionTexture.height; positionTexture = new RenderTexture(width, height, 0, VertexProcessorUtility.float4RenderTextureFormat); positionTexture.filterMode = FilterMode.Point; positionTexture.Create(); velocityTexture = new RenderTexture(width, height, 0, VertexProcessorUtility.float4RenderTextureFormat); velocityTexture.filterMode = FilterMode.Point; velocityTexture.Create(); float[] weights = processor.neoFurAsset.morphWeights; StringBuilder guideTextureKeySB = new StringBuilder(); guideTextureKeySB.Append(processor.baseResourceKey); guideTextureKeySB.Append("_"); guideTextureKeySB.Append(processor.neoFurAsset.data.guideMethod); guideTextureKeySB.Append("_"); if (processor.neoFurAsset.data.guideMethod == NeoFurAssetData.GuideMethod.Morphs) { for (int i = 0; i < weights.Length; i++) { guideTextureKeySB.Append(weights[i].ToString(CultureInfo.InvariantCulture)); if (i < weights.Length - 1) { guideTextureKeySB.Append("_"); } } } else if (processor.neoFurAsset.data.guideMethod == NeoFurAssetData.GuideMethod.Splines) { if (processor.neoFurAsset.SplineGuideData == null) { guideTextureKeySB.Append("null"); } else { guideTextureKeySB.Append(processor.neoFurAsset.SplineGuideData.GetInstanceID().ToString()); } } guideTextureKeySB.Append("_PhysicsGuideTexture"); guideTextureResource = VertexProcessorCache.GetResource <Texture2D>(guideTextureKeySB.ToString()); if (guideTextureResource.value == null) { if (processor.neoFurAsset.data.guideMethod == NeoFurAssetData.GuideMethod.Normals) { DefaultToNormalGuides(); } else if (processor.neoFurAsset.data.guideMethod == NeoFurAssetData.GuideMethod.Morphs) { UnpackedMesh mesh = processor.unpackedMeshResource.value; if (mesh.blendShapes.Count != weights.Length) { Debug.LogError("mesh.blendShapes.Count != weights.Length", processor.neoFurAsset.gameObject); DefaultToNormalGuides(); } else if (weights.Length > 0) { Color[] guideVectorColors = new Color[width * height]; for (int i = 0; i < weights.Length; i++) { float weight = weights[i] / 100.0f; if (weight == 0) { continue; } UnpackedMesh.BlendShape blendShape = mesh.blendShapes[i]; for (int j = 0; j < mesh.vertices.Length; j++) { Vector3 guideVector = blendShape.deltaVertices[j] * weight; guideVectorColors[j] += new Color(guideVector.x, guideVector.y, guideVector.z, 0); } } for (int i = 0; i < mesh.tangents.Length; i++) { Vector3 normal = mesh.normals[i]; Vector4 tangent = mesh.tangents[i]; Color guideVectorColor = guideVectorColors[i]; Vector3 guideVector = new Vector3(guideVectorColor.r, guideVectorColor.g, guideVectorColor.b); Vector3 binormal = Vector3.Cross(normal, tangent); Vector3 tangentSpaceGuide = VertexProcessorUtility.ToTangentSpace(guideVector, normal, binormal, tangent); guideVectorColors[i] = new Color(tangentSpaceGuide.x, tangentSpaceGuide.y, tangentSpaceGuide.z, 0); } guideTextureResource.value = new Texture2D(width, height, VertexProcessorUtility.float4TextureFormat, false); guideTextureResource.value.filterMode = FilterMode.Point; guideTextureResource.value.SetPixels(guideVectorColors); guideTextureResource.value.Apply(); } else { DefaultToNormalGuides(); } } else if (processor.neoFurAsset.data.guideMethod == NeoFurAssetData.GuideMethod.Splines) { NeoFur.Data.PreComputedGuideData splineData = processor.neoFurAsset.SplineGuideData; if (splineData == null) { Debug.LogWarning("Guide mode set to Splines but no spline data file is loaded", processor.neoFurAsset.gameObject); DefaultToNormalGuides(); } else if (splineData.guides.Length == 0 || splineData.guides.Length != processor.unpackedMeshResource.value.vertices.Length) { Debug.Log("num guides = " + splineData.guides.Length + " num verts: " + width * height, processor.neoFurAsset.gameObject); Debug.LogError("Submesh for NFA does not match submesh for Spline Data Asset", processor.neoFurAsset.gameObject); DefaultToNormalGuides(); } else { UnpackedMesh mesh = processor.unpackedMeshResource.value; Color[] guideVectorColors = new Color[width * height]; for (int i = 0; i < splineData.guides.Length; i++) { Vector3 normal = mesh.normals[i]; Vector4 tangent = mesh.tangents[i]; int remappedIndex = processor.optimizedVertexMapResource.value[i]; Vector3 guideVector = splineData.guides[remappedIndex]; Vector3 binormal = Vector3.Cross(normal, tangent); Vector3 tangentSpaceGuide = VertexProcessorUtility.ToTangentSpace(guideVector, normal, binormal, tangent); guideVectorColors[i] = new Color(tangentSpaceGuide.x, tangentSpaceGuide.y, tangentSpaceGuide.z, 0); } guideTextureResource.value = new Texture2D(width, height, VertexProcessorUtility.float4TextureFormat, false); guideTextureResource.value.filterMode = FilterMode.Point; guideTextureResource.value.SetPixels(guideVectorColors); guideTextureResource.value.Apply(); } } } }
private void DoTheBlits() { // get temp RTs RenderTexture posRT = RenderTexture.GetTemporary(processor.positionTexture.width, processor.positionTexture.height, processor.positionTexture.depth, processor.positionTexture.format); posRT.filterMode = FilterMode.Point; RenderTexture normRT = RenderTexture.GetTemporary(processor.normalTexture.width, processor.normalTexture.height, processor.normalTexture.depth, processor.normalTexture.format); normRT.filterMode = FilterMode.Point; RenderTexture tanRT = RenderTexture.GetTemporary(processor.tangentTexture.width, processor.tangentTexture.height, processor.tangentTexture.depth, processor.tangentTexture.format); tanRT.filterMode = FilterMode.Point; // blit using bone material targetBufferCache[0] = posRT.colorBuffer; targetBufferCache[1] = normRT.colorBuffer; targetBufferCache[2] = tanRT.colorBuffer; Graphics.SetRenderTarget(targetBufferCache, posRT.depthBuffer); // process morphs if (bakedFurMorphResources != null) { for (int i = 0; i < bakedFurMorphResources.Length; ++i) { BakedMorph bakedFurMorph = bakedFurMorphResources[i].value; //use this weight for morph targets float blendWeight = processor.neoFurAsset.skinnedMeshRenderer.GetBlendShapeWeight(i) / 100; if (blendWeight == 0) { continue; } // set material properties boneMaterial.SetFloat("_BlendWeight", blendWeight); boneMaterial.SetTexture("_BlendPosOffsetTexture", bakedFurMorph.positionOffsetTexture); boneMaterial.SetTexture("_BlendNormOffsetTexture", bakedFurMorph.normalOffsetTexture); boneMaterial.SetTexture("_BlendTanOffsetTexture", bakedFurMorph.tangentOffsetTexture); // blit using bone material targetBufferCache[0] = posRT.colorBuffer; targetBufferCache[1] = normRT.colorBuffer; targetBufferCache[2] = tanRT.colorBuffer; Graphics.SetRenderTarget(targetBufferCache, posRT.depthBuffer); // blit to target buffer cache Graphics.Blit(null, boneMaterial, 0); // blit/copy target buffers to processor RTs VertexProcessorUtility.CopyTexture(posRT, processor.positionTexture); VertexProcessorUtility.CopyTexture(normRT, processor.normalTexture); VertexProcessorUtility.CopyTexture(tanRT, processor.tangentTexture); } } ProcessBoneWeights(); // blit using bone material targetBufferCache[0] = posRT.colorBuffer; targetBufferCache[1] = normRT.colorBuffer; targetBufferCache[2] = tanRT.colorBuffer; Graphics.SetRenderTarget(targetBufferCache, posRT.depthBuffer); // blit to target buffer cache Graphics.Blit(null, boneMaterial, 1); // blit/copy target buffers to processor RTs VertexProcessorUtility.CopyTexture(posRT, processor.positionTexture); VertexProcessorUtility.CopyTexture(normRT, processor.normalTexture); VertexProcessorUtility.CopyTexture(tanRT, processor.tangentTexture); // release temp RTs RenderTexture.ReleaseTemporary(posRT); RenderTexture.ReleaseTemporary(normRT); RenderTexture.ReleaseTemporary(tanRT); }