浏览代码
Refactored LowEndMobile pipeline to have constant nomeclature across all modules. Organized project strucuture for clearer reference.
/vr_sandbox
Refactored LowEndMobile pipeline to have constant nomeclature across all modules. Organized project strucuture for clearer reference.
/vr_sandbox
Felipe Lira
8 年前
当前提交
870e00ba
共有 39 个文件被更改,包括 1765 次插入 和 17 次删除
-
27Assets/LowEndMobilePipeline/Editor/LowendMobilePipelineMaterialEditor.cs
-
4Assets/LowEndMobilePipeline/TestScenes/Materials/LDRenderPipeMaterials/MobileColors.mat
-
8Assets/LowEndMobilePipeline/LowEndMobilePipeline.shader
-
26Assets/LowEndMobilePipeline/Editor/LegacyMobileToLowendMobileUpgrader.cs
-
113Assets/LowEndMobilePipeline/Editor/LowendPipelineAssetInspector.cs
-
22Assets/LowEndMobilePipeline/Editor/StandardToLowEndMaterialUpgrader.cs
-
381Assets/LowEndMobilePipeline/LowEndMobilePipeline.cs
-
25Assets/LowEndMobilePipeline/LowEndMobilePipelineAsset.asset
-
9Assets/LowEndMobilePipeline/LowEndMobilePipelineAsset.asset.meta
-
145Assets/LowEndMobilePipeline/LowEndMobilePipelineAsset.cs
-
12Assets/LowEndMobilePipeline/LowEndMobilePipelineAsset.cs.meta
-
9Assets/LowEndMobilePipeline/TestScenes.meta
-
1001Assets/LowEndMobilePipeline/TestScenes/LDRenderPipelineBasicScene.unity
-
0/Assets/LowEndMobilePipeline.meta
-
0/Assets/LowEndMobilePipeline/LowEndMobilePipeline.cs.meta
-
0/Assets/LowEndMobilePipeline/TestScenes/Materials.meta
-
0/Assets/LowEndMobilePipeline/TestScenes/Textures.meta
-
0/Assets/LowEndMobilePipeline/TestScenes/Textures
-
0/Assets/LowEndMobilePipeline/Editor.meta
-
0/Assets/LowEndMobilePipeline/TestScenes/LDRenderPipelineVikingVillage
-
0/Assets/LowEndMobilePipeline/TestScenes/LDRenderPipelineBasicScene.meta
-
0/Assets/LowEndMobilePipeline/TestScenes/LDRenderPipelineBasicScene.unity.meta
-
0/Assets/LowEndMobilePipeline/TestScenes/LDRenderPipelineVikingVillage.meta
-
0/Assets/LowEndMobilePipeline/TestScenes/LDRenderPipelineVikingVillage.unity
-
0/Assets/LowEndMobilePipeline/TestScenes/LDRenderPipelineVikingVillage.unity.meta
-
0/Assets/LowEndMobilePipeline/TestScenes/LDRenderPipelineBasicScene
-
0/Assets/LowEndMobilePipeline/Editor/StandardToLowEndMaterialUpgrader.cs.meta
-
0/Assets/LowEndMobilePipeline/Editor/LegacyMobileToLowendMobileUpgrader.cs.meta
-
0/Assets/LowEndMobilePipeline/Editor/LowendMobilePipelineMaterialEditor.cs.meta
-
0/Assets/LowEndMobilePipeline/Editor/LowendPipelineAssetInspector.cs.meta
-
0/Assets/LowEndMobilePipeline/Editor/LowendMobilePipelineMaterialEditor.cs
-
0/Assets/LowEndMobilePipeline/TestScenes/Materials
-
0/Assets/LowEndMobilePipeline/LowEndMobilePipeline.shader.meta
-
0/Assets/LowEndMobilePipeline/LowEndMobilePipeline.shader
|
|||
using System.Collections.Generic; |
|||
using UnityEditor; |
|||
using UnityEditor.Experimental.Rendering; |
|||
|
|||
public class LegacyMobileToLowendMobileUpgrader : MaterialUpgrader |
|||
{ |
|||
[MenuItem("LowEndMobilePipeline/Material Upgraders/Upgrade Legacy Mobile Materials to LowEndMobile")] |
|||
public static void UpgradeMaterialsToLD() |
|||
{ |
|||
List<MaterialUpgrader> materialUpgraders = new List<MaterialUpgrader>(); |
|||
materialUpgraders.Add(new LegacyMobileToLowendMobileUpgrader("Mobile/Diffuse")); |
|||
materialUpgraders.Add(new LegacyMobileToLowendMobileUpgrader("Mobile/Bumped Specular")); |
|||
materialUpgraders.Add(new LegacyMobileToLowendMobileUpgrader("Mobile/Bumped Specular(1 Directional Light)")); |
|||
materialUpgraders.Add(new LegacyMobileToLowendMobileUpgrader("Mobile/Bumped Diffuse")); |
|||
materialUpgraders.Add(new LegacyMobileToLowendMobileUpgrader("Mobile/Unlit (Supports Lightmap)")); |
|||
materialUpgraders.Add(new LegacyMobileToLowendMobileUpgrader("Mobile/VertexLit")); |
|||
|
|||
MaterialUpgrader.UpgradeProjectFolder(materialUpgraders, "Upgrade to LD Materials"); |
|||
} |
|||
|
|||
LegacyMobileToLowendMobileUpgrader(string oldShaderName) |
|||
{ |
|||
RenameShader(oldShaderName, "LowEndMobilePipeline/Specular"); |
|||
RenameFloat("_Shininess", "_Glossiness"); |
|||
} |
|||
} |
|
|||
using UnityEditor; |
|||
|
|||
namespace UnityEngine.Experimental.Rendering.LowendMobile |
|||
{ |
|||
[CustomEditor(typeof(LowEndMobilePipelineAsset))] |
|||
public class LowendPipelineAssetInspector : Editor |
|||
{ |
|||
internal class Styles |
|||
{ |
|||
public static GUIContent renderingLabel = new GUIContent("Rendering"); |
|||
public static GUIContent shadowLabel = new GUIContent("Shadows"); |
|||
|
|||
public static GUIContent maxPixelLights = new GUIContent("Max per-pixel lights supported", |
|||
"Amount of dynamic lights processed in fragment shader. More than 1 per-pixel light is not recommended."); |
|||
|
|||
public static GUIContent enableVertexLightLabel = new GUIContent("Enable Vertex Light", |
|||
"Enable up to 4 per-vertex dynamic lights."); |
|||
|
|||
public static GUIContent enableLightmap = new GUIContent("Enable Lightmap", |
|||
"Only non-directional lightmaps are supported"); |
|||
|
|||
public static GUIContent enableAmbientProbe = new GUIContent("Enable Ambient Probe", |
|||
"Uses light probes as ambient light source for non-lightmapped objects."); |
|||
|
|||
public static GUIContent shadowType = new GUIContent("Shadow Type", |
|||
"Single directional shadow supported. SOFT_SHADOWS applies shadow filtering."); |
|||
|
|||
public static GUIContent shadowNearPlaneOffset = new GUIContent("Shadow Near Plane Offset", |
|||
"Offset shadow near plane to account for large triangles being distorted by pancaking"); |
|||
|
|||
public static GUIContent shadowDistante = new GUIContent("Shadow Distance", "Max shadow drawing distance"); |
|||
public static GUIContent shadowBias = new GUIContent("Shadow Bias"); |
|||
|
|||
public static GUIContent shadowAtlasResolution = new GUIContent("Shadow Map Resolution", |
|||
"Resolution of shadow map texture. If cascades are enabled all cascades will be packed into this texture resolution."); |
|||
|
|||
public static GUIContent shadowCascades = new GUIContent("Shadow Cascades", |
|||
"Number of cascades for directional shadows"); |
|||
|
|||
public static GUIContent shadowCascadeSplit = new GUIContent("Shadow Cascade Split", |
|||
"Percentages to split shadow volume"); |
|||
} |
|||
|
|||
private SerializedProperty m_MaxPixelLights; |
|||
private SerializedProperty m_SupportsVertexLightProp; |
|||
private SerializedProperty m_EnableLightmapsProp; |
|||
private SerializedProperty m_EnableAmbientProbeProp; |
|||
private SerializedProperty m_ShadowTypeProp; |
|||
private SerializedProperty m_ShadowNearPlaneOffsetProp; |
|||
private SerializedProperty m_ShadowBiasProperty; |
|||
private SerializedProperty m_ShadowDistanceProp; |
|||
private SerializedProperty m_ShadowAtlasResolutionProp; |
|||
private SerializedProperty m_ShadowCascadesProp; |
|||
private SerializedProperty m_ShadowCascade2SplitProp; |
|||
private SerializedProperty m_ShadowCascade4SplitProp; |
|||
|
|||
void OnEnable() |
|||
{ |
|||
m_MaxPixelLights = serializedObject.FindProperty("m_MaxPixelLights"); |
|||
m_SupportsVertexLightProp = serializedObject.FindProperty("m_SupportsVertexLight"); |
|||
m_EnableLightmapsProp = serializedObject.FindProperty("m_EnableLightmaps"); |
|||
m_EnableAmbientProbeProp = serializedObject.FindProperty("m_EnableAmbientProbe"); |
|||
m_ShadowTypeProp = serializedObject.FindProperty("m_ShadowType"); |
|||
m_ShadowNearPlaneOffsetProp = serializedObject.FindProperty("m_ShadowNearPlaneOffset"); |
|||
m_ShadowBiasProperty = serializedObject.FindProperty("m_ShadowBias"); |
|||
m_ShadowDistanceProp = serializedObject.FindProperty("m_ShadowDistance"); |
|||
m_ShadowAtlasResolutionProp = serializedObject.FindProperty("m_ShadowAtlasResolution"); |
|||
m_ShadowCascadesProp = serializedObject.FindProperty("m_ShadowCascades"); |
|||
m_ShadowCascade2SplitProp = serializedObject.FindProperty("m_Cascade2Split"); |
|||
m_ShadowCascade4SplitProp = serializedObject.FindProperty("m_Cascade4Split"); |
|||
} |
|||
|
|||
public override void OnInspectorGUI() |
|||
{ |
|||
LowEndMobilePipelineAsset pipeAsset = target as LowEndMobilePipelineAsset; |
|||
serializedObject.Update(); |
|||
|
|||
EditorGUILayout.Space(); |
|||
EditorGUILayout.LabelField(Styles.renderingLabel, EditorStyles.boldLabel); |
|||
EditorGUI.indentLevel++; |
|||
EditorGUILayout.PropertyField(m_MaxPixelLights, Styles.maxPixelLights); |
|||
EditorGUILayout.PropertyField(m_SupportsVertexLightProp, Styles.enableVertexLightLabel); |
|||
EditorGUILayout.PropertyField(m_EnableLightmapsProp, Styles.enableLightmap); |
|||
EditorGUILayout.PropertyField(m_EnableAmbientProbeProp, Styles.enableAmbientProbe); |
|||
EditorGUI.indentLevel--; |
|||
EditorGUILayout.Space(); |
|||
EditorGUILayout.Space(); |
|||
|
|||
EditorGUILayout.LabelField(Styles.shadowLabel, EditorStyles.boldLabel); |
|||
EditorGUI.indentLevel++; |
|||
EditorGUILayout.PropertyField(m_ShadowTypeProp, Styles.shadowType); |
|||
EditorGUILayout.PropertyField(m_ShadowAtlasResolutionProp, Styles.shadowAtlasResolution); |
|||
EditorGUILayout.PropertyField(m_ShadowNearPlaneOffsetProp, Styles.shadowNearPlaneOffset); |
|||
EditorGUILayout.PropertyField(m_ShadowBiasProperty, Styles.shadowBias); |
|||
EditorGUILayout.PropertyField(m_ShadowDistanceProp, Styles.shadowDistante); |
|||
EditorGUILayout.PropertyField(m_ShadowCascadesProp, Styles.shadowCascades); |
|||
|
|||
ShadowCascades cascades = (ShadowCascades) m_ShadowCascadesProp.intValue; |
|||
if (cascades == ShadowCascades.FOUR_CASCADES) |
|||
{ |
|||
EditorGUILayout.PropertyField(m_ShadowCascade4SplitProp, Styles.shadowCascadeSplit); |
|||
} |
|||
else if (cascades == ShadowCascades.TWO_CASCADES) |
|||
{ |
|||
EditorGUILayout.PropertyField(m_ShadowCascade2SplitProp, Styles.shadowCascadeSplit); |
|||
} |
|||
|
|||
EditorGUI.indentLevel--; |
|||
|
|||
serializedObject.ApplyModifiedProperties(); |
|||
} |
|||
} |
|||
} |
|
|||
using System.Collections.Generic; |
|||
using UnityEditor; |
|||
using UnityEditor.Experimental.Rendering; |
|||
|
|||
public class StandardToLowEndMaterialUpgrader : MaterialUpgrader |
|||
{ |
|||
[MenuItem("LowEndMobilePipeline/Material Upgraders/Upgrade Standard Materials to LDRenderPipeline")] |
|||
private static void UpgradeMaterialsToLD() |
|||
{ |
|||
List<MaterialUpgrader> upgraders = new List<MaterialUpgrader>(); |
|||
upgraders.Add(new StandardToLowEndMaterialUpgrader("Standard (Specular setup)")); |
|||
upgraders.Add(new StandardToLowEndMaterialUpgrader("Standard")); |
|||
upgraders.Add(new StandardToLowEndMaterialUpgrader("TerrainSurface")); |
|||
|
|||
MaterialUpgrader.UpgradeProjectFolder(upgraders, "Upgrade to LD Materials"); |
|||
} |
|||
|
|||
StandardToLowEndMaterialUpgrader(string oldShaderName) |
|||
{ |
|||
RenameShader(oldShaderName, "LowEndMobilePipeline/Specular"); |
|||
} |
|||
} |
|
|||
using System; |
|||
using UnityEngine; |
|||
using UnityEngine.Experimental.Rendering; |
|||
using UnityEngine.Rendering; |
|||
|
|||
namespace UnityEngine.Experimental.Rendering.LowendMobile |
|||
{ |
|||
public class LowEndMobilePipeline : RenderPipeline |
|||
{ |
|||
private readonly LowEndMobilePipelineAsset m_Asset; |
|||
|
|||
private static readonly int kMaxCascades = 4; |
|||
private static readonly int kMaxLights = 8; |
|||
private int m_ShadowMapProperty; |
|||
private RenderTargetIdentifier m_ShadowMapRTID; |
|||
private int m_DepthBufferBits = 24; |
|||
|
|||
private static readonly ShaderPassName m_ForwardBasePassName = new ShaderPassName("LowEndMobileForward"); |
|||
|
|||
private Vector4[] m_LightPositions = new Vector4[kMaxLights]; |
|||
private Vector4[] m_LightColors = new Vector4[kMaxLights]; |
|||
private Vector4[] m_LightAttenuations = new Vector4[kMaxLights]; |
|||
private Vector4[] m_LightSpotDirections = new Vector4[kMaxLights]; |
|||
|
|||
private ShadowSettings m_ShadowSettings = ShadowSettings.Default; |
|||
private ShadowSliceData[] m_ShadowSlices = new ShadowSliceData[kMaxCascades]; |
|||
|
|||
public LowEndMobilePipeline(LowEndMobilePipelineAsset asset) |
|||
{ |
|||
m_Asset = asset; |
|||
|
|||
BuildShadowSettings(); |
|||
m_ShadowMapProperty = Shader.PropertyToID("_ShadowMap"); |
|||
m_ShadowMapRTID = new RenderTargetIdentifier(m_ShadowMapProperty); |
|||
} |
|||
|
|||
public override void Render(ScriptableRenderContext context, Camera[] cameras) |
|||
{ |
|||
var prevPipe = Shader.globalRenderPipeline; |
|||
Shader.globalRenderPipeline = "LowEndMobilePipeline"; |
|||
base.Render(context, cameras); |
|||
|
|||
foreach (Camera camera in cameras) |
|||
{ |
|||
CullingParameters cullingParameters; |
|||
camera.farClipPlane = 1000.0f; |
|||
if (!CullResults.GetCullingParameters(camera, out cullingParameters)) |
|||
continue; |
|||
|
|||
cullingParameters.shadowDistance = m_ShadowSettings.maxShadowDistance; |
|||
CullResults cull = CullResults.Cull(ref cullingParameters, context); |
|||
|
|||
var cmd = new CommandBuffer() {name = "Clear"}; |
|||
cmd.ClearRenderTarget(true, true, Color.black); |
|||
context.ExecuteCommandBuffer(cmd); |
|||
cmd.Dispose(); |
|||
|
|||
// Render Shadow Map
|
|||
bool shadowsRendered = RenderShadows(cull, context); |
|||
|
|||
// Draw Opaques with support to one directional shadow cascade
|
|||
// Setup camera matrices
|
|||
context.SetupCameraProperties(camera); |
|||
|
|||
// Setup light and shadow shader constants
|
|||
SetupLightShaderVariables(cull.visibleLights, context); |
|||
if (shadowsRendered) |
|||
SetupShadowShaderVariables(context, camera.nearClipPlane, cullingParameters.shadowDistance, |
|||
m_ShadowSettings.directionalLightCascadeCount); |
|||
|
|||
// Render Opaques
|
|||
var settings = new DrawRendererSettings(cull, camera, m_ForwardBasePassName); |
|||
settings.sorting.flags = SortFlags.CommonOpaque; |
|||
settings.inputFilter.SetQueuesOpaque(); |
|||
|
|||
if (m_Asset.EnableLightmap) |
|||
settings.rendererConfiguration = settings.rendererConfiguration | |
|||
RendererConfiguration.PerObjectLightmaps; |
|||
|
|||
if (m_Asset.EnableAmbientProbe) |
|||
settings.rendererConfiguration = settings.rendererConfiguration | |
|||
RendererConfiguration.PerObjectLightProbe; |
|||
|
|||
context.DrawRenderers(ref settings); |
|||
|
|||
var discardRT = new CommandBuffer(); |
|||
discardRT.ReleaseTemporaryRT(m_ShadowMapProperty); |
|||
context.ExecuteCommandBuffer(discardRT); |
|||
discardRT.Dispose(); |
|||
|
|||
// TODO: Check skybox shader
|
|||
context.DrawSkybox(camera); |
|||
|
|||
// Render Alpha blended
|
|||
settings.sorting.flags = SortFlags.CommonTransparent; |
|||
settings.inputFilter.SetQueuesTransparent(); |
|||
context.DrawRenderers(ref settings); |
|||
} |
|||
|
|||
context.Submit(); |
|||
Shader.globalRenderPipeline = prevPipe; |
|||
} |
|||
|
|||
private void BuildShadowSettings() |
|||
{ |
|||
m_ShadowSettings = ShadowSettings.Default; |
|||
m_ShadowSettings.directionalLightCascadeCount = m_Asset.CascadeCount; |
|||
|
|||
m_ShadowSettings.shadowAtlasWidth = m_Asset.ShadowAtlasResolution; |
|||
m_ShadowSettings.shadowAtlasHeight = m_Asset.ShadowAtlasResolution; |
|||
m_ShadowSettings.maxShadowDistance = m_Asset.ShadowDistance; |
|||
|
|||
switch (m_ShadowSettings.directionalLightCascadeCount) |
|||
{ |
|||
case 1: |
|||
m_ShadowSettings.directionalLightCascades = new Vector3(1.0f, 0.0f, 0.0f); |
|||
break; |
|||
|
|||
case 2: |
|||
m_ShadowSettings.directionalLightCascades = new Vector3(m_Asset.Cascade2Split, 1.0f, 0.0f); |
|||
break; |
|||
|
|||
default: |
|||
m_ShadowSettings.directionalLightCascades = m_Asset.Cascade4Split; |
|||
break; |
|||
} |
|||
} |
|||
|
|||
#region HelperMethods
|
|||
|
|||
private void SetupLightShaderVariables(VisibleLight[] lights, ScriptableRenderContext context) |
|||
{ |
|||
if (lights.Length <= 0) |
|||
return; |
|||
|
|||
int pixelLightCount = Mathf.Min(lights.Length, m_Asset.MaxSupportedPixelLights); |
|||
int vertexLightCount = (m_Asset.SupportsVertexLight) |
|||
? Mathf.Min(lights.Length - pixelLightCount, kMaxLights) |
|||
: 0; |
|||
int totalLightCount = pixelLightCount + vertexLightCount; |
|||
|
|||
for (int i = 0; i < totalLightCount; ++i) |
|||
{ |
|||
VisibleLight currLight = lights[i]; |
|||
if (currLight.lightType == LightType.Directional) |
|||
{ |
|||
Vector4 dir = -currLight.localToWorld.GetColumn(2); |
|||
m_LightPositions[i] = new Vector4(dir.x, dir.y, dir.z, 0.0f); |
|||
} |
|||
else |
|||
{ |
|||
Vector4 pos = currLight.localToWorld.GetColumn(3); |
|||
m_LightPositions[i] = new Vector4(pos.x, pos.y, pos.z, 1.0f); |
|||
} |
|||
|
|||
m_LightColors[i] = currLight.finalColor; |
|||
|
|||
float rangeSq = currLight.range*currLight.range; |
|||
float quadAtten = (currLight.lightType == LightType.Directional) ? 0.0f : 25.0f/rangeSq; |
|||
|
|||
if (currLight.lightType == LightType.Spot) |
|||
{ |
|||
Vector4 dir = currLight.localToWorld.GetColumn(2); |
|||
m_LightSpotDirections[i] = new Vector4(-dir.x, -dir.y, -dir.z, 0.0f); |
|||
|
|||
float spotAngle = Mathf.Deg2Rad*currLight.spotAngle; |
|||
float cosOuterAngle = Mathf.Cos(spotAngle*0.5f); |
|||
float cosInneAngle = Mathf.Cos(spotAngle*0.25f); |
|||
float angleRange = cosInneAngle - cosOuterAngle; |
|||
m_LightAttenuations[i] = new Vector4(cosOuterAngle, |
|||
Mathf.Approximately(angleRange, 0.0f) ? 1.0f : angleRange, quadAtten, rangeSq); |
|||
} |
|||
else |
|||
{ |
|||
m_LightSpotDirections[i] = new Vector4(0.0f, 0.0f, 1.0f, 0.0f); |
|||
m_LightAttenuations[i] = new Vector4(-1.0f, 1.0f, quadAtten, rangeSq); |
|||
} |
|||
} |
|||
|
|||
CommandBuffer cmd = new CommandBuffer() {name = "SetupShadowShaderConstants"}; |
|||
cmd.SetGlobalVectorArray("globalLightPos", m_LightPositions); |
|||
cmd.SetGlobalVectorArray("globalLightColor", m_LightColors); |
|||
cmd.SetGlobalVectorArray("globalLightAtten", m_LightAttenuations); |
|||
cmd.SetGlobalVectorArray("globalLightSpotDir", m_LightSpotDirections); |
|||
cmd.SetGlobalVector("globalLightCount", new Vector4(pixelLightCount, totalLightCount, 0.0f, 0.0f)); |
|||
SetShadowKeywords(cmd); |
|||
context.ExecuteCommandBuffer(cmd); |
|||
cmd.Dispose(); |
|||
} |
|||
|
|||
private bool RenderShadows(CullResults cullResults, ScriptableRenderContext context) |
|||
{ |
|||
int cascadeCount = m_ShadowSettings.directionalLightCascadeCount; |
|||
|
|||
VisibleLight[] lights = cullResults.visibleLights; |
|||
int lightCount = lights.Length; |
|||
|
|||
int shadowResolution = 0; |
|||
int lightIndex = -1; |
|||
for (int i = 0; i < lightCount; ++i) |
|||
{ |
|||
if (lights[i].light.shadows != LightShadows.None && lights[i].lightType == LightType.Directional) |
|||
{ |
|||
lightIndex = i; |
|||
shadowResolution = GetMaxTileResolutionInAtlas(m_ShadowSettings.shadowAtlasWidth, |
|||
m_ShadowSettings.shadowAtlasHeight, cascadeCount); |
|||
break; |
|||
} |
|||
} |
|||
|
|||
if (lightIndex < 0) |
|||
return false; |
|||
|
|||
Bounds bounds; |
|||
if (!cullResults.GetShadowCasterBounds(lightIndex, out bounds)) |
|||
return false; |
|||
|
|||
var setRenderTargetCommandBuffer = new CommandBuffer(); |
|||
setRenderTargetCommandBuffer.name = "Render packed shadows"; |
|||
setRenderTargetCommandBuffer.GetTemporaryRT(m_ShadowMapProperty, m_ShadowSettings.shadowAtlasWidth, |
|||
m_ShadowSettings.shadowAtlasHeight, m_DepthBufferBits, FilterMode.Bilinear, RenderTextureFormat.Depth, |
|||
RenderTextureReadWrite.Linear); |
|||
setRenderTargetCommandBuffer.SetRenderTarget(m_ShadowMapRTID); |
|||
setRenderTargetCommandBuffer.ClearRenderTarget(true, true, Color.black); |
|||
context.ExecuteCommandBuffer(setRenderTargetCommandBuffer); |
|||
setRenderTargetCommandBuffer.Dispose(); |
|||
|
|||
float shadowNearPlane = m_Asset.ShadowNearOffset; |
|||
Vector3 splitRatio = m_ShadowSettings.directionalLightCascades; |
|||
Vector3 lightDir = lights[lightIndex].light.transform.forward; |
|||
for (int cascadeIdx = 0; cascadeIdx < cascadeCount; ++cascadeIdx) |
|||
{ |
|||
Matrix4x4 view, proj; |
|||
var settings = new DrawShadowsSettings(cullResults, lightIndex); |
|||
bool needRendering = cullResults.ComputeDirectionalShadowMatricesAndCullingPrimitives(lightIndex, |
|||
cascadeIdx, cascadeCount, splitRatio, shadowResolution, shadowNearPlane, out view, out proj, |
|||
out settings.splitData); |
|||
|
|||
if (needRendering) |
|||
{ |
|||
SetupShadowSliceTransform(cascadeIdx, shadowResolution, proj, view); |
|||
RenderShadowSlice(ref context, lightDir, cascadeIdx, proj, view, settings); |
|||
} |
|||
} |
|||
|
|||
return true; |
|||
} |
|||
|
|||
private void SetupShadowSliceTransform(int cascadeIndex, int shadowResolution, Matrix4x4 proj, Matrix4x4 view) |
|||
{ |
|||
// Assumes MAX_CASCADES = 4
|
|||
m_ShadowSlices[cascadeIndex].atlasX = (cascadeIndex%2)*shadowResolution; |
|||
m_ShadowSlices[cascadeIndex].atlasY = (cascadeIndex/2)*shadowResolution; |
|||
m_ShadowSlices[cascadeIndex].shadowResolution = shadowResolution; |
|||
m_ShadowSlices[cascadeIndex].shadowTransform = Matrix4x4.identity; |
|||
|
|||
var matScaleBias = Matrix4x4.identity; |
|||
matScaleBias.m00 = 0.5f; |
|||
matScaleBias.m11 = 0.5f; |
|||
matScaleBias.m22 = 0.5f; |
|||
matScaleBias.m03 = 0.5f; |
|||
matScaleBias.m23 = 0.5f; |
|||
matScaleBias.m13 = 0.5f; |
|||
|
|||
// Later down the pipeline the proj matrix will be scaled to reverse-z in case of DX.
|
|||
// We need account for that scale in the shadowTransform.
|
|||
if (SystemInfo.usesReversedZBuffer) |
|||
matScaleBias.m22 = -0.5f; |
|||
|
|||
var matTile = Matrix4x4.identity; |
|||
matTile.m00 = (float) m_ShadowSlices[cascadeIndex].shadowResolution/ |
|||
(float) m_ShadowSettings.shadowAtlasWidth; |
|||
matTile.m11 = (float) m_ShadowSlices[cascadeIndex].shadowResolution/ |
|||
(float) m_ShadowSettings.shadowAtlasHeight; |
|||
matTile.m03 = (float) m_ShadowSlices[cascadeIndex].atlasX/(float) m_ShadowSettings.shadowAtlasWidth; |
|||
matTile.m13 = (float) m_ShadowSlices[cascadeIndex].atlasY/(float) m_ShadowSettings.shadowAtlasHeight; |
|||
|
|||
m_ShadowSlices[cascadeIndex].shadowTransform = matTile*matScaleBias*proj*view; |
|||
} |
|||
|
|||
private void RenderShadowSlice(ref ScriptableRenderContext context, Vector3 lightDir, int cascadeIndex, |
|||
Matrix4x4 proj, Matrix4x4 view, DrawShadowsSettings settings) |
|||
{ |
|||
var buffer = new CommandBuffer() {name = "Prepare Shadowmap Slice"}; |
|||
buffer.SetViewport(new Rect(m_ShadowSlices[cascadeIndex].atlasX, m_ShadowSlices[cascadeIndex].atlasY, |
|||
m_ShadowSlices[cascadeIndex].shadowResolution, m_ShadowSlices[cascadeIndex].shadowResolution)); |
|||
buffer.SetViewProjectionMatrices(view, proj); |
|||
buffer.SetGlobalVector("_WorldLightDirAndBias", |
|||
new Vector4(-lightDir.x, -lightDir.y, -lightDir.z, m_Asset.ShadowBias)); |
|||
context.ExecuteCommandBuffer(buffer); |
|||
buffer.Dispose(); |
|||
|
|||
context.DrawShadows(ref settings); |
|||
} |
|||
|
|||
private int GetMaxTileResolutionInAtlas(int atlasWidth, int atlasHeight, int tileCount) |
|||
{ |
|||
int resolution = Mathf.Min(atlasWidth, atlasHeight); |
|||
if (tileCount > Mathf.Log(resolution)) |
|||
{ |
|||
Debug.LogError( |
|||
String.Format( |
|||
"Cannot fit {0} tiles into current shadowmap atlas of size ({1}, {2}). ShadowMap Resolution set to zero.", |
|||
tileCount, atlasWidth, atlasHeight)); |
|||
return 0; |
|||
} |
|||
|
|||
int currentTileCount = atlasWidth/resolution*atlasHeight/resolution; |
|||
while (currentTileCount < tileCount) |
|||
{ |
|||
resolution = resolution >> 1; |
|||
currentTileCount = atlasWidth/resolution*atlasHeight/resolution; |
|||
} |
|||
return resolution; |
|||
} |
|||
|
|||
void SetupShadowShaderVariables(ScriptableRenderContext context, float shadowNear, float shadowFar, |
|||
int cascadeCount) |
|||
{ |
|||
float shadowResolution = m_ShadowSlices[0].shadowResolution; |
|||
|
|||
// PSSM distance settings
|
|||
float shadowFrustumDepth = shadowFar - shadowNear; |
|||
Vector3 shadowSplitRatio = m_ShadowSettings.directionalLightCascades; |
|||
|
|||
// We set PSSMDistance to infinity for non active cascades so the comparison test always fails for unavailable cascades
|
|||
Vector4 PSSMDistances = new Vector4( |
|||
shadowNear + shadowSplitRatio.x*shadowFrustumDepth, |
|||
(shadowSplitRatio.y > 0.0f) ? shadowNear + shadowSplitRatio.y*shadowFrustumDepth : Mathf.Infinity, |
|||
(shadowSplitRatio.z > 0.0f) ? shadowNear + shadowSplitRatio.z*shadowFrustumDepth : Mathf.Infinity, |
|||
1.0f/shadowResolution); |
|||
|
|||
const int maxShadowCascades = 4; |
|||
Matrix4x4[] shadowMatrices = new Matrix4x4[maxShadowCascades]; |
|||
for (int i = 0; i < cascadeCount; ++i) |
|||
shadowMatrices[i] = (cascadeCount >= i) ? m_ShadowSlices[i].shadowTransform : Matrix4x4.identity; |
|||
|
|||
// TODO: shadow resolution per cascade in case cascades endup being supported.
|
|||
float invShadowResolution = 1.0f/shadowResolution; |
|||
float[] pcfKernel = |
|||
{ |
|||
-0.5f*invShadowResolution, 0.5f*invShadowResolution, |
|||
0.5f*invShadowResolution, 0.5f*invShadowResolution, |
|||
-0.5f*invShadowResolution, -0.5f*invShadowResolution, |
|||
0.5f*invShadowResolution, -0.5f*invShadowResolution |
|||
}; |
|||
|
|||
var setupShadow = new CommandBuffer() {name = "SetupShadowShaderConstants"}; |
|||
SetShadowKeywords(setupShadow); |
|||
setupShadow.SetGlobalMatrixArray("_WorldToShadow", shadowMatrices); |
|||
setupShadow.SetGlobalVector("_PSSMDistancesAndShadowResolution", PSSMDistances); |
|||
setupShadow.SetGlobalFloatArray("_PCFKernel", pcfKernel); |
|||
SetShadowKeywords(setupShadow); |
|||
context.ExecuteCommandBuffer(setupShadow); |
|||
setupShadow.Dispose(); |
|||
} |
|||
|
|||
void SetShadowKeywords(CommandBuffer cmd) |
|||
{ |
|||
switch (m_Asset.CurrShadowType) |
|||
{ |
|||
case ShadowType.NO_SHADOW: |
|||
cmd.DisableShaderKeyword("HARD_SHADOWS"); |
|||
cmd.DisableShaderKeyword("SOFT_SHADOWS"); |
|||
break; |
|||
|
|||
case ShadowType.HARD_SHADOWS: |
|||
cmd.EnableShaderKeyword("HARD_SHADOWS"); |
|||
cmd.DisableShaderKeyword("SOFT_SHADOWS"); |
|||
break; |
|||
|
|||
case ShadowType.SOFT_SHADOWS: |
|||
cmd.DisableShaderKeyword("HARD_SHADOWS"); |
|||
cmd.EnableShaderKeyword("SOFT_SHADOWS"); |
|||
break; |
|||
} |
|||
} |
|||
|
|||
#endregion
|
|||
} |
|||
} |
|
|||
%YAML 1.1 |
|||
%TAG !u! tag:unity3d.com,2011: |
|||
--- !u!114 &11400000 |
|||
MonoBehaviour: |
|||
m_ObjectHideFlags: 0 |
|||
m_PrefabParentObject: {fileID: 0} |
|||
m_PrefabInternal: {fileID: 0} |
|||
m_GameObject: {fileID: 0} |
|||
m_Enabled: 1 |
|||
m_EditorHideFlags: 0 |
|||
m_Script: {fileID: 11500000, guid: bf2edee5c58d82540a51f03df9d42094, type: 3} |
|||
m_Name: LowEndMobilePipelineAsset |
|||
m_EditorClassIdentifier: |
|||
m_MaxPixelLights: 1 |
|||
m_SupportsVertexLight: 1 |
|||
m_EnableLightmaps: 1 |
|||
m_EnableAmbientProbe: 1 |
|||
m_ShadowType: 1 |
|||
m_ShadowAtlasResolution: 1024 |
|||
m_ShadowNearPlaneOffset: 2 |
|||
m_ShadowDistance: 50 |
|||
m_ShadowBias: 0.05 |
|||
m_ShadowCascades: 4 |
|||
m_Cascade2Split: 0.25 |
|||
m_Cascade4Split: {x: 0.067, y: 0.2, z: 0.467} |
|
|||
fileFormatVersion: 2 |
|||
guid: 877878ed40e8ad94095582ff91179016 |
|||
timeCreated: 1488808435 |
|||
licenseType: Pro |
|||
NativeFormatImporter: |
|||
mainObjectFileID: 11400000 |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
namespace UnityEngine.Experimental.Rendering.LowendMobile |
|||
{ |
|||
public enum ShadowCascades |
|||
{ |
|||
NO_CASCADES = 1, |
|||
TWO_CASCADES = 2, |
|||
FOUR_CASCADES = 4, |
|||
} |
|||
|
|||
public enum ShadowType |
|||
{ |
|||
NO_SHADOW = 0, |
|||
HARD_SHADOWS, |
|||
SOFT_SHADOWS, |
|||
} |
|||
|
|||
public enum ShadowResolution |
|||
{ |
|||
_512 = 512, |
|||
_1024 = 1024, |
|||
_2048 = 2048 |
|||
} |
|||
|
|||
public class LowEndMobilePipelineAsset : RenderPipelineAsset |
|||
{ |
|||
#region AssetAndPipelineCreation
|
|||
|
|||
#if UNITY_EDITOR
|
|||
[UnityEditor.MenuItem("LowEndMobilePipeline/Create Pipeline Asset")] |
|||
static void CreateLowEndPipeline() |
|||
{ |
|||
var instance = ScriptableObject.CreateInstance<LowEndMobilePipelineAsset>(); |
|||
UnityEditor.AssetDatabase.CreateAsset(instance, |
|||
"Assets/LowEndMobilePipeline/LowEndMobilePipelineAsset.asset"); |
|||
} |
|||
#endif
|
|||
|
|||
protected override IRenderPipeline InternalCreatePipeline() |
|||
{ |
|||
return new LowEndMobilePipeline(this); |
|||
} |
|||
|
|||
#endregion
|
|||
|
|||
#region PipelineAssetSettings
|
|||
|
|||
[SerializeField] private int m_MaxPixelLights = 1; |
|||
|
|||
[SerializeField] private bool m_SupportsVertexLight = true; |
|||
|
|||
[SerializeField] private bool m_EnableLightmaps = true; |
|||
|
|||
[SerializeField] private bool m_EnableAmbientProbe = true; |
|||
|
|||
[SerializeField] private ShadowType m_ShadowType = ShadowType.HARD_SHADOWS; |
|||
|
|||
[SerializeField] private ShadowResolution m_ShadowAtlasResolution = ShadowResolution._1024; |
|||
|
|||
[SerializeField] private float m_ShadowNearPlaneOffset = 2.0f; |
|||
|
|||
[SerializeField] private float m_ShadowDistance = 50.0f; |
|||
|
|||
[SerializeField] private float m_ShadowBias = 0.0005f; |
|||
|
|||
[SerializeField] private ShadowCascades m_ShadowCascades = ShadowCascades.NO_CASCADES; |
|||
|
|||
[SerializeField] private float m_Cascade2Split = 0.25f; |
|||
|
|||
[SerializeField] private Vector3 m_Cascade4Split = new Vector3(0.067f, 0.2f, 0.467f); |
|||
|
|||
public int MaxSupportedPixelLights |
|||
{ |
|||
get { return m_MaxPixelLights; } |
|||
private set { m_MaxPixelLights = value; } |
|||
} |
|||
|
|||
public bool SupportsVertexLight |
|||
{ |
|||
get { return m_SupportsVertexLight; } |
|||
private set { m_SupportsVertexLight = value; } |
|||
} |
|||
|
|||
public bool EnableLightmap |
|||
{ |
|||
get { return m_EnableLightmaps; } |
|||
private set { m_EnableLightmaps = value; } |
|||
} |
|||
|
|||
public bool EnableAmbientProbe |
|||
{ |
|||
get { return m_EnableAmbientProbe; } |
|||
private set { m_EnableAmbientProbe = value; } |
|||
} |
|||
|
|||
public ShadowType CurrShadowType |
|||
{ |
|||
get { return m_ShadowType; } |
|||
private set { m_ShadowType = value; } |
|||
} |
|||
|
|||
public int ShadowAtlasResolution |
|||
{ |
|||
get { return (int) m_ShadowAtlasResolution; } |
|||
private set { m_ShadowAtlasResolution = (ShadowResolution) value; } |
|||
} |
|||
|
|||
public float ShadowNearOffset |
|||
{ |
|||
get { return m_ShadowNearPlaneOffset; } |
|||
private set { m_ShadowNearPlaneOffset = value; } |
|||
} |
|||
|
|||
public float ShadowDistance |
|||
{ |
|||
get { return m_ShadowDistance; } |
|||
private set { m_ShadowDistance = value; } |
|||
} |
|||
|
|||
public float ShadowBias |
|||
{ |
|||
get { return m_ShadowBias; } |
|||
private set { m_ShadowBias = value; } |
|||
} |
|||
|
|||
public int CascadeCount |
|||
{ |
|||
get { return (int) m_ShadowCascades; } |
|||
private set { m_ShadowCascades = (ShadowCascades) value; } |
|||
} |
|||
|
|||
public float Cascade2Split |
|||
{ |
|||
get { return m_Cascade2Split; } |
|||
private set { m_Cascade2Split = value; } |
|||
} |
|||
|
|||
public Vector3 Cascade4Split |
|||
{ |
|||
get { return m_Cascade4Split; } |
|||
private set { m_Cascade4Split = value; } |
|||
} |
|||
|
|||
#endregion
|
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: bf2edee5c58d82540a51f03df9d42094 |
|||
timeCreated: 1488808083 |
|||
licenseType: Pro |
|||
MonoImporter: |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
fileFormatVersion: 2 |
|||
guid: 2c0fa72aa713a664b9be2de857697293 |
|||
folderAsset: yes |
|||
timeCreated: 1488808638 |
|||
licenseType: Pro |
|||
DefaultImporter: |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
1001
Assets/LowEndMobilePipeline/TestScenes/LDRenderPipelineBasicScene.unity
文件差异内容过多而无法显示
查看文件
文件差异内容过多而无法显示
查看文件
撰写
预览
正在加载...
取消
保存
Reference in new issue