当前位置: 首页 > news >正文

【UE5】将2D切片图渲染为体积纹理,最终实现使用RT实时绘制体积纹理【第二篇-着色器制作】

在上一篇文章中,我们已经理顺了实现流程。
接下来,我们将在UE5中,从头开始一步一步地构建一次流程。
通过这种方法,我们可以借助一个熟悉的开发环境,使那些对着色器不太熟悉的朋友们更好地理解着色器的工作原理。

这篇文章中,我们将使用这样一个纹理,点此下载

在这里插入图片描述
我喜欢先实现着色器,因此先用这个贴图作为占位
这是一个体积纹理的二维展开,最终我们会用RT纹理来代替这种静态的贴图,在runtime用RT进行实时的绘制

创建材质

在这里插入图片描述
首先创建材质,并将混合模式调整为 半透明 ,着色模式调整为 无光照

制作基础体积着色器

一、光线步进

采样贴图并通过步进对密度进行累计


在这里插入图片描述
首先,我们先创建Custom节点,并添加输入
在这里插入图片描述

Tip:
在这里插入图片描述
可以复制下方代码,然后在UE中,通过 输入 右键鼠标,进行粘贴

((InputName="Tex"),(InputName="XYFrames"),(InputName="NumFrames"),(InputName="MaxSteps"),(InputName="StepSize"),(InputName="LocalCamVec"),(InputName="CurPos"))
输入说明
Tex将要进行采样的2D切片纹理对象
XYFramesfloat2 切片的XY数量
NumFrames切片总数
MaxSteps最大步进数
StepSize步大小
LocalCamVec本地空间相机方向
CurPos采样位置

接下来我们将编写一个 光线步进(Ray Marching) 着色器,当然在这里更准确的称呼应该是Camera Ray。
其基本原理是,让屏幕上的每个像素沿着相机的朝向发射射线。这条射线从起点到终点的过程被称为"步进(Step)"。在每一步中,我们采样纹理,如果纹理中有值,则将其累加,这个累加值称为每一步的密度。达到最大步数后,通过查看这条射线累积了多少密度,就可以确定这个像素的光线穿透程度。
在这里插入图片描述

在代码中粘贴如下代码,对每一步的功能进行了注释

//创建变量,从0开始累加沿相机方向步进过程中的总密度
float accumdens = 0;//使用 MaxSteps 作为最大步数进行循环,每次循环执行以下操作
for (int i = 0; i < MaxSteps; i++)
{// 在当前步进位置进行纹理采样,采样的是 R 通道// PseudoVolumeTexture 函数用于伪体积纹理采样,函数需要的参数在括号内传递float cursample = PseudoVolumeTexture(Tex, TexSampler, saturate(CurPos), XYFrames, NumFrames).r;// 将当前采样到的密度值累加到总密度中// 乘以步长是为了将采样密度与步进距离相匹配accumdens += cursample * StepSize;// 为下次循环更新射线位置,沿着相机方向步进CurPos += -LocalCamVec * StepSize;
}//返回累计结果
return accumdens;

在这里插入图片描述
创建对应变量输入,并将其连接到输出,就可以查看结果了

有几个新手要注意的点:

  • Tex 输入的是“纹理对象”而不是“纹理采样”
  • 使用TransfromVector函数将CameraVector由场景转换为本地
  • 如果你是较早的UE5版本,Custom的代码要填在"这里"
    在这里插入图片描述
  • 代码中的PseudoVolumeTexture是内建的采样函数,运作原理在第一篇
  • 函数BoundingBoxBased_0-1_UVW 就像他的名字一样,输出bound体积中的每个位置,你可以将RGB连接到输出查看

在这里插入图片描述
在这里插入图片描述
他会基于Bound提供位置


二、修复伪影

当从侧方看去,会发现有伪影

正面侧面
在这里插入图片描述在这里插入图片描述

这里发生的事:
在这里插入图片描述

我们可以力大砖飞!

我们可以力大砖飞 的通过提高MaxSteps解决,但我们有更好的办法

在这里插入图片描述

