材质变体 PSO学习笔记
学习笔记
参考各路知乎大佬文章
首先是对变体的基本认知
概括就是变体是指根据引擎中上层编写(UnityShaderLab/UE连连看)中的各种defines情况,根据不同平台编译成的底层shader,OpenGL-glsl/DX(9-11)-dxbc DX12-dxil/Vulkan-spirv,是打到游戏包里的
在引擎开发编辑模式下,Unity/UE用户层写的是HLSL,根据引擎选择的目标平台,编译底层shader的流程也有区别。项目打包出来到目标平台上,是不会用开发时的HLSL再在目标平台上实时编译成底层shader的,是在游戏打包时,将目标平台的所有shader变体(glsl/dxbc/spirv)生成好打包进去
并且由于压缩,变体数对于游戏包体的影响可能不是很大
DX9-DX11 dxbc是字节码,GPU上跑的机器码还需要进一步转换成二进制码
DX12(2014年推出) dxil,GPU仍需要转成二进制码,但是多了很重要的PSO Cache流程
OpenGL glsl不需要离线编译,直接交给GPU驱动编译成机器码。OpenGL 4.1以上可以通过glGetProgramBinary回读这个二进制码,省去之后的编译工作
OpenGL ES 3.0(2012年推出)以上也可以通过glGetProgramBinary回读厂商的机器码
Metal(2014年推出) AIR字节码,交给GPU驱动编译成机器码
最后GPU上跑的不是glsl/dxbc/spirv GPU上跑的是机器码
现在的各种游戏,第一次进入游戏时总会有一个编译着色器的流程,这一步是在做什么?Unity和UE项目做的事是不太一样的,后面讲到PSO时再提及
首先看看手机OpenGL ES流程
以OpenGL ES3.0为例,不同的硬件厂商的GPU其机器码标准是不一样的,所以第一次进游戏时,需要把hlsl编译成当前手机硬件的GPU机器码,并且可以通过glGetProgramBinary回读厂商的机器码将编译好的机器码存在本地磁盘,下次进游戏时直接从磁盘读取编译好的产物
那么有没有办法不在游戏第一次打开时,不想等这么久的着色器编译,可以快速开始游戏呢?有的,随着厂商的发展,有抽象出一种中间格式的语言,这种语言机器友好,编译非常快速,并且具备跨机器运行的能力
及以下三家及对应的中间语言,如果以后的游戏是用DX12/Vulkan/Metal开发的,游戏打包时就可以将shader编译成对应的中间语言,但是这样做同样有问题,那就是这种中间格式的大小比shader源码大很多
然后看看PC DX(9-11)/12的流程
DX(9-11)的dxbc传递给显卡生成机器码
DX12 dxil取代了dxbc
由于dxbc和dxil是互不相通的,所以游戏为了支持不支持DX12的老电脑,只能将shader源码打到游戏包中,实际根据用户电脑是否支持DX12,再编译成dxbc/dxil,最后再是dxil生成PSO Cache,所以黑猴耗时长的部分在源码到dxbc/dxil这一步
PSO Cache(Pipeline State Object Cache渲染管线状态对象缓存)
Metal和Vulkan中有和PSO对应的概念,但并不叫PSO,只是经常用PSO替代称呼,OpenGL/ES没有PSO概念
要了解PSO是什么,先回忆一下GPU流水线。绘制一个物体的整个流程(pipeline),除开shader,其中的还有很多状态设置,比如是否进行透明度混合,混合方式是什么等等。
PSO Cache做的事就是把整个pipeline生成的机器码存下来
这里的PSO包括了shader和应用层设置渲染状态的代码
PSO和硬件是强绑定的,不同显卡/显卡驱动生成的PSO缓存也是不能通用的
OK有了上述认知,我们现在知道了现代API(DX12/Metal/Vulkan)提供了在应用层cache PSO的功能,针对不同的平台,引擎应用层会做相应的处理,那么接下来就可以看一下应用层的游戏引擎对应PSO Cache的相关流程了。
https://zhuanlan.zhihu.com/p/572503905
Unity
先看Unity,Unity6(2024.10.17发布)之前的版本是没有PSO Cache的功能的
老版本Unity Unity - Manual: Shader loading
是把加载的场景或资源所有的材质变体都加载到CPU中的,并且有一个可自定义大小的CPU空间存所有的变体,首次加载时,创建PSO的流程还是要走,可能会出现卡顿。创建过一次之后,会缓存该变体。当没有任何物体引用到某变体时从CPU和GPU中清掉。
为了提高效率,方案是变体WarmUp和变体收集文件ShaderVariantCollection的组合拳。
可以看出老版本的Unity,是无法省掉创建PSO的开销的,所以项目的重点会在于减少项目变体,剔除掉不用的变体,以及尽可能跑全变体收集文件上。
Unity6+ 对应UE的Bundle PSO Cache 当前只支持(DX12/Metal/Vulkan)
Unity - Scripting API: GraphicsStateCollection
新增PSO工作流,主要的功能在GraphicsStateCollection对象
流程还是跑游戏,根据目标平台缓存本地PSO Cache文件,因为开发期中材质变体可能会经常变动,所以跑游戏更新cache的思路是和原来的变体收集文件是一样的
cache的结果同样可以查看包含的变体,以及修改每个变体关联的渲染状态
PSO Cache也需要WarmUp,有同步和异步俩种方法执行
UE
UE中的PSO类型,这里主要关心的是Graphics PSO
UE4
Bundle PSO Cache
首先shader会在打包时编译成字节码,这些字节码有三种保存形式
1、在项目设置中,ShareMaterialShaderCode开关勾选才能走PSO Cache流程,如果没有勾选,字节码会打包附带于每个材质变体自身上,这样影响包体大小,虽然热更只需考虑增量,但这个方案大体量一些的项目基本都不会用
2、勾选,存成ushaderbytecode,UE维护一个ShaderCodeLibrary归档这些字节码,除Metal语言外的所有语言都使用该ShaderCodeLibrary
3、勾选,存成Native(metallib/metalmap),Metal原生ShaderCodeLibrary
后续没走PSO Cache的流程,创建PSO时就读取对应的字节码,然后二次编译PSO
PSO Cache文件有俩种文件类型:
.upipelinecache类型文件,这种是运行游戏时记录的 其中不会直接保存shader代码(无论是源码或者编译好的机器码),也不保存shader路径,保存的是shader路径的SHA hash作为索引
.spc(Stable PSO cache)类型文件 稳定的缓存信息
存储预计多个版本中不会改变的信息,如材质名称,顶点工厂名称,着色器类型等的描述称为stable key,UE5 UE4.27用.shk/UE4老版本用.scl.csv文件表示
Bundle PSO Cache的流程
https://dev.epicgames.com/documentation/en-us/unreal-engine/optimizing-rendering-with-pso-caches-in-unreal-engine?application_version=5.4
https://zhuanlan.zhihu.com/p/681319390
总体流程就是
1、打包时Cook一遍工程,扫使用到的所有材质变体,将编译成的平台无关的字节码存到shaderCodeLibrary,生成.shk文件
2、手机上跑游戏收集PSO,存到.upipelinecache文件中
增量收集
3、根据.shk文件和.upipelinecache文件,用ShaderPipelineCacheTools命令行生成.spc文件,然后将该.spc文件放到项目中再打包,spc文件会转换成upipelinecache文件打进包中,UE会整理成对应平台的PSOList
4、再次启动游戏,自动加载upipelinecache,编译shader时使用PSO Caching,收集的是对应GPU上编译成的机器码
5、重复流程
6、项目材质有重大改变时,可能需要重新记录Cache信息,因为老的没用到的PSO如果更新后根本没用到就纯浪费了
以上是项目打包相关的相关流程,接下来看一下手机跑游戏时PSO编译的流程
首先是三个关键流程
UE Graphics PSO缓存的信息包括
其中BoundShaderStateInput(BSS)包括
根据平台的不同,上诉信息可能只有部分作为PSO提交,其余走FallBack设置
之前提到OpenGL本身没有PSO机制,但是UE这套PSO Cache的流程,也将OpenGL的渲染状态抽象为PSO,起作用是PSO中的一部分信息BoundShaderState
UE虽然也提供了后台异步编译的功能,但是手游基本都会关闭此功能,而是在第一次加载游戏时全部一次性编译完
Usage机制
默认引擎会加载PSOList中的所有PSO,UsageMask可以添加筛选机制
LRU机制
生成的PSO可以缓存在内存中,OpenGL和Vulkan提供了LRU机制,可以限制加载到内存中的PSO数量,Metal没有该机制
UE5+
多了一套PSO Precache流程 UE5.3首次出现,5.4默认开启
https://dev.epicgames.com/documentation/en-us/unreal-engine/pso-precaching-for-unreal-engine?application_version=5.4
https://zhuanlan.zhihu.com/p/679832250
这是一套相对自动收集PSO Cache的方案,在Loading后就开始走收集流程,并在后台线程上异步编译
目前仅适用于D3D12 手游项目制作和Precache这套暂时无缘
如何控制项目材质变体的数量
UE变体数太多会导致什么问题
如果变体数很多,影响游戏包体大小,首次运行游戏时编译PSOCache耗时会比较长,全量编译PSO低端机可能会OOM,并且垃圾一点的手机编的也慢,加上发热等,影响玩家第一次的游玩体验。Metal编译生成的MemoryCache也会很大,而且随着游戏版本持续运营,又一直在出新效果玩法,对后续的膨胀问题就很难把控。还有图形驱动的升级会清掉PSO缓存,IOS升系统等导致得重新编译一次,又影响体验。
是时候回忆一下UE的材质系统了
VertexFactory
材质面板中勾选Usage后,UE会编译相应VertexFactory的shader变体
https://zhuanlan.zhihu.com/p/707759496
FShader持有ShaderCode在FShaderMapResource中的索引
FShaderType
FShaderType是FShader的元类,负责桥接FShader与对应的usf文件,FShader对应的FShaderType用using指定
当使用IMPLEMENT_MATERIAL_SHADER_TYPE时,就会为FShader构造一个相应的FShaderType,将FShader、Shader入口函数名,ShaderFrequency桥接起来,同时将FShaderType注册到一个全局列表中。编译Shader时会使用到这个全局列表
FMaterial/FMaterialResource
FMaterialShaderMap
FMaterialShaderMap中存储着材质在特定QualityLevel + ShaderPlatform下编译出的所有shader数据
其父类FShaderMapBase中的几个重要数据
FShaderMapResourceCode
FShaderMapResourceCode中存储的是编译后的shader代码,通过FShader存储的ShaderIndex索引
FShaderMapResource
FShaderMapResource负责创建和存储多个RHI端的shader,其子类有FShaderMapResource_SharedCode和FShaderMapResource_InlineCode,对应不同获取ShaderCode的方式,SharedCode就是前文所说,如果项目设置勾选了ShareMaterialShaderCode,保存在.uasset中的代码会统一放在.ushaderbytecode文件中,运行时创建一个FShaderCodeLibrary管理
FShaderMapContent
FMaterialShaderMap持有一个FShaderMapContent的引用,FShaderMapContent存有特定VertexFactoryType和ShaderType设置下对应的FShader实例
整体的流程可以分为俩个大的步骤,编译流程和绘制流程
首先看编译流程
https://zhuanlan.zhihu.com/p/85340922
https://zhuanlan.zhihu.com/p/707759496
材质编辑器中连的蓝图节点可以理解为只是HLSL生成过程中的一种输入,具体Pass用到什么shader,还得根据shader主干文件(如移动端BasePass的MobileBasePassVertexShader.usf MobileBasePassPixelShader.usf),VertexFactory,Common文件等生成最终的HLSL,然后再根据对应图形API将HLSL编译成对应shaderCode
其中FHLSLMaterialTranslator MaterialTemplate.usf模版的填充,自定义材质节点的一些使用之前也提过这里就不再提了
编译流程,我们需要关心的大的步骤就是
UMaterial->FMaterial/FMaterialResource->FMaterialShaderMap
编译好的ShaderCode是保存在FShaderMapResource中的
不同VertexFactoryType ShaderType对应ShaderMap的生成逻辑在
FMaterialShaderMap::Compile()
FMaterial::GetDependentShaderAndVFTypes()中
https://zhuanlan.zhihu.com/p/467788335
然后是绘制流程
谈及变体主要涉及的是MeshMaterialShader(MaterialShader的子类),那么就需要回忆下Mesh Draw Pipeline的流程
https://dev.epicgames.com/documentation/en-us/unreal-engine/mesh-drawing-pipeline?application_version=4.27
MeshBatch的Cache和Dynamic生成流程,后续的MeshPassProcessor和MeshDrawCommand生成流程之前讲过,这里就不再重述了。
mesh如何知道自己对应的vertexFactory就在生成MeshBatch流程中完成
FMeshBatchElement包含的是一个基本的绘制需要的信息
MeshDrawCommand包含了一次drawCall所需的全部信息,渲染信息的收集绑定是在MeshPassProcessor中完成的
渲染所需相关的数据由MeshPassProcessor收集
渲染时shader的获取,关注
XXMeshProcessor::Process中的GetXXPassShaders如
其中根据RenderPass创建特定FShader对应的FShaderType实例,最后用TryGetShaders方法获取FShader实例
FMaterial::TryGetShaders中,先获取FMaterial中的FShaderMapContent,然后用FShaderMapContent::GetShader通过ShaderType template实例字符串索引对应的FShader实例
而FShader持有ShaderCode在FShaderMapResource中的索引
后续提交给RHI Thread找对应的硬件编译过的机器码或者PSO Cache绘制即可
要更细的话,其实还有一个游戏加载时的流程
https://zhuanlan.zhihu.com/p/681306302
OK 在有了以上内容的认知之后,我们就可以来看一下UE项目中有哪些地方可以优化变体和PSO Cache了
可以从正反俩角度出发分析
首先正向分析,项目中那些地方会影响产生的变体
https://zhuanlan.zhihu.com/p/681316533
1、静态材质开关
包含连连看中的staticSwitchParameter和.usf中项目自己加的#ifdef
设A为主材质(无论有多少个静态开关),BC为A的材质实例,如果BC的开关override情况是相同的,那么BC会有俩个shaderMap,对应的俩个shaderCode内容是一样的,经过ShaderCodeLibrary相同结果剔除机制,进包后是一个shaderCode。
这时D也是A的材质实例,E是C的材质实例,DE的开关override情况相同且与BC不同,那么DE也是俩个shaderMap,俩相同内容的shaderCode,进包后也是一个shaderCode。如果FE开关override没改动,那么FEC是同一套shaderMap。
2、材质Usage 注意这里的Usage和PSO Cache那个UsageMask不是一个概念
如前文所说,材质Usage的设置主要影响VertexFactory组合
项目中的主材质,尤其是通用主材质,AutoUsage开关都应该关闭,然后根据美术实际的使用情况,酌情考虑开关勾选以及是否需要拆分主材质
3、PSO UsageMask
做更细致的UsageMask拆分
然后是反向的分析
项目打包流程的.shk .spc文件都是很好的参考用于分析项目实际用到的变体情况,当然由于这俩是二进制文件,所以还得转成可阅读的文本文件
正向分析看不到实际用到的ShaderType情况和项目中图程侧的一些管线上的自定义修改。从.shk .spc反向分析shaderType,VFType,QulityLevel等条目还是很有必要的
相关文章:
材质变体 PSO学习笔记
学习笔记 参考各路知乎大佬文章 首先是对变体的基本认知 概括就是变体是指根据引擎中上层编写(UnityShaderLab/UE连连看)中的各种defines情况,根据不同平台编译成的底层shader,OpenGL-glsl/DX(9-11)-dxbc DX12-dxil/Vulkan-spirv,是打到游…...
2024年【烟花爆竹储存】考试及烟花爆竹储存复审模拟考试
题库来源:安全生产模拟考试一点通公众号小程序 烟花爆竹储存考试参考答案及烟花爆竹储存考试试题解析是安全生产模拟考试一点通题库老师及烟花爆竹储存操作证已考过的学员汇总,相对有效帮助烟花爆竹储存复审模拟考试学员顺利通过考试。 1、【单选题】( …...
文件夹操作
文件夹操作 opendir closedir readdir write(fd,buf,strlen(buf)); return 0; } 作用 : 打开目录 opendir 所有头文件 : #include <sys/types.h> #include <dirent.h> 函数 : DIR *opendir(const char *name); 参数: name :目…...
如何制作一台自己想要的无人机?无人机改装调试技术详解
制作一台符合个人需求的无人机并对其进行改装调试,是一个既具挑战性又充满乐趣的过程。以下是从设计、选购材料、组装、调试到改装的详细步骤: 一、明确需求与设计 1. 明确用途与性能要求: 确定无人机的使用目的,如航拍、比赛、…...
Linux -- 进程间通信、初识匿名管道
目录 进程间通信 什么是进程间通信 进程间通信的一般规律 前言: 管道 代码预准备: 如何创建管道 -- pipe 函数 参数: 返回值: wait 函数 参数: 验证管道的运行: 源文件 test.c : m…...
网站的SSL证书快到期了怎么办?怎么续签?
网站的SSL证书即将到期时,需要续签一个新的证书以保持网站的安全性和信任度。以下是续签SSL证书的一般步骤: 1. 选择证书提供商 如果您之前使用的是免费证书,您可以选择继续使用同一提供商的免费证书服务进行续签。如果您需要更高级别的证书…...
解決爬蟲代理連接的方法
爬蟲在運行過程中常常會遇到代理連接的問題,這可能導致數據抓取的效率降低甚至失敗。 常見的代理連接問題 代理IP失效:這是最常見的問題之一。有些代理IP可能在使用一段時間後失效,導致連接失敗。 連接超時:由於網路不穩定或代…...
Prometheus 监控Harbor
你好!今天分享的是基于Prometheus监控harbor服务。 在之前的文章中分别介绍了harbor基于离线安装的高可用汲取设计和部署。那么,如果我们的harbor服务主机或者harbor服务及组件出现异常,我们该如何快速处理呢? Harbor v2.2及以上…...
SQL 干货 | SQL 半连接
大多数数据库开发人员和管理员都熟悉标准的内、外、左和右连接类型。虽然可以使用 ANSI SQL 编写这些连接类型,但还有一些连接类型是基于关系代数运算符的,在 SQL 中没有语法表示。今天我们将学习一种这样的连接类型:半连接(Semi …...
洛谷 P1226:【模板】快速幂
【题目来源】https://www.luogu.com.cn/problem/P1226【题目描述】 给你三个整数 a,b,p,求 a^b mod p。【输入格式】 输入只有一行三个整数,分别代表 a,b,p。【输出格式】 输出一行一个字符串 a^b mod ps&a…...
nginx常规操作
Linux下查找Nginx配置文件位置 1、查看Nginx进程 ps -aux | grep nginx 圈出的就是Nginx的二进制文件 2、测试Nginx配置文件 /usr/sbin/nginx -t 可以看到nginx配置文件位置 3、nginx的使用(启动、重启、关闭) 首先利用配置文件启动nginx。 nginx -c /usr/local/nginx/conf…...
Docker镜像不能访问
Get "https://registry-1.docker.io/v2/": dial tcp 192.168.10.194:443: connect: connection refused Idea推送镜像至Harbor私服,报以上错误,Docker镜像地址不能访问,更新Harbor服务器Docker镜像地址,重启Docker服务…...
TCP simultaneous open测试
源代码 /*************************************************************************> File Name: common.h> Author: hsz> Brief:> Created Time: 2024年10月23日 星期三 09时47分51秒**********************************************************************…...
Spring 配置文件动态读取pom.xml中的属性
需求: 配置文件中的 spring.profiles.active${env}需要打包时动态绑定。 一、方案: 在pom.xml文件中配置启用占位符替换 <profiles><!-- 本地开发 --><profile><id>dev</id><properties><env>dev</env>…...
Konva 组,层级
代码: <template><div class"rect"><div class"header"> <!-- <el-button type"primary" click"show">展示</el-button>--> <!-- <el-button type"success&quo…...
vue图片加载失败的图片
1.vue图片加载失败的图片 这个问题发生在测试环境和开发本地,线上环境是可以的,测试环境估计被第三方屏蔽了 2.图片有,却加载不出来 <template v-slot:imageUrlsSlots"{ row }"><div class"flexRow rowCenter"&…...
终止,半成收入来自海外,收入可持续性被质疑
芬尼科技终止原因如下:芬尼科技4年期间经历了两次IPO失败,公司半成收入来自海外,然而公司泳池收入面临欧洲地区冲突冲击及德国新节能措施影响。交易所质疑其收入是否具有可持续性。 作者:Eric 来源:IPO魔女 9月25日&a…...
日常记录,使用springboot,vue2,easyexcel使实现字段的匹配导入
目前的需求是数据库字段固定,而excel的字段不固定,需要实现excel导入到一个数据库内。 首先是前端的字段匹配,显示数据库字段和表头字段 读取表头字段: 我这里实现的是监听器导入,需要新建一个listen类。 读Excel …...
Unable to open nested entry ‘********.jar‘ 问题解决
今天把现网版本的task的jar拖回来然后用7-zip打开拖了一个jar进去替换mysql-connector-java-5.1.47.jar 为 mysql-connector-java-5.1.27.jar 启动微服务的时候就报错下面的 Exception in thread "main" java.lang.IllegalStateException: Failed to get nested ar…...
反编译华为-研究功耗联网监控日志
摘要 待机功耗中联网目前已知的盲点:App自己都不知道的push类型的被动联网、app下载场景所需时长、组播联网、路由器打醒AP。 竞品 策略 华为 灭屏使用handler定时检测(若灭屏30分钟内则周期1分钟,否则为2分钟),检…...
线程池——Java
一、前言 在字符串常量池中,字符串常量在java程序运行之前就已经创建好了,等程序运行起来后,就可以直接从常量池中拿到字符串并加载到内存中,这样的设计就省下了字符串的构造与销毁的内存开销。 二、优势 操作系统由内核与应用程…...
java 17天 TreeSet以及Collections
SortedSet TreeSet Collections 所有单值集合 1 SortedSet 特点:有序 唯一 实现类:TreeSet 利用TreeSet特有的对数据进行升序,再放到ArryList进行for下标倒序打印,或者利用自身的pollLast()取出最后元…...
JavaScript 第27章:构建工具与自动化
在现代JavaScript开发中,构建工具、代码转换工具、代码质量和代码格式化工具对于提高开发效率、保持代码整洁以及确保代码质量有着至关重要的作用。下面将分别介绍Webpack、Babel、ESLint和Prettier的配置与使用,并给出一些示例。 1. 构建工具ÿ…...
Android原生ROM出现WIFI显示网络连接受限,网络无法连接的问题
Android原生ROM出现WIFI显示网络连接受限,网络无法连接的问题 最近手里一台乐视的手机root后, 连接wifi时一直提示网络连接受限,wifi图标显示叹号. 但是不影响正常的网络访问. 解决办法: adb shell settings delete global captive_portal_modeadb shell settings put globa…...
如何实现网页上的闪烁效果
在网页上实现闪烁效果通常可以通过CSS或者JavaScript来完成。有两种方法:一种是使用纯CSS,另一种是结合JavaScript来创建更复杂的闪烁效果。 方法一:使用纯CSS CSS中可以使用animation属性来创建简单的动画效果,包括闪烁效果。这…...
事件总线—Event Bus 使用及讲解
一、工作原理 事件总线,主要用来实现非父子组件之间的传值。 它的工作原理:通过new Vue()再创建一个新的 Vue 实例对象bus,将这个新的实例对象作为桥梁,来实现两个组件之间的传值。 二、工作步骤 1、创建事件总线 bus 我们可以…...
信息安全工程师(67)网络流量清洗技术与应用
前言 网络流量清洗技术是现代网络安全领域中的一项关键技术,它主要用于过滤和清理网络流量中的恶意部分,确保正常的网络通信。 一、网络流量清洗技术的定义与原理 网络流量清洗技术,也称为流量清理(Traffic Scrubbing)…...
【项目】论坛系统测试
文章目录 一、项目介绍二、测试环境三、测试用例3.1 论坛系统功能测试用例3.2 论坛系统非功能测试用例 四、测试计划1. 手工测试1.1 注册页面1.2 登陆页面1.3 主页面(列表页) 2. 自动化测试2.1 添加对应的依赖2.2 Utils类(公有类)…...
XJ02、消费金融|消费金融业务模式中的主要主体
根据所持有牌照类型的不同,消费金融服务供给方主要分为商业银行、汽车金融公司、消费金融公司和小贷公司,不同类型机构定位不同、提供消费金融服务与产品类型也各不相同。此外,互联网金融平台也成为中国消费金融业务最重要的参与方之一&#…...
基于神经网络的农业病虫害损失预测
【摘 要】鉴于农业病虫害经济损失的预测具有较强的复杂性和非线性特性,设计了一种新型的GRNN预测模型,对农业病虫害经济损失进行预测。该模型基于人工神经网络捕捉非线性变化独特的优越性,在神经网络技术和江苏省气象局提供的数据的基础上&am…...
哪家做网站做的好/怎么让网站排名上去
truffle自动化测试脚本 补充一个unbox 1.部署本地ganache环境 配置文件地址为本地地址 localhost:XXXX 上线的环境为 infura的url 2.命令: truffle console migrate test 部署 yarn //找不到网络 truffle.js改成如下的: networks: { developm…...
wordpress弹窗登录插件/百度大数据搜索引擎
MyBatis之一对多, 多对一 关联查询 Hello,大家好,本周博主为大家带来MyBatis中的一对多,多对一查询,关于MyBatis中查询的操作,下面步入正题 开发环境 IDE:IntelliJ IDEA jdk:1.8 数据库:mysql 5…...
设计网站公司优选亿企邦/整站营销系统
Author:Maddock Date:2015.04.22 转载请注明出处:http://www.cnblogs.com/adong7639/p/4446828.html DNG格式基本概念 DNG格式是在TIFF的基础上扩展出来的,要了解DNG,需要清楚TIFF, TIFF/EP, DNG,RAW之间的关系。 TIFF…...
建设主流媒体网站/百度网盘下载速度慢破解方法
QtCore.QSettings()的东西存到哪了 存在注册表里了...
找人做网站不算诈骗罪吗/seo关键词排名优化推荐
我觉得下面文章讲的非常不错,适合nodejs入门学习。 七天学会NodeJS...
沈阳自助建站软件/西安高端网站建设公司
题意,四个柱子的汉诺塔 来自:http://blog.csdn.net/pmt123456/article/details/53571989 一、经典汉诺塔 有三根相邻的柱子,标号为A,B,C,A柱子上从下到上按金字塔状叠放着n个不同大小的圆盘,要把所有盘子一个一个移动到…...