Jack Huang's Blog


  • 首页

  • 标签

  • 归档

  • 搜索

编译原理学习笔记

发表于 2019-12-29

编译原理是计算机专业的一门重要专业课,旨在介绍编译程序构造的一般原理和基本方法。内容包括语言和文法、词法分析、语法分析、语法制导翻译、中间代码生成、存储管理、代码优化和目标代码生成。

基本概念

  • 词法分析

从左到右逐个字符地扫描,从中识别出一个个“单词”符号。“单词”符号是程序设计语言的基本语法单位,如关键字、标识符、常数、运算符和分隔符等。

  • 语法分析

根据语言的语法规则将单词符号序列分解成各类语法单位,比如表达式、语句和程序等。语法规则就是各类语法单位的构成规则。通过语法分析确定整个输入串是否构成一个语法上正确的程序。

  • 语义分析

检查源程序是否包含静态语义错误,并收集类型信息供后面的代码生成阶段使用。只有语法和语义都正确的源程序才能被翻译成正确的目标代码。

语义分析的一个主要工作是进行类型分析和检查。程序语言中的一个数据类型一般包含两个方面的内容:类型的载体及其上的运算。例如:整除取余运算只能对整型数据进行运算,若其运算对象中有浮点数就认为是类型不匹配的错误。静态的语义错误是指编译程序可以发现,动态的语义错误是指源程序虽然能够被编译和执行,但是结果不对,一般是逻辑上的错误。

编译的过程

编译程序的工作过程一般可以分为5个阶段:

  1. 词法分析
  2. 语法分析
  3. 语义分析和中间代码的产生
  4. 优化
  5. 目标代码生成

参考链接

  1. AST 抽象语法树,by Jartto.
  2. 【编译原理】编译原理简单介绍,by cflys.
  3. 编译原理,by junhey.

3D模型动画分类及其使用

发表于 2019-12-28

3DMax、Blender之类的3D建模软件易学难精,其原因在于很多人不了解其背后的计算机图形学原理。因此,掌握相关的计算机图形学原理和知识,对于我们熟练运用3D建模软件是十分必要的。下面简单介绍3D模型的分类及其使用方法。

3D模型动画分类

3D模型动画的基本原理是让模型中各顶点的位置随时间变化。 主要种类有Morph(变形)动画,关节动画和骨骼蒙皮动画(SkinnedMesh)。从动画数据的角度来说,三者一般都采用关键帧技术,即只给出关键帧的数据,其他帧的数据使用插值得到。但由于这三种技术的不同,关键帧的数据是不一样的。

变形动画

Morph(渐变,变形)动画是直接指定动画每一帧的顶点位置,其动画关键中存储的是Mesh所有顶点在关键帧对应时刻的位置。

关节动画

关节动画的模型不是一个整体的Mesh,而是分成很多部分(Mesh),通过一个父子层次结构将这些分散的Mesh组织在一起,父Mesh带动其下子Mesh的运动,各Mesh中的顶点坐标定义在自己的坐标系中,这样各个Mesh是作为一个整体参与运动的。

动画帧中设置各子Mesh相对于其父Mesh的变换(主要是旋转,当然也可包括移动和缩放),通过子到父,一级级的变换累加(当然从技术上,如果是矩阵操作是累乘)得到该Mesh在整个动画模型所在的坐标空间中的变换(从本文的视角来说就是世界坐标系了,下同),从而确定每个Mesh在世界坐标系中的位置和方向,然后以Mesh为单位渲染即可。

关节动画的问题是,各部分Mesh中的顶点是固定在其Mesh坐标系中的,这样在两个Mesh结合处就可能产生裂缝。

骨骼蒙皮动画

骨骼蒙皮动画即SkinnedMesh了,骨骼蒙皮动画的出现解决了关节动画的裂缝问题。骨骼动画的基本原理可概括为:在骨骼控制下,通过顶点混合动态计算蒙皮网格的顶点,而骨骼的运动相对于其父骨骼,并由动画关键帧数据驱动。

一个骨骼动画通常包括骨骼层次结构数据,网格(Mesh)数据,网格蒙皮数据(skin info)和骨骼的动画(关键帧)数据。