为了按照上图中的方式进行采样,我们将要使用这个函数:
在这里插入图片描述
他属于Volumetrics插件,如果你开启了这个插件就可以直接使用
在这里插入图片描述

注意:

  • 如果并不想开启这个插件,接下来将制作这个函数
  • 如果你启用了这个插件,也需要将此函数复制一个,因为后续需要对其修改

创建材质函数VolumeBoxIntersect

在这里插入图片描述

为VolumeBoxIntersect函数建立输入和输出
输入①输入说明输出②输出说明
Plane alignment对齐起始位置与平面间隔以减少采样伪影Box Distance-
Steps应该使用多少步进来进行平面对齐。应与步进匹配Intersection Position-
创建Custom函数

重命名为 Ray March Cube Setup
在这里插入图片描述

要注意:

  1. 输出类型为float4
  2. 在这里将Custom节点重命名

输入粘贴为:

((InputName="PlaneAlignment",Input=(Expression="/Script/Engine.MaterialExpressionFunctionInput'/Engine/Transient.MaterialFunction_0:MaterialExpressionFunctionInput_1'")),(InputName="MaxSteps",Input=(Expression="/Script/Engine.MaterialExpressionFunctionInput'/Engine/Transient.MaterialFunction_0:MaterialExpressionFunctionInput_0'")),(InputName="scenedepth",Input=(Expression="/Script/Engine.MaterialExpressionSceneDepth'/Engine/Transient.MaterialFunction_0:MaterialExpressionSceneDepth_1'",Mask=1,MaskR=1)))

代码为:

float localscenedepth = scenedepth;float3 camerafwd = mul(float3(0.00000000,0.00000000,1.00000000),(float3x3)ResolvedView.ViewToTranslatedWorld);float3 depthpos = ((Parameters.CameraVector * localscenedepth) / abs( dot( camerafwd, Parameters.CameraVector ) ) );depthpos = mul(depthpos,  (float3x3)WSDemote(GetWorldToLocal(Parameters))).xyz;depthpos /= 256;localscenedepth = length(depthpos);//0-1
//localscenedepth /= (GetPrimitiveData(Parameters).LocalObjectBoundsMax.x * 2 * scale);
//localscenedepth /= abs( dot( camerafwd, Parameters.CameraVector ) );//bring vectors into local space to support object transforms
float3 localcampos = mul(float4( DFDemote(ResolvedView.WorldCameraOrigin),1.00000000), (WSDemote(GetWorldToLocal(Parameters)))).xyz;
float3 localcamvec = -normalize( mul(Parameters.CameraVector, (float3x3)WSDemote(GetWorldToLocal(Parameters))) );//make camera position 0-1
localcampos = (localcampos / (GetPrimitiveData(Parameters).LocalObjectBoundsMax.x * 2)) + 0.5;float3 invraydir = 1 / localcamvec;float3 firstintersections = (0 - localcampos) * invraydir;
float3 secondintersections = (1 - localcampos) * invraydir;
float3 closest = min(firstintersections, secondintersections);
float3 furthest = max(firstintersections, secondintersections);float t0 = max(closest.x, max(closest.y, closest.z));
float t1 = min(furthest.x, min(furthest.y, furthest.z));float planeoffset = 1-frac( ( t0 - length(localcampos-0.5) ) * MaxSteps );t0 += (planeoffset / MaxSteps) * PlaneAlignment;
t1 = min(t1, localscenedepth);
t0 = max(0, t0);float boxthickness = max(0, t1 - t0);float3 entrypos = localcampos + (max(0,t0) * localcamvec);return float4( entrypos, boxthickness );

计算过程上一篇有介绍,这里不赘述,效果如下

在这里插入图片描述

Done

现在我们已经完成了对伪影的修复。可以看到,原本四周存在伪影的部分现在呈现出一种“扭曲”效果,这是因为当前的 MaxSteps 设定为 16。

为了获得更好的效果,可以将 MaxSteps 适当提升到 32 或 64,这样仍能保持不错的性能。

如果不进行伪影修复,而是通过增加步数的方法(力大砖飞)来提升细节质量,通常需要将 MaxSteps 调至 256 甚至更高,才能达到相同的细节水平。
而循环里目前仅仅只有三个步骤,后续扩展效果几乎不可能,因此这一步伪影处理是必须的

