3D模型人物换装系统三(优化合批处理,提取合批配置可,封装)

3D模型人物换装系统三(优化合批处理,提取合批配置可,封装)

  • 介绍
  • 法线贴图问题
  • 规划以及封装
    • 缺陷
    • 修改整理
  • 整合
  • 总结

介绍

本文使用2018.4.4和2020.3.26进行的测试
这里先说一下我上一篇没有解决的问题,法线贴图不正确,如果按照我之前的文章创建其他贴图的方式去创建法线贴图,你会发现法线贴图不正确。
如果这里不太明白换装的流程可以参考我之前
3D模型人物换装系统一
3D模型人物换装系统二
请添加图片描述

法线贴图问题

之前创建贴图的方式如下所示
这里能看到我创建所有图片的时候的格式都是使用的RGBA32,但是后来我在网上查了以后才发现,其实法线贴图是不带A通道的图片,所以这里应该使用的是RGB24而不是使用的RGBA32,前后对比图我就不放了,因为我对这里的方法进行了封装,已经不是原来的方式创建和合并贴图了。

newAlbedoMapTex = new Texture2D(COMBINE_TEXTURE_MAX, COMBINE_TEXTURE_MAX, TextureFormat.RGBA32, true);
newNormalMapTex = new Texture2D(COMBINE_TEXTURE_MAX, COMBINE_TEXTURE_MAX, TextureFormat.RGBA32, true);
newMaskMapTex = new Texture2D(COMBINE_TEXTURE_MAX, COMBINE_TEXTURE_MAX, TextureFormat.RGBA32, true);

规划以及封装

这里我大概讲一下我之前脚本设计的缺陷,以及我想修改成的样子,在文章最后面我会把我修改完成的脚本和资源都放过来,如果大家在后面使用脚本的过程中遇到问题可以在询问我。

缺陷

  1. 原来合并设计的是太过于死板,材质球的属性是直接提取出来的并没有动态去做,也就是说我这里只能手动修改,如果换一个四个贴图的材质还需要修改下面的代码,这样太不方便,需要封装一下这里
    private const string COMBINE_ALBEDOMAP_TEXTURE = "_AlbedoMap";private const string COMBINE_NORMALMAP_TEXTURE = "_NormalMap";private const string COMBINE_MASKMAP_TEXTURE = "_MaskMap";
  1. 创建贴图的大小也是固定死的现在,这里也是有缺陷,没法动态的调整
   /// <summary>/// Only for merge materials./// </summary>private const int COMBINE_TEXTURE_MAX = 256;
  1. 合并这里或多或少有点缺陷,但是不算是有问题,这里传入的如果是true则就是需要合并,但是如果合并不成功的话就直接报错
