cascaded shadow maps

pull/2/head
cosmonaut 2020-09-18 04:00:53 -07:00
parent 10f3d9cd98
commit a55e33f9a9
5 changed files with 243 additions and 102 deletions

View File

@ -2,22 +2,32 @@ using Microsoft.Xna.Framework;
namespace Kav namespace Kav
{ {
public struct Camera public struct PerspectiveCamera
{ {
public Matrix Transform { get; } public Matrix View { get; }
public Matrix View
{
get
{
return Matrix.CreateLookAt(Transform.Translation, Transform.Translation + Transform.Forward, Transform.Up);
}
}
public Matrix Projection { get; } public Matrix Projection { get; }
public Camera(Matrix transform, Matrix projection) public Vector3 Position { get; }
public Vector3 Forward { get; }
public Vector3 Up { get; }
public float FieldOfView { get; }
public float AspectRatio { get; }
public float NearPlane { get; }
public float FarPlane { get; }
public PerspectiveCamera(Vector3 position, Vector3 forward, Vector3 up, float fieldOfView, float aspectRatio, float nearPlane, float farPlane)
{ {
Transform = transform; Position = position;
Projection = projection; Forward = forward;
Up = up;
View = Matrix.CreateLookAt(Position, Position + Forward, Up);
FieldOfView = fieldOfView;
AspectRatio = aspectRatio;
NearPlane = nearPlane;
FarPlane = farPlane;
Projection = Matrix.CreatePerspectiveFieldOfView(FieldOfView, AspectRatio, NearPlane, FarPlane);
} }
} }
} }

View File