三、相机进入内部

现在,相机不可以进入box内部。因为着色器只在模型表面进行渲染

我们可以力大砖飞!

我们可以力大砖飞 的通过开启材质双面解决,但我们依旧有更好的办法

创建法线向内的Box模型

使用建模模式,快速的创建一个法线向内的Box
(如果你有轴在中心的法线向内的box模型则可以跳过)

进入建模模式

在这里插入图片描述

如果你没找到建模模式,你需要开启引擎的插件:在这里插入图片描述

创建Box

在这里插入图片描述

  1. 选择建模模式
  2. 选择创建功能
  3. 选择创建Box
  4. 枢纽点选择居中
  5. 在场景中单击,放置模型
  6. 点击接受创建模型
调整法线

在这里插入图片描述

  1. 保持选中模型
  2. 选择属性修改
  3. 选择法线修改
  4. 勾选翻转法线
  5. 接受修改

现在将材质放入
在这里插入图片描述
Done
可以看到相机进入"内部"也不会超出模型承载的渲染范围

四、介质光吸收

在这里插入图片描述
将输出连入不透明度,再加上一个颜色。此时能更好的看到它的密度看上去非常“扁平”。
为此要使用布格-朗伯-比尔定律,来更好的计算介质对光的吸收
它的公式在上一篇中有介绍,这里不赘述,这里我们直接使用自带的函数BeersLaw
在这里插入图片描述
它将返回有多少光被材质吸收
在这里插入图片描述

现在看上去好多了。
虽然还没有阴影和光照,但在这之前,我们先去处理另外的问题

五、体积深度

在这里插入图片描述
我们目前还缺乏体积的深度,体积只是被渲染到了模型的内表面 ,通过这个对比可以看到发生了什么:

shadermesh
在这里插入图片描述在这里插入图片描述

1.禁用深度测试

在这里插入图片描述
现在我们为其重新制作深度
为此进入材质,禁用深度测试,接下来深度由我们说的算

2.制作深度

计算 MaxSteps

BoxDistance是框距离,相当于是射线穿透框的厚度,将其乘MaxSteps对其缩放,使用Floor取整,且使用clamp确保它不会超过限制
在这里插入图片描述

修改 VolumeBoxIntersect

在这里插入图片描述
可以看到当前的深度对的不多
现在要修复这个问题:

在这里插入图片描述
重新进入到 VolumeBoxIntersect 函数的 Custom
在这里插入图片描述
这里有几行被注释掉的内容,大体上是用于将局部场景深度转换到 0-1 范围内

为Custom增加输入 scale

scale = length(TransformLocalVectorToWorld(Parameters,float3( 1.0 , 0.0 , 0.0 )).xyz);

其蓝图也就是:
在这里插入图片描述

Tip:
Q:为什么不直接写进cutom?
A:尽最大可能的把计算过程写为蓝图,而不要在custom内计算
看编译后的HLSL就会知道,UE的材质编译器会对蓝图的内容进行接近疯狂的优化(而custom不会,写什么就是什么)
(后续会用蓝图重制这个custom的大部分内容,但目前先这样,当下还有很多工作没完成)

然后我们注释掉红框,并解除绿框的注释:
在这里插入图片描述
修改后的函数如下:
在这里插入图片描述
修改后的 Ray March Cube Setup 代码为:

