《DirectX12 3D 游戏开发实战》

Q&S


Common

  • “HANDLE CreateEventExW(LPSECURITY_ATTRIBUTES,LPCWSTR,DWORD,DWORD)”: 无法将参数 2 从“bool”转换为“LPCWSTR” DirectX12\Common\d3dApp.cpp 535

    • VS2019 报错,将 CreateEventEx(nullptr, false, false, EVENT_ALL_ACCESS); 第二个参数false改为nullptr;
  • LNK2019 无法解析的外部符号 _main,函数 “int __cdecl invoke_main(void)” (?invoke_main@@YAHXZ) 中引用了该符号 DirectX12\D3DCommon\MSVCRTD.lib(exe_main.obj)

    • 初始化时没有将项目设置为桌面应用程序,右键项目-> 属性 -> 配置属性 -> C/C++ -> 预处理器 -> 预处理器定义中将_CONSOLE 改为 _WINDOWS;../-> 链接器 -> 系统 -> 子系统改为”窗口 (/SUBSYSTEM:WINDOWS)”

Linear Algebra

向量绝对值

  • ||v|| = √(x^2+y^2+…)

Dot Product 点积、内积 P·Q

几何定义:

avatar

代数定义:

avatar

主要用于

  • 计算向量夹角余弦值

  • 计算a向量在b向量上的投影: a的单位向量乘以b向量长度再乘以两向量夹角余弦
    avatar

  • sqrt(dot(a,a)) = length(a)


Cross Product 外积 P x Q

||PxQ|| = ||P|| ||Q|| sinα

代数定义:

avatar

主要用于

  • 判断左右,右手螺旋定则,a x b,z为正则在a左侧,反之则右侧,0两个向量平行
  • 判断点是否包含于图形
    avatar
    AB x AP, BC x BP, CA x CP, 若z值同向则包含ABC包含P

Orthonormal bases 正交,内积为0则为正交向量

Coordinate frames


ShaderToy

1
2
3
4
5
6
7
8
9
10
11
12
// 平滑过渡
float smoothstep(float a, float b, float x){
// saturate 取0 ~ 1范围内的值
float t = saturate((x - a)/(b - a));
return t*t*(3.0 - (2.0*t));
}

// 混合函数
vec3 mix(vec3 x,vec3 y,float a){
return x * (1. - a) + y * a;
}

类型

  • 声明对象
    • object:
      1
      2
      let person = new Object()
      let person = {}
    • Array:
      1
      2
      let arr = new Array()
      let arr = {}

检测类型

  • 基础数据类型

    • undefined,null,boolean,number,string,symbol
  • 引用数据类型

    • object
  • typeof

    • “undefined”
    • “boolean”
    • “string”
    • “number”
    • “object” 对象或者 null
    • “function”
  • 引用类型

    • instanceof
  • 检测数组

    • Array.isArray()
  • 检测类型

    1
    2
    Object.prototype.toString.call()


实现重载

1
2
3
4
5
6
7
8
9
10
function addMethod(obj,name,func){
var old = obj[name];
obj[name] = function(){
if(arguments.length === func.length){
return func.apply(this,arguments);
}else if(typeof old === "function"){
return old.apply(this,arguments);
}
}
}

数组操作

  • push() 推入数组末尾
  • pop() 从数组末尾取出
  • unshift() 数组前端添加
  • shift() 数组前端取出

栈操作

  • push() 推入 pop()取出

队列操作

  • push() 推入 shift()取出

操作数组

  • slice(a,b) 返回 a-b 之间的值,含 a 不含 b
  • splice(a,b,…) 删除 a 开始,b 个值,包含 a. 再插入…

EventLoop

event loop 主要为三个部分,主线程,宏队列,微队列。

宏队列:settimeout/setImmediate、I/O、UI rendering。

微队列:promise.then、process.nextTick

执行顺序

  1. 先执行主线程

  2. 遇到宏队列(macrotask)放到宏队列(macrotask)

  3. 遇到微队列(microtask)放到微队列(microtask)

  4. 主线程执行完毕

  5. 执行微队列(microtask),微队列(microtask)执行完毕

  6. 执行一次宏队列(macrotask)中的一个任务,执行完毕

  7. 执行微队列(microtask),执行完毕

  8. 依次循环

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
console.log(1)
process.nextTick(() => {
console.log(8)
setTimeout(() => {
console.log(9)
})
})
setTimeout(() => {
console.log(2)
new Promise(() => {
console.log(11)
})
})
requestIdleCallback(() => {
console.log(7)
})// 特殊说明: new Promise()属于主线程任务
let promise = new Promise((resolve,reject) => {
setTimeout(() => {
console.log(10)
})
resolve() // 这个console也属于主线程任务
console.log(4)
})
fn()
console.log(3)
promise.then(() => {
console.log(12)
})
function fn(){
console.log(6)
}

log: 1 4 6 3 12 8 2 11 10 9 7

call() bind() apply()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
let C = {
bName: "bName",
func: function (a, b, c) {
console.log("func", this.bName, a, b, c);
},
func1: () => {
console.log("func1", this.bName);
},
};

this.bName = "gName";

C.func(1, 2);
C.func1();
C.func.call(this, 1, 2, 3);

let f = C.func.bind(C, 1);
let f1 = C.func;
let f2 = C.func1;

f(4);
f1(1, 2, 3);
f2();

Unity VR

环境配置

