如何构造只能在堆/栈上创建对象的类

核心思想:****阻止栈资源的释放 当编译器在栈上分配资源时,必须确保其能够在离开作用域时通过调用析构函数被释放。如果人为指定析构函数不可见,那么编译器就会报错,从而阻止了栈上的资源分配。也就是说,需要**破坏编译器在在栈上自动管理生命周期的能力**: private : HeapOnly() = default; 此时类对象位于堆上,需要通过指针进行管理,因此在类中定义一个“静态工厂函数”: static std::unique_ptr create(){ return std::unique_ptr(new HeapOnly()); } 二:只能在栈上创建对象的类 核心思想:禁止一切形式的 new 操作 当我们在外部使用“new T()”创建类对象时,编译器会在类或全局作用域下寻找 new 的重载,如果将 new 标记为 delete,就能从源头切断堆上的分配: // 禁止单个对象的堆分配 void* operator new(std::size_t)= delete; void operator delete(void*)= delete; // 禁止数组形式的堆分配 void* operator new[](std::size_t) = delete; void operator delete[](void*) = delete;

May 10, 2026 · 1 min · 榎aaaa

如何混合法线贴图

一:Linear Blending 代码实现: 1 2float3 normal_1 = tex2D(normal_tex1, uv).xyz * 2.0f - 1.0f; 3 4float3 normal_2 = tex2D(normal_tex2, uv).xyz * 2.0f - 1.0f; 5 6float3 n = normalize(normal_1 + normal_2); 这是一种非常暴力的方法,实现起来也是最简单的(相加后再归一化即可);虽然最终可以实现混合法线贴图的效果,但是会导致混合后的法线变平,细节也就会更加模糊 产生这种结果的原因有两个,可以分别从几何维度与物理维度的方向来分析: 1.几何维度: 法线本质上是定义在球面上的向量,当我们使用线性的公式对两个法线向量进行混合时,计算的路径实际上是沿着“弦”而非“弧”进行的;这会导致两个法线向量相加得到的中间向量的模始终小于 1,虽然可以通过normalize 将模长拉回至 1,但这又会使得“** 角速度非均匀** ”,表现在混合后的法线上就是:混合结果在中间部分的变化比两端更慢,并且高频的法线会在这种非线性的映射中被抹平,产生“细节模糊”;细节模糊的另一个原因是——当两个法线的方向差异过大(接近180度,也就是反向)时,这样的线性混合得到的结果会趋近于垂直向上,丢失了原有的细节 2.物理维度: 法线贴图存储的并不是颜色,而是物体表面的偏导数(斜率),如果使用处理颜色的办法去混合两个法线,只会导致数据的平均,而不是细节的叠加 e.g. 有两张法线贴图,一张代表“砖块的粗糙纹理”,另一张代表“划痕”,线性混合的行为逻辑是:“我有 50% 像砖块,50% 像划痕”, 但真实的逻辑应该是:“在砖块的斜率基础上,叠加划痕的斜率” 代码实现: 1 2float3 normal_1 = tex2D(normal_tex1, uv).xyz * 2.0f - 1.0f; 3 4float3 normal_2 = tex2D(normal_tex2, uv).xyz * 2.0f - 1.0f; 5 6float3 n = normal_1 < 0.5 ? 2 * normal_1 * normal_2 : 1 – 2 * (1 - normal_1) * (1 - normal_2); 7 8n = normalize(n * 2 - 1); 相比于线性混合,Overlay Blending 是对两张法线贴图进行了类似 PS 中“正片叠底”的处理,虽然 overlay 对于增强二维图像的对比度又很好的效果,但是法线贴图本身并不应该被当作颜色贴图进行处理;overlay 并不理解法线贴图存储的是斜率信息,因此他会对x、y、z分量无差别地进行非线性缩放,这会导致严重的数学错误与视觉伪影 三:Partical Derivative Blending 代码实现: 1 2float3 normal_1 = tex2D(texBase, uv).xyz*2 - 1; 3 4float3 normal_2 = tex2D(texDetail, uv).xyz*2 - 1; 5 6float2 pd = normal_1.xy/normal_1.z + normal_2.xy/normal_2.z; //Add the PDs 7 8float3 n = normalize(float3(pd, 1)); 根据导数的线性性质: $$ \frac{\partial F_{total}}{\partial x} = \frac{\partial f_1}{\partial x} + \frac{\partial f_2}{\partial x} $$可以得知要想混合两个法线,需要对它们在切空间中对应的表面梯度进行线性累加,然后将合成后的梯度重新投影回法线空间 ...

