0%

RoadMap

  • 编程基础:C++, 设计模式 —> C++ STL
  • 图形管线:WebGL —> OpenGL
  • 项目实践:闫令琪GAMES101 GAMES202 GAME104 TA百人计划

仿射变换和齐次坐标

仿射变换(Affine Transformation):位移 缩放 旋转 错切(单一方向等比例缩放)

仿射变换前后保持一致的“平直行” 即直线变换后仍然为直线 相互平行的关系变换后仍然平行

齐次坐标是解决仿射变换中“平移无法用矩阵乘法表示”这一问题的关键。

在二维空间中,一个笛卡尔坐标点 $(x, y)$ 对应的齐次坐标是一个三元组 $(x, y, 1)$

使用齐次坐标的二维变换矩阵
现在,所有变换都可以表示为 $3 \times 3$ 矩阵:

  • 平移:
  • 缩放:
  • 旋转:
  • 组合变换:
    变换的顺序至关重要(通常不满足交换律)。例如,先缩放后旋转,与先旋转后缩放结果不同。
    要表示“先变换 $A$,再变换 $B$”,最终的变换矩阵为 $M = B \cdot A$。
    例如,绕一个任意点 $(c_x, c_y)$ 旋转:
    1. 平移至原点: $T(-c_x, -c_y)$
    2. 绕原点旋转: $R(\theta)$
    3. 平移回去: $T(c_x, c_y)$
      总变换矩阵 $M = T(c_x, c_y) \cdot R(\theta) \cdot T(-c_x, -c_y)$。

三维仿射变换

笛卡尔坐标点 $(x, y, z)$ 的齐次坐标为 $(x, y, z, 1)$

主要的三维仿射变换矩阵

所有变换都由一个 $4 \times 4$ 的矩阵表示。

平移

沿 $x, y, z$ 轴分别移动 $t_x, t_y, t_z$。

缩放

在 $x, y, z$ 轴方向分别缩放 $s_x, s_y, s_z$。

3.2.3 旋转

旋转比二维复杂,因为需要指定旋转轴。我们使用右手坐标系。

  • 绕 X 轴旋转 $\theta$ (Pitch):
  • 绕 Y 轴旋转 $\theta$ (Yaw):
  • 绕 Z 轴旋转 $\theta$ (Roll):

    组合变换

    与二维相同,组合变换通过矩阵乘法实现,且顺序至关重要。例如,一个常见的场景相机的视图变换可以表示为 T * R * S 的形式,具体取决于实现方式。
  • camera: position lookat lookup
  • 视图变换 camera移动至原点 绕轴旋转 反向位移

  • 透视投影(锥形视场 近大远小) 正交投影(相机无限远 远近投影一致)

旋转矩阵的转置即逆矩阵,这种矩阵为正交矩阵

采样 混叠 深度

屏幕呈现图像的过程是以屏幕分辨率对原始图像采样的结果,当采样频率与图像频率相乘的结果呈现与原始形态不同的规律形态时即发生了混叠

消除高频然后采样

DLSS(Deep Learning Super Sampling)

‘挤压’到投影空间 保留z轴分量的目的是根据投影结果深度 区分前后遮挡 投影计算的迭代过程中保留最小深度数据 复杂度O(n) 不适用于透明物体

光照强度

$k_d$为漫反射系数 光照强度与光源距离的平方成反比

https://marmoset.co/posts/physically-based-rendering-and-you-can-too/
https://marmoset.co/posts/basic-theory-of-physically-based-rendering/

纹理映射

纹理映射中随透视距离拉大 纹理图像缩小 若采样点不足 贴图出现混叠 远处呈现摩尔纹

Mipmap 多级纹理映射 生成级数下降的低分辨率纹理 根据投影距离映射不同分辨率纹理 结合滤波处理 削弱高频

texture map在没有指定uv坐标的情况下 由引擎自动按照一定规则或重复或拉伸素材生成默认的uv坐标序列 这样映射出的纹理可能存在明显的失真和接缝

blender等建模软件提供了自定义uv的功能 blender Doc: uv工具

对于接缝可指定接缝处映射

Texture can affact shading 类似蒙版用纹理深浅作用于面片法线(fake normal) 从而使之作用于光照 如凹凸贴图 法线贴图 物体边缘和自身投影会露馅 因为没有实际的起伏细节