Project Settings

  • XR Plug-in Management -> Oculus -> Stereo Rendering Mode -> Multi Pass

  • Player -> android -> Other Settings -> Graphics APIs 添加 OpenGLES3

Build Settings

  • Android

    • Run Device -> Oculus Quest -> Switch Platform

    • Texture Compression -> ASTC

排序算法

冒泡排序

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
const main = () => {
let count = 0;
let length = arr.length - 1;
let pos = 0;
for (let i = 0; i < arr.length - 1; i++) {
let swap = false;
for (let j = 0; j < length; j++) {
count += 1;
if (arr[j] > arr[j + 1]) {
const temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
swap = true;
pos = j;
}
}
length = pos
if (!swap) {
break;
}
}
console.log(count, arr);
};

main();

快速排序

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
const arr = [3, 7, 8, 4, 5, 1, 2, 6, 9];

const main = () => {
quickSort(arr, 0, arr.length - 1);
console.log(arr);
};

function quickSort(arr, left, right) {
if (left < right) {
let splitIndex = split(arr, left, right);
quickSort(arr, left, splitIndex - 1);
quickSort(arr, splitIndex + 1, right);
}
return arr;
}

function split(arr, left, right) {
const temp = left;
let index = left + 1;

for (let i = index; i <= right; i++) {
if (arr[i] < arr[temp]) {
swap(arr, i, index);
index++;
}
}

swap(arr, temp, index - 1);
return index - 1;
}

function swap(arr, i, j) {
const temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}

main();

插入排序

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
const arr = [3, 7, 8, 4, 5, 1, 2, 6, 9];

const main = () => {
insertionSort(arr);
console.log(arr);
};

const insertionSort = (arr) => {
for (let i = 1; i < arr.length; i++) {
let j = i;
while (j > 0 && arr[j] < arr[j - 1]) {
swap(arr, j, j - 1);
j--;
}
}
};

const swap = (arr, i, j) => {
const temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
};

main();

链表算法

删除链表的第 N 个节点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
var removeNthFromEnd = function (head, n) {
let newList = new ListNode(0, head);
let first = newList;
let second = head;
let index = 1;

while (second != null) {

second = second.next;

if (index < n) {
index += 1;
} else {
if (second) {
first = first.next;
}
}
}
first.next = first.next.next;

return newList.next;
};

递归算法

模型导出适配Unity

1. 导出前的核心准备(必须做)

在 Blender 的物体模式(Object Mode)下:

  1. 选中模型。
  2. 按下 Ctrl + A
  3. 选择 **所有变换 (All Transforms)**。

重要:这一步是为了确保物体的初始旋转值为 0,缩放为 1,否则导出的轴向配置会失效。

2. FBX 导出面板配置

File > Export > FBX 窗口的右侧设置栏中,修改以下参数:

Transform(变换)选项卡

这是解决轴向问题的核心:

  • Apply Scalings(应用缩放):改为 FBX All(非常重要,防止 Unity 里出现 100 倍缩放)。
  • Forward(前进方向):选择 -Z Forward
  • Up(向上方向):选择 Y Up
  • Apply Unit(应用单位):勾选。
  • Use Space Transform(使用空间变换):务必勾选。

Geometry(几何体)选项卡

  • Smoothing(平滑):设置为 Face(防止法线在 Unity 里看起来硬邦邦)。
  • Apply Modifiers(应用修改器):勾选。

C#

https://learn.microsoft.com/zh-cn/dotnet/csharp/

Struct

良好的结构可以优化缓存命中率

C++

explicit

构造用explicit声明,防止非必要的隐式转换

reference &

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

int main()
{
int val = 1024;
int &refVal = ival;

int ii = val;

std::cout << val << " " << refVal << " " << ii << std::endl;

val = 1025;
std::cout << val << " " << refVal << " " << ii << std::endl;

refVal = 1026;
std::cout << val << " " << refVal << " " << ii << std::endl;

return 0;
}

// 1024 1024 1024
// 1025 1025 1024
// 1026 1026 1024

Error Debug

Cmake GLFW Error

$\color{red}{Could not find any instance of Visual Studio.}$

  • Visual Studio Installer 安装 单个组件 -> 用于Cmake的工具、工作负载 -> Visual Studio 扩展开发

$\color{red}{No CMAKE_C_COMPILER could be found.}$

  • Visual Studio Installer 安装 单个组件 -> windows SDK

零食

饼干

  • 法丽兹曲奇饼干

    不要买抹茶的。

  • 费列罗榛子巧克力夹心威化饼干

    最好吃的威化。

  • 费列罗能多益榛子巧克力夹心饼干

    不如夹心威化。

  • 煌记黑松露火腿苏打饼干

    好吃,偏咸口。

  • Aji 惊奇脆片饼干

肉类

  • 京东京造 超干风干牛肉片麻辣味

    好吃,品控不稳定,遇到过怪味的,发霉的。

豆干

  • 源氏香菇豆干
  • 大话三国张飞豆干夹心脆笋豆卷

巧克力

  • Lindt 瑞士莲巧克力软心夹心黑巧克力

    量大好吃

菌菇

  • 滇二娃云南即食菌菇

即食

  • 思念猪肉豆角焖面

    味正,口感也可以

  • 金拉面

    面口感號

  • 悦味纪 全麦荠菜膳食包

    健康

  • 正宗建德豆腐包

    好吃

0%