在 StartupModule() 中添加调用栈输出的方法 方法 1:使用 FPlatformStackWalk::StackWalkAndDump

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include "HAL/PlatformStackWalk.h"  // 需要添加这个头文件

void FGPULightmassModule::StartupModule()
{
UE_LOG(LogGPULightmass, Log, TEXT("GPULightmass module is loaded"));

// 输出调用栈
ANSICHAR StackTrace[65536] = {0};
constexpr int32 NumStackFramesToIgnore = 1; // 忽略当前函数本身
FPlatformStackWalk::StackWalkAndDump(StackTrace, UE_ARRAY_COUNT(StackTrace), NumStackFramesToIgnore, nullptr);

// 将 ANSI 字符串转换为 FString 并输出
FString StackTraceString = ANSI_TO_TCHAR(StackTrace);
UE_LOG(LogGPULightmass, Log, TEXT("Call Stack:\n%s"), *StackTraceString);

// Maps virtual shader source directory /Plugin/GPULightmass to the plugin's actual Shaders directory.
FString PluginShaderDir = FPaths::Combine(IPluginManager::Get().FindPlugin(TEXT("GPULightmass"))->GetBaseDir(), TEXT("Shaders"));
AddShaderSourceDirectoryMapping(TEXT("/Plugin/GPULightmass"), PluginShaderDir);

FStaticLightingSystemInterface::Get()->RegisterImplementation(FName(TEXT("GPULightmass")), this);
}
方法 2:使用 CaptureStackBackTrace
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
#include "HAL/PlatformStackWalk.h"

void FGPULightmassModule::StartupModule()
{
UE_LOG(LogGPULightmass, Log, TEXT("GPULightmass module is loaded"));

// 捕获调用栈地址
constexpr int32 MaxDepth = 20;
uint64 BackTrace[MaxDepth] = {0};
uint32 CapturedDepth = FPlatformStackWalk::CaptureStackBackTrace(BackTrace, MaxDepth);

// 输出调用栈
UE_LOG(LogGPULightmass, Log, TEXT("Call Stack (Depth: %d):"), CapturedDepth);
for (uint32 i = 0; i < CapturedDepth; ++i)
{
FProgramCounterSymbolInfo SymbolInfo;
FPlatformStackWalk::ProgramCounterToSymbolInfo(BackTrace[i], SymbolInfo);

UE_LOG(LogGPULightmass, Log, TEXT(" [%d] %s!%s [%s:%d]"),
i,
ANSI_TO_TCHAR(SymbolInfo.ModuleName),
ANSI_TO_TCHAR(SymbolInfo.FunctionName),
ANSI_TO_TCHAR(SymbolInfo.Filename),
SymbolInfo.LineNumber);
}

}
阅读全文 »

蓄水池抽样作为一类随机采样方法,是为了解决从的样本流中随机选取个样本的问题。通常未知或很大,无法一次性将样本装载到内存,而是以stream的方式读取。

Reservoir sampling

证明

阅读全文 »

UE4通过ightmapPathTracing.usf实现静态物体的lightmap烘焙。lightmap是把模型表面的光照情况预计算并缓存起来的一张贴图,首先讲模型表面展开到uv空间且不能uv覆盖,因为平常的uv贴图可以复用,但是模型上每一个点的光照情况可能都不一样;然后,对lightmap texel对应的模型表面点,做光照的半球积分。

lightmap的材质限定

Lightmap本质上存储的是表面的入射辐照度(irradiance),它隐含的假设是最终着色时该表面以 Lambertian 漫反射来使用这份光照数据,运行时乘以 diffuse albedo 得到出射颜色。UE4 lightmass在烘焙lightmap时,在计算间接光弹射时,所有中间弹射表面也被作为diffuse reflector处理,在中间弹射点做cosine-weighted半球采样,忽略材质的specular、roughness、metallic等属性,忽略特殊的光效,比如焦散(caustics,即 LSDE光照路径)。Lightmass 烘焙的整个光照传输链路中,每一次弹射都是diffuse的,Lightmass取Base Color作为弹射albedo,理论上金属化的表面(metallic = 1)在PBR中几乎没有diffuse分量,这样的处理可能会有不一致的问题。

