MainModel

/**
 * Created by wisdom on 2017/11/23.
 */
import android.os.Handler;
import android.os.Looper;

import com.google.gson.Gson;

import java.io.IOException;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.Response;
public class MainModel implements IMainModel {
    private Handler handler = new Handler(Looper.getMainLooper());


    public void getGoods(final OnNetListener<GoosBean> onNetListener) {
        HttpUtils.getHttpUtils().doGet(Api.url, new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {

            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                String string = response.body().string();
                final GoosBean goosBean = new Gson().fromJson(string, GoosBean.class);
                handler.post(new Runnable() {
                    @Override
                    public void run() {
                        onNetListener.onSuccess(goosBean);
                    }
                });
            }
        });
    }
}
using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; using UnityEditor; using UnityEngine; using TriLibCore; using UltimateGameTools.MeshSimplifier; namespace ModelLODTool { // 尺寸类型枚举 public enum ObjectSizeType { Tiny, Small, MediumSmall, SmallMedium, Medium, MediumLarge, Large, Giant } // LOD层级配置 [Serializable] public class LODLevelConfig { public int lodIndex; public float distance; public float trianglePercentage; public GameObject meshObject; public string assetPath; } // 模型配置 [Serializable] public class ModelConfig : ScriptableObject { public string objectName; public string chineseName; public string englishName; public ObjectSizeType sizeType; public string modelPath; public List<LODLevelConfig> lodLevels = new List<LODLevelConfig>(); } // 配置数据库 public class ModelConfigDatabase : ScriptableObject { public List<ModelConfig> modelConfigs = new List<ModelConfig>(); public ModelConfig GetConfig(string name) { return modelConfigs.FirstOrDefault(c => c.objectName == name); } public void AddConfig(ModelConfig config) { if (!modelConfigs.Contains(config)) modelConfigs.Add(config); } public void UpdateConfig(ModelConfig config) { int index = modelConfigs.FindIndex(c => c.objectName == config.objectName); if (index != -1) modelConfigs[index] = config; } public bool ContainsConfig(string name) { return modelConfigs.Any(c => c.objectName == name); } } // LOD管理器(场景中使用) public class ModelLODManager : MonoBehaviour { public string modelName; public LODGroup lodGroup; public ModelConfig config; public void ApplyLODConfig() { if (lodGroup == null || config == null || config.lodLevels == null) return; var lods = new LOD[config.lodLevels.Count]; for (int i = 0; i < config.lodLevels.Count; i++) { var lodConfig = config.lodLevels[i]; if (lodConfig.meshObject) { var renderers = lodConfig.meshObject.GetComponentsInChildren<Renderer>(); lods[i] = new LOD(1 - (i / (float)config.lodLevels.Count), renderers); } } lodGroup.SetLODs(lods); lodGroup.RecalculateBounds(); } } // 主工具类 public class ModelLODConfigTool : EditorWindow { // 配置与UI变量 private ModelConfig currentConfig; private ModelConfigDatabase configDatabase; private readonly string dbPath = "Assets/ModelLODConfig/ModelConfigDatabase.asset"; private Vector2 scrollPos; private GameObject previewRoot; private GameObject mainModel; private string[] configNames; private int selectedConfigIndex = -1; private bool showPreview = true; // LOD距离预设(按尺寸类型) private readonly Dictionary<ObjectSizeType, List<float>> sizeLodDistances = new Dictionary<ObjectSizeType, List<float>> { { ObjectSizeType.Tiny, new() { 0.5f, 1f, 2f } }, { ObjectSizeType.Small, new() { 1f, 2f, 3f } }, { ObjectSizeType.MediumSmall, new() { 1f, 3f, 5f } }, { ObjectSizeType.SmallMedium, new() { 1f, 5f, 10f } }, { ObjectSizeType.Medium, new() { 2f, 7f, 15f } }, { ObjectSizeType.MediumLarge, new() { 4f, 10f, 20f } }, { ObjectSizeType.Large, new() { 8f, 20f, 50f } }, { ObjectSizeType.Giant, new() { 10f, 50f, 100f } }, }; // 面数百分比预设 private readonly List<float> lodTrianglePercent = new() { 100f, 50f, 10f }; [MenuItem("Tools/模型LOD配置工具")] public static void ShowWindow() => GetWindow<ModelLODConfigTool>("模型LOD配置工具"); private void OnEnable() { LoadDatabase(); CreatePreviewRoot(); CreateNewConfig(); } private void OnDisable() { if (previewRoot) DestroyImmediate(previewRoot); } private void OnGUI() { scrollPos = EditorGUILayout.BeginScrollView(scrollPos); DrawConfigSelection(); DrawModelInfo(); DrawMainModelSection(); DrawLODConfig(); DrawPreview(); DrawActionButtons(); EditorGUILayout.EndScrollView(); } #region UI绘制 private void DrawConfigSelection() { EditorGUILayout.LabelField("配置管理", EditorStyles.boldLabel); EditorGUILayout.BeginHorizontal(); if (configNames != null && configNames.Length > 0) { selectedConfigIndex = EditorGUILayout.Popup("选择配置", selectedConfigIndex, configNames); if (GUILayout.Button("加载", GUILayout.Width(60)) && selectedConfigIndex >= 0) LoadSelectedConfig(); } if (GUILayout.Button("新建", GUILayout.Width(60))) CreateNewConfig(); EditorGUILayout.EndHorizontal(); } private void DrawModelInfo() { EditorGUILayout.Space(); EditorGUILayout.LabelField("模型信息", EditorStyles.boldLabel); currentConfig.objectName = EditorGUILayout.TextField("物体名称", currentConfig.objectName); currentConfig.chineseName = EditorGUILayout.TextField("中文名称", currentConfig.chineseName); currentConfig.englishName = EditorGUILayout.TextField("英文名称", currentConfig.englishName); currentConfig.sizeType = (ObjectSizeType)EditorGUILayout.EnumPopup("尺寸类型", currentConfig.sizeType); if (GUILayout.Button("应用尺寸预设LOD")) ApplySizeLodPreset(); } private void DrawMainModelSection() { EditorGUILayout.Space(); EditorGUILayout.LabelField("主模型", EditorStyles.boldLabel); EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField(mainModel ? $"已加载: {mainModel.name}" : "未加载模型"); if (GUILayout.Button("加载主模型", GUILayout.Width(100))) LoadMainModel(); EditorGUILayout.EndHorizontal(); } private void DrawLODLevel(int index) { var lod = currentConfig.lodLevels[index]; EditorGUILayout.BeginVertical(EditorStyles.helpBox); EditorGUILayout.LabelField($"LOD {index}", EditorStyles.boldLabel); lod.distance = EditorGUILayout.FloatField("距离阈值(m)", lod.distance); lod.trianglePercentage = EditorGUILayout.FloatField("面数百分比(%)", lod.trianglePercentage); EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField(lod.meshObject ? lod.meshObject.name : "未加载模型"); if (GUILayout.Button("加载模型", GUILayout.Width(80))) LoadLODModel(index); EditorGUILayout.EndHorizontal(); EditorGUILayout.EndVertical(); } private void DrawLODConfig() { EditorGUILayout.Space(); EditorGUILayout.LabelField("LOD配置", EditorStyles.boldLabel); for (int i = 0; i < currentConfig.lodLevels.Count; i++) { DrawLODLevel(i); EditorGUILayout.Space(); } if (GUILayout.Button("自动生成LOD")) GenerateAutoLOD(); } private void DrawPreview() { EditorGUILayout.Space(); EditorGUILayout.LabelField("预览", EditorStyles.boldLabel); showPreview = EditorGUILayout.Toggle("显示预览", showPreview); if (showPreview && previewRoot) { Rect rect = GUILayoutUtility.GetRect(position.width - 40, 200); EditorGUI.DrawPreviewTexture(rect, GeneratePreviewTex()); } } private void DrawActionButtons() { EditorGUILayout.Space(); EditorGUILayout.BeginHorizontal(); if (GUILayout.Button("保存配置")) SaveConfig(); if (GUILayout.Button("应用到场景")) ApplyToScene(); if (GUILayout.Button("导出LOD")) ExportLODs(); EditorGUILayout.EndHorizontal(); } #endregion #region 核心逻辑 private void LoadDatabase() { configDatabase = AssetDatabase.LoadAssetAtPath<ModelConfigDatabase>(dbPath); if (!configDatabase) { Directory.CreateDirectory(Path.GetDirectoryName(dbPath)); configDatabase = CreateInstance<ModelConfigDatabase>(); AssetDatabase.CreateAsset(configDatabase, dbPath); AssetDatabase.SaveAssets(); } UpdateConfigNames(); } private void UpdateConfigNames() => configNames = configDatabase.modelConfigs.Select(c => c.objectName).ToArray(); private void CreateNewConfig() { currentConfig = CreateInstance<ModelConfig>(); currentConfig.objectName = "新模型"; currentConfig.sizeType = ObjectSizeType.Medium; InitLODLevels(); ClearPreview(); selectedConfigIndex = -1; } private void InitLODLevels() { currentConfig.lodLevels.Clear(); var distances = sizeLodDistances[currentConfig.sizeType]; for (int i = 0; i < distances.Count; i++) { currentConfig.lodLevels.Add(new LODLevelConfig { lodIndex = i, distance = distances[i], trianglePercentage = lodTrianglePercent[i] }); } } private void LoadSelectedConfig() { currentConfig = configDatabase.GetConfig(configNames[selectedConfigIndex]); if (currentConfig == null) return; if (!string.IsNullOrEmpty(currentConfig.modelPath) && File.Exists(currentConfig.modelPath)) LoadModel(currentConfig.modelPath, go => mainModel = go); for (int i = 0; i < currentConfig.lodLevels.Count; i++) { var lod = currentConfig.lodLevels[i]; if (!string.IsNullOrEmpty(lod.assetPath) && File.Exists(lod.assetPath)) LoadModel(lod.assetPath, go => currentConfig.lodLevels[i].meshObject = go); } } private void ApplySizeLodPreset() { var distances = sizeLodDistances[currentConfig.sizeType]; for (int i = 0; i < distances.Count; i++) currentConfig.lodLevels[i].distance = distances[i]; } private void LoadMainModel() { string path = EditorUtility.OpenFilePanel("选择主模型", "", "fbx,obj,glb,gltf"); if (string.IsNullOrEmpty(path)) return; LoadModel(path, go => { mainModel = go; mainModel.transform.SetParent(previewRoot.transform); mainModel.transform.localPosition = Vector3.zero; currentConfig.modelPath = path; }); } private void LoadLODModel(int index) { string path = EditorUtility.OpenFilePanel($"选择LOD {index}模型", "", "fbx,obj,glb,gltf"); if (string.IsNullOrEmpty(path)) return; LoadModel(path, go => { currentConfig.lodLevels[index].meshObject = go; currentConfig.lodLevels[index].assetPath = path; go.transform.SetParent(previewRoot.transform); go.transform.localPosition = new Vector3(index * 2, 0, 0); }); } // 模型加载(完全适配TriLib 2.2.0) private void LoadModel(string path, Action<GameObject> onLoaded) { if (!File.Exists(path)) { EditorUtility.DisplayDialog("错误", "文件不存在!", "确定"); return; } try { var options = AssetLoader.CreateDefaultLoaderOptions(); options.ImportMaterials = true; // 使用TriLib 2.2.0的异步加载方法 AssetLoader.LoadModelFromFile( path, // 成功回调 - 只接受AssetLoaderContext参数 context => { GameObject rootGameObject = context.RootGameObject; if (rootGameObject != null) { onLoaded?.Invoke(rootGameObject); Repaint(); } else { EditorUtility.DisplayDialog("加载失败", "无法获取加载的游戏对象", "确定"); } }, // 进度回调 - 接受AssetLoaderContext和float两个参数 (context, progress) => { EditorUtility.DisplayProgressBar("加载中", $"进度: {progress:P0}", progress); if (progress >= 1f) EditorUtility.ClearProgressBar(); }, // 错误回调 error => { EditorUtility.ClearProgressBar(); string errorMsg = error != null ? error.GetErrorMessage() : "未知错误"; EditorUtility.DisplayDialog("加载失败", errorMsg, "确定"); }, null, // 取消回调 null, // 自定义资源创建器 options // 加载选项 ); } catch (NotImplementedException niex) { EditorUtility.ClearProgressBar(); Debug.LogError($"未实现的方法: {niex.Message}"); EditorUtility.DisplayDialog("错误", $"遇到未实现的方法: {niex.Message}\n\n请检查TriLib插件版本是否兼容。", "确定"); } catch (Exception ex) { EditorUtility.ClearProgressBar(); Debug.LogError($"加载失败: {ex.Message}"); EditorUtility.DisplayDialog("错误", ex.Message, "确定"); } } // 自动生成LOD(适配Mesh Simplifier v1.11) private void GenerateAutoLOD() { if (!mainModel) { EditorUtility.DisplayDialog("错误", "请先加载主模型!", "确定"); return; } // 清空现有LOD foreach (var lod in currentConfig.lodLevels) if (lod.meshObject) DestroyImmediate(lod.meshObject); // 获取主模型网格和材质 var mainMeshFilter = mainModel.GetComponentInChildren<MeshFilter>(); if (mainMeshFilter == null) { EditorUtility.DisplayDialog("错误", "主模型无网格数据!", "确定"); return; } Mesh mainMesh = mainMeshFilter.sharedMesh; var mainMaterials = mainModel.GetComponentInChildren<Renderer>().sharedMaterials; try { // 初始化网格简化器 - 适配Mesh Simplifier v1.11 var simplifier = new Simplifier(); simplifier.ProtectionMode = 1; // 保护UV接缝和边界 simplifier.MaximumError = 0.01f; // 设置最大误差 simplifier.KeepSymmetry = true; // 保持对称性 simplifier.KeepBorderEdges = true; // 保持边界边 simplifier.KeepUVSeamEdges = true; // 保持UV接缝边 // 生成各层级LOD for (int i = 0; i < currentConfig.lodLevels.Count; i++) { var lod = currentConfig.lodLevels[i]; float ratio = lod.trianglePercentage / 100f; EditorUtility.DisplayProgressBar("生成LOD", $"正在生成LOD {i} ({ratio:P0})", (float)i / currentConfig.lodLevels.Count); try { // 执行网格简化 - 使用v1.11的正确API Mesh simplifiedMesh = new Mesh(); // 配置简化参数 simplifier.VertexCountReduction = ratio; // 执行简化 simplifier.ReduceMesh(mainMesh, ref simplifiedMesh); // 确保简化后的网格有效 if (simplifiedMesh.vertexCount > 0 && simplifiedMesh.triangles.Length > 0) { // 创建LOD模型 GameObject lodObj = new GameObject($"LOD{i}_({ratio:P0})"); lodObj.transform.SetParent(previewRoot.transform); lodObj.transform.localPosition = new Vector3(i * 2, 0, 0); // 配置网格和材质 var filter = lodObj.AddComponent<MeshFilter>(); filter.sharedMesh = simplifiedMesh; var renderer = lodObj.AddComponent<MeshRenderer>(); renderer.sharedMaterials = mainMaterials; lod.meshObject = lodObj; } else { throw new Exception("简化后的网格无效,请调整简化参数"); } } catch (NotImplementedException niex) { EditorUtility.ClearProgressBar(); Debug.LogError($"Mesh Simplifier中未实现的方法: {niex.Message}"); EditorUtility.DisplayDialog("错误", $"生成LOD {i}时遇到未实现的方法: {niex.Message}\n\n请检查Mesh Simplifier插件版本是否兼容。", "确定"); return; } catch (Exception ex) { EditorUtility.ClearProgressBar(); Debug.LogError($"生成LOD {i}失败: {ex.Message}"); EditorUtility.DisplayDialog("错误", $"生成LOD {i}失败: {ex.Message}", "确定"); return; } } EditorUtility.ClearProgressBar(); EditorUtility.DisplayDialog("成功", "LOD生成完成!", "确定"); } catch (NotImplementedException niex) { EditorUtility.ClearProgressBar(); Debug.LogError($"Mesh Simplifier中未实现的方法: {niex.Message}"); EditorUtility.DisplayDialog("错误", $"初始化网格简化器时遇到未实现的方法: {niex.Message}\n\n请检查Mesh Simplifier插件版本是否兼容。", "确定"); } catch (Exception ex) { EditorUtility.ClearProgressBar(); Debug.LogError($"生成LOD失败: {ex.Message}"); EditorUtility.DisplayDialog("错误", $"生成LOD时出错: {ex.Message}", "确定"); } } private void SaveConfig() { if (string.IsNullOrEmpty(currentConfig.objectName)) { EditorUtility.DisplayDialog("错误", "请输入物体名称!", "确定"); return; } if (configDatabase.ContainsConfig(currentConfig.objectName)) { if (!EditorUtility.DisplayDialog("提示", "覆盖现有配置?", "是", "否")) return; configDatabase.UpdateConfig(currentConfig); } else { configDatabase.AddConfig(currentConfig); AssetDatabase.AddObjectToAsset(currentConfig, dbPath); } EditorUtility.SetDirty(configDatabase); AssetDatabase.SaveAssets(); UpdateConfigNames(); EditorUtility.DisplayDialog("成功", "配置已保存!", "确定"); } private void ApplyToScene() { GameObject obj = new GameObject(currentConfig.objectName); LODGroup lodGroup = obj.AddComponent<LODGroup>(); ModelLODManager manager = obj.AddComponent<ModelLODManager>(); manager.modelName = currentConfig.objectName; manager.lodGroup = lodGroup; manager.config = currentConfig; for (int i = 0; i < currentConfig.lodLevels.Count; i++) { if (currentConfig.lodLevels[i].meshObject) { GameObject lodObj = Instantiate(currentConfig.lodLevels[i].meshObject, obj.transform); lodObj.transform.localPosition = Vector3.zero; } } manager.ApplyLODConfig(); Selection.activeObject = obj; } private void ExportLODs() { string path = EditorUtility.OpenFolderPanel("选择导出目录", "", ""); if (string.IsNullOrEmpty(path)) return; for (int i = 0; i < currentConfig.lodLevels.Count; i++) { EditorUtility.DisplayProgressBar("导出LOD", $"正在导出LOD {i}", (float)i / currentConfig.lodLevels.Count); var lod = currentConfig.lodLevels[i]; if (lod.meshObject) { try { string exportPath = $"{path}/{currentConfig.objectName}_LOD{i}.fbx"; ExportMesh(lod.meshObject.GetComponent<MeshFilter>().sharedMesh, exportPath); lod.assetPath = exportPath; } catch (Exception ex) { EditorUtility.ClearProgressBar(); Debug.LogError($"导出LOD {i}失败: {ex.Message}"); EditorUtility.DisplayDialog("错误", $"导出LOD {i}失败: {ex.Message}", "确定"); return; } } } EditorUtility.ClearProgressBar(); EditorUtility.DisplayDialog("成功", "导出完成!", "确定"); } private void ExportMesh(Mesh mesh, string path) { try { // 使用Unity的FBX导出功能 GameObject temp = new GameObject("TempExport"); var filter = temp.AddComponent<MeshFilter>(); filter.sharedMesh = mesh; // 使用反射调用UnityEditor.FBXExporter(如果可用) var exporterType = Type.GetType("UnityEditor.FBXExporter,UnityEditor"); if (exporterType != null) { var exportMethod = exporterType.GetMethod("ExportObject", BindingFlags.Static | BindingFlags.Public); if (exportMethod != null) { exportMethod.Invoke(null, new object[] { path, temp }); } else { // 备用方法:使用AssetDatabase if (AssetDatabase.Contains(mesh)) { string assetPath = AssetDatabase.GetAssetPath(mesh); AssetDatabase.CopyAsset(assetPath, path); } else { AssetDatabase.CreateAsset(mesh, path); } } } else { // 备用方法:使用AssetDatabase if (AssetDatabase.Contains(mesh)) { string assetPath = AssetDatabase.GetAssetPath(mesh); AssetDatabase.CopyAsset(assetPath, path); } else { AssetDatabase.CreateAsset(mesh, path); } } DestroyImmediate(temp); } catch (Exception ex) { Debug.LogError($"导出网格失败: {ex.Message}"); throw; // 重新抛出异常,由调用者处理 } } #endregion #region 辅助方法 private void CreatePreviewRoot() { if (!previewRoot) { previewRoot = new GameObject("LOD预览根节点"); previewRoot.hideFlags = HideFlags.HideAndDontSave; } else ClearPreview(); } private void ClearPreview() { if (previewRoot) foreach (Transform child in previewRoot.transform) DestroyImmediate(child.gameObject); mainModel = null; } private Texture2D GeneratePreviewTex() { Texture2D tex = new Texture2D(256, 256); Color[] pixels = new Color[256 * 256]; Array.Fill(pixels, new Color(0.1f, 0.1f, 0.1f)); tex.SetPixels(pixels); tex.Apply(); return tex; } #endregion } } 严重性 代码 说明 项目 文件 行 禁止显示状态 错误(活动) CS1593 委托“Action<AssetLoaderContext>”未采用 2 个参数 Assembly-CSharp-Editor H:\YaoMo\MeshLod\Assets\Editor\ModelLODConfigTool.cs 393 错误(活动) CS1593 委托“Action<AssetLoaderContext, float>”未采用 1 个参数 Assembly-CSharp-Editor H:\YaoMo\MeshLod\Assets\Editor\ModelLODConfigTool.cs 400 错误(活动) CS1061 “Simplifier”未包含“VertexCountReduction”的定义,并且找不到可接受第一个“Simplifier”类型参数的可访问扩展方法“VertexCountReduction”(是否缺少 using 指令或程序集引用?) Assembly-CSharp-Editor H:\YaoMo\MeshLod\Assets\Editor\ModelLODConfigTool.cs 472 错误(活动) CS1061 “Simplifier”未包含“ReduceMesh”的定义,并且找不到可接受第一个“Simplifier”类型参数的可访问扩展方法“ReduceMesh”(是否缺少 using 指令或程序集引用?) Assembly-CSharp-Editor H:\YaoMo\MeshLod\Assets\Editor\ModelLODConfigTool.cs 475 错误(活动) CS1061 “Simplifier”未包含“ProtectionMode”的定义,并且找不到可接受第一个“Simplifier”类型参数的可访问扩展方法“ProtectionMode”(是否缺少 using 指令或程序集引用?) Assembly-CSharp-Editor H:\YaoMo\MeshLod\Assets\Editor\ModelLODConfigTool.cs 452 错误(活动) CS1061 “Simplifier”未包含“MaximumError”的定义,并且找不到可接受第一个“Simplifier”类型参数的可访问扩展方法“MaximumError”(是否缺少 using 指令或程序集引用?) Assembly-CSharp-Editor H:\YaoMo\MeshLod\Assets\Editor\ModelLODConfigTool.cs 453 错误(活动) CS1061 “Simplifier”未包含“KeepUVSeamEdges”的定义,并且找不到可接受第一个“Simplifier”类型参数的可访问扩展方法“KeepUVSeamEdges”(是否缺少 using 指令或程序集引用?) Assembly-CSharp-Editor H:\YaoMo\MeshLod\Assets\Editor\ModelLODConfigTool.cs 456 错误(活动) CS1061 “Simplifier”未包含“KeepSymmetry”的定义,并且找不到可接受第一个“Simplifier”类型参数的可访问扩展方法“KeepSymmetry”(是否缺少 using 指令或程序集引用?) Assembly-CSharp-Editor H:\YaoMo\MeshLod\Assets\Editor\ModelLODConfigTool.cs 454 错误(活动) CS1061 “Simplifier”未包含“KeepBorderEdges”的定义,并且找不到可接受第一个“Simplifier”类型参数的可访问扩展方法“KeepBorderEdges”(是否缺少 using 指令或程序集引用?) Assembly-CSharp-Editor H:\YaoMo\MeshLod\Assets\Editor\ModelLODConfigTool.cs 455
07-19
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值