if (combine){Shader tmpShader = Shader.Find("E3D/Actor/PBR-MaskRG-Normal");newMaterial = new Material(tmpShader);oldUV = new List<Vector2[]>();// merge the textureList<Texture2D> AlbedoTextures = new List<Texture2D>();List<Texture2D> NormalTextures = new List<Texture2D>();List<Texture2D> MaskTextures = new List<Texture2D>();for (int i = 0; i < materials.Count; i++){AlbedoTextures.Add(materials[i].GetTexture(COMBINE_ALBEDOMAP_TEXTURE) as Texture2D);NormalTextures.Add(materials[i].GetTexture(COMBINE_NORMALMAP_TEXTURE) as Texture2D);MaskTextures.Add(materials[i].GetTexture(COMBINE_MASKMAP_TEXTURE) as Texture2D);}newAlbedoMapTex = new Texture2D(COMBINE_TEXTURE_MAX, COMBINE_TEXTURE_MAX, TextureFormat.RGBA32, true);newNormalMapTex = new Texture2D(COMBINE_TEXTURE_MAX, COMBINE_TEXTURE_MAX, TextureFormat.RGBA32, true);newMaskMapTex = new Texture2D(COMBINE_TEXTURE_MAX, COMBINE_TEXTURE_MAX, TextureFormat.RGBA32, true);Rect[] uvs = newAlbedoMapTex.PackTextures(AlbedoTextures.ToArray(), 0);//newNormalMapTex.PackTextures(NormalTextures.ToArray(), 0);newMaskMapTex.PackTextures(MaskTextures.ToArray(), 0);newMaterial.SetTexture(COMBINE_ALBEDOMAP_TEXTURE, newAlbedoMapTex);newMaterial.SetTexture(COMBINE_NORMALMAP_TEXTURE, newNormalMapTex);newMaterial.SetTexture(COMBINE_MASKMAP_TEXTURE, newMaskMapTex);// reset uvVector2[] uva, uvb;for (int i = 0; i < combineInstances.Count; i++){uva = combineInstances[i].mesh.uv;uvb = new Vector2[uva.Length];for (int k = 0; k < uva.Length; k++){uvb[k] = new Vector2((uva[k].x * uvs[i].width) + uvs[i].x, (uva[k].y * uvs[i].height) + uvs[i].y);}oldUV.Add(uva);combineInstances[i].mesh.uv = uvb;}}if (combine){r.material = newMaterial;for (int i = 0; i < combineInstances.Count; i++){combineInstances[i].mesh.uv = oldUV[i];}}
  1. Shader也是写死的,不是动态的
 Shader tmpShader = Shader.Find("E3D/Actor/PBR-MaskRG-Normal");

修改整理

  1. 创建一个配置类,当创建模型的时候根据自己需要传入定制化配置文件,这样可以动态调整创建贴图的大小、动态调整合并贴图的数量、动态修改想要合并成的材质Shader。

/// <summary>
/// 贴图属性
/// </summary>
public class CombineClass
{/// <summary>/// 新Shader属性名/// </summary>public string NewShaderPropertiesName = "_AlbedoMap";/// <summary>/// 原始Shader属性名/// </summary>public string OriginalPropertiesName = "_AlbedoMap";/// <summary>/// 图片格式/// </summary>public TextureFormat Format = TextureFormat.RGBA32;/// <summary>/// /// </summary>public bool MipChain = true;/// <summary>/// 实例化/// </summary>/// <param name="propertiesName"></param>/// <param name="format"></param>/// <param name="mipChain"></param>public CombineClass(string newPropertiesName, string orinalPropertiesName, TextureFormat format, bool mipChain){this.NewShaderPropertiesName = newPropertiesName;this.OriginalPropertiesName = orinalPropertiesName;this.Format = format;this.MipChain = mipChain;}
}public class CombineConfig
{/// <summary>/// Only for merge materials./// 仅适用于合并材质./// </summary>private int COMBINE_TEXTURE_MAX = 256;/// <summary>/// Shader名称/// </summary>private string ShaderName = "";/// <summary>/// 贴图设置集合/// </summary>private List<CombineClass> combineClasses = new List<CombineClass>();/// <summary>/// 实例化/// </summary>/// <param name="COMBINE_TEXTURE_MAX"></param>/// <param name="combineClasses"></param>public CombineConfig(int COMBINE_TEXTURE_MAX, string ShaderName, List<CombineClass> combineClasses){this.COMBINE_TEXTURE_MAX = COMBINE_TEXTURE_MAX;this.ShaderName = ShaderName;this.combineClasses = combineClasses;}/// <summary>/// 获取合并贴图大小/// </summary>/// <returns></returns>public int CombineTextureMax() { return this.COMBINE_TEXTURE_MAX; }/// <summary>/// 获取Shader名/// </summary>/// <returns></returns>public string GetShaderName() { return this.ShaderName; }/// <summary>/// 获取贴图设置集合数量/// </summary>/// <returns></returns>public int GetCombineCount() { return this.combineClasses.Count; }/// <summary>/// 获取贴图设置集合/// </summary>/// <returns></returns>public List<CombineClass> GetCombineList() { return combineClasses; }
}
  1. 获取需要合并的模型的所有的所有Shader,如果是只有一个Shader则你combine为true时会进行合批处理,如果Shader数量多了哪怕你combine为true则也不进行合批。
  2. 加入了一个材质回调,这样在调用的时候可以对材质球进行设置

整合

CombineClass.cs


/// <summary>
/// 贴图属性
/// </summary>
public class CombineClass
{/// <summary>/// 新Shader属性名/// </summary>public string NewShaderPropertiesName = "_AlbedoMap";/// <summary>/// 原始Shader属性名/// </summary>public string OriginalPropertiesName = "_AlbedoMap";/// <summary>/// 图片格式/// </summary>public TextureFormat Format = TextureFormat.RGBA32;/// <summary>/// /// </summary>public bool MipChain = true;/// <summary>/// 实例化/// </summary>/// <param name="propertiesName"></param>/// <param name="format"></param>/// <param name="mipChain"></param>public CombineClass(string newPropertiesName, string orinalPropertiesName, TextureFormat format, bool mipChain){this.NewShaderPropertiesName = newPropertiesName;this.OriginalPropertiesName = orinalPropertiesName;this.Format = format;this.MipChain = mipChain;}
}

CombineConfig.cs


public class CombineConfig
{/// <summary>/// Only for merge materials./// 仅适用于合并材质./// </summary>private int COMBINE_TEXTURE_MAX = 256;/// <summary>/// Shader名称/// </summary>private string ShaderName = "";/// <summary>/// 贴图设置集合/// </summary>private List<CombineClass> combineClasses = new List<CombineClass>();/// <summary>/// 实例化/// </summary>/// <param name="COMBINE_TEXTURE_MAX"></param>/// <param name="combineClasses"></param>public CombineConfig(int COMBINE_TEXTURE_MAX, string ShaderName, List<CombineClass> combineClasses){this.COMBINE_TEXTURE_MAX = COMBINE_TEXTURE_MAX;this.ShaderName = ShaderName;this.combineClasses = combineClasses;}/// <summary>/// 获取合并贴图大小/// </summary>/// <returns></returns>public int CombineTextureMax() { return this.COMBINE_TEXTURE_MAX; }/// <summary>/// 获取Shader名/// </summary>/// <returns></returns>public string GetShaderName() { return this.ShaderName; }/// <summary>/// 获取贴图设置集合数量/// </summary>/// <returns></returns>public int GetCombineCount() { return this.combineClasses.Count; }/// <summary>/// 获取贴图设置集合/// </summary>/// <returns></returns>public List<CombineClass> GetCombineList() { return combineClasses; }
}

UCombineSkinnedMgr.cs

using UnityEngine;
using System.Collections.Generic;
using System.IO;
using System;public class UCombineSkinnedMgr
{/// <summary>/// Combine SkinnedMeshRenderers together and share one skeleton./// 将蒙皮网格渲染器组合在一起并共享一个骨架.(优化合批报错,如果无法合批但是combine为true,则进行不分批处理)/// Merge materials will reduce the drawcalls, but it will increase the size of memory./// 合并材质会减少drawcalls,但会增加内存大小./// </summary>/// <param name="skeleton">combine meshes to this skeleton(a gameobject)</param>/// <param name="meshes">meshes need to be merged</param>/// <param name="combine">merge materials or not</param>public void CombineObject(CombineConfig config, GameObject skeleton, SkinnedMeshRenderer[] meshes, bool combine = false, Action<Material> action = null){//Fetch all bones of the skeleton//获取所有的骨骼List<Transform> transforms = new List<Transform>();transforms.AddRange(skeleton.GetComponentsInChildren<Transform>(true));//the list of materialsList<Shader> shaders = new List<Shader>();//the list of materials//所有材质球List<Material> materials = new List<Material>();//the list of meshes//所有网格List<CombineInstance> combineInstances = new List<CombineInstance>();//the list of bones//所有骨骼节点List<Transform> bones = new List<Transform>();#region 合批使用// Below informations only are used for merge materilas(bool combine = true)//以下信息仅用于合并材料(bool-combine=true)原始UV坐标List<Vector2[]> oldUV = null;//合并之后得新材质球Material newMaterial = null;//创建新贴图集合List<Texture2D> MapTex = new List<Texture2D>();for (int i = 0; i < config.GetCombineCount(); i++){MapTex.Add(null);}#endregion// Collect information from meshes and shader// 获取网格和shader信息for (int i = 0; i < meshes.Length; i++){SkinnedMeshRenderer smr = meshes[i];materials.AddRange(smr.materials);for (int j = 0; j < smr.materials.Length; j++){if (!shaders.Contains(smr.materials[j].shader)){shaders.Add(smr.materials[j].shader);}}// Collect meshesfor (int sub = 0; sub < smr.sharedMesh.subMeshCount; sub++){CombineInstance ci = new CombineInstance();ci.mesh = smr.sharedMesh;ci.subMeshIndex = sub;combineInstances.Add(ci);}// Collect bonesfor (int j = 0; j < smr.bones.Length; j++){int tBase = 0;for (tBase = 0; tBase < transforms.Count; tBase++){if (smr.bones[j].name.Equals(transforms[tBase].name)){bones.Add(transforms[tBase]);break;}}}}// merge materials//合并材质if (combine && shaders.Count == 1){if (config.GetShaderName() == "") newMaterial = new Material(shaders[0]);else newMaterial = new Material(Shader.Find(config.GetShaderName()));oldUV = new List<Vector2[]>();// merge the texture//合并贴图List<List<Texture2D>> texture2Ds = new List<List<Texture2D>>();for (int i = 0; i < config.GetCombineCount(); i++){texture2Ds.Add(new List<Texture2D>());}for (int i = 0; i < materials.Count; i++){Material mat = materials[i];for (int j = 0; j < config.GetCombineCount(); j++){texture2Ds[j].Add(mat.GetTexture(config.GetCombineList()[j].OriginalPropertiesName) as Texture2D);}//int ind = 0;//texture2Ds.ForEach((txtLst) =>//{//    txtLst.Add(mat.GetTexture(config.GetCombineList()[ind].OriginalPropertiesName) as Texture2D);//    ind++;//});}Rect[] uvs = new Rect[config.GetCombineCount()];for (int i = 0; i < config.GetCombineCount(); i++){MapTex[i] = new Texture2D(config.CombineTextureMax(), config.CombineTextureMax(), config.GetCombineList()[i].Format, config.GetCombineList()[i].MipChain);uvs = MapTex[i].PackTextures(texture2Ds[i].ToArray(), 0);newMaterial.SetTexture(config.GetCombineList()[i].NewShaderPropertiesName, MapTex[i]);}action?.Invoke(newMaterial);#region 导出图片//WriteIntoPic(TextureToTexture2D(newMaterial.GetTexture(COMBINE_ALBEDOMAP_TEXTURE)), "albedo");//WriteIntoPic(TextureToTexture2D(newMaterial.GetTexture(COMBINE_NORMALMAP_TEXTURE)), "normal");//WriteIntoPic(TextureToTexture2D(newMaterial.GetTexture(COMBINE_MASKMAP_TEXTURE)), "mask");#endregion// reset uvVector2[] uva, uvb;for (int i = 0; i < combineInstances.Count; i++){uva = combineInstances[i].mesh.uv;uvb = new Vector2[uva.Length];for (int k = 0; k < uva.Length; k++){uvb[k] = new Vector2((uva[k].x * uvs[i].width) + uvs[i].x, (uva[k].y * uvs[i].height) + uvs[i].y);}oldUV.Add(uva);combineInstances[i].mesh.uv = uvb;}}// Create a new SkinnedMeshRendererSkinnedMeshRenderer oldSKinned = skeleton.GetComponent<SkinnedMeshRenderer>();if (oldSKinned != null){GameObject.DestroyImmediate(oldSKinned);}SkinnedMeshRenderer r = skeleton.AddComponent<SkinnedMeshRenderer>();r.sharedMesh = new Mesh();r.sharedMesh.CombineMeshes(combineInstances.ToArray(), combine && shaders.Count == 1, false);// Combine meshesr.bones = bones.ToArray();// Use new bonesif (combine && shaders.Count == 1){r.material = newMaterial;for (int i = 0; i < combineInstances.Count; i++){combineInstances[i].mesh.uv = oldUV[i];}}else{r.materials = materials.ToArray();}}#region 导出图片private Texture2D TextureToTexture2D(Texture texture){Texture2D texture2D = new Texture2D(texture.width, texture.height, TextureFormat.RGBA32, false);RenderTexture currentRT = RenderTexture.active;RenderTexture renderTexture = RenderTexture.GetTemporary(texture.width, texture.height, 32);Graphics.Blit(texture, renderTexture);RenderTexture.active = renderTexture;texture2D.ReadPixels(new Rect(0, 0, renderTexture.width, renderTexture.height), 0, 0);texture2D.Apply();RenderTexture.active = currentRT;RenderTexture.ReleaseTemporary(renderTexture);return texture2D;}public void WriteIntoPic(Texture2D tex, string name){//编码纹理为PNG格式 var bytes = tex.EncodeToPNG();File.WriteAllBytes(Application.dataPath + "/" + name + ".png", bytes);}#endregion
}

UCharacterController.cs

using UnityEngine;public class UCharacterController
{/// <summary>/// GameObject reference/// </summary>public GameObject Instance = null;/// <summary>/// 换装总组装数量/// </summary>public int m_MeshCount = 7;public string Role_Skeleton;public string Role_Body;public string Role_Clothes;public string Role_Hair;public string Role_Head;public string Role_Pants;public string Role_Shoes;public string Role_Socks;/// <summary>/// 创建对象/// </summary>/// <param name="job"></param>/// <param name="skeleton"></param>/// <param name="body"></param>/// <param name="cloak"></param>/// <param name="face"></param>/// <param name="hair"></param>/// <param name="hand"></param>/// <param name="leg"></param>/// <param name="mainweapon"></param>/// <param name="retina"></param>/// <param name="subweapon"></param>/// <param name="combine"></param>public UCharacterController(CombineConfig config, string job, string skeleton, string body, string clothes, string hair, string head, string pants, string shoes, string socks, bool combine = false, System.Action<Material> action = null){Object res = Resources.Load("RoleMesh/" + job + "/" + job + "/" + skeleton);this.Instance = GameObject.Instantiate(res) as GameObject;this.Role_Skeleton = skeleton;this.Role_Body = body;this.Role_Clothes = clothes;this.Role_Hair = hair;this.Role_Head = head;this.Role_Pants = pants;this.Role_Shoes = shoes;this.Role_Socks = socks;string[] equipments = new string[m_MeshCount];equipments[0] = "Body/" + Role_Body;equipments[1] = "Clothes/" + Role_Clothes;equipments[2] = "Hair/" + Role_Hair;equipments[3] = "Head/" + Role_Head;equipments[4] = "Pants/" + Role_Pants;equipments[5] = "Shoes/" + Role_Shoes;equipments[6] = "Socks/" + Role_Socks;SkinnedMeshRenderer[] meshes = new SkinnedMeshRenderer[m_MeshCount];GameObject[] objects = new GameObject[m_MeshCount];for (int i = 0; i < equipments.Length; i++){res = Resources.Load("RoleMesh/" + job + "/" + equipments[i]);objects[i] = GameObject.Instantiate(res) as GameObject;meshes[i] = objects[i].GetComponentInChildren<SkinnedMeshRenderer>();}UCharacterManager.Instance.CombineSkinnedMgr.CombineObject(config, Instance, meshes, combine, action);for (int i = 0; i < objects.Length; i++){GameObject.DestroyImmediate(objects[i].gameObject);}}public void Delete(){GameObject.Destroy(Instance);}
}

测试代码
UCharacterManager.cs

using UnityEngine;
using System.Collections.Generic;/// <summary>
/// 换装管理器
/// </summary>
public class UCharacterManager : MonoBehaviour
{public static UCharacterManager Instance;private UCombineSkinnedMgr skinnedMgr = null;public UCombineSkinnedMgr CombineSkinnedMgr { get { return skinnedMgr; } }private int characterIndex = 0;private Dictionary<int, UCharacterController> characterDic = new Dictionary<int, UCharacterController>();public UCharacterManager(){skinnedMgr = new UCombineSkinnedMgr();}private void Awake(){Instance = this;}public UCharacterController mine;private void Start(){//mine = Generatecharacter(new CombineConfig(256, "", new List<CombineClass> {//    new CombineClass("_AlbedoMap","_AlbedoMap",TextureFormat.RGBA32,true),//    new CombineClass("_NormalMap","_NormalMap",TextureFormat.RGB24,true),//    new CombineClass("_MaskMap","_MaskMap", TextureFormat.RGBA32,true),//}), "MaTa", "MaTa", "Body1", "Clothes1", "Hair1", "Head1", "Pants1", "Shoes1", "Socks1", true, (mat) =>//{//    mat.SetFloat("_SideLightScale", 0);//});mine = Generatecharacter(new CombineConfig(256, "Standard", new List<CombineClass> {new CombineClass("_MainTex","_AlbedoMap",TextureFormat.RGBA32,true),new CombineClass("_BumpMap","_NormalMap",TextureFormat.RGB24,true),new CombineClass("_DetailMask","_MaskMap", TextureFormat.RGBA32,true),}), "MaTa", "MaTa", "Body1", "Clothes1", "Hair1", "Head1", "Pants1", "Shoes1", "Socks1", true, (mat) =>{mat.SetFloat("_SideLightScale", 0);});}private void Update(){if (Input.GetKeyDown(KeyCode.Space)){ChangeRole();}}public void ChangeRole(){//if (mine != null)//{//    mine.Delete();//}//int a = Random.Range(1, 4);//mine = Generatecharacter("MaTa", "MaTa", "Body" + a, "Clothes" + a, "Hair" + a, "Head" + a, "Pants" + a, "Shoes" + a, "Socks" + a, true);}#region 创建人物模型骨骼public UCharacterController Generatecharacter(CombineConfig config, string job, string skeleton, string body, string clothes, string hair, string hand, string pants, string shoes, string socks, bool combine = false, System.Action<Material> action = null){UCharacterController instance = new UCharacterController(config, job, skeleton, body, clothes, hair, hand, pants, shoes, socks, combine, action);characterDic.Add(characterIndex, instance);characterIndex++;return instance;}#endregion
}

完整资源

总结

人物换装的优化这篇文章后面应该不会在出了,预计得优化大概就是这样,如果有别的好点子可以私信我交流一下。希望这篇文章能给大家带来帮助,感谢大家的支持和关注,感谢点赞。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/141755.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

计算机网络基础知识-网络协议

一:计算机网络层次划分 1. 网络层次划分 2. OSI七层网络模型 1)物理层(Physical Layer):及硬件设备,物理层确保原始的数据可在各种物理媒体上传输,常见的设备名称如中继器(Repeater,也叫放大器)和集线器; 2)数据链路层(Data Link Layer):数据链路层在物理层提…

