private VertexDeclaration GetVertexDeclaration(ShaderFX shader) { var d = new VertexDeclaration(); d.Types = VertexDeclarationTypes.GTAV1; d.Unknown_6h = 0; switch (shader.Name) { default: case 3839837909: //default d.Flags = 89; d.Stride = 36; d.Count = 4; break; case 1330140418: //normal d.Flags = 16473; d.Stride = 52; d.Count = 5; break; } return(d); }
private void UpdateRenderableParams(DrawableBase dwbl, ShaderFX shader) { foreach (var model in dwbl.AllModels) { if (model?.Geometries == null) { continue; } foreach (var geom in model.Geometries) { if (geom.Shader == shader) { geom.UpdateRenderableParameters = true; } } } }
private ShaderFX TryConvertMaterial(FbxNode matNode) { var shader = new ShaderFX(); var spsName = "default"; var texConns = new List <FbxNode>(); var texNames = new List <string>(); #region 3dsmax/GIMS properties //var floatValueNames = new List<string>(); //var floatValues = new List<Vector4>(); //var texValueNames = new List<string>(); //var texValues = new List<FbxNode>(); //var matProps = matNode["Properties70"]; //foreach (var matProp in matProps.Nodes)//currently broken due to GIMS not doing things right //{ // if (matProp == null) continue; // if (matProp.Name != "P") continue; // var propStr = GetStringFromObjectList(matProp.Properties, 4); // var propId = matProp.Value as string; // if (propId == null) continue; // if (propId == "3dsMax|params|SPSName") spsName = propStr?.ToLowerInvariant() ?? "default"; // if (propId.StartsWith("3dsMax|params|FloatValueNames|FloatValueNames")) floatValueNames.Add(propStr); // if (propId.StartsWith("3dsMax|params|FloatValues|FloatValues")) floatValues.Add(GetVector4FromObjectList(matProp.Properties, 4)); // if (propId.StartsWith("3dsMax|params|TexValueNames|TexValueNames")) texValueNames.Add(propStr); // if (propId.StartsWith("3dsMax|params|TexValues|TexValues")) texValues.Add(matProp); //} #endregion foreach (var conn in matNode.Connections) { if (conn.Name == "Texture") { texConns.Add(conn); var texName = GetStringFromObjectList(conn.Properties, 1)?.Replace("Texture::", ""); var ftexName = conn["FileName"]?.Value as string; if (ftexName != null) { try { texName = Path.GetFileNameWithoutExtension(ftexName); } catch { } } texNames.Add(texName); } } if (texNames.Count > 1) { spsName = "normal"; } var spsFileName = spsName + ".sps"; shader.Name = JenkHash.GenHash(spsName); shader.FileName = JenkHash.GenHash(spsFileName); shader.ParametersList = new ShaderParametersBlock(); var paramsBlock = shader.ParametersList; var pNames = new List <ShaderParamNames>(); var pVals = new List <ShaderParameter>(); shader.Unknown_Ch = 0; shader.RenderBucket = 0; shader.Unknown_12h = 32768;//shrugs shader.Unknown_1Ch = 0; shader.Unknown_24h = 0; shader.Unknown_26h = 0; shader.Unknown_28h = 0; switch (spsName) { default: case "default": //shader.RenderBucket = 3; //shader.ParameterSize = 208; //shader.ParameterDataSize = 272; AddShaderParam(pNames, pVals, ShaderParamNames.DiffuseSampler, GetTextureBaseParam(texNames, 0)); //assume first texture is diffuse... AddShaderParam(pNames, pVals, ShaderParamNames.matMaterialColorScale, new Vector4(1, 0, 0, 1)); AddShaderParam(pNames, pVals, ShaderParamNames.HardAlphaBlend, new Vector4(0, 0, 0, 0)); AddShaderParam(pNames, pVals, ShaderParamNames.useTessellation, new Vector4(0, 0, 0, 0)); AddShaderParam(pNames, pVals, ShaderParamNames.wetnessMultiplier, new Vector4(1, 0, 0, 0)); AddShaderParam(pNames, pVals, ShaderParamNames.globalAnimUV1, new Vector4(0, 1, 0, 0)); AddShaderParam(pNames, pVals, ShaderParamNames.globalAnimUV0, new Vector4(1, 0, 0, 0)); break; case "normal": //shader.RenderBucket = 0; //shader.ParameterSize = 320; //shader.ParameterDataSize = 400; AddShaderParam(pNames, pVals, ShaderParamNames.DiffuseSampler, GetTextureBaseParam(texNames, 0)); //assume first texture is diffuse... AddShaderParam(pNames, pVals, ShaderParamNames.BumpSampler, GetTextureBaseParam(texNames, 1)); //assume 2nd texture is normalmap.. AddShaderParam(pNames, pVals, ShaderParamNames.HardAlphaBlend, new Vector4(1, 0, 0, 0)); AddShaderParam(pNames, pVals, ShaderParamNames.useTessellation, new Vector4(0, 0, 0, 0)); AddShaderParam(pNames, pVals, ShaderParamNames.wetnessMultiplier, new Vector4(1, 0, 0, 0)); AddShaderParam(pNames, pVals, ShaderParamNames.bumpiness, new Vector4(1, 0, 0, 0)); AddShaderParam(pNames, pVals, ShaderParamNames.specularIntensityMult, new Vector4(0.5f, 0, 0, 0)); AddShaderParam(pNames, pVals, ShaderParamNames.specularFalloffMult, new Vector4(20, 0, 0, 0)); //too metallic? AddShaderParam(pNames, pVals, ShaderParamNames.specularFresnel, new Vector4(0.9f, 0, 0, 0)); AddShaderParam(pNames, pVals, ShaderParamNames.globalAnimUV1, new Vector4(0, 1, 0, 0)); AddShaderParam(pNames, pVals, ShaderParamNames.globalAnimUV0, new Vector4(1, 0, 0, 0)); break; } for (int i = 0; i < pVals.Count; i++) { var pVal = pVals[i]; if (pVal.DataType == 1) { pVal.Unknown_1h = (byte)(160 + ((pVals.Count - 1) - i));//seriously wtf is this and why } } MetaName[] nameHashes = new MetaName[pNames.Count]; for (int i = 0; i < pNames.Count; i++) { nameHashes[i] = (MetaName)pNames[i]; } paramsBlock.Hashes = nameHashes; paramsBlock.Parameters = pVals.ToArray(); paramsBlock.Count = pVals.Count; shader.ParameterSize = paramsBlock.ParametersSize; shader.ParameterDataSize = (ushort)(paramsBlock.BlockLength + 36);//but why +36? shader.ParameterCount = (byte)pVals.Count; shader.TextureParametersCount = paramsBlock.TextureParamsCount; shader.RenderBucketMask = (1u << shader.RenderBucket) | 0xFF00; return(shader); }
public Exporter(string name, ResourcePointerList64 <DrawableModel> models, GameFileCache Cache) { using (StreamWriter FBXwriter = new StreamWriter("FBX/" + name + ".fbx")) { var timestamp = DateTime.Now; int BaseId = 10000; StringBuilder fbx = new StringBuilder(); StringBuilder ob = new StringBuilder(); //Objects builder StringBuilder cb = new StringBuilder(); //Connections builder StringBuilder mb = new StringBuilder(); //Materials builder to get texture count in advance StringBuilder cb2 = new StringBuilder(); //and keep connections ordered cb.Append("\n}\n"); //Objects end cb.Append("\nConnections: {"); List <DrawableGeometry> Geoms = new List <DrawableGeometry>(); List <ShaderFX> Shaders = new List <ShaderFX>(); List <Texture> Textures = new List <Texture>(); //Models for (int mi = 0; mi < models.data_items.Length; mi++) { var model = models.data_items[mi]; //SubMesh & Materials foreach (var geom in model.Geometries.data_items) { if ((geom.Shader != null) && (geom.Shader.ParametersList != null) && (geom.Shader.ParametersList.Hashes != null)) { Geoms.Add(geom); Shaders.Add(geom.Shader); var gname = "Geom" + Geoms.Count; //创建节点 ob.AppendFormat("\n\tModel: 1{0}, \"Model::{1}\", \"Mesh\" {{", BaseId + Geoms.Count, gname); ob.Append("\n\t\tVersion: 232"); ob.Append("\n\t\tProperties70: {"); ob.Append("\n\t\t\tP: \"InheritType\", \"enum\", \"\", \"\",1"); ob.Append("\n\t\t\tP: \"ScalingMax\", \"Vector3D\", \"Vector\", \"\",0,0,0"); ob.Append("\n\t\t\tP: \"DefaultAttributeIndex\", \"int\", \"Integer\", \"\",0"); ob.AppendFormat("\n\t\t\tP: \"Lcl Translation\", \"Lcl Translation\", \"\", \"A\",{0},{1},{2}", 0, 0, 0); ob.AppendFormat("\n\t\t\tP: \"Lcl Rotation\", \"Lcl Rotation\", \"\", \"A\",{0},{1},{2}", 0, 0, 0);//handedness is switched in quat ob.AppendFormat("\n\t\t\tP: \"Lcl Scaling\", \"Lcl Scaling\", \"\", \"A\",{0},{1},{2}", 1, 1, 1); ob.Append("\n\t\t}"); ob.Append("\n\t\tShading: T"); ob.Append("\n\t\tCulling: \"CullingOff\"\n\t}"); //把节点挂在根节点上 cb.AppendFormat("\n\n\t;Model::{0}, Model::RootNode", gname); cb.AppendFormat("\n\tC: \"OO\",1{0},0", BaseId + Geoms.Count); //把几何体挂在节点上 cb2.AppendFormat("\n\n\t;Geometry::, Model::{0}", gname); cb2.AppendFormat("\n\tC: \"OO\",3{0},1{1}", BaseId + Geoms.Count, BaseId + Geoms.Count); //把材质挂在节点上 cb2.AppendFormat("\n\n\t;Material::, Model::{0}", gname); cb2.AppendFormat("\n\tC: \"OO\",6{0},1{1}", BaseId + Shaders.Count, BaseId + Geoms.Count); var pl = geom.Shader.ParametersList; var h = pl.Hashes; var p = pl.Parameters; for (int ip = 0; ip < h.Length; ip++) { var hash = pl.Hashes[ip]; var parm = pl.Parameters[ip]; var tex = parm.Data as TextureBase; if (tex != null) { var t = tex as Texture; if (t == null) { YtdFile file = Cache.TryGetTextureDictForTexture(tex.NameHash); if (file != null) { t = file.TextureDict.Lookup(tex.NameHash); } } var tstr = tex.Name.Trim(); if (t != null) { Textures.Add(t); cb2.AppendFormat("\n\n\t;Texture::, Material::{0}", geom.Shader.Name); cb2.AppendFormat("\n\tC: \"OP\",7{0},6{1}, ", BaseId + Textures.Count, BaseId + Shaders.Count); switch (hash.ToString().Trim()) { case "DiffuseSampler": cb2.Append("\"DiffuseColor\""); break; case "BumpSampler": cb2.Append("\"NormalMap\""); break; case "SpecSampler": cb2.Append("\"SpecularColor\""); break; case "DetailSampler": break; } } } } } } } fbx.Append("; FBX 7.1.0 project file"); fbx.Append("\nFBXHeaderExtension: {\n\tFBXHeaderVersion: 1003\n\tFBXVersion: 7100\n\tCreationTimeStamp: {\n\t\tVersion: 1000"); fbx.Append("\n\t\tYear: " + timestamp.Year); fbx.Append("\n\t\tMonth: " + timestamp.Month); fbx.Append("\n\t\tDay: " + timestamp.Day); fbx.Append("\n\t\tHour: " + timestamp.Hour); fbx.Append("\n\t\tMinute: " + timestamp.Minute); fbx.Append("\n\t\tSecond: " + timestamp.Second); fbx.Append("\n\t\tMillisecond: " + timestamp.Millisecond); fbx.Append("\n\t}\n\tCreator: \"Unity Studio by Chipicao\"\n}\n"); fbx.Append("\nGlobalSettings: {"); fbx.Append("\n\tVersion: 1000"); fbx.Append("\n\tProperties70: {"); fbx.Append("\n\t\tP: \"UpAxis\", \"int\", \"Integer\", \"\",1"); fbx.Append("\n\t\tP: \"UpAxisSign\", \"int\", \"Integer\", \"\",1"); fbx.Append("\n\t\tP: \"FrontAxis\", \"int\", \"Integer\", \"\",2"); fbx.Append("\n\t\tP: \"FrontAxisSign\", \"int\", \"Integer\", \"\",1"); fbx.Append("\n\t\tP: \"CoordAxis\", \"int\", \"Integer\", \"\",0"); fbx.Append("\n\t\tP: \"CoordAxisSign\", \"int\", \"Integer\", \"\",1"); fbx.Append("\n\t\tP: \"OriginalUpAxis\", \"int\", \"Integer\", \"\",1"); fbx.Append("\n\t\tP: \"OriginalUpAxisSign\", \"int\", \"Integer\", \"\",1"); fbx.AppendFormat("\n\t\tP: \"UnitScaleFactor\", \"double\", \"Number\", \"\",1"); fbx.Append("\n\t\tP: \"OriginalUnitScaleFactor\", \"double\", \"Number\", \"\",1.0"); fbx.Append("\n\t}\n}\n"); fbx.Append("\nDocuments: {"); fbx.Append("\n\tCount: 1"); fbx.Append("\n\tDocument: 1234567890, \"\", \"Scene\" {"); fbx.Append("\n\t\tProperties70: {"); fbx.Append("\n\t\t\tP: \"SourceObject\", \"object\", \"\", \"\""); fbx.Append("\n\t\t\tP: \"ActiveAnimStackName\", \"KString\", \"\", \"\", \"\""); fbx.Append("\n\t\t}"); fbx.Append("\n\t\tRootNode: 0"); fbx.Append("\n\t}\n}\n"); fbx.Append("\nReferences: {\n}\n"); fbx.Append("\nDefinitions: {"); fbx.Append("\n\tVersion: 100"); // fbx.AppendFormat("\n\tCount: {0}", 1 + 2 * GameObjects.Count + Materials.Count + 2 * Textures.Count + ((bool)Properties.Settings.Default["exportDeformers"] ? Skins.Count + DeformerCount + Skins.Count + 1 : 0)); fbx.Append("\n\tObjectType: \"GlobalSettings\" {"); fbx.Append("\n\t\tCount: 1"); fbx.Append("\n\t}"); fbx.Append("\n\tObjectType: \"Model\" {"); fbx.AppendFormat("\n\t\tCount: {0}", 1); fbx.Append("\n\t}"); fbx.Append("\n\tObjectType: \"Geometry\" {"); fbx.AppendFormat("\n\t\tCount: {0}", Geoms.Count); fbx.Append("\n\t}"); fbx.Append("\n\tObjectType: \"Material\" {"); fbx.AppendFormat("\n\t\tCount: {0}", Shaders.Count); fbx.Append("\n\t}"); fbx.Append("\n\tObjectType: \"Texture\" {"); fbx.AppendFormat("\n\t\tCount: {0}", Textures.Count); fbx.Append("\n\t}"); fbx.Append("\n}\n"); fbx.Append("\nObjects: {"); FBXwriter.Write(fbx); fbx.Clear(); for (int i = 0; i < Shaders.Count; i++) { ShaderFX Shader = Shaders[i]; mb.AppendFormat("\n\tMaterial: 6{0}, \"Material::{1}\", \"\" {{", BaseId + i + 1, Shader.Name); mb.Append("\n\t\tVersion: 102"); mb.Append("\n\t\tShadingModel: \"phong\""); mb.Append("\n\t\tMultiLayer: 0"); mb.Append("\n\t\tProperties70: {"); mb.Append("\n\t\t\tP: \"ShadingModel\", \"KString\", \"\", \"\", \"phong\""); //mb.Append("\n\t\t\tP: \"SpecularFactor\", \"Number\", \"\", \"A\",0"); mb.Append("\n\t\t}"); mb.Append("\n\t}"); } for (int i = 0; i < Geoms.Count; i++) { MeshFBX(Geoms[i], BaseId + i + 1, ob); //write data 8MB at a time if (ob.Length > (8 * 0x100000)) { FBXwriter.Write(ob); ob.Clear(); } } for (int i = 0; i < Textures.Count; i++) { Texture t = Textures[i]; //TODO check texture type and set path accordingly; eg. CubeMap, Texture3D string texFilename = Path.GetFullPath("FBX/" + t.Name + ".png"); byte[] bytes = DDSIO.GetPixels(t, 0); FileStream stream = new FileStream(texFilename, FileMode.Create); PngBitmapEncoder encoder = new PngBitmapEncoder(); encoder.Interlace = PngInterlaceOption.On; encoder.Frames.Add(BitmapFrame.Create(BitmapSource.Create(t.Width, t.Height, 96, 96, PixelFormats.Bgra32, null, bytes, t.Width * 4))); encoder.Save(stream); stream.Close(); // File.WriteAllBytes(texFilename, DDSIO.GetDDSFile(t)); ob.AppendFormat("\n\tTexture: 7{0}, \"Texture::{1}\", \"\" {{", BaseId + i + 1, t.Name); ob.Append("\n\t\tType: \"TextureVideoClip\""); ob.Append("\n\t\tVersion: 202"); ob.AppendFormat("\n\t\tTextureName: \"Texture::{0}\"", t.Name); ob.Append("\n\t\tProperties70: {"); ob.Append("\n\t\t\tP: \"UVSet\", \"KString\", \"\", \"\", \"UVChannel_0\""); ob.Append("\n\t\t\tP: \"UseMaterial\", \"bool\", \"\", \"\",1"); ob.Append("\n\t\t}"); ob.AppendFormat("\n\t\tMedia: \"Video::{0}\"", t.Name); ob.AppendFormat("\n\t\tFileName: \"{0}\"", texFilename); ob.AppendFormat("\n\t\tRelativeFilename: \"{0}\"", texFilename); ob.Append("\n\t}"); } ob.Append(mb); mb.Clear(); cb.Append(cb2); cb2.Clear(); FBXwriter.Write(ob); ob.Clear(); cb.Append("\n}");//Connections end FBXwriter.Write(cb); cb.Clear(); } }