文章目录

  • 一、前言
  • 二、直观感受法线贴图
  • 三、表面法线
    • 1、表面法线的概念
    • 2、空间与坐标系
      • 2.1、世界空间——世界坐标系
      • 2.2、局部空间——局部坐标系
      • 2.3、切线空间——切线坐标系
      • 2.4、小结
  • 四、法线贴图
    • 1、法线贴图如何存储法线数据
    • 2、有法线贴图与无法线贴图效果对比
    • 3、徒手画法线贴图凹凸效果
  • 五、场景法线颜色可视化
    • 1、shader,法线信息转rgb颜色
    • 2、摄像机应用shader,Camera.SetReplacementShader
    • 3、运行测试
    • 4、发挥想象力: 结合粒子系统
  • 六、使用python大法
    • 1、通过python生成法线图
    • 2、爬虫爬取二次元美女图片
    • 3、批量生成二次元美女法线图
    • 4、猜猜这三个二次元美女是谁
  • 七、结束语
  • 八、附录:NormalVisualizerWithGizmo.cs代码

一、前言

嗨,大家好,我是新发。
3D项目的同学应该对法线贴图不陌生,新手同学可能一开始比较懵逼,什么是表面法线?什么是法线贴图?为什么法线贴图长这个样子?法线贴图有什么用?等等这些问题,今天,我就带大家来一次【法线探险之旅】吧~

二、直观感受法线贴图

首先我们先来直观感受下法线贴图的效果,我们打开下面这个网站,
地址:https://cpetry.github.io/NormalMap-Online/
这个网站可以在线生成法线贴图,中间那张偏蓝紫色的图片就是法线图了,右边是应用了这张法线贴图的平面,可以看到这个平面具有了凹凸的效果。

三、表面法线

1、表面法线的概念

首先我们需要先知道什么是表面法线。Unity官方的解释是:

The surface angle can be represented as a line protruding in a perpendicular direction from the surface, and this direction (which is a vector) relative to the surface is called a “surface normal”, or simply, a normal.

翻译成人话就是垂直于模型表面的向量就是表面法线,为了方便大家理解,我刻意做了个Demo来演示表面法线,如下:

注:显示表面法线的代码见文章末尾附录:NormalVisualizerWithGizmo.cs代码。


我们的3D模型是由网格组成的,一般都是由一个个三角网格组成,一个三角网格就是一个小平面,垂直于这个平面的向量就是法线了。

2、空间与坐标系

Unity中,我们常听到的是世界坐标和局部坐标,对应的空间是世界空间和局部空间;而我们的法线是基于切线空间的,在介绍切线空间之前,我们先温习一下世界空间和局部空间。

2.1、世界空间——世界坐标系

世界坐标的方向是绝对的,如果我们从电脑屏幕往里看,则世界坐标系的x轴(红色)朝右,y轴(黄绿色)朝上,z轴(蓝色)朝屏幕里面,像这样子:

注:了演示我特意去找了个笔记本的模型,把笔记本的贴图扣成透明的,方便透过屏幕看到屏幕里面的妹子,效果还不错吧~

2.2、局部空间——局部坐标系

局部坐标系是物体内部的一个相对的坐标系,局部坐标系为随着物体的位移、旋转而发生变化,我们可以在Unity的工具栏这里切换世界坐标系和局部坐标系,如下:

如果你把一个物体A作为另一个物体B的子物体,则我们在Inspector界面看到物体A的坐标为局部坐标,只有当一个物体没有父物体的时候,Inspector显示的坐标才为世界坐标。

2.3、切线空间——切线坐标系

或许你也常听说过UV坐标,其实,纹理的UV坐标就是切线空间的x轴和y轴,不过U、V坐标的范围是0~1

注:为什么用UV这两个字母呢?因为XYZ三个字母被用了,所以用UV

聪明的你肯定发现了,如果再加上一个W轴,不就构成了UVW坐标系了吗?没错,这个就是切线空间坐标系了,不过切线坐标系的轴的命名有另一套叫法:TBN,为了方便对照,我画个表格:

切线空间坐标轴 名称 对应关系
T 切线轴(tangant) 对应x轴,或u轴
B 副切线轴(bitangent) 对应y轴,或v轴
N 法线轴(normal) 对应z轴,或w轴

模型网格的每个三角网格都有各自的切线空间,而我们的法线向量就是基于切线空间坐标系的。