May 10, 2026 · 1 min · 榎aaaa

蒙特卡洛积分推导笔记

整理蒙特卡洛积分推导相关手写笔记。

May 8, 2026 · 1 min · 榎aaaa

重要性采样笔记

整理重要性采样与多重重要性采样相关手写笔记。

May 8, 2026 · 1 min · 榎aaaa

BRDF 相关公式笔记

整理 BRDF 与常见微表面反射模型相关手写笔记。

May 8, 2026 · 1 min · 榎aaaa

Hello

榎 aaaa

April 19, 2026 · 1 min · 榎aaaa

Fundamentals of Cpp:现代 C++ 核心笔记

这里是整理的一些c++基础知识…. 就这样吧…. 语法 1.C++的三大特性 封装,继承,多态(同时也是面向对象编程的三大特性) 1).简要解释一下上面三者 ·封装:隐藏内部具体的实现细节,对外部只暴露必要的接口来访问对象 ·继承:允许一个类从另一个类继承属性和方法,从而实现代码复用和层次化抽象 ·多态:同一个函数名拥有多种状态,或是同一个接口具有不同的行为 LINK: 如何理解面向对象编程三大特性——封装、继承、多态 2).多态的类别 ·运行时多态(动态联编):通过继承和虚函数实现 ·编译时多态(静态联编):通过重载和模板实现 2.虚函数 简单来说,虚函数就是允许在基类(父类)中定义一个函数,并允许派生类(子类)对其进行重写 (Override) 1).虚函数的实现机制 ·通过虚函数表实现,虚函数表是一个由编译器生成的静态数组,位于类的全局静态内存区中,包含了一个类所有的虚函数的地址(即该类所有虚函数的入口) ·在类对象(不是类!)内存空间的头部,有一个虚函数表指针,它指向该类虚函数表的首地址 ·当子类对象对父类虚函数进行重写的时候,虚函数表中相应的虚函数的地址会被更改为重写后的虚函数地址 2).虚函数调用是在编译时确定还是运行时确定的?如何确定调用哪个函数? ·一般来说是在运行时确定,可以通过虚函数表中的地址来确定调用什么函数 3).能否在基类的构造函数和析构函数中调用虚函数? ·在语法上来说没有问题,但是在实际调用时,无法实现多态的效果,因为构造函数会先初始化基类的成员,而此时子类的成员还是一片空白,如果这时使用子类中还未被初始化的成员,会出现错误;同理,析构函数是先从子类开始析构,如果在基类的析构函数中调用虚函数的话,因为此时子类已经被析构,是无法调用其特有成分的 4).当一个类需要被继承时,它的析构函数必须是虚函数 如果基类的析构函数不为虚函数,那么当对派生类对象进行删除(delete)操作时,就只会调用基类的析构函数,这会导致内存泄漏; 而当基类包含虚析构函数时,在同样的情况下,编译器会先查询虚函数表,并调用对应的析构函数 3.C++的内存管理 1).C++有哪些内存区域 ·栈:由编译器自动分配与释放,多用于存储局部变量;速度极快,但空间有限(通常只有几MB) ·堆:需要手动控制生存周期, 从 new 或 malloc 开始,直到 delete 或 free;空间极大,分配位置不连续 ·全局/静态存储区: 存储全局变量和静态变量,在程序启动时分配,程序退出时才释放 ; .data 段:存储已初始化的全局/静态变量。 .bss 段:存储未初始化的全局/静态变量(自动初始化****为 0)。 ·常量存储区: 存储只读数据 ·自由存储区:通过new和delete分配和释放空间的内存,具体实现可能是堆或者内存池 ·代码区:存储经过编译之后的机器指令(二进制代码) Link: C++内存管理 - 还没放弃的老张 - 博客园 2).栈 与 堆 的区别 1.堆的内存空间大,栈的内存空间小 ...

April 19, 2026 · 3 min · 榎aaaa

DXR / DX12 常用函数

整理 TraceRay 的参数、光线递归深度设置和 OMSetStencilRef 等函数的用途。

March 22, 2026 · 1 min · 榎aaaa

DXR / DX12 常用类型

记录 IDxcBlob、DXC 编译产物和 XMVECTOR 等 DirectX 开发中的常用类型。

March 22, 2026 · 1 min · 榎aaaa

DXR 基础笔记

记录 DXR 着色器、TLAS 与 BLAS、光线追踪管线,以及资源描述结构在 CPU 与 GPU 之间的作用。

March 1, 2026 · 1 min · 榎aaaa