SkinnedMesh原理

SkinnedMesh中文一般称作骨骼蒙皮动画,正如其名,这种动画中包含骨骼(Bone)和蒙皮(Skinned Mesh)两个部分,Bone的层次结构和关节动画类似,Mesh则和关节动画不同:

关节动画中是使用多个分散的Mesh,而Skinned Mesh中Mesh是一个整体,也就是说只有一个Mesh,实际上如果没有骨骼让Mesh运动变形,Mesh就和静态模型一样了。

Skinned Mesh技术的精华在于蒙皮,所谓的皮并不是模型的贴图(也许会有人这么想过吧),而是Mesh本身,蒙皮是指将Mesh中的顶点附着(绑定)在骨骼之上,而且每个顶点可以被多个骨骼所控制,这样在关节处的顶点由于同时受到父子骨骼的拉扯而改变位置就消除了裂缝。

Skinned Mesh这个词从字面上理解似乎是有皮的模型,哦,如果贴图是皮,那么普通静态模型不也都有吗?所以我觉得应该理解为具有蒙皮信息的Mesh或可当做皮肤用的Mesh,这个皮肤就是Mesh。而为了有皮肤功能,Mesh还需要蒙皮信息,即Skin数据,没有Skin数据就是一个普通的静态Mesh了。

Skin数据决定顶点如何绑定到骨骼上。顶点的Skin数据包括顶点受哪些骨骼影响以及这些骨骼影响该顶点时的权重(weight),另外对于每块骨骼还需要骨骼偏移矩阵(BoneOffsetMatrix)用来将顶点从Mesh空间变换到骨骼空间。

SkinnedMesh结构

  • 骨骼决定了模型整体在世界坐标系中的位置和朝向。

先看看静态模型吧,静态模型没有骨骼,我们在世界坐标系中放置静态模型时,只要指定模型自身坐标系在世界坐标系中的位置和朝向。在骨骼动画中,不是把Mesh直接放到世界坐标系中,Mesh只是作为Skin使用的,是依附于骨骼的,真正决定模型在世界坐标系中的位置和朝向的是骨骼。

在渲染静态模型时,由于模型的顶点都是定义在模型坐标系中的,所以各顶点只要经过模型坐标系到世界坐标系的变换后就可进行渲染。而对于骨骼动画,我们设置模型的位置和朝向,实际是在设置根骨骼的位置和朝向,然后根据骨骼层次结构中父子骨骼之间的变换关系计算出各个骨骼的位置和朝向,然后根据骨骼对Mesh中顶点的绑定计算出顶点在世界坐标系中的坐标,从而对顶点进行渲染。要记住,在骨骼动画中,骨骼才是模型主体,Mesh不过是一层皮,一件衣服。

  • 骨骼可理解为一个坐标空间。

骨骼只是一个形象的说法,实际上骨骼可理解为一个坐标空间,关节可理解为骨骼坐标空间的原点。关节的位置由它在父骨骼坐标空间中的位置描述。上图中有三块骨骼,分别是上臂,前臂和两个手指。Clavicle(锁骨)是一个关节,它是上臂的原点,同样肘关节(elbow joint)是前臂的原点,腕关节(wrist)是手指骨骼的原点。关节既决定了骨骼空间的位置,又是骨骼空间的旋转和缩放中心。

骨骼就是坐标空间,骨骼层次就是嵌套的坐标空间。关节只是描述骨骼的位置即骨骼自己的坐标空间原点在其父空间中的位置,绕关节旋转是指骨骼坐标空间(包括所有子空间)自身的旋转。

但还有两个可能的疑问,一是骨骼的长度问题,由于骨骼是坐标空间,没有所谓的长度和宽度的限制,我们看到的长度一方面是蒙皮后的结果,另一方面子骨骼的原点(也就是关节)的位置往往决定了视觉上父骨骼的长度,比如这里upper arm线段的长度实际是由elbow joint的位置决定的。