位移贴图 作用于顶点坐标 产生实际移动

三维纹理 和 体渲染 CT影像

几何体

隐式表示和显式表示

隐式表示方式:

  • 数学公式 如
  • Constructive Solid Geometry—构造性立体几何(CSG) 即利用基础集合形体的交并关系
  • 距离函数
  • 水平集
  • 分形

重心坐标
已知三角形三个顶点的坐标$P_1, P_2, P_3$ 则三角形内任一点可以用三个顶点坐标的线性组合表示

且有 $b_1+b_2+b_3=1$

贝塞尔曲线 任意t∈(0,1) 迭代二分控制点线段 得到点p(t) 其轨迹即贝塞尔曲线

光栅化阴影

从光源出发记录投影到光源的像素的深度信息 再从相机出发将投影到相机的像素深度信息与前者比较 深度值大则被遮挡 显示为阴影

因为比较结果是二值化的 因此非黑即白 称为硬阴影

现实中 阴影应有过渡 称为软阴影 光栅化阴影只能通过一些边缘模糊手段模拟软阴影

光线追踪

计算模拟光线自光源射出经过反复的折射、反射、衰减,计算量巨大常用于影视渲染等非实时的场景

在学习React Native时想到的微信小程序
特点:

  • 自带的传播属性 依托微信分享 二维码分享
  • 体量小 使用方便 跨平台
  • 开发成本低 WXML + WXSS + js

其性能逊色与React Native应用 而且只支持有限的原生API,React Native不是单纯的web应用(Hybrid),可以依托C++ Jave开发原生功能模块,以及优化运算性能等。缘于微信平台限制,微信小程序拥有有限的文件访问权限,有限的websocket实时通信功能,React Native还可以开发离线推送 APNs(Apple Push Notification Service)和 FCM(Firebase Cloud Messaging)微信小程序的推送需要通过订阅号间接实现

更适合React Native的开发场景

  • 高性能动画和图形处理
  • 高性能计算和数据处理
  • 深度集成原生功能
  • 实时通信和推送通知
  • 文件系统和数据库操作
  • 第三方库和工具的集成

1
npm i react-native-vision-camera

camera 和 microphone 权限

AndroidManifest.xml中声明该App需要camera 和 microphone 权限:

1
2
3
4
<uses-permission android:name="android.permission.CAMERA" />

<!-- optionally, if you want to record audio: -->
<uses-permission android:name="android.permission.RECORD_AUDIO" />

查询权限
1
2
3
4
5
6
const cameraPermission = Camera.getCameraPermissionStatus()
const microphonePermission = Camera.getMicrophonePermissionStatus()

const showPermissionsPage = cameraPermission !== 'granted' || microphonePermission === 'not-determined'
// 未授权则跳转到 PermissionsPage
props.navigation.navigate(showPermissionsPage?'PermissionsPage':'CameraPage')

getXXXPermissionStatus的结果:

  • granted 授权使用
  • not-determined 尚未申请
  • denied 拒绝(可以再次申请)
  • restricted 禁用

PermissionsPage 请求权限

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
const [cameraPermissionStatus, setCameraPermissionStatus] = useState('not-determined')
const [microphonePermissionStatus, setMicrophonePermissionStatus] = useState('not-determined')

useEffect(()=>{
if(cameraPermissionStatus === 'granted' && microphonePermissionStatus === 'granted'){
navigation.replace('CameraPage')
}

}, [cameraPermissionStatus, microphonePermissionStatus])

const requestPermissions = useCallback(async ()=>{
const cameraPermission = await Camera.requestCameraPermission()
if(cameraPermission === 'denied') await Linking.openSettings() // 设备设置页
setCameraPermissionStatus(cameraPermission)

// ...
})

return (<Text onPress={requestPermissions}>grant</Text>)

Camera视图

1
2
3
4
5
6
7
8
9
10
11
12
const device = useCameraDevice('back')
const { hasPermission } = useCameraPermission()

if (!hasPermission) return <PermissionsPage />
if (device == null) return <NoCameraDeviceError />
return (
<Camera
style={StyleSheet.absoluteFill}
device={device}
isActive={true}
/>
)

设备devices

1
2
const devices = Camera.getAvailableCameraDevices()
const device = getCameraDevice(devices, 'back')

其他针对多摄像头和外部摄像头的选择