2.4、小结

法线向量就是基于切线空间坐标系的,切线坐标系的三个轴是T、B、N

四、法线贴图

有了表面法线数据,那我们如何存储这些法线数据呢?
法线是一个三维向量,比如(0, 0, 1),正好,我们的RGB颜色也是一个三维数据,所以,我们就可以把法线信息使用RGB颜色来存储成为一张图片了。

1、法线贴图如何存储法线数据

在切线空间坐标系中,正常情况下,法线垂直于表面,也就是法线垂直于TB平面(或者UV平面),这种情况,法线向量为(0, 0, 1),如果对应成归一化的RGB就是蓝色了,

可是我们是可以让法线朝者TB轴的负方向偏的,比如(-0.1, -0.4, 1),但,归一化的RGB颜色是范围是0 ~ 1,它不能表示负数,所以,并不是简单地把法线向量作为归一化的RGB颜色值进行存储,而是经过了如下的变换:

rgb = (normal + 1) / 2

假设法线向量为(0, 0, 1),那么通过公式计算出来的归一化RGB则为(0.5, 0.5, 1),对应成颜色值就是(128, 128, 255),效果如下:

2、有法线贴图与无法线贴图效果对比

我们先看一下上面的笔记本电脑模型的法线贴图,看到这里,你应该知道为什么法线贴图的主色调是偏蓝紫色了吧~

模型本身是平平的,如下:

没有法线贴图的效果是这样的:

加上法线贴图后的效果是这样的:

法线贴图的作用就是修改光照的反射使其看起来有凹凸感,这样我们的模型可以减少很多面数,凹凸细节通过法线贴图来实现,是不是很聪明的做法呢~

3、徒手画法线贴图凹凸效果

现在,我们知道了法线贴图的原理,所以,理论上我们是可以徒手画出一个有凹凸效果的法线贴图的。

说干就干!
先用ProBuilder建个模,此处建模纯粹是要表达我想要的凹凸效果,

注:如果大家对ProBuilder建模感兴趣的话,我可以下期出个教程~


接着,把模型抹平,我们要用法线贴图来实现这个凸起的视觉效果,

打开PhotoShop,开始画法线贴图,先给底图铺上颜色(128, 128, 255)

先画左边的斜面,假设斜面与平面的角度是45度

它的法线向量是(-0.5, 0, 1)

根据公式rgb = (normal + 1) / 2计算出RGB颜色为(64, 128, 255)

接着画右边的斜面,它的法线是(0.5, 0, 1),计算出RGB颜色为(192, 128, 255)

一次类推,最终各个块的颜色值如下:

保存为JPG格式,如下,

把法线贴图导入到Unity中,应用到材质球的Normal Map上,

效果如下:

五、场景法线颜色可视化

既然我们可以知道法线信息,也可以知道法线对应的RGB颜色,那么,我们可否把场景中的所有物体的法线都转成颜色并显示为出来呢?
理论存在,实践开始。

1、shader,法线信息转rgb颜色

我们写一个shader,在片元着色器vert中取得法线并转成rbg颜色,如下:

o.color.xyz = v.normal * 0.5 + 0.5;
o.color.w = 1.0;

完整shader代码如下:

Shader "Debug/Normals" {SubShader {Pass {CGPROGRAM#pragma vertex vert#pragma fragment frag#include "UnityCG.cginc"// vertex input: position, normalstruct appdata {float4 vertex : POSITION;float3 normal : NORMAL;};struct v2f {float4 pos : SV_POSITION;fixed4 color : COLOR;};v2f vert (appdata v) {v2f o;o.pos = UnityObjectToClipPos(v.vertex );o.color.xyz = v.normal * 0.5 + 0.5;o.color.w = 1.0;return o;}fixed4 frag (v2f i) : SV_Target { return i.color; }ENDCG}}
}

2、摄像机应用shader,Camera.SetReplacementShader

我们想要全局应用上面的shader,另写一个c#脚本,通过Camera的接口SetReplacementShader来全局应用shader
c#脚本(NormalColor.cs)代码如下:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class NormalColor : MonoBehaviour
{public Shader shader;private Camera cam;void Awake(){cam = GetComponent<Camera>();}void OnEnable(){cam.SetReplacementShader(shader, null);}void OnDisable(){cam.ResetReplacementShader();}
}

NormalColor.cs脚本挂到摄像机上,并赋值shader对象,

3、运行测试

运行Unity,测试效果如下,是不是别有一番风味~

4、发挥想象力: 结合粒子系统

不如结合一下粒子效果,创建一个ParticleSystem,设置它的RendererMeshCube

调节粒子的常规参数,如下,

粒子效果如下:

运行Unity,显示出法线颜色,效果如下:

六、使用python大法

1、通过python生成法线图

不够尽兴,还能怎么玩呢?我们能不能通过python生成常规图片的法线图呢?
我在GitHub上找到了一个,GitHub地址:https://github.com/Mehdi-Antoine/NormalMapGenerator/blob/master/normal_map_generator.py

我做了一些改造,方便批量生成,代码见下方,需要安装numpy、scipp、imageio
使用方法:
把需要转换的图片放在input文件夹中,然后执行gen_normalmap.py脚本即可,

生成结果会放在output目录中,

效果如下:


gen_normalmap.py代码如下:

import numpy as np
import scipy.ndimage
import scipy.misc
from scipy import ndimage
import argparse
import imageio
import shutil
import osinput_dir = 'input'
output_dir = 'output'def smooth_gaussian(im, sigma):if sigma == 0:return imim_smooth = im.astype(float)kernel_x = np.arange(-3*sigma,3*sigma+1).astype(float)kernel_x = np.exp((-(kernel_x**2))/(2*(sigma**2)))im_smooth = scipy.ndimage.convolve(im_smooth, kernel_x[np.newaxis])im_smooth = scipy.ndimage.convolve(im_smooth, kernel_x[np.newaxis].T)return im_smoothdef gradient(im_smooth):gradient_x = im_smooth.astype(float)gradient_y = im_smooth.astype(float)kernel = np.arange(-1,2).astype(float)kernel = - kernel / 2gradient_x = scipy.ndimage.convolve(gradient_x, kernel[np.newaxis])gradient_y = scipy.ndimage.convolve(gradient_y, kernel[np.newaxis].T)return gradient_x,gradient_ydef sobel(im_smooth):gradient_x = im_smooth.astype(float)gradient_y = im_smooth.astype(float)kernel = np.array([[-1,0,1],[-2,0,2],[-1,0,1]])gradient_x = scipy.ndimage.convolve(gradient_x, kernel)gradient_y = scipy.ndimage.convolve(gradient_y, kernel.T)return gradient_x,gradient_ydef compute_normal_map(gradient_x, gradient_y, intensity=1):width = gradient_x.shape[1]height = gradient_x.shape[0]max_x = np.max(gradient_x)max_y = np.max(gradient_y)max_value = max_xif max_y > max_x:max_value = max_ynormal_map = np.zeros((height, width, 3), dtype=np.float32)intensity = 1 / intensitystrength = max_value / (max_value * intensity)normal_map[..., 0] = gradient_x / max_valuenormal_map[..., 1] = gradient_y / max_valuenormal_map[..., 2] = 1 / strengthnorm = np.sqrt(np.power(normal_map[..., 0], 2) + np.power(normal_map[..., 1], 2) + np.power(normal_map[..., 2], 2))normal_map[..., 0] /= normnormal_map[..., 1] /= normnormal_map[..., 2] /= normnormal_map *= 0.5normal_map += 0.5return normal_mapdef walk_pic():for root, dirs, fs in os.walk(input_dir):for f in fs:if f.endswith('png') or f.endswith('jpg'):yield os.path.join(root, f)def main():if os.path.exists(output_dir):shutil.rmtree(output_dir)os.mkdir(output_dir)parser = argparse.ArgumentParser(description='Compute normal map of an image')parser.add_argument('-s', '--smooth', default=0., type=float, help='smooth gaussian blur applied on the image')parser.add_argument('-it', '--intensity', default=1., type=float, help='intensity of the normal map')args = parser.parse_args()sigma = args.smoothintensity = args.intensityfor input_file in walk_pic():(_,output_file_name) = os.path.split(input_file)output_file = output_dir + '/_normal_' + output_file_nameim = np.array(imageio.imread(input_file))if im.ndim == 3:im_grey = np.zeros((im.shape[0],im.shape[1])).astype(float)im_grey = (im[...,0] * 0.3 + im[...,1] * 0.6 + im[...,2] * 0.1)im = im_greyim_smooth = smooth_gaussian(im, sigma)sobel_x, sobel_y = sobel(im_smooth)normal_map = compute_normal_map(sobel_x, sobel_y, intensity)imageio.imsave(output_file, normal_map)if __name__ == "__main__":main()

2、爬虫爬取二次元美女图片

我有个大胆的想法,写个python爬虫,爬取二次元美女图片,然后…
话不多说,上爬虫:

import requests
import os
import urllib# 百度图片爬虫
class Spider_baidu_image():def __init__(self):self.url = 'http://image.baidu.com/search/acjson?'self.headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.\3497.81 Safari/537.36'}self.headers_image = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.\3497.81 Safari/537.36','Referer':'http://image.baidu.com/search/index?tn=baiduimage&ipn=r&ct=201326592&cl=2&lm=-1&st=-1&fm=result&fr=&sf=1&fmq=1557124645631_R&pv=&ic=&nc=1&z=&hd=1&latest=0&copyright=0&se=1&showtab=0&fb=0&width=&height=&face=0&istype=2&ie=utf-8&sid=&word=%E8%83%A1%E6%AD%8C'}# 构造参数数组def get_param(self):keyword = urllib.parse.quote(self.keyword)params = []for i in range(1,self.paginator+1):params.append('tn=resultjson_com&ipn=rj&ct=201326592&is=&fp=result&queryWord={}&cl=2&lm=-1&ie=utf-8&oe=utf-8&adpicid=&st=-1&z=&ic=&hd=1&latest=0&copyright=0&word={}&s=&se=&tab=&width=&height=&face=0&istype=2&qc=&nc=1&fr=&expermode=&force=&cg=star&pn={}&rn=30&gsm=78&1557125391211='.format(keyword,keyword,30*i))return params# 构造url数组def get_urls(self, params):urls = []for i in params:urls.append(self.url+i)return urls# 遍历请求url并下载图片def get_image(self, urls):cwd = os.getcwd()file_name = os.path.join(cwd,self.keyword)if not os.path.exists(self.keyword):os.mkdir(file_name)index = 0for url in urls:json_data = requests.get(url,headers = self.headers).json()json_data = json_data.get('data')for i in json_data:if i:image_url = i.get('thumbURL')index += 1with open(file_name+'\\{}.jpg'.format(index),'wb') as f:f.write(requests.get(image_url, headers = self.headers_image).content)print('下载: ' + image_url)def __call__(self, *args, **kwargs):# 构造参数params = self.get_param()# 构造url数组urls = self.get_urls(params)# 请求self.get_image(urls)if __name__ == '__main__':spider = Spider_baidu_image()# 关键字spider.keyword = '二次元美女'# 页数,每页30张图spider.paginator = 100# 开始执行spider()

爬图片中…

3、批量生成二次元美女法线图

然后放到gen_normalmap.py同级目录的input文件夹中,执行gen_normalmap.py生对应的法线图,

4、猜猜这三个二次元美女是谁

这是其中三张法线图,大家猜得出这三个二次元美女是谁吗~

七、结束语

好了,就先写这么多吧~
喜欢Unity的同学,不要忘记点击关注,如果有什么Unity相关的技术难题,也欢迎留言或私信~

推荐阅读:

  • 《Unity+人工智能,让小朋友的画成真,六一儿童节一起来画猫猫吧(Unity | 人工智能 | 绘图 | 爬虫 | 猫妖)》
  • 《[Unity 3D] 权游红袍女在火中看到了什么,我看到了…(粒子系统 | 火焰特效 | ParticleSystem | 手把手制作)》
  • 《[Unity 2D] 重温红白机经典FC游戏,顺便教你快速搭建2D游戏关卡(Tilemap | 场景 | 地图)》
  • 《520程序员的浪漫,给CSDN近两万的粉丝比心心(python爬虫 | Unity循环复用列表 | 头像加载与缓存)》
  • 《ShaderGraph使用教程与各种特效案例:Unity2020(持续更新)》
  • 《Unity使用ShaderGraph配合粒子系统,制作子弹拖尾特效(Fate/stay night金闪闪的大招效果)》
  • 《使用Unity ShaderGraph实现在模型上涂鸦的效果,那么,纹个手吧》
  • 《学Unity的猫——第十五章:Unity粒子系统ParticleSystem,下雪啦下雪啦》
  • 《Unity实现水果忍者切水果的刀痕效果教程(两种实现方式:TrailRenderer、LineRenderer)》
  • 《Unity流体模拟,支持粒子系统,支持流体碰撞交互(Obi Fluid插件使用教程)》
  • 《玩转贝塞尔曲线,教你在Unity中画Bezier贝塞尔曲线(二阶、三阶),手把手教你推导公式》
  • 《Unity UGUI制作雷达图/天赋图/属性图/能力图,因为太怕痛就全点了防御力》
  • 《使用Unity ShaderGraph实现刮刮乐的刮卡剔除效果,感受一下刮中500万的时刻》

八、附录:NormalVisualizerWithGizmo.cs代码

using UnityEngine;[ExecuteInEditMode]
public class NormalVisualizerWithGizmo : MonoBehaviour
{#region Enumpublic enum Type{Vertex,Surface}#endregion Enum#region Fieldpublic Type drawType = NormalVisualizerWithGizmo.Type.Surface;[Range(0f, 1)]public float normalLength = 0.1f;public Color normalColor = Color.white;public bool  normalColorFromDirection = true;protected Mesh mesh;protected new Transform transform;#endregion Field#region Methodprotected virtual void OnEnable(){if (this.mesh == null){MeshFilter meshFilter = base.gameObject.GetComponent<MeshFilter>();if (meshFilter == null){this.mesh = base.gameObject.GetComponent<SkinnedMeshRenderer>().sharedMesh;}else{this.mesh = base.gameObject.GetComponent<MeshFilter>().sharedMesh;}}if (this.transform == null){this.transform = base.transform;}}protected virtual void OnDrawGizmos(){Color     previousColor  = Gizmos.color;Matrix4x4 previousMatrix = Gizmos.matrix;Gizmos.matrix = Matrix4x4.TRS(this.transform.position,this.transform.rotation,this.transform.localScale);switch (this.drawType){case Type.Surface:{DrawSurfaceNormalGizmos();break;}case Type.Vertex:{DrawVertexNormalGizmos();break;}}Gizmos.color  = previousColor;Gizmos.matrix = previousMatrix;}protected virtual void DrawVertexNormalGizmos(){Vector3 [] vertices = this.mesh.vertices;Vector3 [] normals  = this.mesh.normals;Vector3 normal;Gizmos.color = this.normalColor;for (int i = 0; i< this.mesh.vertexCount; i++){normal = Vector3.Normalize(normals[i]);if (this.normalColorFromDirection){Gizmos.color = new Color(normal.x, normal.y, normal.z);}Gizmos.DrawRay(vertices[i], normal * this.normalLength);}}protected virtual void DrawSurfaceNormalGizmos(){Vector3[] vertices  = this.mesh.vertices;Vector3[] normals   = this.mesh.normals;int[] triangles = this.mesh.triangles;Vector3 normal;Vector3 position;int triangleIndex0;int triangleIndex1;int triangleIndex2;Gizmos.color = this.normalColor;for (int i = 0; i <= triangles.Length - 3; i += 3){triangleIndex0 = triangles[i];triangleIndex1 = triangles[i + 1];triangleIndex2 = triangles[i + 2];position = (vertices[triangleIndex0]+ vertices[triangleIndex1]+ vertices[triangleIndex2]) / 3;normal = (normals[triangleIndex0]+ normals[triangleIndex1]+ normals[triangleIndex2]) / 3;normal = Vector3.Normalize(normal);if (this.normalColorFromDirection){Gizmos.color = new Color(normal.x, normal.y, normal.z);}Gizmos.DrawRay(position, normal * this.normalLength);}}#endregion Method
}

【游戏开发进阶】带你玩转模型法线,实验一下大胆的想法(法线贴图 | shader | Unity | python | 爬虫)相关推荐

  1. HTML5游戏开发进阶指南(亚马逊5星畅销书,教你用HTML5和JavaScript构建游戏!)

    HTML5游戏开发进阶指南(亚马逊5星畅销书,教你用HTML5和JavaScript构建游戏!) [印]香卡(Shankar,A.R.) 著 谢光磊 译 ISBN 978-7-121-21226-0 ...

  2. 【游戏开发进阶】教你Unity通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)

    文章目录 一.前言 二.Jenkins简介 三.Jenkins的下载与安装 1.JDK下载与安装 2.Jenkins下载 3.Jenkins安装 4.Jenkins初始化 四.Jenkins的基本操作 ...

  3. DirectX游戏开发之一个API玩转音乐

    DirectX游戏开发之一个API玩转音乐 当你闭上眼睛,打开一款游戏,如刺客信条,英雄联盟,DNF,或者是当有一个人坐在你背后玩一款新游戏,第一时间吸引你的是什么? 没错,就是各种游戏的音效,包括背 ...

  4. HTML5游戏开发进阶指南

    <HTML5游戏开发进阶指南> 基本信息 作者: (印)香卡(Shankar,A.R.) 译者: 谢光磊 出版社:电子工业出版社 ISBN:9787121212260 上架时间:2013- ...

  5. 世嘉MD游戏开发进阶篇【三】:向量归一化的实现及应用

    向量归一化是非常有用的,游戏中经常能用到,就说大家都见过的,FC魂斗罗的敌人发射子弹就能用到了,敌人向玩家发射子弹首先要获取到向量,这个向量不能直接作为方向去用,必须要经过归一化处理才行,经过归一化处 ...

  6. 学习3D游戏开发进阶之路

    笔者从事IT行业15年了,一直奋斗在一线编程,从普通程序员逐步成长到上市公司技术总监,目前在创业公司担任技术合伙人,主要负责公司整个项目团队的技术管理.在网上或者论坛上很多同学请教过我关于如何学习3D ...

  7. Unity3D游戏开发初探—2.初步了解3D模型基础

    一.什么是3D模型? 1.1 3D模型概述 简而言之,3D模型就是三维的.立体的模型,D是英文Dimensions的缩写. 3D模型也可以说是用3Ds MAX建造的立体模型,包括各种建筑.人物.植被. ...

  8. cocos2dx掼蛋_精通Cocos2d-x游戏开发(进阶卷) (王永宝著) 完整pdf扫描版[98MB]

    <精通Cocos2d-x游戏开发>分为<基础卷>和<进阶卷>两册.这两册都有明确的写作目的.<基础卷>专注于Cocos2d-x引擎基础,致力于让Coco ...

  9. 【游戏开发进阶】新发带你玩转Unity日志打印技巧(彩色日志 | 日志存储与上传 | 日志开关 | 日志双击溯源)

    文章目录 一.前言 二.常规日志打印 1.打印Hello World 2.打印任意类型的数据 3.context参数干嘛的 4.格式化输出 三.彩色日志打印 四.日志存储与上传 1.打印日志事件 2. ...