SpringCache(Redis)

一、springcache是什么 springcache是spring的缓存框架&#xff0c;利用了AOP&#xff0c;实现了基于注解的缓存功能&#xff0c;并且进行了合理的抽象&#xff0c;业务代码不用关心底层是使用了什么缓存框架&#xff0c;只需要简单地加一个注解&#xff0c;就能实现缓存功能了…

Git企业开发级讲解(二)

&#x1f4d8;北尘_&#xff1a;个人主页 &#x1f30e;个人专栏:《Linux操作系统》《经典算法试题 》《C》 《数据结构与算法》 ☀️走在路上&#xff0c;不忘来时的初心 文章目录 一、添加⽂件--场景⼀1、操作2、演示 二、查看 .git ⽂件1、tree .git命令2、内容讲解3、总结…

HTTP-FLV详解及分析

文章目录 前言一、HTTP-FLV 简介1、市场上使用 http-flv 的商家2、http-flv、rtmp 和 hls 直播的优缺点3、http-flv 技术实现 二、Nginx 配置 http-flv1、Windows 安装 nginx&#xff0c;已经集成 nginx-http-flv-module2、nginx.conf 配置文件3、运行 nginx 服务器4、ffmpeg 推…

K8S知识点(十)

&#xff08;1&#xff09;Pod详解-启动命令 创建Pod&#xff0c;里面的两个容器都正常运行 &#xff08;2&#xff09;Pod详解-环境变量 &#xff08;3&#xff09;Pod详解-端口设置 &#xff08;4&#xff09;Pod详解-资源配额 修改&#xff1a;memory 不满足条件是不能正常…