isActive可用于暂停会话(pause the session: isActive={false}) 相比于unmount可以更快速再次调用

生命周期
onInitialized — onStarted — onPreviewStarted — onPreviewStopped — onStopped、

格式

1
2
3
4
const format = getCameraFormat(device, [
{ videoResolution: 'max' },
{ photoResolution: 'max' }
])

other format settings

Preview预览

1
2
3
4
5
6
7
8
9
10
11
const camera = useRef<Camera>(null)
...
return(
<Camera {...props}
ref={camera}
photo={true} {/* enable take photo */}
preview={isPausePreview}
onPreviewStarted={() => console.log('Preview started!')}
onPreviewStopped={() => console.log('Preview stopped!')}
androidPreviewViewType="texture-view" />
)

拍照
1
2
3
4
const file = await camera.current.takePhoto()
await CameraRoll.save(`file://${file.path}`, {
type: 'photo',
})

  • RN和Ionic是相似的,基于js/ts的UI桥接原生组件 而Flutter(Dart语言)使用自己的渲染引擎

  • 发布到ios需要ios系统

20250106 Apple Store Top Paid App:

  • 75 Hard 自律
  • hotschedules 员工排班考勤,可能是国外版钉钉
  • Procreate Pocket 绘图动画 图像处理
  • Paprika Recipe Manager 3 菜谱

“生活不会在你都准备好了以后才开始”。面试也一样,面试考验的不是那几轮的面试表现,而是你在长期生活、工作中积累的硬技能和软技能
这些包括:你的专业能力,框架能力,思维能力,性格和心态,沟通能力,价值观等等。你只是刚好在这几轮的面试里表现出了你的这些积累,吸引到了对方,最后拿到了Offer。如果临时抱佛脚,光背概念和知识点,没有结合项目深入思考,那么面试的时候会表现的很空洞,给人的印象只是在堆砌一些关键词,这样面试挂掉的可能性就很高。
———— Keraun https://zhuanlan.zhihu.com/p/145079928

“费曼学习法”

  • “有结果检验的导向 + 功利 + 逻辑”
  • “现学现卖,消化最快”:刚学的知识教别人,消化最快
  • “即时反馈”:学习可以达到即时反馈,这是游戏引人入胜的原理之一
  • “简洁”:简洁不是真相的表现形式,而是真相本身

Remote Procedure Call 远程过程调用

APNG, 全称是“Animated Portable Network Graphics”, 是PNG的位图动画扩展,可以实现png格式的动态图片效果。

React 支持

React18 react-app.d.ts中缺少对*.apng模块的定义,因为不能直接导入为组件,但可以将格式改为PNG,虽然直接用浏览器打开不会显示动画,但在React中却正常显示

1
2
3
4
import TipAnimation from "../../images/tip.apng" //Cannot find module defination
import TipAnimation from "../../images/tip.png"

<img src={TipAnimation} alt="tip_animation" />

CMake 是通用的自动化构建工具, 可用于构建各种类型的项目,包括C++、C、Python、Java

CMake 是个“链接”的工具 假设有牛人用文本编辑器写了很精妙的代码 传给了你 你在使用编译工具build出可执行文件之前 需要将离散的源代码文件 组织成IDE可以加载的项目(如vcxproject, sln) 这时便需要CMake

将源代码文件添加到CMake 设置好生成目标(如Visual Studio 16 2019, Ninja, MinGW)

项目的CMake构建配置文件CMakeLists.txt(文件名固定,区分大小写)形如

1
2
3
4
5
6
7
8
9
10
11
12
# 指定CMake版本
cmake_minimum_required(VERSION 3.10)

# 指定项目名称
project(hello)

# 设置构建变量
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/CMake")

# 添加源代码文件
add_executable(hello hello.cpp)


基于配置文件构建项目:
1
2
3
4
mkdir build  # 创建一个build文件夹
cd build # 进入build文件夹
cmake .. # 生成Makefile文件 ..表示去上级目录找到并使用CMakeLists.txt
make # 编译源代码并生成可执行文件

对于将使用vs开发的项目 如
1
cmake -G "Visual Studio 16 2019" ..

Facebook开发的开源深度学习框架 相比tensorflow更容易上手 使用动态计算图(即时执行) 当前研究和开源社区的主流

到工业/产线部署阶段 可以使用工具转换成Tensorflow框架 以提高性能或适应跨端环境

use v2.7