float localscenedepth = scenedepth;float3 camerafwd = mul(float3(0.00000000,0.00000000,1.00000000),(float3x3)ResolvedView.ViewToTranslatedWorld);/*
float3 depthpos = ((Parameters.CameraVector * localscenedepth) / abs( dot( camerafwd, Parameters.CameraVector ) ) );depthpos = mul(depthpos,  (float3x3)WSDemote(GetWorldToLocal(Parameters))).xyz;depthpos /= 256;localscenedepth = length(depthpos);
*///0-1
localscenedepth /= (GetPrimitiveData(Parameters).LocalObjectBoundsMax.x * 2 * scale);
localscenedepth /= abs( dot( camerafwd, Parameters.CameraVector ) );//bring vectors into local space to support object transforms
float3 localcampos = mul(float4( DFDemote(ResolvedView.WorldCameraOrigin),1.00000000), (WSDemote(GetWorldToLocal(Parameters)))).xyz;
float3 localcamvec = -normalize( mul(Parameters.CameraVector, (float3x3)WSDemote(GetWorldToLocal(Parameters))) );//make camera position 0-1
localcampos = (localcampos / (GetPrimitiveData(Parameters).LocalObjectBoundsMax.x * 2)) + 0.5;float3 invraydir = 1 / localcamvec;float3 firstintersections = (0 - localcampos) * invraydir;
float3 secondintersections = (1 - localcampos) * invraydir;
float3 closest = min(firstintersections, secondintersections);
float3 furthest = max(firstintersections, secondintersections);float t0 = max(closest.x, max(closest.y, closest.z));
float t1 = min(furthest.x, min(furthest.y, furthest.z));float planeoffset = 1-frac( ( t0 - length(localcampos-0.5) ) * MaxSteps );t0 += (planeoffset / MaxSteps) * PlaneAlignment;
t1 = min(t1, localscenedepth);
t0 = max(0, t0);float boxthickness = max(0, t1 - t0);float3 entrypos = localcampos + (max(0,t0) * localcamvec);return float4( entrypos, boxthickness );

在这里插入图片描述
深度已经正常,一切都好起来了…?
在这里插入图片描述

六、精度修复

当你试图缩放cube,你会发现它破碎了
在这里插入图片描述
在这里插入图片描述
眼看着美好的事物在你的操作下支离破碎,这可太令人崩溃了,究其原因在于
在这里插入图片描述
TransformVector节点的精度不足,那么我们使用Custom手搓一个使用LWC精度的替代节点吧:

  • 创建Custom,命名为TransFromVector_WorldToLocal
  • 添加输入CameraVector
    在这里插入图片描述
  • 代码如下
return normalize(mul(CameraVector,(float3x3)LWCToFloat(GetPrimitiveData(Parameters).WorldToLocal)));

在这里插入图片描述

Done

七、阶梯纹理修复

在这里插入图片描述
没有时间庆祝,接下来赶到战场的是阶梯问题。深度和缩放一旦被修复,图中画圈位置的阶梯状图形就会非常显眼。
这很明显这是由step产生的,因为我们的步(step)是预计算的,因此步与步之间就形成了这种阶梯纹理

我们可以力大砖飞!

我们可以力大砖飞 的通过增加MaxSteps数量,用更小的细分来解决,但总是有更好的办法

实际上我们只需要在进行额外一次采样就可以了
在这里插入图片描述

  • 使用frac取小数作为一小步FinalStepSize输入
  • 在Custom中的for后再进行一次采样

修改后代码如下:

//创建变量,从0开始累加沿相机方向步进过程中的总密度
float accumdens = 0;//使用 MaxSteps 作为最大步数进行循环,每次循环执行以下操作
for (int i = 0; i < MaxSteps; i++)
{// 在当前步进位置进行纹理采样,采样的是 R 通道// PseudoVolumeTexture 函数用于伪体积纹理采样,函数需要的参数在括号内传递float cursample = PseudoVolumeTexture(Tex, TexSampler, saturate(CurPos), XYFrames, NumFrames).r;// 将当前采样到的密度值累加到总密度中// 乘以步长是为了将采样密度与步进距离相匹配accumdens += cursample * StepSize;// 为下次循环更新射线位置,沿着相机方向步进CurPos += -LocalCamVec * StepSize;
}//修复阶梯 额外在循环后再进行一次小步(FinalStepSize)的采样,累计到密度
CurPos -= -LocalCamVec * StepSize;
CurPos += -LocalCamVec * StepSize * FinalStepSize;
float cursample = PseudoVolumeTexture(Tex, TexSampler, saturate(CurPos), XYFrames, NumFrames).r;
accumdens += cursample * StepSize * FinalStepSize;//返回累计结果
return accumdens;

在这里插入图片描述
Done
到此一个最基本的体积纹理渲染就做好了