leetcode:2935. 找出强数对的最大异或值 II【最大异或值还是得看01Trie树啊!】

题目截图 题目分析 排序后&#xff0c;限定了x和y的相对位置 假设y > x&#xff0c;随着y的移动&#xff0c;必须要保证2x > y 所以可以使用滑动窗口维护一堆满足条件的x 这些x的异或值记录在Trie树中即可 ac code class Node:__slots__ children, cntdef __init__(s…

Pandas画图报错:ValueError: signal only works in main thread

Pandas画图报错&#xff1a;ValueError: signal only works in main thread 基于Django 解决方法 按如下方式运行服务器 python manage.py runserver --nothreading --noreload

SpringCloud Alibaba(上):注册中心-nacos、负载均衡-ribbon、远程调用-feign

Nacos 概念&#xff1a;Nacos是阿里巴巴推出的一款新开源项目&#xff0c;它是一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。Nacos致力于帮助用户发现、配置和管理微服务&#xff0c;它提供了一组简单易用的特性集&#xff0c;包括动态服务发现、服务配置…

【Pytorch和深度学习】栏目导读

一、栏目说明 本栏目《pytorch实践》是为初学者入门深度学习准备的。本文是该栏目的导读部分&#xff0c;因为计划本栏目在明年完成&#xff0c;因此&#xff0c;导读部分&#xff0c;即本文也在持续更新中。 本栏目设计目标是将深度学习全面用pytorch实践一遍&#xff0c;由浅…

