尚未完成的页面。
占位用。
前言
目标
在本页进行的实验中,目的是:
控制物体是否被渲染
- 尽管可以通过
setActive()
修改物体状态,使得物体不被显示;但我们的目的是从渲染角度,减少draw call开销。 - 更具体一些,我们希望定制渲染流程,以控制物体的剔除/过滤/排序渲染顺序等,并分离透明/不透明物体或通道。
- 尽管可以通过
提供其他视野
- 我们希望获得其他角度的视角观察物体。
因此,选择自定义渲染管线,以达到目的。
在一些教程中,这被称为SRP(Scripted Render Pipeline),或URP。
必要知识
什么是渲染管线?
渲染管线是把3D场景内的物体投影到2D屏幕上的过程。
什么是材质?
着色器的实例。给一个确定的几何体指定颜色。
什么是着色器?
为GPU指定场景内几何体(顶点)和像素颜色的代码。
参考资料
实验一
https://catlikecoding.com/unity/tutorials/custom-srp/custom-render-pipeline/
https://zhuanlan.zhihu.com/p/133144555
实验二
https://blog.csdn.net/qq_38913715/article/details/122308196
实验一:渲染指定材质的物体
准备工作:创建场景
在Unity中创建一个简单场景,放置数个具有不同材质的物体。
创建自定义渲染管线
1.新建一个脚本,我把它取名为myRenderPipeline
, 令其继承RenderPipeline
类。
这个类将用于控制场景内的camera,设置其渲染管线参数。
1 |
|
[CreateAssetMenu(menuName = "Rendering/my Render Pipeline")]
public class myRenderPipelineAsset : RenderPipelineAsset
{
protected override RenderPipeline CreatePipeline()
{
return new myRenderPipeline();
}
}
1 |
|
using UnityEngine;
using UnityEngine.Rendering;
public class myCameraRenderer
{
ScriptableRenderContext context;
Camera camera;
public void Render(ScriptableRenderContext context, Camera camera)
{
this.context = context;
this.camera = camera;
}
}
1 |
|
myCameraRenderer mCR = new myCameraRenderer();
protected override void Render(ScriptableRenderContext context, Camera[] cameras)
{
foreach (Camera camera in cameras)
{
mCR.Render(context, camera);
}
}
1 | 5.在project settings->player中,将SRP设置为新建的渲染管线对象。 |
void DrawVisibleGeometry ()
{
// 绘制天空盒
context.DrawSkybox(camera);
}
1 |
|
void Submit ()
{
context.Submit();
}
1 |
|
public void Render(ScriptableRenderContext context, Camera camera)
{
this.context = context;
this.camera = camera;
DrawVisibleGeometry();
Submit();
}
1 | 这时天空盒已经可以看到了,但角度似乎不太正常。这是由于未从世界坐标系转换到相机视角坐标系所致。 |
public void Render(ScriptableRenderContext context, Camera camera)
{
this.context = context;
this.camera = camera;
Setup();
DrawVisibleGeometry();
Submit();
}
void Setup()
{
context.SetupCameraProperties(camera);
// 下一步用到
buffer.ClearRenderTarget(true, true, Color.clear);
buffer.BeginSample(bufferName);
ExecuteBuffer();
}
1 |
|
const string bufferName = "Render Camera";
CommandBuffer buffer = new CommandBuffer
{
name = bufferName
};
1 | 并修改submit() |
void Submit ()
{
// 从缓冲区读取,需要与BeginSample()配对
buffer.EndSample(bufferName);
// 清理深度缓冲区 (另见:渲染管线知识 一文)
buffer.ClearRenderTarget(true, true, Color.clear);
// 执行缓冲区命令,这个函数是自己定义的
ExecuteBuffer();
// 提交
context.Submit();
}
void ExecuteBuffer ()
{
// 执行命令,这个方法是unity提供的
context.ExecuteCommandBuffer(buffer);
// 清楚命令缓冲区
buffer.Clear();
}
1 |
|
CullingResults cullingResults;
bool Cull ()
{
if (camera.TryGetCullingParameters(out ScriptableCullingParameters p))
{
cullingResults = context.Cull(ref p);
return true;
}
return false;
}
1 |
|
public void Render (ScriptableRenderContext context, Camera camera)
{
this.context = context;
this.camera = camera;
if (!Cull())
{
return;
}
Setup();
DrawVisibleGeometry();
Submit();
}
1 |
|
static ShaderTagId unlitShaderTagId = new ShaderTagId("SRPDefaultUnlit");
void DrawVisibleGeometry()
{
// 设置渲染对象排序方法
var sortingSettings = new SortingSettings(camera)
{
criteria = SortingCriteria.CommonOpaque
};
var drawingSettings = new DrawingSettings(
unlitShaderTagId, sortingSettings
);
// 选取不透明物体渲染
var filteringSettings = new FilteringSettings(RenderQueueRange.opaque);
context.DrawRenderers(
cullingResults, ref drawingSettings, ref filteringSettings
);
// 选取透明物体渲染
filteringSettings = new FilteringSettings(RenderQueueRange.transparent);
context.DrawRenderers(
cullingResults, ref drawingSettings, ref filteringSettings
);
// 最后绘制天空盒
context.DrawSkybox(camera);
}
1 |
|
static Material errorMaterial;
static ShaderTagId[] legacyShaderTagIds = {
new ShaderTagId("Always"),
new ShaderTagId("ForwardBase"),
new ShaderTagId("PrepassBase"),
new ShaderTagId("Vertex"),
new ShaderTagId("VertexLMRGBM"),
new ShaderTagId("VertexLM")
};
void DrawUnsupportedShaders()
{
if (errorMaterial == null)
{
errorMaterial =
new Material(Shader.Find("Hidden/InternalErrorShader"));
}
var drawingSettings = new DrawingSettings(
legacyShaderTagIds[0], new SortingSettings(camera)
)
{
overrideMaterial = errorMaterial
};
//var drawingSettings = new DrawingSettings(
// legacyShaderTagIds[0], new SortingSettings(camera)
//);
for (int i = 1; i < legacyShaderTagIds.Length; i++)
{
drawingSettings.SetShaderPassName(i, legacyShaderTagIds[i]);
}
var filteringSettings = FilteringSettings.defaultValue;
context.DrawRenderers(
cullingResults, ref drawingSettings, ref filteringSettings
);
}
处理其他类型的材质。
`ShaderTagId[] legacyShaderTagIds`定义了可被此方法处理的材质列表。
至此,所有物体都应该显示了。
![set](/Road-To-Graphics-2/final1-noErrMaterial.PNG)
> 如果不设置errorMaterial,非支持材质物体将为黑色,这是由于未正确设置光照导致的。
![set](/Road-To-Graphics-2/final1.PNG)
> 设置errorMaterial后的效果
## 实验二:多相机视角
到上一步为止,我们添加了自定义渲染管线`myRenderPipeline`,并对所有相机生效。这一节我们将设置多个相机视角。
1. 复制main camera对象,**修改其tag为`untagged`**
(这是为了在hololens 等ar设备中使用,否则多个主摄像机会导致AR设备混乱)。
2. 在project中新建`Render Texture`对象,并将新的相机对象的`render texture`选项设置为新建的RT。
![set](/Road-To-Graphics-2/set22.PNG)
3. 新建一个`Unlit/Texture`材质,设置纹理为刚才新建的RT;
![set](/Road-To-Graphics-2/set21.PNG)
4. 场景中新建一个`Image`物体,设置其`material`参数为刚才设置好的材质;
![set](/Road-To-Graphics-2/set23.PNG)
5. 调整相机和画布位置。现在可以看到多个摄像机画面了。
![set](/Road-To-Graphics-2/final2.PNG)
If you like this blog or find it useful for you, you are welcome to comment on it. You are also welcome to share this blog, so that more people can participate in it. If the images used in the blog infringe your copyright, please contact the author to delete them. Thank you !