在下一篇进行【制作进阶体积着色器】,继续为其实现光照等效果


相关文章:

【UE5】将2D切片图渲染为体积纹理,最终实现使用RT实时绘制体积纹理【第二篇-着色器制作】

在上一篇文章中&#xff0c;我们已经理顺了实现流程。 接下来&#xff0c;我们将在UE5中&#xff0c;从头开始一步一步地构建一次流程。 通过这种方法&#xff0c;我们可以借助一个熟悉的开发环境&#xff0c;使那些对着色器不太熟悉的朋友们更好地理解着色器的工作原理。 这篇…...

【OceanBase 诊断调优】—— GC问题根因分析

GC 流程涉及到 RS 的状态切换和 LS 的资源安全回收&#xff0c;流程上较长。且 GC 线程每个租户仅有一个&#xff0c;某个日志流 GC Hang 死时会卡住所有其余日志流的 GC&#xff0c;进而造成更大的影响。 本文档会帮助大家快速定位到 GC 故障的模块&#xff0c;直达问题核心。…...

图像面积计算一般方法及MATLAB实现

一、引言 在数字图像处理中&#xff0c;经常需要获取感兴趣区域的面积属性&#xff0c;下面给出图像处理的一般步骤。 1.读入的彩色图像 2.将彩色图像转化为灰度图像 3.灰度图像转化为二值图像 4.区域标记 5.对每个区域的面积进行计算和显示 二、程序代码 %面积计算 cle…...

指挥平台在应急场所中的主要表现有哪些

在应对自然灾害、公共安全事件等突发危机时&#xff0c;指挥平台作为应急管理体系的核心枢纽&#xff0c;其重要性不言而喻。它不仅承载着信息的快速汇聚、精准分析与高效调度功能&#xff0c;更在应急场所中有一定的关键表现。接下来就跟着北京嘉德立一起了解一下。 一、信息集…...

智能养殖场人机交互检测系统源码分享

智能养殖场人机交互检测检测系统源码分享 [一条龙教学YOLOV8标注好的数据集一键训练_70全套改进创新点发刊_Web前端展示] 1.研究背景与意义 项目参考AAAI Association for the Advancement of Artificial Intelligence 项目来源AACV Association for the Advancement of Co…...

数据集-目标检测系列-海洋鱼类检测数据集 fish>> DataBall

数据集-目标检测系列-海洋鱼类检测数据集 fish>> DataBall 数据集-目标检测系列-海洋鱼类检测数据集 fish 数据量&#xff1a;1W 数据项目地址&#xff1a; gitcode: https://gitcode.com/DataBall/DataBall-detections-100s/overview github: https://github.com/…...

网络威慑战略带来的影响

文章目录 前言一、网络威慑的出现1、人工智能带来的机遇二、网络空间的威慑困境1、威慑概念的提出2、网络威慑的限度3、人类对网络威胁的认知变化4、网络空间的脆弱性总结前言 网络威慑是国家为应对网络空间风险和威胁而采取的战略。冷战时期核威慑路径难以有效复制至网络空间…...

决策树算法在机器学习中的应用

决策树算法在机器学习中的应用 决策树&#xff08;Decision Tree&#xff09;算法是一种基本的分类与回归方法&#xff0c;它通过树状结构对数据进行建模&#xff0c;以解决分类和回归问题。决策树算法在机器学习中具有广泛的应用&#xff0c;其直观性、易于理解和实现的特点使…...

Leetcode面试经典150题-39.组合总数进阶:40.组合总和II

本题是扩展题&#xff0c;真实考过&#xff0c;看这个题之前先看一下39题 Leetcode面试经典150题-39.组合总数-CSDN博客 给定一个候选人编号的集合 candidates 和一个目标数 target &#xff0c;找出 candidates 中所有可以使数字和为 target 的组合。 candidates 中的每个数…...

ProcessOn为什么导出有水印!!!(利用SVG转PNG)

processon-svg2png ProcessOn 一个非常好用的思维导图网站&#xff0c;但是为什么导出有水印&#xff01;&#xff01;&#xff01;。 功能 支持按钮拖拽支持将流程图svg 转成 png下载支持修改自定义文字下载svg&#xff08;开发中&#xff09; 安装/使用方法 安装并使用…...

