local AssetDataAnalysis = {} --存储超标数据,在最后输出汇总报表 local analysisData = { ["Basic"] = {}, ["Overdraw"] = {}, ["Mipmaps"] = {}, } local parentDir = "AssetAnalysisResult/" --档位名称转换 local LODName = { ["LOD0"] = "低", ["LOD1"] = "中", ["LOD2"] = "高", } --读取和写入csv --TODO【新增检查项】需要扩展对应模块 local ModuleCSVTitle = { ["Common"] = { "AssetType", "LOD", "CameraModel", "Tips", }, ["Basic"] = { "AssetName", "BatchesCount", "TrianglesCount", "DrawCallsCount", "TextureMemory", "MeshMemory", "AnimationClipMemory", "BoneCount", "MaterialMemory", "TextureCount", "MeshCount", "MaterialCount", "AnimationClipCount", "SetPassCallsCount", "VerticesCount", }, ["Overdraw"] = { "AssetName", "ScreenPixels", "OverdrawPixels", "OverdrawPixelsQuChong", "OverdrawMaxLayer", "OverdrawPixelsRatio", "OverdrawPixelsRatioQuChong", }, ["Mipmaps"] = { "AssetName", "MaterialName", "TextureName", "TextureSize", "MaxMipmapSize", "AvgMipmapSize", "AdvanceMipmapSize", "MipmapRatio", }, } --提示用,输出csv使用,以及单位名称 --TODO【新增检查项】需要扩展 local NameConfig = { ["AssetName"] = {name = "资源", unit = ""}, ["TextureMemory"] = {name = "贴图内存", unit = "MB"}, ["TextureCount"] = {name = "贴图数量", unit = ""}, ["MeshMemory"] = {name = "网格内存", unit = "MB"}, ["MeshCount"] = {name = "网格数量", unit = ""}, ["MaterialMemory"] = {name = "材质内存", unit = "KB"}, ["MaterialCount"] = {name = "材质数量", unit = ""}, ["AnimationClipMemory"] = {name = "动画内存", unit = "MB"}, ["AnimationClipCount"] = {name = "动画数量", unit = ""}, ["SetPassCallsCount"] = {name = "SetPassCount", unit = ""}, ["DrawCallsCount"] = {name = "DrawCallCount", unit = ""}, ["BatchesCount"] = {name = "BatchCount", unit = ""}, ["VerticesCount"] = {name = "顶点数", unit = ""}, ["TrianglesCount"] = {name = "三角面数", unit = ""}, ["BoneCount"] = {name = "骨骼数量", unit = ""}, ["ScreenPixels"] = {name = "屏幕总像素", unit = ""}, ["OverdrawPixels"] = {name = "重绘总像素", unit = ""}, ["OverdrawPixelsQuChong"] = {name = "重绘去重像素", unit = ""}, ["OverdrawMaxLayer"] = {name = "最大重绘层", unit = ""}, ["OverdrawPixelsRatio"] = {name = "重绘像素倍率", unit = ""}, ["OverdrawPixelsRatioQuChong"] = {name = "去重像素倍率", unit = ""}, ["MaterialName"] = {name = "材质", unit = ""}, ["TextureName"] = {name = "贴图", unit = ""}, ["TextureSize"] = {name = "贴图尺寸", unit = ""}, ["MaxMipmapSize"] = {name = "最大mipmap尺寸", unit = ""}, ["AvgMipmapSize"] = {name = "平均mipmap尺寸", unit = ""}, ["AdvanceMipmapSize"] = {name = "推荐mipmap尺寸", unit = ""}, ["MipmapRatio"] = {name = "贴图mipmap倍率", unit = ""}, ["AssetType"] = {name = "资源类型"}, ["LOD"] = {name = "画质档位"}, ["CameraModel"] = {name = "相机模式"}, ["Tips"] = {name = "超出标准数据"}, } --数据标准 --TODO【新增检查项】需要扩展标准 local DataConfig = { ["Basic"] = { ["模型"] = { --TypeA:大类,英雄、宠物等 --TypeB:中类,展示、PVP、主城 --TypeC:小类,模型,武器 --角色Basic数据标准 ["Hero"] = { ["Normal"] = { ["Model"] = { ["TextureMemory"] = {min = 0, max = 8.0}, --Hero_LvBu 6.6M ["MeshMemory"] = {min = 0, max = 4.0}, --Hero_LvBu 3.5M ["AnimationClipMemory"] = {min = 0, max = 8.0}, --Hero_LvBu 6.8M ["DrawCallsCount"] = {min = 0, max = 10}, ["BatchesCount"] = {min = 0, max = 10}, ["TrianglesCount"] = {min = 0, max = 42000}, --LvBu 41692 ["BoneCount"] = {min = 0, max = 170}, --LvBu 161 }, ["Weapon"] = { ["TextureMemory"] = {min = 0, max = 2.0}, --Hero_LvBu_Weapon_Right 1.4M ["MeshMemory"] = {min = 0, max = 1.0}, --Hero_LvBu_Weapon_Right 0.14M ["AnimationClipMemory"] = {min = 0, max = 2.0}, --Hero_DiaoChan 0.91M ["DrawCallsCount"] = {min = 0, max = 1}, ["BatchesCount"] = {min = 0, max = 1}, ["TrianglesCount"] = {min = 0, max = 3500}, ["BoneCount"] = {min = 0, max = 5}, }, }, ["PVP"] = { ["Model"] = { ["TextureMemory"] = {min = 0, max = 1.0}, --Hero_LvBu_PVP 0.45M ["MeshMemory"] = {min = 0, max = 2.0}, --Hero_LvBuP2_PVP 1.14M ["AnimationClipMemory"] = {min = 0, max = 4.0}, --Hero_DiaoChan_PVP 3.1M ["DrawCallsCount"] = {min = 0, max = 1}, ["BatchesCount"] = {min = 0, max = 1}, ["TrianglesCount"] = {min = 0, max = 4000}, ["BoneCount"] = {min = 0, max = 90}, --LvBu 83 }, ["Weapon"] = { ["TextureMemory"] = {min = 0, max = 1.0}, --Hero_LvBu_PVP_Weapon_Right 0.45M ["MeshMemory"] = {min = 0, max = 0.5}, --Hero_LvBu_PVP_Weapon_Right 0.026M ["AnimationClipMemory"] = {min = 0, max = 1.0}, --Hero_DiaoChan_PVP_Weapon_Right 0.7M ["DrawCallsCount"] = {min = 0, max = 1}, ["BatchesCount"] = {min = 0, max = 1}, ["TrianglesCount"] = {min = 0, max = 500}, ["BoneCount"] = {min = 0, max = 5}, }, }, ["Show"] = { ["Model"] = { ["TextureMemory"] = {min = 0, max = 10.0}, --Hero_LvBu_Show 8.3M ["MeshMemory"] = {min = 0, max = 10.0}, --Hero_LvBu_Show 8.3M ["AnimationClipMemory"] = {min = 0, max = 2.0}, --Hero_LvBuS1_Show 2.2M ["DrawCallsCount"] = {min = 0, max = 30}, --预留Fur材质可能会有的20个DC ["BatchesCount"] = {min = 0, max = 30}, ["TrianglesCount"] = {min = 0, max = 120000}, --同样允许展示材质的渲染面数过高 Hero_LvBu_Show 115908面数 ["BoneCount"] = {min = 0, max = 180}, --LvBu_Show 171 }, ["Weapon"] = { ["TextureMemory"] = {min = 0, max = 4.0}, --Hero_LvBuS1_Show_Weapon_Right 3.4M ["MeshMemory"] = {min = 0, max = 1.0}, --Hero_LvBu_Show_Weapon_Right 0.56M ["AnimationClipMemory"] = {min = 0, max = 0.5}, --Hero_DiaoChanS1_Show_Weapon_Right 0.1M ["DrawCallsCount"] = {min = 0, max = 25}, --预留Fur材质可能会有的20个DC ["BatchesCount"] = {min = 0, max = 25}, ["TrianglesCount"] = {min = 0, max = 15000}, --Hero_LvBuS1_Show_Weapon_Right 12616 ["BoneCount"] = {min = 0, max = 5}, }, } }, --宠物Basic数据标准 ["Pet"] = { ["Normal"] = { ["Model"] = { ["TextureMemory"] = {min = 0, max = 10.0}, ["MeshMemory"] = {min = 0, max = 4.0}, ["AnimationClipMemory"] = {min = 0, max = 1.0}, ["DrawCallsCount"] = {min = 0, max = 10}, ["BatchesCount"] = {min = 0, max = 10}, ["TrianglesCount"] = {min = 0, max = 42000}, --大龙女46253、中龙女39163, ["BoneCount"] = {min = 0, max = 130}, --大龙女 127 }, }, ["PVP"] = { ["Model"] = { ["TextureMemory"] = {min = 0, max = 1.0}, ["MeshMemory"] = {min = 0, max = 1.0}, ["AnimationClipMemory"] = {min = 0, max = 1.0}, ["DrawCallsCount"] = {min = 0, max = 3}, ["BatchesCount"] = {min = 0, max = 3}, ["TrianglesCount"] = {min = 0, max = 6000}, ["BoneCount"] = {min = 0, max = 50}, --TODO 待定 }, }, ["Show"] = { ["Model"] = { ["TextureMemory"] = {min = 0, max = 45.0}, --大龙女42M ["MeshMemory"] = {min = 0, max = 10.0}, ["AnimationClipMemory"] = {min = 0, max = 2.0}, ["DrawCallsCount"] = {min = 0, max = 30}, ["BatchesCount"] = {min = 0, max = 30}, ["TrianglesCount"] = {min = 0, max = 150000}, ["BoneCount"] = {min = 0, max = 130}, --大龙女 127 }, } }, }, ["特效"] = { ["LOD0"] = { ["DrawCallsCount"] = {min = 0, max = 10}, ["BatchesCount"] = {min = 0, max = 5}, ["TextureMemory"] = {min = 0, max = 3}, ["TrianglesCount"] = {min = 0, max = 6000}, --诸葛亮技能SA_1 5285, 最复杂的技能SkillAttack_4_2 4088 }, ["LOD1"] = { ["DrawCallsCount"] = {min = 0, max = 20}, ["BatchesCount"] = {min = 0, max = 10}, ["TextureMemory"] = {min = 0, max = 5}, ["TrianglesCount"] = {min = 0, max = 30000}, --诸葛亮技能SA_1 39768, 最复杂的技能SkillAttack_4_2 23354 }, ["LOD2"] = { ["DrawCallsCount"] = {min = 0, max = 40}, ["BatchesCount"] = {min = 0, max = 20}, ["TextureMemory"] = {min = 0, max = 5}, ["TrianglesCount"] = {min = 0, max = 30000}, --诸葛亮技能SA_1 48860, 最复杂的技能SkillAttack_4_2 33552 } } }, ["Mipmaps"] = { ["展示相机"] = { ["MipmapRatio"] = {min = 0.5, max = 2.0}, }, ["主城相机"] = { ["MipmapRatio"] = {min = 0.5, max = 2.0}, }, ["PVP相机"] = { ["MipmapRatio"] = {min = 0.5, max = 2.0}, } }, ["Overdraw"] = { ["LOD0"] = { ["OverdrawPixelsRatio"] = {min = 0.0, max = 2.0}, }, ["LOD1"] = { ["OverdrawPixelsRatio"] = {min = 0.0, max = 3.5}, }, ["LOD2"] = { ["OverdrawPixelsRatio"] = {min = 0.0, max = 4.5}, } } } --分析CSV数据 function AssetDataAnalysis.AnalysisProfilerData(csvPath) if not LuaExt.FileExists(csvPath) then return end local pathArray = string.split(csvPath, "/") local fileName = pathArray[#pathArray] local fileNameSplit = string.split(fileName, "-") local modules = fileNameSplit[1] local cameraModel = fileNameSplit[3] local assetType = fileNameSplit[4] local lod = fileNameSplit[5] local csvData = AssetDataAnalysis.ReadAnalysisCSVData(csvPath, modules) if modules == "Basic" then AssetDataAnalysis.AnalysisProfilerModule(csvData, assetType, lod, cameraModel) elseif modules == "Overdraw" then AssetDataAnalysis.AnalysisOverdrawModule(csvData, assetType, lod, cameraModel) elseif modules == "Mipmaps" then AssetDataAnalysis.AnalysisMipmapModule(csvData, assetType, lod, cameraModel) end end --输出超标数据到csv function AssetDataAnalysis.OutputAnalysisResult2CSV() local BasicCSVStr = AssetDataAnalysis.OutputCSVStr(ModuleCSVTitle.Basic, analysisData.Basic) local OverdrawCSVStr = AssetDataAnalysis.OutputCSVStr(ModuleCSVTitle.Overdraw, analysisData.Overdraw) local mipmapsCSVStr = AssetDataAnalysis.OutputCSVStr(ModuleCSVTitle.Mipmaps, analysisData.Mipmaps) local curDate = UTL.Time.OsDateOriginal("*t", os.time()) local timeStr = string.format("%s月%s日%s时%s分%s秒", curDate.month, curDate.day, curDate.hour, curDate.min, curDate.sec) if not string.isNilOrEmpty(BasicCSVStr) then local fileName = string.format("Basic-%s-性能数据报告汇总.csv", timeStr) AssetDataAnalysis.WriteCSVWithBom(parentDir .. fileName, BasicCSVStr) end if not string.isNilOrEmpty(OverdrawCSVStr) then local fileName = string.format("Overdraw-%s-性能数据报告汇总.csv", timeStr) AssetDataAnalysis.WriteCSVWithBom(parentDir .. fileName, OverdrawCSVStr) end if not string.isNilOrEmpty(mipmapsCSVStr) then local fileName = string.format("Mipmaps-%s-性能数据报告汇总.csv", timeStr) AssetDataAnalysis.WriteCSVWithBom(parentDir .. fileName, mipmapsCSVStr) end analysisData.Basic = {} analysisData.Overdraw = {} analysisData.Mipmaps = {} end function AssetDataAnalysis.WriteCSVWithBom(path, str) LuaExt.FileWriteText(path, str) local bytes = LuaExt.FileReadBytes(path) local bom = string.char(0xEF, 0xBB, 0xBF) bytes = bom .. bytes LuaExt.FileWriteBytes(path, false, bytes) end function AssetDataAnalysis.OutputCSVStr(moduleTitleTable, dataTable) if dataTable == nil then return nil end if not next(dataTable) then return nil end local resultStr = "" --输出表头 local titleTable = {} for i = 1, #ModuleCSVTitle.Common do table.insert(titleTable, NameConfig[ModuleCSVTitle.Common[i]].name .. NameConfig[moduleTitleTable[i]].unit) end for i = 1, #moduleTitleTable do table.insert(titleTable, NameConfig[moduleTitleTable[i]].name .. NameConfig[moduleTitleTable[i]].unit) end resultStr = resultStr .. table.concat(titleTable, ',') .. "\r\n" --输出表数据 for k, v in pairs(dataTable) do local lineData = {} for i = 1, #ModuleCSVTitle.Common do table.insert(lineData, v[ModuleCSVTitle.Common[i]]) end for i = 1, #moduleTitleTable do table.insert(lineData, v[moduleTitleTable[i]]) end resultStr = resultStr .. table.concat(lineData, ',') .. "\r\n" end return resultStr end function AssetDataAnalysis.startWith(str, startStr) return string.sub(str, 1, string.len(startStr)) == startStr end function AssetDataAnalysis.endWith(str, endStr) return endStr == '' or string.sub(str, -string.len(endStr)) == endStr end function AssetDataAnalysis.GetAssetType(assetName) --typeA:大类,英雄、宠物等 --typeB:中类,展示、PVP、主城 --typeC:小类,模型,武器 local typeA, typeB, typeC = "" local isPet = AssetDataAnalysis.startWith(assetName, "Pet_") local isHero = AssetDataAnalysis.startWith(assetName, "Hero_") --TODO 以后新加,需要扩展 if isPet then typeA = "Pet" elseif isHero then typeA = "Hero" else typeA = "Hero" end local isWeapon = string.find(assetName, "Weapon", 1, true) ~= nil local isShow = string.find(assetName, "Show", 1, true) ~= nil local isPVP = string.find(assetName, "PVP", 1, true) ~= nil if isPVP then typeB = "PVP" elseif isShow then typeB = "Show" else typeB = "Normal" end if isWeapon then typeC = "Weapon" else typeC = "Model" end return typeA, typeB, typeC end function AssetDataAnalysis.AnalysisProfilerModule(csvData, assetType, lod, cameraModel) if assetType == "模型" then for k, v in pairs(csvData) do local tips = {} local assetName = v.AssetName local config --优先使用匹配的参数,如果找不到,使用角色的配置,并报错提示 local typeA, typeB, typeC = AssetDataAnalysis.GetAssetType(assetName) if DataConfig["Basic"][assetType][typeA] ~= nil and DataConfig["Basic"][assetType][typeA][typeB] ~= nil and DataConfig["Basic"][assetType][typeA][typeB][typeC] ~= nil then config = DataConfig["Basic"][assetType][typeA][typeB][typeC] else logging.error(LTAG.ERROR, "找不到配置数据 Basic -", assetType, typeA, typeB, typeC) config = DataConfig["Basic"][assetType]["Hero"]["Normal"]["Model"] end for m, n in pairs(config) do local analysisName = m local analysisValue = tonumber(v[m]) if not (analysisValue >= n.min and analysisValue <= n.max) then local nameConfig = NameConfig[analysisName] table.insert(tips, nameConfig.name .. "[" .. n.min .. "-" .. n.max .. "]" .. nameConfig.unit) end end if next(tips) then v["AssetType"] = assetType v["LOD"] = LODName[lod] v["CameraModel"] = cameraModel v["Tips"] = table.concat(tips, ' ') table.insert(analysisData.Basic, v) end end elseif assetType == "特效" then for k, v in pairs(csvData) do local tips = {} for m, n in pairs(DataConfig["Basic"][assetType][lod]) do local analysisName = m local analysisValue = tonumber(v[m]) if not (analysisValue >= n.min and analysisValue <= n.max) then local nameConfig = NameConfig[analysisName] table.insert(tips, nameConfig.name .. "[" .. n.min .. "-" .. n.max .. "]" .. nameConfig.unit) end end if next(tips) then v["AssetType"] = assetType v["LOD"] = LODName[lod] v["CameraModel"] = cameraModel v["Tips"] = table.concat(tips, ' ') table.insert(analysisData.Basic, v) end end end end function AssetDataAnalysis.AnalysisOverdrawModule(csvData, assetType, lod, cameraModel) if assetType == "特效" then for k, v in pairs(csvData) do local tips = {} for m, n in pairs(DataConfig["Overdraw"][lod]) do local analysisName = m local analysisValue = tonumber(v[m]) if not (analysisValue >= n.min and analysisValue <= n.max) then local nameConfig = NameConfig[analysisName] table.insert(tips, nameConfig.name .. "[" .. n.min .. "-" .. n.max .. "]" .. nameConfig.unit) end end if next(tips) then v["AssetType"] = assetType v["LOD"] = LODName[lod] v["CameraModel"] = cameraModel v["Tips"] = table.concat(tips, ' ') table.insert(analysisData.Overdraw, v) end end end end function AssetDataAnalysis.AnalysisMipmapModule(csvData, assetType, lod, cameraModel) if assetType == "模型" then for k, v in pairs(csvData) do local tips = {} local assetName = v.AssetName local isShow = string.find(assetName, "Show", 1, true) ~= nil local isPVP = string.find(assetName, "PVP", 1, true) ~= nil local isNormal = not isPVP and not isShow if (cameraModel == "展示相机" and isShow) or (cameraModel == "PVP相机" and isPVP) or (cameraModel == "主城相机" and isNormal) then for m, n in pairs(DataConfig["Mipmaps"][cameraModel]) do local analysisName = m local analysisValue = tonumber(v[m]) if not (analysisValue >= n.min and analysisValue <= n.max) then local nameConfig = NameConfig[analysisName] table.insert(tips, nameConfig.name .. "[" .. n.min .. "-" .. n.max .. "]" .. nameConfig.unit) end end if next(tips) then v["AssetType"] = assetType v["LOD"] = LODName[lod] v["CameraModel"] = cameraModel v["Tips"] = table.concat(tips, ' ') table.insert(analysisData.Mipmaps, v) end end end end end --根据不同模块,读取原始CSV数据 function AssetDataAnalysis.ReadAnalysisCSVData(csvPath, module) local csvData = {} if not LuaExt.FileExists(csvPath) then return csvData end local titles = ModuleCSVTitle[module] local str = LuaExt.FileReadText(csvPath) local allLines = string.split(str, "\r\n") for i = 2, #allLines do local line = allLines[i] if not string.isNilOrEmpty(line) then local lineData = string.split(line, ",") local tempCsvData = {} for j = 1, #titles do tempCsvData[titles[j]] = lineData[j] end table.insert(csvData, tempCsvData) end end return csvData end return AssetDataAnalysis