第二个问题,手指的那个端点是啥啊?实际上在我们的例子中手指没有子骨骼,所以那个端点并不存在:)那是为了方便演示画上去的。实际问题中总有最下层的骨骼,他们不能决定其他骨骼了,他们的作用只剩下控制Mesh顶点。对了,那么手指的长度如何确定?我们看到的长度应该是由蒙皮决定的,也就是由Mesh中属于手指的那些点离腕关节的距离决定。

3D模型动画使用

下面给出一段在Unity3D中控制3D模型动画的代码,作为参考。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

using UnityEngine;
using System.Collections;

public class AnimationScript : MonoBehaviour
{
void Start()
{
Animation animation = this.animation;//动画控制器
animation.Play("idle");//上来直接播放idle动画
}
void OnGUI()
{
if (GUI.Button(new Rect(0, 0, 100, 30), "行走"))
{
animation.Play("run");
}
if (GUI.Button(new Rect(100, 0, 100, 30), "停止"))
{
animation.Play("idle");
}
if (GUI.Button(new Rect(200, 0, 100, 30), "攻击"))
{
animation.Play("attack");
animation.PlayQueued("idle");//播放完attack之后再播放idle
}
}
}

参考链接

  1. 骨骼蒙皮动画(SkinnedMesh)的原理解析,by feng.
  2. 【Unity3D】3D模型的使用——FBX的使用与Animation设置,by yongh701.

GitBook入门教程

发表于 2019-12-26 | 更新于 2020-01-28

GitBook是一种制作在线书籍的工具。它基于Git支持多人协作,支持将采用Markdown语法编辑的文档导出成 PDF,EPUB,HTML等多种格式。

GitBook安装

环境要求

  • NodeJS (v4.0.0 and above is recommended)
  • Windows, Linux, Unix, or Mac OS X

NPM安装GitBook

通过NPM工具安装GitBook是最佳的方法:

1
2
$ npm install gitbook-cli -g
$ gitbook init //下载稳定版的gitbook,同时创建在线书籍

gitbook-cli工具可安装多个GitBook版本到系统上。对于Windows平台,gitbook-cli工具安装的多个GitBook版本通常存储在“C:\Users\CurrentLoginUser\.gitbook”。

离线安装GitBook

内网机器上安装GitBook的方法如下:

  • 安装最新Nodejs长期支持版。
  • 使用npm-bundle命令在线打包gitbook-cli
1
2
npm install npm-bundle -g
npm-bundle gitbook-cli
  • 内网机器上安装gitbook-cli
1
npm install ./gitbook-cli.tgz
  • 将“C:\Users\CurrentLoginUser\.gitbook”目录打包拷贝至内网机器对应位置

创建书籍

1
2
3
$ gitbook init    //在当前目录创建书籍
$ gitbook build //构建在线书籍网站
$ gitbook serve //构建在线书籍网站并启动

参考链接

  1. GitBook 从懵逼到入门,by 阿基米东.
  2. 使用 Gitbook 打造你的电子书,by 文艺小青年.
  3. 世上最佳离线markdown编辑工具(gitbook和gitbook editor),by icharm.
  4. 移除GitBook目录下方的“本书使用GitBook发布”字样,by tedxiong.
  5. EbookError: Error during ebook generation: ‘ebook-convert,by 狼爷.
  6. 书籍配置文件(book.json),by wiliam.

glTF2.0格式解析

发表于 2019-12-25 | 更新于 2019-12-27

glTF(GL传输格式的衍生简称)是一种使用JSON标准的3D场景和模型的文件格式。 它是Khronos Group 3D格式工作组开发的一种与API无关的运行时资产交付格式。 它在HTML5DevConf 2016上宣布。此格式旨在成为一种高效,可互操作的格式,具有最小的文件大小和应用程序对运行时的处理。 因此,其创建者将其描述为“3D JPEG”。 glTF还为3D内容工具和服务定义了一种通用的发布格式。本文旨通过对glTF2.0格式的解析,进一步加深对3D建模的理解。

基本概念

在对glTF2.0格式解析之前,应先了解一些3D建模或glTF独有的基本概念:

  • scenes, nodes:场景的基本结构
  • cameras:场景的可视配置
  • meshes:构成3D对象的几何
  • buffers, bufferViews, accessors:数据参考和布局描述
  • materials:定义数据如何被渲染
  • textures, images, samplers:对象表面显示
  • skins:顶点蒙皮信息
  • animations:随时间改变的属性