插入、更新与删除MySQL记录

在现代应用开发中,数据库操作是非常重要的一环。作为程序员,熟练掌握数据库的增删改功能,能够更有效地管理数据并提高开发效率。 本课程将围绕插入、更新与删除记录这三个操作展开,涵盖SQL中的常见语句:INSERT INTO、UPDATE 和 DELETE,并结合实际应用中的常见问题讨论如…...

【ARM】armv8的虚拟化深度解读

Type-1 hypervisor Type-1虚拟化也叫做Bare metal, standalone, Type1 Type2 hypervisor Type-2虚拟化也叫做hosted, Type-2 VM和vCPU(虚拟机和虚拟cpu) 在一个VM&#xff08;虚拟机&#xff09;中有多个vCPU&#xff0c;多个vCPU可能属于同一个Vritual Processor。 EL2…...

9/24作业

1. 分文件编译 分什么要分文件编译&#xff1f; 防止主文件过大&#xff0c;不好修改&#xff0c;简化编译流程 1) 分那些文件 头文件&#xff1a;所有需要提前导入的库文件&#xff0c;函数声明 功能函数&#xff1a;所有功能函数的定义 主函数&#xff1a;main函数&…...

Leetcode 106. 从中序与后序遍历序列构造二叉树

给定两个整数数组 inorder 和 postorder &#xff0c;其中 inorder 是二叉树的中序遍历&#xff0c; postorder 是同一棵树的后序遍历&#xff0c;请你构造并返回这颗 二叉树 。 示例 1: 输入&#xff1a;inorder [9,3,15,20,7], postorder [9,15,7,20,3] 输出&#xff1a;[3…...

针对考研的C语言学习(定制化快速掌握重点1)

1.printf函数的几个要点 printf函数中所有的输出都是右对齐的&#xff0c;除非在%后面添加负号&#xff0c;则表示左对齐 #include<stdio.h> int main() {int num 10;int nums 100;float f 1000.2333333333;printf("%3d\n", nums);//%3d表示输出的总宽度至…...

【大数据入门 | Hive】DDL数据定义语言(数据库DataBase)

1. 数据库(DataBase) 1.1 创建数据库 语法&#xff1a; CREATE DATABASE [IF NOT EXISTS] database_name [COMMENT database_comment] [LOCATION hdfs_path] [WITH DBPROPERTIES (property_nameproperty_value, ...)]; 案例&#xff1a; &#xff08;1&#xff09;创建一个…...

CNVD漏洞和证书挖掘经验总结

前言 本篇文章主要是分享一下本人挖掘CVND漏洞碰到的一些问题&#xff0c;根据过往成功归档的漏洞和未归档的漏洞总结出的经验&#xff0c;也确实给审核的大佬们添了很多麻烦&#xff08;主要真的没人教一下&#xff0c;闷着头尝试犯了好很多错误&#xff0c;希望各位以后交一个…...

阿里rtc旁路推流TypeScript版NODE运行

阿里云音视频服务云端录制typescript版本; 编译后可以使用 node index.js运行 package.json 版本 // npm install --save alicloud/rtc201801112.3.0 "alicloud/rtc20180111": "^2.3.0",引入 import Client, { StartCloudRecordRequest, StopCloudRecord…...

计算机书籍分享

0.简介 数据库系统概念、深入理解计算机系统、领域驱动设计、Linux高性能服务器编程 高清版本pdf 1.链接 数据库系统概念&#xff1a; 链接: https://pan.baidu.com/s/17zz7QFevV2Eni9qHJyLEGA 提取码: wfrx 深入理解计算机系统 链接: https://pan.baidu.com/s/19yiJG8GqHJR…...

处理ASAM-MDF格式的开源python库asammdf

asammdf是一个强大的Python库&#xff0c;专为处理ASAM&#xff08;Association for Standardization of Automation and Measuring Systems&#xff09;MDF&#xff08;Measurement Data Format&#xff09;文件而设计。MDF是一种用于存储测量和诊断数据的标准格式&#xff0c…...