上机实验四 图的最小生成树算法设计 西安石油大学数据结构

实验名称&#xff1a;图的最小生成树算法设计 &#xff08;1&#xff09;实验目的&#xff1a; 掌握最小生成树算法&#xff0c;利用kruskal算法求解最小生成树。 &#xff08;2&#xff09;主要内容&#xff1a; 利用kruskal算法求一个图的最小生成树&#xff0c;设计Krus…

Xilinx Artix7-100T低端FPGA解码MIPI视频,基于MIPI CSI-2 RX Subsystem架构实现,提供工程源码和技术支持

目录 1、前言免责声明 2、我这里已有的 MIPI 编解码方案3、本 MIPI CSI2 模块性能及其优缺点4、详细设计方案设计原理框图OV5640及其配置权电阻硬件方案MIPI CSI-2 RX SubsystemSensor Demosaic图像格式转换Gammer LUT伽马校正VDMA图像缓存AXI4-Stream toVideo OutHDMI输出 5、…

数据校验:Spring Validation

Spring Validation概述 在开发中&#xff0c;我们经常遇到参数校验的需求&#xff0c;比如用户注册的时候&#xff0c;要校验用户名不能为空、用户名长度不超过20个字符、手机号是合法的手机号格式等等。如果使用普通方式&#xff0c;我们会把校验的代码和真正的业务处理逻辑耦…