glTF概念之间的关系

图1 glTF概念之间的关系

参考链接

  1. glTF,by KhronosGroup.
  2. glTF,by wikipedia.
  3. glTF Overview,by KhronosGroup.
  4. 骨骼蒙皮动画(SkinnedMesh)的原理解析,by feng.
  5. 【Unity3D】3D模型的使用——FBX的使用与Animation设置,by yongh701.

jszip使用方法简介

发表于 2019-12-24

当大文件需要在网络中传输时,最好进行压缩传输,然后在终点进行解压。以ZIP压缩为例,压缩后文件大小极具减小,可节约带宽,提高系统并发能力。下面介绍使用jszip在浏览器端的解压方法。

JSZip简介

JSZip是一个用于创建、读取和编辑.zip文件的javascript库,有一个可爱而简单的API。JSZip支持Nodejs和浏览器端的安装使用。具体方法如下:

1
2
3
4
5
6
7
With npm : npm install jszip

With bower : bower install Stuk/jszip

With component : component install Stuk/jszip

Manually : download JSZip and include the file dist/jszip.js or dist/jszip.min.js

浏览器端解压zip文件

后端Nodejs将zip文件以二进制形式存储到数据库中。当前端需要该zip文件时,后端将zip文件以二进制形式传输到前端,前端再解压还原。

Nodejs使用JSZip压缩文件

1
2
3
4
5
6
7
8
9
10
11
12
var JSZip = require("jszip");
var zip = new JSZip();

// create a file
zip.file("hello.txt", "Hello[p my)6cxsw2q");
// oops, cat on keyboard. Fixing !
zip.file("hello.txt", "Hello World\n");

// create a file and a folder
zip.file("nested/hello.txt", "Hello World\n");
// same as
zip.folder("nested").file("hello.txt", "Hello World\n");

浏览器端解压Zip文件

1
2
3
4
5
6
7
8
9
10
import JSZip from 'jszip'

let new_zip = new JSZip();

// Read zip package
new_zip.loadAsync(content)
.then(function(zip) {
// you now have every files contained in the loaded zip
new_zip.file("hello.txt").async("string");
});

参考链接

  1. ZIP格式,by wikipedia.
  2. gzip,bzip2,zip三种格式压缩率对比,by CatDeacon.
  3. JSZip,by stuk.

Python第三方包离线安装

发表于 2019-12-19 | 更新于 2024-01-09

需要在离线的情况下,配置电脑的Python环境,具体方法如下:

  1. 寻找一台与离线电脑架构一致且能上网的干净电脑或虚拟机,在线配置Python环境。
  2. 在线电脑上打包Python环境,拷贝到离线电脑上。
  3. 在离线电脑上安装Python环境。

注意:Python第三方包离线安装可以与python的虚拟环境结合起来,即:

1
python -m venv env

在线配置Python环境

安装Python3之后,使用如下命令安装第三方包:

1
2
# 临时使用清华镜像,加快Python第三方包下载速度
pip3 install -i https://mirrors.aliyun.com/pypi/simple/ matplotlib

打包安装的Python第三方包:

1
2
3
pip3 list #查看安装的包
pip3 freeze >requirements.txt
pip3 download -d C:\Python37\packages -i https://mirrors.aliyun.com/pypi/simple/ -r requirements.txt

离线配置Python环境

在离线电脑上安装与在线电脑同样版本和架构的Python。注意:3.9版本以上python已不支持Windows7。

将打包好的Python环境拷贝到离线电脑后,使用如下命令安装第三方包:

1
pip install --no-index --find-links=C:\Python37\packages -r requirements.txt

参考链接

  1. pypi 镜像使用帮助,by 清华大学开源软件镜像站.
  2. Python pip离线安装package方法总结(以TensorFlow为例),by 毛帅.
  3. 离线环境安装python第三方库,by 接纳自己.

C++中Cout输出到文件

发表于 2019-12-12