最新文章

  1. Spring Boot + MDC 实现全链路调用日志跟踪
  2. Why Spring Boot
  3. uwsgi部署到nginx出现invalid request block size: 4161 (max 4096)...skip问题(亲测)
  4. 【数据结构与算法】之深入解析“压缩字符串”的求解思路与算法示例
  5. 通向架构师的道路(第四天)之Tomcat性能调优-让小猫飞奔
  6. TortoiseSVN无法查看日志和SVN LOG无法查看日志的解决办法。
  7. MySQL 不落地迁移、导入 PostgreSQL - 推荐 rds_dbsync 1
  8. Hadoop生态hive(六)Hive QL表
  9. 中文名称:深入浅出SQL
  10. 计算两日期之间差多少天----日期格式为:yyyy-mm-dd
  11. 周末计划-20171028
  12. jsp购物车和mysql_用jsp和数据库做的购物车的源程序
  13. 服务器系统影子系统,影子系统安装教程
  14. linux系统声卡安装教程,Linux操作系统声卡驱动的安装与配置
  15. 1、4G杂项:Air72XUX平台secure boot使用说明
  16. 统计字符串中含指定字符个数
  17. matlab零状态响应幅度频谱,matlab零状态、零输入响应
  18. docker使用-p参数映射端口失败
  19. 常常反思,让你变成更好的自己
  20. Nginx之父被抓!员工“接私活儿”到底合不合法?

热门文章

  1. 网页报告不能直接转换成Word、PDF格式怎么办?Spire.doc控件可以轻松解决
  2. react生态下jest单元测试
  3. 数据结构——初识数据结构
  4. 改善程序员生活质量的 3 + 10 习惯
  5. 用Python给学弟准备追女神要用的多种流行的表白爱心代码【源码】
  6. 全国39所985高校名单
  7. linux磁盘扩容方案
  8. 单片机设计_打砖块游戏(STM32 OLED)
  9. 最长公共子序列 (LCS) 详解+例题模板(全)
  10. 使用泰克示波器完成以太网调试