K8S篇之etcd数据备份与恢复

一、etcd备份与恢复 基本了解&#xff1a; 1、k8s 使用etcd数据库实时存储集群中的数据&#xff0c;安全起见&#xff0c;一定要备份。 2、备份只需要在一个节点上备份就可以了&#xff0c;每个节点上的数据是同步的&#xff1b;但是数据恢复是需要在每个节点上进行。 3、etcd…

系统韧性研究(4)| 系统韧性的技术分类

系统韧性技术是任何提高系统韧性的架构、设计或实现技术。这些技术&#xff08;例如缓解措施&#xff0c;如冗余、保障措施和网络安全对策&#xff09;或被动地抵御逆境或主动检测逆境&#xff0c;并对其做出反应&#xff0c;亦或者从它们造成的伤害中恢复过来。系统韧性技术是…

ArcGIS实现矢量区域内所有要素的统计计算

1、任务需求&#xff1a;统计全球各国所有一级行政区相关属性的总和。 &#xff08;1&#xff09;有一个全球一级行政区的矢量图&#xff0c;包含以下属性&#xff08;洪灾相关属性 province.shp&#xff09; &#xff08;2&#xff09;需要按照国家来统计各个国家各属性的总值…

突然消失的桌面文件如何恢复?详细教程让你轻松解决问题!

