private void _LoadBone(BlendTypeRepository repository, BlendValueCapsule bone, int parentBoneIndex, ref List <DrawSystem.BoneData> outList) { if (bone != null) { // make bone data var name = bone.GetMember("name").GetAllValueAsString(); float length = bone.GetMember("length").GetRawValue <float>(); var offset = new Vector3() { X = bone.GetMember("head").GetAt(0).GetRawValue <float>(), Y = bone.GetMember("head").GetAt(1).GetRawValue <float>(), Z = bone.GetMember("head").GetAt(2).GetRawValue <float>(), }; offset = BlenderUtil.ChangeCoordsSystem(offset); var elements = new float[16]; for (int i = 0; i < 4; ++i) { for (int j = 0; j < 4; ++j) { elements[i * 4 + j] = bone.GetMember("arm_mat").GetAt(i, j).GetRawValue <float>(); } } var modelTrans = new Matrix(elements); modelTrans = BlenderUtil.ChangeCoordsSystem(modelTrans); var result = new DrawSystem.BoneData() { Name = name, Parent = parentBoneIndex, BoneTransform = modelTrans, // convert local bone transformation after BoneOffset = Matrix.Invert(modelTrans), Length = length, }; outList.Add(result); parentBoneIndex = outList.Count() - 1; //Console.WriteLine(" found bone : " + name); // call for children var childBone = bone.GetMember("childbase").GetMember("first").GetRawValue <BlendAddress>().DereferenceOne(); while (childBone != null) { _LoadBone(repository, childBone, parentBoneIndex, ref outList); childBone = childBone.GetMember("next").GetRawValue <BlendAddress>().DereferenceOne(); } } }
public static DrawModel FromScene(String uid, BlenderScene scene, string fileSearchPath) { var drawSys = DrawSystem.GetInstance(); var drawRepository = drawSys.ResourceRepository; var d3d = drawSys.D3D; var model = new DrawModel(uid); bool hasBone = BlenderUtil.GetLengthOf(scene.NodeList[0].BoneArray) > 0;// boneArray is set to the first node var aabb = Aabb.Invalid(); foreach (var n in scene.NodeList) { if (n.MaterialData.Type == MaterialBase.MaterialTypes.Marker) { // marker material is used as 'Marker' continue; } if (n.Vertics.Count() == 0) { // empty vertex list continue; } // Build a vertex buffer(s) var vertices1 = n.Vertics .Select(v => new _VertexCommon() { Position = v.Position, Normal = v.Normal, Texcoord = v.Texcoord }).ToArray(); var vertices2 = n.Vertics .Select(v => v.Tangent).ToArray(); // update aabb foreach (var v in vertices1) { aabb.ExtendByPoint(MathUtil.ToVector3(v.Position)); } var node = new Node(); node.Material = n.MaterialData; node.IsDebug = false; node.HasBone = hasBone; if (node.HasBone) { // if model has bone, we create a bone vertex info var vertices3 = n.Vertics .Select(v => { Debug.Assert(BlenderUtil.GetLengthOf(v.BoneIndices) == BlenderUtil.GetLengthOf(v.BoneWeights), "both of bone index and bone weight must be matched"); //Debug.Assert(BlenderUtil.GetLengthOf(v.BoneWeights) <= _VertexBoneWeight.MAX_COUNT, "length of bone weight is over :" + BlenderUtil.GetLengthOf(v.BoneWeights)); Debug.Assert(BlenderUtil.GetLengthOf(v.BoneWeights) != 0, "no bone entry"); var tmp = new _VertexBoneWeight() { Index0 = BlenderUtil.GetLengthOf(v.BoneIndices) > 0 ? v.BoneIndices[0] : 0, Weight0 = BlenderUtil.GetLengthOf(v.BoneWeights) > 0 ? v.BoneWeights[0] : 0.0f, Index1 = BlenderUtil.GetLengthOf(v.BoneIndices) > 1 ? v.BoneIndices[1] : 0, Weight1 = BlenderUtil.GetLengthOf(v.BoneWeights) > 1 ? v.BoneWeights[1] : 0.0f, Index2 = BlenderUtil.GetLengthOf(v.BoneIndices) > 2 ? v.BoneIndices[2] : 0, Weight2 = BlenderUtil.GetLengthOf(v.BoneWeights) > 2 ? v.BoneWeights[2] : 0.0f, Index3 = BlenderUtil.GetLengthOf(v.BoneIndices) > 3 ? v.BoneIndices[3] : 0, Weight3 = BlenderUtil.GetLengthOf(v.BoneWeights) > 3 ? v.BoneWeights[3] : 0.0f, }; float sumWeight = tmp.Weight0 + tmp.Weight1 + tmp.Weight2 + tmp.Weight3; tmp.Weight0 /= sumWeight; tmp.Weight1 /= sumWeight; tmp.Weight2 /= sumWeight; tmp.Weight3 /= sumWeight; return(tmp); }).ToArray(); node.Mesh = DrawUtil.CreateMeshData(d3d, PrimitiveTopology.TriangleList, vertices1, vertices2, vertices3); } else { node.Mesh = DrawUtil.CreateMeshData(d3d, PrimitiveTopology.TriangleList, vertices1, vertices2); } // add dispoable /* * foreach (var buf in node.Mesh.Buffers) * { * model._AddDisposable(buf.Buffer); * } */ // create skeleton if (model.m_boneArray == null && n.BoneArray != null) { model.m_boneArray = (DrawSystem.BoneData[])n.BoneArray.Clone(); } // load new texture foreach (var texInfo in n.TextureInfos.Values) { if (!drawRepository.Contains(texInfo.Name)) { var tex = TextureView.FromFile(texInfo.Name, drawSys.D3D, Path.Combine(fileSearchPath, texInfo.Name)); drawRepository.AddResource(tex); } } // copy textures from cache foreach (DrawSystem.TextureTypes textureType in Enum.GetValues(typeof(DrawSystem.TextureTypes))) { if (n.TextureInfos.ContainsKey(textureType)) { node.Material.SetTextureData( textureType, new DrawSystem.TextureData { Resource = drawRepository.FindResource <TextureView>(n.TextureInfos[textureType].Name), UvScale = n.TextureInfos[textureType].UvScale, }); } } model.m_nodeList.Add(node); } model.m_bb = aabb; return(model); }
private bool _LoadScene(BlendTypeRepository repository, List <BlockHeaderEntity> entityList) { // find root BlendValueCapsule root = entityList.Where(e => e.Name == "GLOB").Select(e => e.Children[0].Value).First(); if (root == null) { return(false); } var scene = root.GetMember("curscene").GetRawValue <BlendAddress>().DereferenceOne(); var listBase = scene.GetMember("base"); var nextBase = listBase.GetMember("first").GetRawValue <BlendAddress>().DereferenceOne(); // load mesh while (nextBase != null) { var obj = nextBase.GetMember("object").GetRawValue <BlendAddress>().DereferenceOne(); if (obj != null) { string name = obj.GetMember("id").GetMember("name").GetAllValueAsString(); int restrictFlag = obj.GetMember("restrictflag").GetRawValue <char>(); if ((restrictFlag & 1) != 0) { // invisible object } var data = obj.GetMember("data").GetRawValue <BlendAddress>().DereferenceOne(); if (data != null && data.Type.Name == "Mesh") { // mesh object Console.WriteLine("found mesh : " + name); if (!_LoadMesh(repository, obj)) { return(false); } } var groupId = obj.GetMember("dup_group").GetRawValue <BlendAddress>().DereferenceOne(); if (groupId != null) { // link object Console.WriteLine("found link obj: " + name); var lib = groupId.GetMember("lib").GetRawValue <BlendAddress>().DereferenceOne(); var path = lib.GetMember("filepath").GetAllValueAsString(); // make layout matrix var elements = new float[16]; for (int i = 0; i < 4; ++i) { for (int j = 0; j < 4; ++j) { elements[i * 4 + j] = obj.GetMember("obmat").GetAt(i, j).GetRawValue <float>(); } } var layoutTrans = new Matrix(elements); layoutTrans = BlenderUtil.ChangeCoordsSystem(layoutTrans); var node = new LinkNode() { Name = name, Layout = layoutTrans, TargetFileName = Path.GetFileName(path), }; m_linkList.Add(node); } } nextBase = nextBase.GetMember("next").GetRawValue <BlendAddress>().DereferenceOne(); } return(true); }
private void _LoadAction(BlendTypeRepository repository, BlendValueCapsule bAnimAction, ref List <AnimType.ActionData> animActionList) { var groupList = new List <AnimType.ActionGroupData>(); var bGroup = bAnimAction.GetMember("groups").GetMember("first").GetRawValue <BlendAddress>().DereferenceOne(); while (bGroup != null) { var groupData = new AnimType.ActionGroupData(); groupData.BoneName = bGroup.GetMember("name").GetAllValueAsString(); groupData.Location = AnimType.ChannelData <Vector3> .Empty(); groupData.Rotation = AnimType.ChannelData <Quaternion> .Empty(); groupData.Scale = AnimType.ChannelData <Vector3> .Empty(); //Console.WriteLine(" found anim action group : " + groupData.BoneName); var channelList = new List <AnimType.ChannelData <float> >(); var bChannel = bGroup.GetMember("channels").GetMember("first").GetRawValue <BlendAddress>().DereferenceOne(); while (bChannel != null) { string boneName = ""; string propertyName = ""; var bRnaPath = bChannel.GetMember("rna_path").GetRawValue <BlendAddress>().DereferenceAll(Blender.BlendPrimitiveType.Char()); string rnaPath = Blender.ConvertUtil.CharArray2String(bRnaPath.Select(c => (object)c.GetRawValue <char>())); if (!BlenderUtil.ParseRnaPath(rnaPath, ref boneName, ref propertyName)) { Debug.Fail("Failed to parse rna path(" + rnaPath + ")"); return; } int arrayIndex = bChannel.GetMember("array_index").GetRawValue <int>(); if (boneName == groupData.BoneName) { //Console.WriteLine(String.Format(" {0}.{1}[{2}]", boneName, propertyName, arrayIndex)); var bBeztList = bChannel.GetMember("bezt").GetRawValue <BlendAddress>().DereferenceAll(); var channel = new AnimType.ChannelData <float>(); channel.KeyFrames = new AnimType.KeyData <float> [bBeztList.Count()]; foreach (var bBezt in bBeztList.Select((value, index) => new { value, index })) { float frame = bBezt.value.GetMember("vec").GetAt(1, 0).GetRawValue <float>(); float value = bBezt.value.GetMember("vec").GetAt(1, 1).GetRawValue <float>(); channel.KeyFrames[bBezt.index] = new AnimType.KeyData <float>((int)frame, value); } channelList.Add(channel); } bChannel = bChannel.GetMember("next").GetRawValue <BlendAddress>().DereferenceOne(); } // while if (channelList.Count() == 10) { // channel type convertion // location : floatx3 to Vector3 // rotation : floatx4 to Quatanion // scale : floatx3 to Vector3 groupData.Location.KeyFrames = channelList[0].KeyFrames .Select((key, index) => new AnimType.KeyData <Vector3>(key.Frame, new Vector3(key.Value, channelList[1].KeyFrames[index].Value, channelList[2].KeyFrames[index].Value))) .Select(key => { key.Value = BlenderUtil.ChangeCoordsSystem(key.Value); return(key); }) //.Select(key => { key.Frame--; return key; }) // blender frame index starts from 1 .ToArray(); groupData.Rotation.KeyFrames = channelList[3].KeyFrames .Select((key, index) => new AnimType.KeyData <Quaternion>(key.Frame, new Quaternion(channelList[4].KeyFrames[index].Value, channelList[5].KeyFrames[index].Value, channelList[6].KeyFrames[index].Value, key.Value))) .Select(key => { key.Value = BlenderUtil.ChangeCoordsSystem(key.Value); return(key); }) //.Select(key => { key.Frame--; return key; }) // blender frame index starts from 1 .ToArray(); groupData.Scale.KeyFrames = channelList[7].KeyFrames .Select((key, index) => new AnimType.KeyData <Vector3>(key.Frame, new Vector3(key.Value, channelList[8].KeyFrames[index].Value, channelList[9].KeyFrames[index].Value))) .Select(key => { key.Value = BlenderUtil.ChangeCoordsSystem(key.Value); return(key); }) //.Select(key => { key.Frame--; return key; }) // blender frame index starts from 1 .ToArray(); groupList.Add(groupData); bGroup = bGroup.GetMember("next").GetRawValue <BlendAddress>().DereferenceOne(); } else { Debug.Fail("unexpected the number of channels."); return; } } if (groupList.Count != 0) { var actionData = new AnimType.ActionData(); var actionName = bAnimAction.GetMember("id").GetMember("name").GetAllValueAsString(); actionName = actionName.Substring(2, actionName.Length - 2); // ACArmatureAction => ArmatureAction actionData.Name = actionName; actionData.Groups = groupList.ToArray(); animActionList.Add(actionData); } }
private VertexOriginal[] _CreateOriginalVertices(BlendTypeRepository repository, BlendValueCapsule mesh, int[] deformGroupIndex2BoneIndex) { var mpolyList = mesh.GetMember("mpoly").GetRawValue <BlendAddress>().DereferenceAll(); var mloopList = mesh.GetMember("mloop").GetRawValue <BlendAddress>().DereferenceAll(); var mloopuvList = mesh.GetMember("mloopuv").GetRawValue <BlendAddress>().DereferenceAll(); var mvertList = mesh.GetMember("mvert").GetRawValue <BlendAddress>().DereferenceAll(); var dvertList = mesh.GetMember("dvert").GetRawValue <BlendAddress>().DereferenceAll(); int capacity = mpolyList.Count() * 6; // assume that all polygons is square. var vertices = new List <VertexOriginal>(capacity); foreach (var mpoly in mpolyList) { int offset = mpoly.GetMember("loopstart").GetRawValue <int>(); int count = mpoly.GetMember("totloop").GetRawValue <int>(); short materialIndex = mpoly.GetMember("mat_nr").GetRawValue <short>(); Debug.Assert(count >= 0, "negative totloop is here!"); // todo: ref previous loop int[] plan = null; switch (count) { case 3: plan = new int[] { offset + 2, offset + 1, offset + 0 }; break; case 4: // triangulation plan = new int[] { offset + 2, offset + 1, offset, offset + 3, offset + 2, offset }; break; default: Debug.Fail("tutloop must be 3 or 4"); // todo: ref previous loop break; } if (plan == null) { continue; } foreach (int i in plan) { int vIndex = mloopList[i].GetMember("v").GetRawValue <int>(); var position = mvertList[vIndex].GetMember("co"); var normal = mvertList[vIndex].GetMember("no"); VertexOriginal vertex; vertex.Position.X = position.GetAt(0).GetRawValue <float>(); vertex.Position.Y = position.GetAt(1).GetRawValue <float>(); vertex.Position.Z = position.GetAt(2).GetRawValue <float>(); vertex.Position.W = 1; vertex.Position = BlenderUtil.ChangeCoordsSystem(vertex.Position); vertex.Normal.X = normal.GetAt(0).GetRawValue <short>(); vertex.Normal.Y = normal.GetAt(1).GetRawValue <short>(); vertex.Normal.Z = normal.GetAt(2).GetRawValue <short>(); vertex.Normal = BlenderUtil.ChangeCoordsSystem(vertex.Normal); vertex.Normal.Normalize(); var uv = mloopuvList[i].GetMember("uv"); vertex.Texcoord.X = uv.GetAt(0).GetRawValue <float>(); vertex.Texcoord.Y = 1 - uv.GetAt(1).GetRawValue <float>(); vertex.Tangent = Vector3.Zero; vertex.Binormal = Vector3.Zero; vertex.MaterialIndex = materialIndex; var weights = dvertList == null ? null : dvertList[vIndex].GetMember("dw").GetRawValue <BlendAddress>().DereferenceAll(); if (weights == null || deformGroupIndex2BoneIndex == null) { vertex.BoneWeights = null; vertex.BoneIndices = null; } else { // load bone weights // bone weight can be stored 0, so we ignore this case. //int maxWeightCount = dvertList[vIndex].GetMember("totweight").GetRawValue<int>(); var noneZeroWeightList = weights.Select(w => new Tuple <float, int>(w.GetMember("weight").GetRawValue <float>(), w.GetMember("def_nr").GetRawValue <int>())) .OrderByDescending(tuple => tuple.Item1) // sort by descending .Where(tuple => tuple.Item1 > 0.0f); // ignore zero value too int weightCount = noneZeroWeightList.Count(); vertex.BoneWeights = new float[weightCount]; vertex.BoneIndices = new uint[weightCount]; int wIndex = 0; foreach (var tuple in noneZeroWeightList) { float weight = tuple.Item1; int deformGroupIndex = tuple.Item2; vertex.BoneWeights[wIndex] = weight; // def_nr is NOT index of bones, but index of deform group // we must replace to index of bones using bone-deform mapping. vertex.BoneIndices[wIndex] = (uint)deformGroupIndex2BoneIndex[deformGroupIndex]; wIndex++; } } vertices.Add(vertex); } } // compute tangent and binormal int polyCount = vertices.Count / 3; for (int polyIndex = 0; polyIndex < polyCount; ++polyIndex) { var posArray = new Vector4[] { vertices[polyIndex * 3].Position, vertices[polyIndex * 3 + 1].Position, vertices[polyIndex * 3 + 2].Position, }; var normalArray = new Vector3[] { vertices[polyIndex * 3].Normal, vertices[polyIndex * 3 + 1].Normal, vertices[polyIndex * 3 + 2].Normal, }; var uvArray = new Vector2[] { vertices[polyIndex * 3].Texcoord, vertices[polyIndex * 3 + 1].Texcoord, vertices[polyIndex * 3 + 2].Texcoord, }; var faceTangent = MathUtil.ComputeFaceTangent(posArray[0], posArray[1], posArray[2], uvArray[0], uvArray[1], uvArray[2]); for (int vIndex = 0; vIndex < 3; ++vIndex) { // calc tangent var normal = normalArray[vIndex]; var tangent = faceTangent; MathUtil.Orthonormalize(ref normal, ref tangent); // calc binormal var binormal = Vector3.Cross(normalArray[vIndex], tangent); //binormal.Normalize(); var oldVertex = vertices[polyIndex * 3 + vIndex]; oldVertex.Tangent = tangent; oldVertex.Binormal = binormal; vertices[polyIndex * 3 + vIndex] = oldVertex; } } return(vertices.ToArray()); }