public class TableNodeCell
{
public RectInt Rect { get; set; }
public PagePayload Payload { get; set; }
public int MipLevel { get; }
public TableNodeCell(int x, int y, int width, int height,int mip)
{
Rect = new RectInt(x, y, width, height);
MipLevel = mip;
Payload = new PagePayload();
}
}
这里Unity有几个坑逼的地方,首先unity调用drawMeshInstanced传入的那个矩阵他会修改里边的数据,导致我不能直接使用那个数据,因为我这里不是标准的MVP矩阵,他可能帮我转换了,我这里重新弄了一个矩阵instanceData。还有一点就是如果你在shader里不使用UNITY_MATRIX_M这个变量,unity就认为你这个不是drawInstance。所以我在shader里加了一句无意义的代码float4x4 mat = UNITY_MATRIX_M;
最近在卷UE5的自定义光照模型,所以就写一个笔记,记录一下/Recently, I’ve been experimenting with custom shading models in Unreal Engine 5 (UE5), so I decided to write some notes to keep track of my progress.
分三个模块,1.拉取源代码,2.C++部分添加custom shading model,3.shader 部分/Divide it into three modules: 1. Fetching the source code, 2. Adding the custom shading model in C++, 3. Working on the shader part.
一. 拉取UE源代码/Fetching the source code
主要步骤还是根据UE官方档案来操作 从源代码构建虚幻引擎 | 虚幻引擎文档 (unrealengine.com)/The main steps to build Unreal Engine from source code should be followed based on the official documentation provided by Unreal Engine.
二.C++部分添加Custom Shading Model/To add a custom shading model in C++
To make Unreal Engine aware of your custom shading model and have it appear in the dropdown menu of the lighting model, you need to modify the EngineTypes.h and MaterialShader.cpp files. The essence of this modification is to add a new enumeration.
At this point, we have completed the modifications in the C++ part. Overall, it wasn’t difficult; it was mostly a matter of following a similar pattern. Let’s compile the engine now to see if our changes are successful.
看到这几个就相当于添加成功了
接着我们开始修改shader部分
Let’s continue with the modification of the shader part.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Rendering.Universal;
[System.Serializable]
public struct RenderFeatureToggle
{
public ScriptableRendererFeature feature;
public bool isEnabled;
}
[ExecuteAlways]
public class RenderFeatureToggler : MonoBehaviour
{
[SerializeField]
private List<RenderFeatureToggle> renderFeatures = new List<RenderFeatureToggle>();
[SerializeField]
private UniversalRenderPipelineAsset pipelineAsset;
private void Update()
{
foreach (RenderFeatureToggle toggleObj in renderFeatures)
{
toggleObj.feature.SetActive(toggleObj.isEnabled);
}
}
}
改一下可以用脚本控制
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Rendering.Universal;
[System.Serializable]
public struct RenderFeatureToggle
{
public ScriptableRendererFeature feature;
public bool isEnabled;
}
[ExecuteAlways]
public class RenderFeatureToggler : MonoBehaviour
{
[SerializeField]
private List<RenderFeatureToggle> renderFeatures = new List<RenderFeatureToggle>();
[SerializeField]
private UniversalRenderPipelineAsset pipelineAsset;
private void Update()
{
//foreach (RenderFeatureToggle toggleObj in renderFeatures)
//{
// toggleObj.feature.SetActive(toggleObj.isEnabled);
//}
}
public void OpenRenderFeatureToggle()
{
foreach (RenderFeatureToggle toggleObj in renderFeatures)
{
toggleObj.feature.SetActive(true);
}
}
public void OffRenderFeatureToggle()
{
foreach (RenderFeatureToggle toggleObj in renderFeatures)
{
toggleObj.feature.SetActive(false);
}
}
}
using System;
using System.Collections.Generic;
using UnityEngine;
public class FadingObject : MonoBehaviour, IEquatable<FadingObject>
{
public List<Renderer> Renderers = new List<Renderer>();
public Vector3 Position;
public List<Material> Materials = new List<Material>();
[HideInInspector]
public float InitialAlpha;
//public float InitialFadeScale;
private void Awake()
{
Position = transform.position;
if (Renderers.Count == 0)
{
Renderers.AddRange(GetComponentsInChildren<Renderer>());
}
foreach(Renderer renderer in Renderers)
{
Materials.AddRange(renderer.materials);
}
InitialAlpha = Materials[0].color.a;
Materials[0].SetFloat("_DitherThreshold", 1f);
}
public bool Equals(FadingObject other)
{
return Position.Equals(other.Position);
}
public override int GetHashCode()
{
return Position.GetHashCode();
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class FadeObjectBlockingObject : MonoBehaviour
{
[SerializeField]
private LayerMask LayerMask;
[SerializeField]
private Transform Target;
[SerializeField]
private Camera Camera;
[SerializeField]
[Range(0, 1f)]
private float FadedAlpha = 0.33f;
[SerializeField]
private bool RetainShadows = true;
[SerializeField]
private Vector3 TargetPositionOffset = Vector3.up;
[SerializeField]
private float FadeSpeed = 1;
[Header("Read Only Data")]
[SerializeField]
private List<FadingObject> ObjectsBlockingView = new List<FadingObject>();
private Dictionary<FadingObject, Coroutine> RunningCoroutines = new Dictionary<FadingObject, Coroutine>();
private RaycastHit[] Hits = new RaycastHit[10];
private void OnEnable()
{
StartCoroutine(CheckForObjects());
}
private IEnumerator CheckForObjects()
{
while (true)
{
int hits = Physics.RaycastNonAlloc(
Camera.transform.position,
(Target.transform.position + TargetPositionOffset - Camera.transform.position).normalized,
Hits,
Vector3.Distance(Camera.transform.position, Target.transform.position + TargetPositionOffset),
LayerMask
);
if (hits > 0)
{
for (int i = 0; i < hits; i++)
{
FadingObject fadingObject = GetFadingObjectFromHit(Hits[i]);
if (fadingObject != null && !ObjectsBlockingView.Contains(fadingObject))
{
if (RunningCoroutines.ContainsKey(fadingObject))
{
if (RunningCoroutines[fadingObject] != null)
{
StopCoroutine(RunningCoroutines[fadingObject]);
}
RunningCoroutines.Remove(fadingObject);
}
RunningCoroutines.Add(fadingObject, StartCoroutine(FadeObjectOut(fadingObject)));
ObjectsBlockingView.Add(fadingObject);
}
}
}
FadeObjectsNoLongerBeingHit();
ClearHits();
yield return null;
}
}
private void FadeObjectsNoLongerBeingHit()
{
List<FadingObject> objectsToRemove = new List<FadingObject>(ObjectsBlockingView.Count);
foreach (FadingObject fadingObject in ObjectsBlockingView)
{
bool objectIsBeingHit = false;
for (int i = 0; i < Hits.Length; i++)
{
FadingObject hitFadingObject = GetFadingObjectFromHit(Hits[i]);
if (hitFadingObject != null && fadingObject == hitFadingObject)
{
objectIsBeingHit = true;
break;
}
}
if (!objectIsBeingHit)
{
if (RunningCoroutines.ContainsKey(fadingObject))
{
if (RunningCoroutines[fadingObject] != null)
{
StopCoroutine(RunningCoroutines[fadingObject]);
}
RunningCoroutines.Remove(fadingObject);
}
RunningCoroutines.Add(fadingObject, StartCoroutine(FadeObjectIn(fadingObject)));
objectsToRemove.Add(fadingObject);
}
}
foreach(FadingObject removeObject in objectsToRemove)
{
ObjectsBlockingView.Remove(removeObject);
}
}
private IEnumerator FadeObjectOut(FadingObject FadingObject)
{
foreach (Material material in FadingObject.Materials)
{
material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.SrcAlpha);
material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
material.SetInt("_ZWrite", 0);
material.SetInt("_Surface", 1);
material.renderQueue = (int)UnityEngine.Rendering.RenderQueue.Transparent;
material.SetShaderPassEnabled("DepthOnly", false);
material.SetShaderPassEnabled("SHADOWCASTER", RetainShadows);
material.SetOverrideTag("RenderType", "Transparent");
material.EnableKeyword("_SURFACE_TYPE_TRANSPARENT");
material.EnableKeyword("_ALPHAPREMULTIPLY_ON");
}
float time = 0;
while (FadingObject.Materials[0].color.a > FadedAlpha)
{
foreach (Material material in FadingObject.Materials)
{
if (material.HasProperty("_BaseColor"))
{
float a = Mathf.Lerp(FadingObject.InitialAlpha, FadedAlpha, time * FadeSpeed);
material.color = new Color(
material.color.r,
material.color.g,
material.color.b,
a
);
//print("_1");
//Setting fade value
material.SetFloat("_DitherThreshold", a);
}
}
time += Time.deltaTime;
yield return null;
}
if (RunningCoroutines.ContainsKey(FadingObject))
{
StopCoroutine(RunningCoroutines[FadingObject]);
RunningCoroutines.Remove(FadingObject);
}
}
private IEnumerator FadeObjectIn(FadingObject FadingObject)
{
float time = 0;
while (FadingObject.Materials[0].color.a < FadingObject.InitialAlpha)
{
foreach (Material material in FadingObject.Materials)
{
if (material.HasProperty("_BaseColor"))
{
float a = Mathf.Lerp(FadedAlpha, FadingObject.InitialAlpha, time * FadeSpeed);
material.color = new Color(
material.color.r,
material.color.g,
material.color.b,
a
);
//Setting fade value
material.SetFloat("_DitherThreshold", a);
}
}
time += Time.deltaTime;
yield return null;
}
foreach (Material material in FadingObject.Materials)
{
material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One);
material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.Zero);
material.SetInt("_ZWrite", 1);
material.SetInt("_Surface", 0);
material.renderQueue = (int)UnityEngine.Rendering.RenderQueue.Geometry;
material.SetShaderPassEnabled("DepthOnly", true);
material.SetShaderPassEnabled("SHADOWCASTER", true);
material.SetOverrideTag("RenderType", "Opaque");
material.DisableKeyword("_SURFACE_TYPE_TRANSPARENT");
material.DisableKeyword("_ALPHAPREMULTIPLY_ON");
}
if (RunningCoroutines.ContainsKey(FadingObject))
{
StopCoroutine(RunningCoroutines[FadingObject]);
RunningCoroutines.Remove(FadingObject);
}
}
private void ClearHits()
{
System.Array.Clear(Hits, 0, Hits.Length);
}
private FadingObject GetFadingObjectFromHit(RaycastHit Hit)
{
return Hit.collider != null ? Hit.collider.GetComponent<FadingObject>() : null;
}
}