桌面文件突然消失&#xff0c;对于很多人来说&#xff0c;可能是个令人头疼的问题。这些文件可能包含重要的信息&#xff0c;也可能是数日甚至数周的努力成果。那么&#xff0c;当这种情况发生时&#xff0c;我们如何恢复丢失的文件呢&#xff1f;本文将提供一些实用的建议。 1…

【ArcGIS Pro微课1000例】0031:las点云提取(根据范围裁剪点云)

本文讲解ArcGIS Pro3.0中,las点云数据的提取(根据范围裁剪点云)方法。 文章目录 一、加载数据二、工具介绍三、点云裁剪一、加载数据 打开ArcGIS Pro,新建地图,加载配套实验数据包中的0031.rar中的点云数据point.las与范围bound.shp,如下图所示: 二、工具介绍 名称:提…

一张图搞懂什么是BCD8421编码

如图所示 BCD8421编码的意义是 用四位二进制数表达一位的十进制数 因此十进制下的0&#xff5e;9在BCD8421编码下与其二进制表达是一样的 而多位的十进制数 比如说“10” 则需要将它拆分成两个单独的数“1”和“0” 分别用BCD8421编码表示这两个数 十进制“1” -> 0001 十进…

内衣洗衣机和手洗哪个干净?好用的内衣洗衣机推荐

在日常生活中&#xff0c;我们的衣服不可避免地会沾染上各种细菌、毛发和污渍&#xff0c;将它们与贴身衣物混合清洗&#xff0c;很容易发生交叉感染&#xff0c;而被感染后&#xff0c;贴身衣物也有可能导致我们人体引起皮肤病。这也是为什么大部分人都喜欢用手洗的原因&#…

@CacheInvalidate(name = “xxx“, key = “#results.![a+b]“,multi = true)是什么意思

@CacheInvalidate 注解是 JetCache 框架提供的注解,它是由阿里巴巴开源的组织 Alibaba Group 开发和维护的。JetCache 是一款基于注解的缓存框架,提供了丰富的缓存功能和灵活的配置选项,可用于增强应用程序的性能和可扩展性。JetCache 支持多种缓存后端,包括内存缓存、Redi…