多云管理“拦路虎”:深入解析网络互联、身份同步与成本可视化的技术复杂度​

一、引言&#xff1a;多云环境的技术复杂性本质​​ 企业采用多云策略已从技术选型升维至生存刚需。当业务系统分散部署在多个云平台时&#xff0c;​​基础设施的技术债呈现指数级积累​​。网络连接、身份认证、成本管理这三大核心挑战相互嵌套&#xff1a;跨云网络构建数据…...

云原生核心技术 (7/12): K8s 核心概念白话解读(上):Pod 和 Deployment 究竟是什么?

大家好&#xff0c;欢迎来到《云原生核心技术》系列的第七篇&#xff01; 在上一篇&#xff0c;我们成功地使用 Minikube 或 kind 在自己的电脑上搭建起了一个迷你但功能完备的 Kubernetes 集群。现在&#xff0c;我们就像一个拥有了一块崭新数字土地的农场主&#xff0c;是时…...

UE5 学习系列(三)创建和移动物体

这篇博客是该系列的第三篇&#xff0c;是在之前两篇博客的基础上展开&#xff0c;主要介绍如何在操作界面中创建和拖动物体&#xff0c;这篇博客跟随的视频链接如下&#xff1a; B 站视频&#xff1a;s03-创建和移动物体 如果你不打算开之前的博客并且对UE5 比较熟的话按照以…...

《用户共鸣指数(E)驱动品牌大模型种草:如何抢占大模型搜索结果情感高地》

在注意力分散、内容高度同质化的时代&#xff0c;情感连接已成为品牌破圈的关键通道。我们在服务大量品牌客户的过程中发现&#xff0c;消费者对内容的“有感”程度&#xff0c;正日益成为影响品牌传播效率与转化率的核心变量。在生成式AI驱动的内容生成与推荐环境中&#xff0…...

数据链路层的主要功能是什么

数据链路层&#xff08;OSI模型第2层&#xff09;的核心功能是在相邻网络节点&#xff08;如交换机、主机&#xff09;间提供可靠的数据帧传输服务&#xff0c;主要职责包括&#xff1a; &#x1f511; 核心功能详解&#xff1a; 帧封装与解封装 封装&#xff1a; 将网络层下发…...

【git】把本地更改提交远程新分支feature_g

创建并切换新分支 git checkout -b feature_g 添加并提交更改 git add . git commit -m “实现图片上传功能” 推送到远程 git push -u origin feature_g...

爬虫基础学习day2

# 爬虫设计领域 工商&#xff1a;企查查、天眼查短视频&#xff1a;抖音、快手、西瓜 ---> 飞瓜电商&#xff1a;京东、淘宝、聚美优品、亚马逊 ---> 分析店铺经营决策标题、排名航空&#xff1a;抓取所有航空公司价格 ---> 去哪儿自媒体&#xff1a;采集自媒体数据进…...

虚拟电厂发展三大趋势:市场化、技术主导、车网互联

市场化&#xff1a;从政策驱动到多元盈利 政策全面赋能 2025年4月&#xff0c;国家发改委、能源局发布《关于加快推进虚拟电厂发展的指导意见》&#xff0c;首次明确虚拟电厂为“独立市场主体”&#xff0c;提出硬性目标&#xff1a;2027年全国调节能力≥2000万千瓦&#xff0…...

JavaScript 数据类型详解

JavaScript 数据类型详解 JavaScript 数据类型分为 原始类型&#xff08;Primitive&#xff09; 和 对象类型&#xff08;Object&#xff09; 两大类&#xff0c;共 8 种&#xff08;ES11&#xff09;&#xff1a; 一、原始类型&#xff08;7种&#xff09; 1. undefined 定…...

Golang——6、指针和结构体

指针和结构体 1、指针1.1、指针地址和指针类型1.2、指针取值1.3、new和make 2、结构体2.1、type关键字的使用2.2、结构体的定义和初始化2.3、结构体方法和接收者2.4、给任意类型添加方法2.5、结构体的匿名字段2.6、嵌套结构体2.7、嵌套匿名结构体2.8、结构体的继承 3、结构体与…...