@ -9,13 +9,24 @@ namespace Kav
EffectParameter gAlbedoParam; EffectParameter gAlbedoParam;
EffectParameter gNormalParam; EffectParameter gNormalParam;
EffectParameter gMetallicRoughnessParam; EffectParameter gMetallicRoughnessParam;
EffectParameter shadowMapParam;
EffectParameter shadowMapOneParam;
EffectParameter shadowMapTwoParam;
EffectParameter shadowMapThreeParam;
EffectParameter shadowMapFourParam;
EffectParameter lightSpaceMatrixOneParam;
EffectParameter lightSpaceMatrixTwoParam;
EffectParameter lightSpaceMatrixThreeParam;
EffectParameter lightSpaceMatrixFourParam;
EffectParameter viewMatrixParam;
EffectParameter cascadeFarPlanesParam;
EffectParameter directionalLightColorParam; EffectParameter directionalLightColorParam;
EffectParameter directionalLightDirectionParam; EffectParameter directionalLightDirectionParam;
EffectParameter eyePositionParam; EffectParameter eyePositionParam;
EffectParameter lightSpaceMatrixParam;
PointLightCollection pointLightCollection; PointLightCollection pointLightCollection;
@ -23,11 +34,22 @@ namespace Kav
public Texture2D GAlbedo { get; set; } public Texture2D GAlbedo { get; set; }
public Texture2D GNormal { get; set; } public Texture2D GNormal { get; set; }
public Texture2D GMetallicRoughness { get; set; } public Texture2D GMetallicRoughness { get; set; }
public Texture2D ShadowMap { get; set; }
public Texture2D ShadowMapOne { get; set; }
public Texture2D ShadowMapTwo { get; set; }
public Texture2D ShadowMapThree { get; set; }
public Texture2D ShadowMapFour { get; set; }
public Matrix LightSpaceMatrixOne { get; set; }
public Matrix LightSpaceMatrixTwo { get; set; }
public Matrix LightSpaceMatrixThree { get; set; }
public Matrix LightSpaceMatrixFour { get; set; }
public Matrix ViewMatrix { get; set; }
public float[] CascadeFarPlanes;
public Vector3 DirectionalLightColor { get; set; } public Vector3 DirectionalLightColor { get; set; }
public Vector3 DirectionalLightDirection { get; set; } public Vector3 DirectionalLightDirection { get; set; }
public Matrix LightSpaceMatrix { get; set; }
public Vector3 EyePosition { get; set; } public Vector3 EyePosition { get; set; }
@ -41,6 +63,8 @@ namespace Kav
public DeferredPBREffect(GraphicsDevice graphicsDevice) : base(graphicsDevice, Resources.DeferredPBREffect) public DeferredPBREffect(GraphicsDevice graphicsDevice) : base(graphicsDevice, Resources.DeferredPBREffect)
{ {
CascadeFarPlanes = new float[4];
CacheEffectParameters(); CacheEffectParameters();
pointLightCollection = new PointLightCollection( pointLightCollection = new PointLightCollection(
@ -82,28 +106,50 @@ namespace Kav
gAlbedoParam.SetValue(GAlbedo); gAlbedoParam.SetValue(GAlbedo);
gNormalParam.SetValue(GNormal); gNormalParam.SetValue(GNormal);
gMetallicRoughnessParam.SetValue(GMetallicRoughness); gMetallicRoughnessParam.SetValue(GMetallicRoughness);
shadowMapParam.SetValue(ShadowMap);
shadowMapOneParam.SetValue(ShadowMapOne);
shadowMapTwoParam.SetValue(ShadowMapTwo);
shadowMapThreeParam.SetValue(ShadowMapThree);
shadowMapFourParam.SetValue(ShadowMapFour);
lightSpaceMatrixOneParam.SetValue(LightSpaceMatrixOne);
lightSpaceMatrixTwoParam.SetValue(LightSpaceMatrixTwo);
lightSpaceMatrixThreeParam.SetValue(LightSpaceMatrixThree);
lightSpaceMatrixFourParam.SetValue(LightSpaceMatrixFour);
viewMatrixParam.SetValue(ViewMatrix);
cascadeFarPlanesParam.SetValue(CascadeFarPlanes);
directionalLightColorParam.SetValue(DirectionalLightColor); directionalLightColorParam.SetValue(DirectionalLightColor);
directionalLightDirectionParam.SetValue(DirectionalLightDirection); directionalLightDirectionParam.SetValue(DirectionalLightDirection);
eyePositionParam.SetValue(EyePosition); eyePositionParam.SetValue(EyePosition);
lightSpaceMatrixParam.SetValue(LightSpaceMatrix);
} }
void CacheEffectParameters() void CacheEffectParameters()
{ {
gPositionParam = Parameters["gPosition"]; gPositionParam = Parameters["gPosition"];
gAlbedoParam = Parameters["gAlbedo"]; gAlbedoParam = Parameters["gAlbedo"];
gNormalParam = Parameters["gNormal"]; gNormalParam = Parameters["gNormal"];
gMetallicRoughnessParam = Parameters["gMetallicRoughness"]; gMetallicRoughnessParam = Parameters["gMetallicRoughness"];
shadowMapParam = Parameters["shadowMap"];
shadowMapOneParam = Parameters["shadowMapOne"];
shadowMapTwoParam = Parameters["shadowMapTwo"];
shadowMapThreeParam = Parameters["shadowMapThree"];
shadowMapFourParam = Parameters["shadowMapFour"];
lightSpaceMatrixOneParam = Parameters["LightSpaceMatrixOne"];
lightSpaceMatrixTwoParam = Parameters["LightSpaceMatrixTwo"];
lightSpaceMatrixThreeParam = Parameters["LightSpaceMatrixThree"];
lightSpaceMatrixFourParam = Parameters["LightSpaceMatrixFour"];
viewMatrixParam = Parameters["ViewMatrix"];
cascadeFarPlanesParam = Parameters["CascadeFarPlanes"];
directionalLightDirectionParam = Parameters["DirectionalLightDirection"]; directionalLightDirectionParam = Parameters["DirectionalLightDirection"];
directionalLightColorParam = Parameters["DirectionalLightColor"]; directionalLightColorParam = Parameters["DirectionalLightColor"];
lightSpaceMatrixParam = Parameters["LightSpaceMatrix"];
eyePositionParam = Parameters["EyePosition"]; eyePositionParam = Parameters["EyePosition"];
} }
} }
} }

Binary file not shown.

View File