最近在调试一个C++程序时,没有报任何错误就直接退出了,Cout输出到控制台的信息没法查看,无法找到错误原因。于是想到将Cout输出重定向到文件,以便分析错误原因。具体代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <iostream>
#include <fstream>

using namespace std;

int main(){
streambuf *psbuf,*backup;
ofstream file;
file.open("test.txt");
backup=cout.rdbuf();
psbuf=file.rdbuf();

cout.rdbuf(psbuf);//将cout输出重定向到文件
cout<< "This will write to test.txt!";

cout.rdbuf(backup);//恢复cout输出重定向到终端
file.close();
return 0;
}

参考链接

  1. NULL指针、零指针、野指针,by fly1988happy.
  2. C++ Null 指针,by w3cschool.
  3. How to redirect cin and cout to files?,by stackoverflow.

红外点源目标探测仿真

发表于 2019-12-11

红外点源目标探测仿真过程中遇到两个问题:一是哪些目标重合到一块,二是如何计算重合目标的中心和半径。这两个问题可分别通过计算图连通分量的算法和最小圆覆盖算法解决。

参考链接

  1. 最小圆覆盖(经典算法【三点定圆),by Coco_T_.
  2. 利用邻接矩阵求解无向图的连通分支的个数,by EsonJohn.
  3. 使用向量叉乘判断线段是否相交并求交点,by leto.
  4. 图的那点事儿(1)-无向图,by SylvanasSun.

C++矩阵的存储方法接出存储方法-行主序与列主序

发表于 2019-12-11

最近要设计一个C++矩阵类,涉及到矩阵元素的存储。根据矩阵元素的存储,通常分为行主序和列主序。

  • 行主序是指以行为优先单位,在内存中逐行存储;

  • 列主序是指以列为优先单位,在内存中逐列存储。

行主序与列主序的代码实现有一定的惯例,表现如下:

  • 行主序以二维数组存储,列主序以一维数组存储;
  • 行主序以二维数组方式命名初始化参数,列主序以一维数组方式命名初始化参数;
  • 行主序以行为单位初始化,列主序以列为单位初始化;

参考链接

  1. OpenGL中矩阵的行主序与列主序,by 天律界中子.

GSL插值函数编译链接出错解决方法

发表于 2019-12-11 | 更新于 2022-07-16

在Windows平台使用VS2017社区版将开源数学库GSL编译链接成DLL后,使用官方示例测试其插值函数。在编译链接该示例过程中报

LNK2001: unresolved external symbol _gsl_interp_cspline

的错误。

解决方法如下,在示例开始处定义如下宏即可。

#define GSL_DLL

完整可运行示例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#define GSL_DLL

#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <gsl/gsl_errno.h>
#include <gsl/gsl_spline.h>

int
main (void)
{
int i;
double xi, yi, x[10], y[10];

printf ("#m=0,S=17\n");

for (i = 0; i < 10; i++)
{
x[i] = i + 0.5 * sin (i);
y[i] = i + cos (i * i);
printf ("%g %g\n", x[i], y[i]);
}

printf ("#m=1,S=0\n");

{
gsl_interp_accel *acc
= gsl_interp_accel_alloc ();
gsl_spline *spline
= gsl_spline_alloc (gsl_interp_cspline, 10);

gsl_spline_init (spline, x, y, 10);

for (xi = x[0]; xi < x[9]; xi += 0.01)
{
yi = gsl_spline_eval (spline, xi, acc);
printf ("%g %g\n", xi, yi);
}
gsl_spline_free (spline);
gsl_interp_accel_free (acc);
}
return 0;
}

参考链接

  1. Interpolation,by gsl homepage.
  2. [Help-gsl] LNK2001: unresolved external symbol _gsl_interp_cspline,by lists.gnu.org.
  3. [Help-gsl] Re: LNK2001: unresolved external symbol _gsl_interp_cspline,by lists.gnu.org.
  4. C++求积分代码,by Firekisser.
  5. matlab代码—插值,by 从小练武功.
上一页1…333435…55下一页

Jack Huang

546 日志
70 标签
© 2026 Jack Huang
由 Hexo 强力驱动
|
主题 — NexT.Muse