阅读全文 »

11. Global Illumination

11.1 The Rendering Equation

Reflectance Equation(反射方程) Rendering Equation(渲染方程) Incoming Radiance, ray casting function

阅读全文 »

  1. 作为脚本附到GameObject上,我选择附到相机上

    Screenshot.csview raw
    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
    // 创建这个脚本,挂在任意 GameObject 上
    using UnityEngine;
    using System.IO;

    public class Screenshot : MonoBehaviour
    {
    [Header("截屏设置")]
    public KeyCode screenshotKey = KeyCode.F12;
    public int superSize = 1; // 1 = 原始分辨率, 2 = 2倍分辨率

    void Update()
    {
    if (Input.GetKeyDown(screenshotKey))
    {
    TakeScreenshot();
    }
    }

    void TakeScreenshot()
    {
    string folderPath = Path.Combine(Application.dataPath, "..", "Screenshots");

    // 创建文件夹
    if (!Directory.Exists(folderPath))
    {
    Directory.CreateDirectory(folderPath);
    }

    // 生成文件名
    string fileName = $"Screenshot_{System.DateTime.Now:yyyy-MM-dd_HH-mm-ss}.png";
    string filePath = Path.Combine(folderPath, fileName);

    // 截图
    ScreenCapture.CaptureScreenshot(filePath, superSize);

    Debug.Log($"截图已保存: {filePath}");
    }
    }

  2. 修改编辑器UI,作为菜单使用;需要放到scene文件同目录的Editor目录下

    Editor/ScreenShotTest.csview raw
    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
    using System.IO;
    using System.Threading.Tasks;
    using UnityEditor;
    using UnityEditorInternal;
    using UnityEngine;

    public class ScreenShotTest : MonoBehaviour
    {
    //ctrl + shift + y 截图
    [MenuItem("Screenshot/Take Screenshot %#y")]
    private static async void Screenshot()
    {
    string folderPath = Directory.GetCurrentDirectory() + "\\Screenshots";
    if (!Directory.Exists(folderPath))
    {
    Directory.CreateDirectory(folderPath);
    }

    var timestamp = System.DateTime.Now;
    var stampString = string.Format("_{0}-{1:00}-{2:00}_{3:00}-{4:00}-{5:00}", timestamp.Year, timestamp.Month, timestamp.Day, timestamp.Hour, timestamp.Minute, timestamp.Second);
    ScreenCapture.CaptureScreenshot(Path.Combine(folderPath , stampString + ".png"));

    Debug.Log("截图中......");
    //等待5秒
    await Task.Delay(5000);
    System.Diagnostics.Process.Start("explorer.exe", folderPath);
    Debug.Log("截图" + stampString + ".png");
    }

    void OnMouseDown()
    {
    ScreenCapture.CaptureScreenshot("SomeLevel.png");
    }
    }
    效果如下:

C++模板成员函数可以是虚函数吗

引言

在C++编程中,虚函数和模板都是强大的特性,但它们不能结合使用。许多开发者都会疑惑:为什么不能声明虚函数模板?这个限制背后的技术原理是什么?本文将深入探讨这个问题,分析技术可行性,并讨论可能的解决方案。

阅读全文 »

配准误差函数 与 SVD + IQR 的完整推导

下面整理配准中计算推导过程,包含:平移 的消去(逐项展开并对 求导的详细步骤)、矩阵/范数形式的推导、SVD(Kabsch)求解旋转 的严格证明,以及 IQR 筛除离群点的直观解释与算法流程。


阅读全文 »

本文内容来自大模型生成和知乎回答

Claude-Sonnet-4

我为你规划一个系统的学习路径:

阅读全文 »
0%
×