@ -2,12 +2,16 @@
static const float PI = 3.141592653589793; static const float PI = 3.141592653589793;
static const int MAX_POINT_LIGHTS = 64; static const int MAX_POINT_LIGHTS = 64;
static const int NUM_SHADOW_CASCADES = 4;
DECLARE_TEXTURE(gPosition, 0); DECLARE_TEXTURE(gPosition, 0);
DECLARE_TEXTURE(gAlbedo, 1); DECLARE_TEXTURE(gAlbedo, 1);
DECLARE_TEXTURE(gNormal, 2); DECLARE_TEXTURE(gNormal, 2);
DECLARE_TEXTURE(gMetallicRoughness, 3); DECLARE_TEXTURE(gMetallicRoughness, 3);
DECLARE_TEXTURE(shadowMap, 4); DECLARE_TEXTURE(shadowMapOne, 4);
DECLARE_TEXTURE(shadowMapTwo, 5);
DECLARE_TEXTURE(shadowMapThree, 6);
DECLARE_TEXTURE(shadowMapFour, 7);
BEGIN_CONSTANTS BEGIN_CONSTANTS
@ -19,9 +23,17 @@ BEGIN_CONSTANTS
float3 DirectionalLightDirection _ps(c129) _cb(c129); float3 DirectionalLightDirection _ps(c129) _cb(c129);
float3 DirectionalLightColor _ps(c130) _cb(c130); float3 DirectionalLightColor _ps(c130) _cb(c130);
float CascadeFarPlanes[NUM_SHADOW_CASCADES] _ps(c131) _cb(c131);
MATRIX_CONSTANTS MATRIX_CONSTANTS
float4x4 LightSpaceMatrix _ps(c131) _cb(c131); float4x4 LightSpaceMatrixOne _ps(c135) _cb(c135);
float4x4 LightSpaceMatrixTwo _ps(c139) _cb(c139);
float4x4 LightSpaceMatrixThree _ps(c143) _cb(c143);
float4x4 LightSpaceMatrixFour _ps(c147) _cb(c147);
// used to select shadow cascade
float4x4 ViewMatrix _ps(c151) _cb(c151);
END_CONSTANTS END_CONSTANTS
@ -89,11 +101,44 @@ float GeometrySmith(float3 N, float3 V, float3 L, float roughness)
return ggx1 * ggx2; return ggx1 * ggx2;
} }
float ComputeShadow(float4 positionLightSpace, float3 N, float L) float ComputeShadow(float3 positionWorldSpace, float3 N, float L)
{ {
float bias = 0.005 * tan(acos(dot(N, L))); float bias = 0.005 * tan(acos(dot(N, L)));
bias = clamp(bias, 0, 0.01); bias = clamp(bias, 0, 0.01);
float4 positionCameraSpace = mul(float4(positionWorldSpace, 1.0), ViewMatrix);
int shadowCascadeIndex = 0; // 0 is closest
for (int i = 0; i < NUM_SHADOW_CASCADES; i++)
{
if (positionCameraSpace.z < CascadeFarPlanes[i])
{
shadowCascadeIndex = i;
break;
}
}
float4x4 lightSpaceMatrix;
if (shadowCascadeIndex == 0)
{
lightSpaceMatrix = LightSpaceMatrixOne;
}
else if (shadowCascadeIndex == 1)
{
lightSpaceMatrix = LightSpaceMatrixTwo;
}
else if (shadowCascadeIndex == 2)
{
lightSpaceMatrix = LightSpaceMatrixThree;
}
else
{
lightSpaceMatrix = LightSpaceMatrixFour;
}
float4 positionLightSpace = mul(float4(positionWorldSpace, 1.0), lightSpaceMatrix);
// maps to [-1, 1] // maps to [-1, 1]
float3 projectionCoords = positionLightSpace.xyz / positionLightSpace.w; float3 projectionCoords = positionLightSpace.xyz / positionLightSpace.w;
@ -102,7 +147,24 @@ float ComputeShadow(float4 positionLightSpace, float3 N, float L)
projectionCoords.y = (projectionCoords.y * 0.5) + 0.5; projectionCoords.y = (projectionCoords.y * 0.5) + 0.5;
projectionCoords.y *= -1; projectionCoords.y *= -1;
float closestDepth = SAMPLE_TEXTURE(shadowMap, projectionCoords.xy).r; float closestDepth;
if (shadowCascadeIndex == 0)
{
closestDepth = SAMPLE_TEXTURE(shadowMapOne, projectionCoords.xy).r;
}
else if (shadowCascadeIndex == 1)
{
closestDepth = SAMPLE_TEXTURE(shadowMapTwo, projectionCoords.xy).r;
}
else if (shadowCascadeIndex == 2)
{
closestDepth = SAMPLE_TEXTURE(shadowMapThree, projectionCoords.xy).r;
}
else
{
closestDepth = SAMPLE_TEXTURE(shadowMapFour, projectionCoords.xy).r;
}
float currentDepth = projectionCoords.z; float currentDepth = projectionCoords.z;
if (currentDepth - bias > closestDepth) if (currentDepth - bias > closestDepth)
@ -176,8 +238,7 @@ float4 ComputeColor(
float3 L = normalize(DirectionalLightDirection); float3 L = normalize(DirectionalLightDirection);
float3 radiance = DirectionalLightColor; float3 radiance = DirectionalLightColor;
float4 positionLightSpace = mul(float4(worldPosition, 1.0), LightSpaceMatrix); float shadow = ComputeShadow(worldPosition, N, L);
float shadow = ComputeShadow(positionLightSpace, N, L);
Lo += ComputeLight(L, radiance, F0, V, N, albedo, metallic, roughness, (1.0 - shadow)); Lo += ComputeLight(L, radiance, F0, V, N, albedo, metallic, roughness, (1.0 - shadow));

View File

@ -6,12 +6,15 @@ namespace Kav
{ {
public class Renderer public class Renderer
{ {
private const int MAX_SHADOW_CASCADES = 4;
private GraphicsDevice GraphicsDevice { get; } private GraphicsDevice GraphicsDevice { get; }
private int RenderDimensionsX { get; } private int RenderDimensionsX { get; }
private int RenderDimensionsY { get; } private int RenderDimensionsY { get; }
private VertexBuffer FullscreenTriangle { get; } private VertexBuffer FullscreenTriangle { get; }
private RenderTarget2D ShadowRenderTarget { get; } private int NumShadowCascades { get; }
private RenderTarget2D[] ShadowRenderTargets { get; }
private DeferredPBREffect DeferredPBREffect { get; } private DeferredPBREffect DeferredPBREffect { get; }
private SimpleDepthEffect SimpleDepthEffect { get; } private SimpleDepthEffect SimpleDepthEffect { get; }
@ -24,22 +27,26 @@ namespace Kav
private RenderTargetBinding[] GBuffer { get; } private RenderTargetBinding[] GBuffer { get; }
private SpriteBatch SpriteBatch { get; } public Renderer(GraphicsDevice graphicsDevice, int renderDimensionsX, int renderDimensionsY, int numShadowCascades)
public Renderer(GraphicsDevice graphicsDevice, int renderDimensionsX, int renderDimensionsY)
{ {
GraphicsDevice = graphicsDevice; GraphicsDevice = graphicsDevice;
RenderDimensionsX = renderDimensionsX; RenderDimensionsX = renderDimensionsX;
RenderDimensionsY = renderDimensionsY; RenderDimensionsY = renderDimensionsY;
ShadowRenderTarget = new RenderTarget2D( NumShadowCascades = (int)MathHelper.Clamp(numShadowCascades, 1, MAX_SHADOW_CASCADES);
GraphicsDevice, ShadowRenderTargets = new RenderTarget2D[numShadowCascades];
1024,
1024, for (var i = 0; i < numShadowCascades; i++)
false, {
SurfaceFormat.Single, ShadowRenderTargets[i] = new RenderTarget2D(
DepthFormat.Depth24 GraphicsDevice,
); 1024,
1024,
false,
SurfaceFormat.Single,
DepthFormat.Depth24
);
}
gPosition = new RenderTarget2D( gPosition = new RenderTarget2D(
GraphicsDevice, GraphicsDevice,
@ -100,21 +107,18 @@ namespace Kav
new VertexPositionTexture(new Vector3(3, -1, 0), new Vector2(2, 0)) new VertexPositionTexture(new Vector3(3, -1, 0), new Vector2(2, 0))
}); });
SpriteBatch = new SpriteBatch(GraphicsDevice);
GraphicsDevice.SetRenderTarget(deferredRenderTarget); GraphicsDevice.SetRenderTarget(deferredRenderTarget);
graphicsDevice.Clear(Color.White); graphicsDevice.Clear(Color.White);
GraphicsDevice.SetRenderTarget(null); GraphicsDevice.SetRenderTarget(null);
} }
public void DeferredRender( public void DeferredRender(
Camera camera, PerspectiveCamera camera,
IEnumerable<(Model, Matrix)> modelTransforms, IEnumerable<(Model, Matrix)> modelTransforms,
IEnumerable<PointLight> pointLights, IEnumerable<PointLight> pointLights,
DirectionalLight directionalLight, DirectionalLight directionalLight
int numCascades
) { ) {
ShadowMapRender(camera, modelTransforms, directionalLight, numCascades); ShadowMapRender(camera, modelTransforms, directionalLight);
GraphicsDevice.SetRenderTargets(GBuffer); GraphicsDevice.SetRenderTargets(GBuffer);
GraphicsDevice.Clear(ClearOptions.Target | ClearOptions.DepthBuffer, Color.Black, 1f, 0); GraphicsDevice.Clear(ClearOptions.Target | ClearOptions.DepthBuffer, Color.Black, 1f, 0);
@ -161,7 +165,23 @@ namespace Kav
DeferredPBREffect.GAlbedo = gAlbedo; DeferredPBREffect.GAlbedo = gAlbedo;
DeferredPBREffect.GNormal = gNormal; DeferredPBREffect.GNormal = gNormal;
DeferredPBREffect.GMetallicRoughness = gMetallicRoughness; DeferredPBREffect.GMetallicRoughness = gMetallicRoughness;
DeferredPBREffect.ShadowMap = ShadowRenderTarget;
DeferredPBREffect.ShadowMapOne = ShadowRenderTargets[0];
if (NumShadowCascades > 1)
{
DeferredPBREffect.ShadowMapTwo = ShadowRenderTargets[1];
}
if (NumShadowCascades > 2)
{
DeferredPBREffect.ShadowMapThree = ShadowRenderTargets[2];
}
if (NumShadowCascades > 3)
{
DeferredPBREffect.ShadowMapFour = ShadowRenderTargets[3];
}
DeferredPBREffect.ViewMatrix = camera.View;
DeferredPBREffect.EyePosition = Matrix.Invert(camera.View).Translation; DeferredPBREffect.EyePosition = Matrix.Invert(camera.View).Translation;
int i = 0; int i = 0;
@ -182,23 +202,15 @@ namespace Kav
GraphicsDevice.SetVertexBuffer(FullscreenTriangle); GraphicsDevice.SetVertexBuffer(FullscreenTriangle);
GraphicsDevice.DrawPrimitives(PrimitiveType.TriangleList, 0, 1); GraphicsDevice.DrawPrimitives(PrimitiveType.TriangleList, 0, 1);
} }
// SpriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied, null, null, null, DeferredPBREffect);
// SpriteBatch.Draw(deferredRenderTarget, Vector2.Zero, Color.White);
// SpriteBatch.End();
} }
public void ShadowMapRender( public void ShadowMapRender(
Camera camera, PerspectiveCamera camera,
IEnumerable<(Model, Matrix)> modelTransforms, IEnumerable<(Model, Matrix)> modelTransforms,
DirectionalLight directionalLight, DirectionalLight directionalLight
int numCascades
) { ) {
GraphicsDevice.SetRenderTarget(ShadowRenderTarget); // set up global light matrix
GraphicsDevice.Clear(Color.White);
GraphicsDevice.DepthStencilState = DepthStencilState.Default;
GraphicsDevice.BlendState = BlendState.Opaque;
var right = Vector3.Cross(Vector3.Up, directionalLight.Direction); var right = Vector3.Cross(Vector3.Up, directionalLight.Direction);
var up = Vector3.Cross(directionalLight.Direction, right); var up = Vector3.Cross(directionalLight.Direction, right);
var cameraBoundingFrustum = new BoundingFrustum(camera.View * camera.Projection); var cameraBoundingFrustum = new BoundingFrustum(camera.View * camera.Projection);
@ -221,48 +233,39 @@ namespace Kav
BoundingBox lightBox = BoundingBox.CreateFromPoints(frustumCorners); BoundingBox lightBox = BoundingBox.CreateFromPoints(frustumCorners);
Vector3 lightPosition = frustumCenter + directionalLight.Direction * -lightBox.Min.Z; Vector3 lightPosition = frustumCenter + directionalLight.Direction * -lightBox.Min.Z;
SimpleDepthEffect.View = Matrix.CreateLookAt(lightPosition, frustumCenter, camera.View.Right); // render the individual shadow maps
SimpleDepthEffect.Projection = Matrix.CreateOrthographicOffCenter(
lightBox.Min.X, var frustumDistance = camera.FarPlane - camera.NearPlane;
lightBox.Max.X, var sectionDistance = frustumDistance / NumShadowCascades;
lightBox.Min.Y,
lightBox.Max.Y, for (var i = 0; i < NumShadowCascades; i++)
0,
lightBox.Max.Z - lightBox.Min.Z
);
DeferredPBREffect.LightSpaceMatrix = SimpleDepthEffect.View * SimpleDepthEffect.Projection;
foreach (var (model, transform) in modelTransforms)
{ {
foreach (var modelMesh in model.Meshes) // divide the view frustum
{ var shadowCamera = new PerspectiveCamera(
foreach (var meshPart in modelMesh.MeshParts) camera.Position,
{ camera.Forward,
GraphicsDevice.SetVertexBuffer(meshPart.VertexBuffer); camera.Up,
GraphicsDevice.Indices = meshPart.IndexBuffer; camera.FieldOfView,
camera.AspectRatio,
SimpleDepthEffect.Model = transform; camera.NearPlane + (i * sectionDistance),
camera.NearPlane + ((i + 1) * sectionDistance)
foreach (var pass in SimpleDepthEffect.CurrentTechnique.Passes) );
{
pass.Apply(); RenderShadowMap(shadowCamera, modelTransforms, directionalLight, i);
GraphicsDevice.DrawIndexedPrimitives(
PrimitiveType.TriangleList,
0,
0,
meshPart.VertexBuffer.VertexCount,
0,
meshPart.Triangles.Length
);
}
}
}
} }
} }
private void RenderShadowMap(Camera camera, IEnumerable<(Model, Matrix)> modelTransforms, DirectionalLight directionalLight) private void RenderShadowMap(
{ PerspectiveCamera camera,
IEnumerable<(Model, Matrix)> modelTransforms,
DirectionalLight directionalLight,
int shadowCascadeIndex
) {
GraphicsDevice.SetRenderTarget(ShadowRenderTargets[shadowCascadeIndex]);
GraphicsDevice.Clear(Color.White);
GraphicsDevice.DepthStencilState = DepthStencilState.Default;
GraphicsDevice.BlendState = BlendState.Opaque;
var right = Vector3.Cross(Vector3.Up, directionalLight.Direction); var right = Vector3.Cross(Vector3.Up, directionalLight.Direction);
var up = Vector3.Cross(directionalLight.Direction, right); var up = Vector3.Cross(directionalLight.Direction, right);
var cameraBoundingFrustum = new BoundingFrustum(camera.View * camera.Projection); var cameraBoundingFrustum = new BoundingFrustum(camera.View * camera.Projection);
@ -295,6 +298,27 @@ namespace Kav
lightBox.Max.Z - lightBox.Min.Z lightBox.Max.Z - lightBox.Min.Z
); );
var lightSpaceMatrix = SimpleDepthEffect.View * SimpleDepthEffect.Projection;
if (shadowCascadeIndex == 0)
{
DeferredPBREffect.LightSpaceMatrixOne = lightSpaceMatrix;
}
else if (shadowCascadeIndex == 1)
{
DeferredPBREffect.LightSpaceMatrixTwo = lightSpaceMatrix;
}
else if (shadowCascadeIndex == 2)
{
DeferredPBREffect.LightSpaceMatrixThree = lightSpaceMatrix;
}
else if (shadowCascadeIndex == 3)
{
DeferredPBREffect.LightSpaceMatrixFour = lightSpaceMatrix;
}
DeferredPBREffect.CascadeFarPlanes[shadowCascadeIndex] = camera.FarPlane;
foreach (var (model, transform) in modelTransforms) foreach (var (model, transform) in modelTransforms)
{ {
foreach (var modelMesh in model.Meshes) foreach (var modelMesh in model.Meshes)
@ -325,7 +349,7 @@ namespace Kav
} }
public void Render( public void Render(
Camera camera, PerspectiveCamera camera,
IEnumerable<(Model, Matrix)> modelTransforms, IEnumerable<(Model, Matrix)> modelTransforms,
IEnumerable<PointLight> pointLights, IEnumerable<PointLight> pointLights,
IEnumerable<DirectionalLight> directionalLights IEnumerable<DirectionalLight> directionalLights