I think you are just missing the color semantic at the end
float4 CreateDepthMapPixelShader(VsOutputCalcSceneDepth input) : COLOR
I think you are just missing the color semantic at the end
float4 CreateDepthMapPixelShader(VsOutputCalcSceneDepth input) : COLOR
I just started working on it again now ill give that a go in a minute.
Edit. well it compiles not sure its actually working though i gotta clean up the cpu side of my test im reorganizing it.
Almost got it now i just have to align the spaces, i think im not sure the output im getting is a little troubling.
Alright i seem to have something off, im getting a entirely shadowed scene but the depth visualization clearly shows that it sees these cubes this has me confused.
Im not sure either if the light position is truely at the cubes center or what is going on.
Heres my game1 and heres my shader currently.
game1
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using System;
namespace TestTextureCube
{
public class Game1 : Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
RenderTargetCube renderTargetCube;
Effect effect;
//
float near = .1f;
float far = 1000f;
//
Matrix world, view, projection;
Matrix worldGrid, worldCamera, worldLight, worldCube;
// well draw a bunch.
Matrix[] worldCubes;
int numberOfCubes = 30;
Vector3 theLightsViewPosition;
// something to draw
Grid3dOrientation grid = new Grid3dOrientation(30, 30, .001f);
CubePNTT cube = new CubePNTT(true);
Quad quad = new Quad(1.7f); // 2.0 is screen scale with a wvp identity matrix.
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
}
protected override void Initialize()
{
base.Initialize();
}
protected override void LoadContent()
{
spriteBatch = this.LoadBasics("Shadow Cube test");
effect = Content.Load<Effect>("EffectCubeMap");
renderTargetCube = new RenderTargetCube(GraphicsDevice, 256, false, SurfaceFormat.Single, DepthFormat.Depth24);
//effect.Parameters["farPlane"].SetValue(far);
world = Matrix.Identity;
SetCreateView(world);
SetProjection(Matrix.CreatePerspectiveFieldOfView((float)MathHelper.Pi * .5f, GraphicsDevice.Viewport.Width / GraphicsDevice.Viewport.Height, near, far));
worldLight = CreateWorldToTarget(new Vector3(3f, 2f, -2f), Vector3.Zero, Vector3.Up);
worldGrid = Matrix.CreateScale(30f) * Matrix.CreateWorld(Vector3.Zero, Vector3.Forward, Vector3.Up);
worldCube = Matrix.CreateScale(1f) * CreateWorldToTarget(new Vector3(3f, .1f, -.5f), Vector3.Zero, Vector3.Up);
worldCamera = CreateWorldToTarget(new Vector3(.5f, -.5f, 4f), Vector3.Zero, Vector3.Up);
MakeBunchesOfCubes();
BasicStuff.camera.CameraType(BasicCamera.MOVEMENT_CAMERA);
BasicStuff.camera.SetPosition(worldCamera.Translation);
}
void MakeBunchesOfCubes()
{
// spiral
var pi2 = MathHelper.Pi *2f;
int len = numberOfCubes;
worldCubes = new Matrix[len];
for(int i = 0; i < len; i++)
{
float r = (float)(i) / (float)(len);
var t = (r) * pi2 * 2f; // 12 radians 2 circles
var x = (float)Math.Sin(t);
var y = 0f;
var z = (float)Math.Cos(t);
Vector3 p = new Vector3(x,y,z) * (2f + r * 4f ) + worldLight.Translation; // spirals instead
worldCubes[i] = Matrix.CreateScale(.4f + r) * Matrix.CreateWorld(p, Vector3.Forward, Vector3.Up);
}
}
protected override void UnloadContent()
{
this.UnloadBasics();
}
protected override void Update(GameTime gameTime)
{
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || Keyboard.GetState().IsKeyDown(Keys.Escape))
Exit();
BasicStuff.Update(gameTime);
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.Black);
GraphicsDevice.Clear(ClearOptions.DepthBuffer, Color.Black, 1, 0);
GraphicsDevice.RasterizerState = new RasterizerState() { FillMode = FillMode.Solid, CullMode = CullMode.None };
GraphicsDevice.DepthStencilState = new DepthStencilState() { DepthBufferEnable = true, DepthBufferFunction = CompareFunction.LessEqual };
//
// Render to each face of the cube this will need a spacial partition of some type later on.
//
GraphicsDevice.SetRenderTarget(renderTargetCube, CubeMapFace.NegativeX);
SetCreateView(worldLight.Translation, Vector3.Left, Vector3.Up);
RenderSceneDepth();
GraphicsDevice.SetRenderTarget(renderTargetCube, CubeMapFace.NegativeY);
SetCreateView(worldLight.Translation, Vector3.Down, Vector3.Forward);
RenderSceneDepth();
GraphicsDevice.SetRenderTarget(renderTargetCube, CubeMapFace.NegativeZ);
SetCreateView(worldLight.Translation, Vector3.Forward, Vector3.Up);
RenderSceneDepth();
GraphicsDevice.SetRenderTarget(renderTargetCube, CubeMapFace.PositiveX);
SetCreateView(worldLight.Translation, Vector3.Right, Vector3.Up);
RenderSceneDepth();
GraphicsDevice.SetRenderTarget(renderTargetCube, CubeMapFace.PositiveY);
SetCreateView(worldLight.Translation, Vector3.Up, Vector3.Backward);
RenderSceneDepth();
GraphicsDevice.SetRenderTarget(renderTargetCube, CubeMapFace.PositiveZ);
SetCreateView(worldLight.Translation, Vector3.Backward, Vector3.Up);
RenderSceneDepth();
//
// Draw the scene with shadow from our depth cube.
//
GraphicsDevice.SetRenderTarget(null); // Switch back to the buffer.
SetCreateView(BasicStuff.camera.World); // We switch our view to the scene camera.
// Draw the scene with shadow.
DrawSceneWithShadowing();
// Draw the visualization enviromental cube. , note don't bother rotating it into place
DrawVisualizationCube();
base.Draw(gameTime);
}
public void RenderSceneDepth()
{
effect.CurrentTechnique = effect.Techniques["RenderShadowDepth"];
effect.Parameters["worldLightPosition"].SetValue(worldLight.Translation);
//// render grids depth // Dont render this depth for the moment.
//SetWorld(worldGrid);
//grid.Draw(GraphicsDevice, effect, 0);
//grid.Draw(GraphicsDevice, effect, 1);
//grid.Draw(GraphicsDevice, effect, 2);
// render cubes depth
effect.Parameters["TextureA"].SetValue(BasicTextures.checkerBoard);
effect.Parameters["TextureB"].SetValue(renderTargetCube);
for (int i = 0; i < worldCubes.Length;i++)
{
SetWorld(worldCubes[i]);
cube.Draw(GraphicsDevice, effect);
}
}
public void DrawSceneWithShadowing()
{
effect.CurrentTechnique = effect.Techniques["LightShadowCubeBasicShader"];
effect.Parameters["worldLightPosition"].SetValue(worldLight.Translation);
SetCreateView(BasicStuff.camera.World); // We switch our view to camera.
// draw grid
SetWorld(worldGrid);
effect.Parameters["TextureB"].SetValue(renderTargetCube);
//
effect.Parameters["TextureA"].SetValue(BasicTextures.red);
grid.Draw(GraphicsDevice, effect, 0);
effect.Parameters["TextureA"].SetValue(BasicTextures.green);
grid.Draw(GraphicsDevice, effect, 1);
effect.Parameters["TextureA"].SetValue(BasicTextures.blue);
grid.Draw(GraphicsDevice, effect, 2);
// draw cubes
effect.Parameters["TextureA"].SetValue(BasicTextures.checkerBoard);
effect.Parameters["TextureB"].SetValue(renderTargetCube);
for (int i = 0; i < worldCubes.Length; i++)
{
SetWorld(worldCubes[i]);
cube.Draw(GraphicsDevice, effect);
}
}
public void DrawVisualizationCube()
{
// draw a cube at the light with the depth visualization
effect.CurrentTechnique = effect.Techniques["DepthVisualization"];
SetWorld(worldLight);
effect.Parameters["TextureA"].SetValue(BasicTextures.checkerBoard);
effect.Parameters["TextureB"].SetValue(renderTargetCube);
cube.Draw(GraphicsDevice, effect);
}
//____________________
// some extra helper stuff
// ___________________
Matrix CreateWorldToTarget(Vector3 position, Vector3 targetPosition, Vector3 up)
{
return Matrix.CreateWorld(position, targetPosition - position, up);
}
void SetWorld(Matrix World)
{
world = World;
effect.Parameters["World"].SetValue(world);
}
void SetCreateView(Matrix worldForCamera)
{
view = Matrix.CreateLookAt(worldForCamera.Translation, worldForCamera.Forward + worldForCamera.Translation, worldForCamera.Up);
effect.Parameters["View"].SetValue(view);
}
void SetCreateView(Vector3 position, Vector3 direction, Vector3 up)
{
view = Matrix.CreateLookAt(position, position + direction, up);
effect.Parameters["View"].SetValue(view);
}
Vector3 GetViewPosition()
{
return view.Translation;
}
// humm should i be using the lights view position because of the targetcube.
Vector3 GetLightPosition(Matrix theLightsWorldMatrix)
{
var temp = Matrix.CreateLookAt(theLightsWorldMatrix.Translation, theLightsWorldMatrix.Forward + theLightsWorldMatrix.Translation, theLightsWorldMatrix.Up);
return temp.Translation;
}
void SetProjection(Matrix Projection)
{
projection = Projection;
effect.Parameters["Projection"].SetValue(projection);
}
void SetCreatePerspectiveProjection(float near, float far, float fovInDegrees)
{
projection= Matrix.CreatePerspectiveFieldOfView((float)MathHelper.Pi * MathHelper.ToRadians(fovInDegrees), GraphicsDevice.Viewport.Width / GraphicsDevice.Viewport.Height, near, far);
effect.Parameters["Projection"].SetValue(projection);
}
}
}
shader
//____________________
//EffectCubeMap.fx
//____________________
#if OPENGL
#define SV_POSITION POSITION
#define VS_SHADERMODEL vs_3_0
#define PS_SHADERMODEL ps_3_0
#else
#define VS_SHADERMODEL vs_4_0_level_9_1
#define PS_SHADERMODEL ps_4_0_level_9_1
#endif
//_______________________
// Common Functions
//_______________________
// _______________________
// Texture samplers.
//_______________________
Texture TextureA; // primary texture.
Texture TextureB; // render texture or secondary multi texture.
sampler TextureSamplerA = sampler_state
{
texture = <TextureA>;
//magfilter = LINEAR; //minfilter = LINEAR; //mipfilter = LINEAR; //AddressU = mirror; //AddressV = mirror;
};
sampler TextureSamplerB = sampler_state
{
texture = <TextureB>;
//magfilter = LINEAR; //minfilter = LINEAR; //mipfilter = LINEAR; //AddressU = mirror; //AddressV = mirror;
};
//_______________________
// Shader globals
//_______________________
matrix World;
matrix View;
matrix Projection;
float3 worldLightPosition;
//_______________________________________________________________
// technique
// Render shadow depth
//_______________________________________________________________/
struct VsInputCalcSceneDepth
{
float4 Position : POSITION0;
float2 TexCoords : TEXCOORD0;
};
struct VsOutputCalcSceneDepth
{
float4 Position : SV_Position;
float4 Position3D : TEXCOORD0;
};
// Shader.
VsOutputCalcSceneDepth CreateDepthMapVertexShader(VsInputCalcSceneDepth input)//(float4 inPos : POSITION)
{
VsOutputCalcSceneDepth output;
output.Position3D = mul(input.Position, World);
float4x4 wvp = mul(World, mul(View, Projection));
output.Position = mul(input.Position, wvp);
return output;
}
float4 CreateDepthMapPixelShader(VsOutputCalcSceneDepth input) : COLOR
{
float lightDepth = input.Position3D.z;
return lightDepth;
}
//_________
// techniques
technique RenderShadowDepth
{
pass Pass0
{
VertexShader = compile VS_SHADERMODEL CreateDepthMapVertexShader();
PixelShader = compile PS_SHADERMODEL CreateDepthMapPixelShader();
}
}
//_______________________________________________________________
// technique
// DrawLightOrShadow
//_______________________________________________________________
struct VsInLightShadow
{
float4 Position : POSITION0;
float3 Normal : NORMAL0;
float2 TexureCoordinateA : TEXCOORD0;
};
struct VsOutLightShadow
{
float4 Position : SV_Position;
float2 TexureCoordinateA : TEXCOORD0;
float4 Position3D : TEXCOORD1;
};
struct PsOutLightShadow
{
float4 Color : COLOR0;
};
// shaders
VsOutLightShadow VsLightShadow(VsInLightShadow input)
{
VsOutLightShadow output;
output.Position3D = mul(input.Position, World);
float4x4 wvp = mul(World, mul(View, Projection));
output.Position = mul(input.Position, wvp);
output.TexureCoordinateA = input.TexureCoordinateA;
return output;
}
PsOutLightShadow PsLightShadow(VsOutLightShadow input)
{
PsOutLightShadow output;
float3 pixelpos = input.Position3D;
float3 lightpos = worldLightPosition;
float3 lightToPixelDir = pixelpos - lightpos;
float pixelDistance = distance(pixelpos, lightpos);
float4 texelcolor = tex2D(TextureSamplerA, input.TexureCoordinateA); // *input.Color;
float shadowDepth = texCUBE(TextureSamplerB, float4(lightToPixelDir, 0)).x;
if (shadowDepth < pixelDistance)
texelcolor = float4(0.7f, 0.7f, 0.7f, 1.0f); // light gray
output.Color = texelcolor;
return output;
}
//_________
// techniques
technique LightShadowCubeBasicShader
{
pass
{
VertexShader = compile VS_SHADERMODEL VsLightShadow();
PixelShader = compile PS_SHADERMODEL PsLightShadow();
}
}
//_______________________________________________________________
// technique
// Depth Visualization
//_______________________________________________________________
// shaders
VsOutLightShadow VsDepthVisualization(VsInLightShadow input)
{
VsOutLightShadow output;
output.Position3D = mul(input.Position, World);
float4x4 wvp = mul(World, mul(View, Projection));
output.Position = mul(input.Position, wvp);
output.TexureCoordinateA = input.TexureCoordinateA;
return output;
}
PsOutLightShadow PsDepthVisualization(VsOutLightShadow input)
{
PsOutLightShadow output;
float3 pixelpos = input.Position3D.xyz; // / input.Position3D.w;
float3 lightpos = worldLightPosition;
float3 lightToPixelDir = pixelpos - lightpos;
float4 texelcolor = tex2D(TextureSamplerA, input.TexureCoordinateA);
float shadowDepth = texCUBE(TextureSamplerB, float4(lightToPixelDir, 0)).x;
texelcolor = (texelcolor + shadowDepth) * 0.5f;
output.Color = texelcolor;
return output;
}
technique DepthVisualization
{
pass
{
VertexShader = compile VS_SHADERMODEL VsDepthVisualization();
PixelShader = compile PS_SHADERMODEL PsDepthVisualization();
}
}
Now if i change this.
pixelposition despite the name and all of the comparison variables should be in world space.
/*if (shadowDepth < pixelDistance)*/
if (shadowDepth < pixelpos.z)
i get this below…
What is even happening here i have no idea.
As the grid lines are not being depth rendered.
I can zip up the project, if you want to take a look at the whole thing.
Newer bug test is below.
OK, I got it working. Here are the main things I had to change:
You used the normal scene camera projection matrix also for the shadowmap. The shadowmap camera needs to have aspect ratio 1.
Return distance(worldLightPosition, input.Position3D) instead of Position3D.z in CreateDepthMapPixelShader.
Add a bit of an offset to avoid z-fighting In PsLightShadow:
if (shadowDepth*1.01 < lightToPixelDist)
Removed all rotations from the DepthVisualization shader. The shadowmap cube needs to be world-axis aligned.
The RenderTargetCube needs to be cleared to max depth rather than black. Since you can’t clear to values bigger than 1 with the default clearscreen (you need a custom shader), I just surrounded the scene with a huge cube in RenderSceneDepth.
The top and bottom faces might still need the up vector corrected. There’s nothing above or below the light, so I couldn’t check that.
The corrected game class:
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using System;
namespace TestTextureCube
{
public class Game1 : Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
RenderTargetCube renderTargetCube;
Effect effect;
//
float near = .1f;
float far = 1000f;
//
Matrix world, view, projection;
Matrix worldGrid, worldCamera, worldLight, worldCube;
Matrix mainProjection, shadowMapProjection;
// well draw a bunch.
Matrix[] worldCubes;
int numberOfCubes = 30;
Vector3 theLightsViewPosition;
// something to draw
Grid3dOrientation grid = new Grid3dOrientation(30, 30, .001f);
CubePNTT cube = new CubePNTT(true);
Quad quad = new Quad(1.7f); // 2.0 is screen scale with a wvp identity matrix.
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
}
protected override void Initialize()
{
base.Initialize();
}
protected override void LoadContent()
{
spriteBatch = this.LoadBasics("Shadow Cube test");
effect = Content.Load<Effect>("EffectCubeMap");
renderTargetCube = new RenderTargetCube(GraphicsDevice, 512, false, SurfaceFormat.Single, DepthFormat.Depth24);
//effect.Parameters["farPlane"].SetValue(far);
world = Matrix.Identity;
SetCreateView(world);
mainProjection = Matrix.CreatePerspectiveFieldOfView((float)MathHelper.Pi * .5f, (float)GraphicsDevice.Viewport.Width / GraphicsDevice.Viewport.Height, near, far);
shadowMapProjection = Matrix.CreatePerspectiveFieldOfView((float)MathHelper.Pi * .5f, 1, near, far);
worldLight = CreateWorldToTarget(new Vector3(3f, 2f, -2f), Vector3.Zero, Vector3.Up);
worldGrid = Matrix.CreateScale(30f) * Matrix.CreateWorld(Vector3.Zero, Vector3.Forward, Vector3.Up);
worldCube = Matrix.CreateScale(1f) * CreateWorldToTarget(new Vector3(3f, .1f, -.5f), Vector3.Zero, Vector3.Up);
worldCamera = CreateWorldToTarget(new Vector3(.5f, -.5f, 4f), Vector3.Zero, Vector3.Up);
MakeBunchesOfCubes();
BasicStuff.camera.CameraType(BasicCamera.MOVEMENT_CAMERA);
BasicStuff.camera.SetPosition(worldCamera.Translation);
}
void MakeBunchesOfCubes()
{
// spiral
var pi2 = MathHelper.Pi *2f;
int len = numberOfCubes;
worldCubes = new Matrix[len];
for(int i = 0; i < len; i++)
{
float r = (float)(i) / (float)(len);
var t = (r) * pi2 * 2f; // 12 radians 2 circles
var x = (float)Math.Sin(t);
var y = 0f;
var z = (float)Math.Cos(t);
Vector3 p = new Vector3(x,y,z) * (1f + r * 5f ) + worldLight.Translation; // spirals instead
worldCubes[i] = Matrix.CreateScale(.05f + r * 1.6f) * Matrix.CreateWorld(p, Vector3.Forward, Vector3.Up);
}
}
protected override void UnloadContent()
{
this.UnloadBasics();
}
protected override void Update(GameTime gameTime)
{
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || Keyboard.GetState().IsKeyDown(Keys.Escape))
Exit();
BasicStuff.Update(gameTime);
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
SetProjection(shadowMapProjection);
GraphicsDevice.Clear(Color.Black);
GraphicsDevice.Clear(ClearOptions.DepthBuffer, Color.Black, 1, 0);
GraphicsDevice.RasterizerState = new RasterizerState() { FillMode = FillMode.Solid, CullMode = CullMode.None };
GraphicsDevice.DepthStencilState = new DepthStencilState() { DepthBufferEnable = true, DepthBufferFunction = CompareFunction.LessEqual };
//
// Render to each face of the cube this will need a spacial partition of some type later on.
GraphicsDevice.SetRenderTarget(renderTargetCube, CubeMapFace.NegativeX);
SetCreateView(worldLight.Translation, Vector3.Left, Vector3.Down);
RenderSceneDepth();
GraphicsDevice.SetRenderTarget(renderTargetCube, CubeMapFace.NegativeY);
SetCreateView(worldLight.Translation, Vector3.Down, Vector3.Forward);
RenderSceneDepth();
GraphicsDevice.SetRenderTarget(renderTargetCube, CubeMapFace.NegativeZ);
SetCreateView(worldLight.Translation, Vector3.Forward, Vector3.Down);
RenderSceneDepth();
GraphicsDevice.SetRenderTarget(renderTargetCube, CubeMapFace.PositiveX);
SetCreateView(worldLight.Translation, Vector3.Right, Vector3.Down);
RenderSceneDepth();
GraphicsDevice.SetRenderTarget(renderTargetCube, CubeMapFace.PositiveY);
SetCreateView(worldLight.Translation, Vector3.Up, Vector3.Backward);
RenderSceneDepth();
GraphicsDevice.SetRenderTarget(renderTargetCube, CubeMapFace.PositiveZ);
SetCreateView(worldLight.Translation, Vector3.Backward, Vector3.Down);
RenderSceneDepth();
//
// Draw the scene with shadow from our depth cube.
//
SetProjection(mainProjection);
GraphicsDevice.SetRenderTarget(null); // Switch back to the buffer.
SetCreateView(BasicStuff.camera.World); // We switch our view to the scene camera.
// Draw the scene with shadow.
DrawSceneWithShadowing();
// Draw the visualization enviromental cube. , note don't bother rotating it into place
DrawVisualizationCube();
base.Draw(gameTime);
}
public void RenderSceneDepth()
{
effect.CurrentTechnique = effect.Techniques["RenderShadowDepth"];
effect.Parameters["worldLightPosition"].SetValue(worldLight.Translation);
//// render grids depth // we wont render this depth for the moment.
//SetWorld(worldGrid);
//grid.Draw(GraphicsDevice, effect, 0);
//grid.Draw(GraphicsDevice, effect, 1);
//grid.Draw(GraphicsDevice, effect, 2);
// render cubes depth
//effect.Parameters["TextureA"].SetValue(BasicTextures.checkerBoard);
//effect.Parameters["TextureB"].SetValue(renderTargetCube);
// draw huge background cube, replaces clearing the rendertarget to maxdepth
SetWorld(Matrix.CreateScale(far/2));
cube.Draw(GraphicsDevice, effect);
// draw regular cubes
for (int i = 0; i < worldCubes.Length;i++)
{
SetWorld(worldCubes[i]);
cube.Draw(GraphicsDevice, effect);
}
}
public void DrawSceneWithShadowing()
{
effect.CurrentTechnique = effect.Techniques["LightShadowCubeBasicShader"];
effect.Parameters["worldLightPosition"].SetValue(worldLight.Translation);
SetCreateView(BasicStuff.camera.World); // We switch our view to camera.
// draw grid
SetWorld(worldGrid);
effect.Parameters["TextureB"].SetValue(renderTargetCube);
//
effect.Parameters["TextureA"].SetValue(BasicTextures.red);
grid.Draw(GraphicsDevice, effect, 0);
effect.Parameters["TextureA"].SetValue(BasicTextures.green);
grid.Draw(GraphicsDevice, effect, 1);
effect.Parameters["TextureA"].SetValue(BasicTextures.blue);
grid.Draw(GraphicsDevice, effect, 2);
// draw cubes
effect.Parameters["TextureA"].SetValue(BasicTextures.checkerBoard);
effect.Parameters["TextureB"].SetValue(renderTargetCube);
for (int i = 0; i < worldCubes.Length; i++)
{
SetWorld(worldCubes[i]);
cube.Draw(GraphicsDevice, effect);
}
}
public void DrawVisualizationCube()
{
// draw a cube at the light with the depth visualization
effect.CurrentTechnique = effect.Techniques["DepthVisualization"];
effect.Parameters["worldLightPosition"].SetValue(worldLight.Translation);
effect.Parameters["TextureB"].SetValue(renderTargetCube);
cube.Draw(GraphicsDevice, effect);
}
//____________________
// some extra helper stuff
// ___________________
Matrix CreateWorldToTarget(Vector3 position, Vector3 targetPosition, Vector3 up)
{
return Matrix.CreateWorld(position, targetPosition - position, up);
}
void SetWorld(Matrix World)
{
world = World;
effect.Parameters["World"].SetValue(world);
}
void SetCreateView(Matrix worldForCamera)
{
view = Matrix.CreateLookAt(worldForCamera.Translation, worldForCamera.Forward + worldForCamera.Translation, worldForCamera.Up);
effect.Parameters["View"].SetValue(view);
}
void SetCreateView(Vector3 position, Vector3 direction, Vector3 up)
{
view = Matrix.CreateLookAt(position, position + direction, up);
effect.Parameters["View"].SetValue(view);
}
Vector3 GetViewPosition()
{
return view.Translation;
}
// humm im not to sure about this.
Vector3 GetLightPosition(Matrix theLightsWorldMatrix)
{
var temp = Matrix.CreateLookAt(theLightsWorldMatrix.Translation, theLightsWorldMatrix.Forward + theLightsWorldMatrix.Translation, theLightsWorldMatrix.Up);
return temp.Translation;
}
void SetProjection(Matrix Projection)
{
projection = Projection;
effect.Parameters["Projection"].SetValue(projection);
}
void SetCreatePerspectiveProjection(float near, float far, float fovInDegrees)
{
projection= Matrix.CreatePerspectiveFieldOfView((float)MathHelper.Pi * MathHelper.ToRadians(fovInDegrees), GraphicsDevice.Viewport.Width / GraphicsDevice.Viewport.Height, near, far);
effect.Parameters["Projection"].SetValue(projection);
}
}
}
and the corrected shader:
//____________________
//EffectCubeMap.fx
//____________________
#if OPENGL
#define SV_POSITION POSITION
#define VS_SHADERMODEL vs_3_0
#define PS_SHADERMODEL ps_3_0
#else
#define VS_SHADERMODEL vs_4_0_level_9_1
#define PS_SHADERMODEL ps_4_0_level_9_1
#endif
//_______________________
// Common Functions
//_______________________
// _______________________
// Texture samplers.
//_______________________
Texture TextureA; // primary texture.
Texture TextureB; // render texture or secondary multi texture.
sampler TextureSamplerA = sampler_state
{
texture = <TextureA>;
//magfilter = LINEAR; //minfilter = LINEAR; //mipfilter = LINEAR; //AddressU = mirror; //AddressV = mirror;
};
sampler TextureSamplerB = sampler_state
{
texture = <TextureB>;
//magfilter = LINEAR; //minfilter = LINEAR; //mipfilter = LINEAR; //AddressU = mirror; //AddressV = mirror;
};
//_______________________
// Shader globals
//_______________________
matrix World;
matrix View;
matrix Projection;
float3 worldLightPosition;
//_______________________________________________________________
// technique
// Render shadow depth
//_______________________________________________________________/
struct VsInputCalcSceneDepth
{
float4 Position : POSITION0;
};
struct VsOutputCalcSceneDepth
{
float4 Position : SV_Position;
float4 Position3D : TEXCOORD0;
};
// Shader.
VsOutputCalcSceneDepth CreateDepthMapVertexShader(VsInputCalcSceneDepth input)//(float4 inPos : POSITION)
{
VsOutputCalcSceneDepth output;
output.Position3D = mul(input.Position, World);
float4x4 vp = mul(View, Projection);
output.Position = mul(output.Position3D, vp);
return output;
}
float4 CreateDepthMapPixelShader(VsOutputCalcSceneDepth input) : COLOR
{
return distance(worldLightPosition, input.Position3D);
}
//_________
// techniques
technique RenderShadowDepth
{
pass Pass0
{
VertexShader = compile VS_SHADERMODEL CreateDepthMapVertexShader();
PixelShader = compile PS_SHADERMODEL CreateDepthMapPixelShader();
}
}
//_______________________________________________________________
// technique
// DrawLightOrShadow
//_______________________________________________________________
struct VsInLightShadow
{
float4 Position : POSITION0;
float3 Normal : NORMAL0;
float2 TexureCoordinateA : TEXCOORD0;
};
struct VsOutLightShadow
{
float4 Position : SV_Position;
float2 TexureCoordinateA : TEXCOORD0;
float4 Position3D : TEXCOORD1;
};
struct PsOutLightShadow
{
float4 Color : COLOR0;
};
// shaders
VsOutLightShadow VsLightShadow(VsInLightShadow input)
{
VsOutLightShadow output;
output.Position3D = mul(input.Position, World);
float4x4 vp = mul(View, Projection);
output.Position = mul(output.Position3D, vp);
output.TexureCoordinateA = input.TexureCoordinateA;
return output;
}
PsOutLightShadow PsLightShadow(VsOutLightShadow input)
{
PsOutLightShadow output;
float3 pixelpos = input.Position3D.xyz;
float3 lightpos = worldLightPosition;
float3 lightToPixelDir = pixelpos - lightpos;
float lightToPixelDist = length(lightToPixelDir);
float4 texelcolor = tex2D(TextureSamplerA, input.TexureCoordinateA); // *input.Color;
float shadowDepth = texCUBE(TextureSamplerB, float4(lightToPixelDir, 0)).x;
if (shadowDepth*1.01 < lightToPixelDist)
texelcolor *= float4(0.3f, 0.3f, 0.3f, 1.0f); // dark gray
output.Color = texelcolor;
return output;
}
//_________
// techniques
technique LightShadowCubeBasicShader
{
pass
{
VertexShader = compile VS_SHADERMODEL VsLightShadow();
PixelShader = compile PS_SHADERMODEL PsLightShadow();
}
}
//_______________________________________________________________
// technique
// Depth Visualization
//_______________________________________________________________
// shaders
struct VsOutDepthVisualization
{
float4 Position : SV_Position;
float3 dir : TEXCOORD0;
};
VsOutDepthVisualization VsDepthVisualization(VsInLightShadow input)
{
VsOutDepthVisualization output;
float4 worldPos = float4(worldLightPosition + input.Position, 1);
float4x4 vp = mul(View, Projection);
output.Position = mul(worldPos, vp);
output.dir = input.Position;
return output;
}
float4 PsDepthVisualization(VsOutDepthVisualization input) : COLOR
{
float shadowDepth = texCUBE(TextureSamplerB, float4(input.dir, 0)).x;
return shadowDepth * 0.1;
}
technique DepthVisualization
{
pass
{
VertexShader = compile VS_SHADERMODEL VsDepthVisualization();
PixelShader = compile PS_SHADERMODEL PsDepthVisualization();
}
}
//_______________________________________________________________
// techniques
// Quad Draw
//_______________________________________________________________
struct VsInputQuad
{
float4 Position : POSITION0;
float3 Normal : NORMAL0;
float2 TexureCoordinateA : TEXCOORD0;
};
struct VsOutputQuad
{
float4 Position : SV_Position;
float2 TexureCoordinateA : TEXCOORD0;
};
struct PsOutputQuad
{
float4 Color : COLOR0;
};
// ____________________________
VsOutputQuad VertexShaderQuadDraw(VsInputQuad input)
{
VsOutputQuad output;
float4x4 wvp = mul(World, mul(View, Projection));
output.Position = mul(input.Position, wvp); // basically matrix identity
output.TexureCoordinateA = input.TexureCoordinateA;
return output;
}
PsOutputQuad PixelShaderQuadDraw(VsOutputQuad input)
{
PsOutputQuad output;
output.Color = tex2D(TextureSamplerA, input.TexureCoordinateA); // *input.Color;
return output;
}
technique QuadDraw
{
pass
{
VertexShader = compile VS_SHADERMODEL VertexShaderQuadDraw();
PixelShader = compile PS_SHADERMODEL PixelShaderQuadDraw();
}
}
//__________________________
//struct VertexShaderInput
//{
// float4 Position : POSITION0;
// float4 Color : COLOR0;
//};
//
//struct VertexShaderOutput
//{
// float4 Position : SV_POSITION;
// float4 Color : COLOR0;
//};
//
//VertexShaderOutput MainVS(in VertexShaderInput input)
//{
// VertexShaderOutput output = (VertexShaderOutput)0;
//
// output.Position = mul(input.Position, WorldViewProjection);
// output.Color = input.Color;
//
// return output;
//}
//
//float4 MainPS(VertexShaderOutput input) : COLOR
//{
// return input.Color;
//}
//
//technique BasicColorDrawing
//{
// pass P0
// {
// VertexShader = compile VS_SHADERMODEL MainVS();
// PixelShader = compile PS_SHADERMODEL MainPS();
// }
//};
EDIT
Fixed the aspect ratio for the main camera as well. Wit the integer division you are loosing everything after the comma.
Edit
Oh snap it almost works.
I was racking my brain till my eyeballs were poping out.
Ill have to wait till i have more time later, to study the changes you made.
Ill probably simplify it later on and leave a trimmed down example for others as a reference.
Thanks so much markus.
Ah ok this is not so solved as i thought.
Last night i had some time to mess with this again and i was double checking it after i drew the grid lines and they were off.
So i altered the cube draw to be off tilt to check it.
i got the below.
No problem i thought ill manually fit each cube face to place.
I figured the view would have to be tweeked anyways.
but …
What i didn’t expect is that the coordinates couldn’t be tweeked no matter what orthagonal up i placed for the forward view that corresponds to the negativeZ render cube, it appears to be giving me back inverse Y coordinates or inverse X coordinates no matter what up i set for the view matrix.
No matter how i change it, if i use the up down right or left on every one of them i get a bad mapping to the shadow u,v depth texture.
Not sure how to handle this if i should try to transpose the matrix’s before sending them, try that on the shader, or reverse the direction and flip the view forward to the positive z render ? I can’t manually invert the u or v on the render cube.
Or is it possible im missing something simple entirely?
.
.
.
ill upload the newer test in a minute if anyone has any thoughts so they can run it themselves.
It’s messier but the first ones in there too, i fixed a couple things in between like the cube so its properly aligned to a regular cube or skybox with individual textures makes it easier to see.
Edit: tried everything i could think off the forward alone only appears to align with a up of right but it still wont align with the shadow. Doing it the old way i can’t transpose the matrix to make it align in the shader… Im stumped i looked at kosmotos shader but hes using a orthographic. projection.
I think the problem is that Matrix.CreateLookAt creates a right-handed view matrix, but those cubemaps want left-handed DirectX coordinates. You could fix it in the texCUBE lookup, but you can also just make a left-handed view matrix like that:
void SetCreateCubeMapView(Vector3 position, Vector3 direction, Vector3 up)
{
Matrix view = Matrix.Identity;
view.Translation = position;
view.Forward = direction;
view.Up = up;
view.Right = Vector3.Cross(up, direction);
view = Matrix.Invert(view);
effect.Parameters["View"].SetValue(view);
}
You should be able to optimize this to get rid of the matrix inversion, but it works. You can then create the individual cube faces like that:
GraphicsDevice.SetRenderTarget(renderTargetCube, CubeMapFace.NegativeX);
SetCreateCubeMapView(worldLight.Translation, Vector3.Left, Vector3.Up);
RenderSceneDepth();
GraphicsDevice.SetRenderTarget(renderTargetCube, CubeMapFace.NegativeY); // bottom
SetCreateCubeMapView(worldLight.Translation, Vector3.Down, Vector3.Backward); // bottom
RenderSceneDepth();
GraphicsDevice.SetRenderTarget(renderTargetCube, CubeMapFace.NegativeZ); // front
SetCreateCubeMapView(worldLight.Translation, Vector3.Forward, Vector3.Up);// front
RenderSceneDepth();
GraphicsDevice.SetRenderTarget(renderTargetCube, CubeMapFace.PositiveX);
SetCreateCubeMapView(worldLight.Translation, Vector3.Right, Vector3.Up);
RenderSceneDepth();
GraphicsDevice.SetRenderTarget(renderTargetCube, CubeMapFace.PositiveY); // top
SetCreateCubeMapView(worldLight.Translation, Vector3.Up, Vector3.Forward); // top
RenderSceneDepth();
GraphicsDevice.SetRenderTarget(renderTargetCube, CubeMapFace.PositiveZ);
SetCreateCubeMapView(worldLight.Translation, Vector3.Backward, Vector3.Up);
RenderSceneDepth();
Thats a world matrix with the right negated then inverted also.
Humm
I can just hard code the values and pre-compute them as long as i don’t want to spin the rendering.
but…
Shouldn’t this be considered a bug ?
That its very much un-intuitive behavior at the least.
This is the same on dx as well as gl.
Well im glad your here cause i don’t think i would of figured it out i was trying all kinds of stuff.
That’s what a view matrix basically is. It’s just the camera’s world matrix, but inverted. It makes a lot of sense when you think about it. If your camera moves towards the right, your view of the world moves towards the left. If you camera rotates clockwise, your view rotates counterclockwise. Your view always does the exact opposite of you camera, that’s what the inversion is for.
It definitely looks like a coordinate system inconsistency. I don’t know what the exact backstory is here.
@kosmonautgames I’d be interested to hear if you experienced the same. Did you also have to make you view matrix left-handed, or, change the lookup-direction in texCUBE to compensate for left/right handedness?
Ya but the view matrix alters the position a bit if i remember right were the create world doesn’'t well not on its own it doesn’t.
Im still a little worried about how that might affect the uv calculation on the cube under perspective.
Now that its clear whats going on though.
I suppose if it really turns out to be a problem i can find the direct dx create LH LookAt function the code is on the msdn somewere i found it before.
Still i feel like this needs documentation or a outright helper method in the rendertargetcube itself or something to make this clear. I mean this is going to end up a extension method for sure for me.
I think it’s fine, you’ve probably just looked at view matrix code that optimized away the inversion.
Or just take the Monogame CreateLookat code and negate the right vector.
Agreed.
Thanks again markus.
I put up a issue about this on github.
just take the Monogame CreateLookat code and negate the right vector.
Not sure this is right but it appears to be.
public Matrix CreateLookAtLeftHanded( Vector3 cameraPosition, Vector3 cameraTarget, Vector3 cameraUpVector)
{
var vector = Vector3.Normalize(cameraPosition - cameraTarget);
var vector2 = -Vector3.Normalize(Vector3.Cross(cameraUpVector, vector));
var vector3 = Vector3.Cross(-vector, vector2);
Matrix result = Matrix.Identity;
result.M11 = vector2.X;
result.M12 = vector3.X;
result.M13 = vector.X;
result.M14 = 0f;
result.M21 = vector2.Y;
result.M22 = vector3.Y;
result.M23 = vector.Y;
result.M24 = 0f;
result.M31 = vector2.Z;
result.M32 = vector3.Z;
result.M33 = vector.Z;
result.M34 = 0f;
result.M41 = -Vector3.Dot(vector2, cameraPosition);
result.M42 = -Vector3.Dot(vector3, cameraPosition);
result.M43 = -Vector3.Dot(vector, cameraPosition);
result.M44 = 1f;
return result;
}
Here is a Desktop GL demo version that demonstrates the results of the post for reference.
I also found a inconsistancy on Dx.
Within the shader this struct will run on GL uncommented but not on DX.
struct VsInLightShadow
{
float4 Position : POSITION0;
// float3 Normal : NORMAL0; // uncommented this will run on gl but not on dx.
float2 TexureCoordinateA : TEXCOORD0;
};
Well it seems im finding a lot of weird bugs with using the rendertargetcube.
Here is one that really is weird.
The depth buffer is recording weird depths along objects it looks cool but these are visible error shadows on the textures of the objects. The actual visual shadow error on the objects themselves is really terrible looking.
looking at what the cube see’s for depths i get this. you can litterally see the bad shadow depths.
Im guessing this is a precision error why and how i have no idea
What exactly are we looking at here? Are you outputting depth from the main camera with some RGB conversion?
Thats from inside the the light cube what it sees as shadows red green blue represent different depths.
The first issue with lines showing up here and there i just figured out.
The RenderTargetCube texture sampler needs to have its Address u v set to clamp.
The other issue with those circles and lines in purple appearing on the spheres and cubes i havent. Looking at it from the lights depth view above it appears to be localized and have some pattern. They are extremely ugly shadow depth errors.
This is what its doing visibly.
But im thinking its another sampler state issue, or thier just simply isnt enough precision.
I stuck the encoding back in to get the extra 8 bits and also because i was going to code a reflection cube, but i got side tracked on trying to figure out why these shadows look so bad.
Ive got it bumped up to 32 bits encoded at this point doesn’t really make a difference.
The only artifacts I’m seeing are in the transition areas btw. light and shadow. I’m not seeing anything from those purple circle artifacts.
The light-shadow artifacts get better if you increase the RenderTargetCube resolution, but I’m sure there’s something else you can do to improve this.
SurfaceFormat.Single is already 32 bits per pixel, if you go to Vector4 you get 128 bits per pixel, which is complete overkill for depth. For reflections you should use 8 bit per channel, or 16 bit if you do HDR rendering, otherwise those cubemaps get so large.
if you go to Vector4 you get 128 bits per pixel
Oh i didn’t realize Vector4 in that context was actually 32 bits per element.
Well i probably should of picked color i was only encoding 8 bits per element anyways.
Anyways i cant get a decimal resolution bias less then about here
if (shadowDepth + 0.05 < pixelToLightDist)
For 32 bits of floating point accuracy that doesn’t seem right.
Well this really sucks ^^^^.
The light-shadow artifacts get better if you increase the
RenderTargetCube resolution, but I’m sure there’s something else you can
do to improve this.
Ya uping the res doesn’t do to much im not sure what those circles and lines are going across but they are there. If i lower the bias a bit they become extremely visible. Which is the resolution problem, the lower the bias the better the shadows, but those circles and lines are were z fighting is about to occur, What is causing them i have no clue they shouldn’t be there at all.
The fact they are there is just a additional limitation on lowering the depth bias. It’s just irking me that i don’t know what is going on with that.
What else i can do im not sure, should i look into using a alternate techqnique to blend the shadows or do more sampling around the first sample or something ? Those edges look horrible.
Now that i think about it maybe its wiser to move the shadows onto the vertice shader ?
Possibly even shadow against the normals ?
You mean you RGB encoding? I don’t think you need that anyway, but if you use it, why not encode to 32-bit?
My guess is that a lot of the artifacts come from the cubemap not beeing filtered. Keep in mind that automatic texture filtering for floating point textures only works in newer shader models. In older shader models you have to do it manually. I don’t know off top of my head what the minimum shader model is for automatic filtering.
Ah i dunno what i mean.
The more i think about it the more it doesn’t make sense.
.06 isn’t even 8 bits !
I cant get accurracy to .01 with a 24 bit float ? Worse still a 32 bit float.
Even encoding it im not getting any different accuracy which makes no sense.
Maybe i should just try squaring these values and comparing them instead of finding the lengths.
It’s like any small fractional value has super bad precision period.
Well i couldn’t get more then .06 precision safely no matter what i did so i gave up on it.
Anyways i fliped the culling on the rendered depth cubes.
backed up the shadow.
cut the lighting off the back of the objects
looks decent.
I just have one little problem other then the spritebatch issue.
Im getting specular highlight bleeding thru.
Heres my shader atm i didn’t use the half vector last time but im trying to use it this time the only problem is i don’t know how to stop the bleed thru when using it.
I tried to dot the surface normal against the pixel to camera why its not working i dunno i guess cause the half vector flips.
float4 PsLightShadowNormal(VsOutLightShadowNormal input) : Color
{
float3 pixelToCamera = normalize(CameraPosition - input.Position3D);
float3 pixelToLight = WorldLightPosition - input.Position3D;
float pixelToLightDist = length(pixelToLight);
pixelToLight = pixelToLight / pixelToLightDist; // cheapen a normalize.
float3 cubelookup = -pixelToLight;
//float LightDistanceIntensity = 1.0f - saturate(pixelToLightDist / (IlluminationRange + 0.001f));
float LightDistanceIntensity = 1.0f;
//float shadowDepth = DecodeFloatRGBA(texCUBE(TextureDepthSampler, float4(cubelookup, 0)).xyzw);
float shadowDepth = texCUBE(TextureDepthSampler, float4(cubelookup, 0)).x;
float4 TexelColor = tex2D(TextureSamplerA, input.TexureCoordinateA);
// shadow
float LightOrShadow = 1.0f;
if (shadowDepth + .2f < pixelToLightDist)
LightOrShadow = 0.0f;
// lighting
float3 L = pixelToLight;
float3 N = input.Normal;
float3 H = normalize(pixelToCamera + L);
float DiffuseIntensity = max(dot(N, L) *.9 +.1f, 0.0f);
// Arrrrrrgggggggggggggggg......
float NS = 1.0f;
//float NS = max(dot(N, L), 0.0f);
//NS = sign(DiffuseIntensity); // this straight cuts it off
//float NS =DiffuseIntensity; // this dims it and destroys the specular too much
//float specularRange = max( (dot(N, L) - 0.33f) * 1.5f , 0.0f); //sign(DiffuseIntensity); // sign(dot(N, -CameraForward));
//float NS = max((dot(N, L) + 0.33f) * .66f, 0.0f);
float SpecularIntensity = saturate(dot(H, N) * NS);
SpecularIntensity = pow(SpecularIntensity, SpecularSharpnes);
float3 Ambient = AmbientStrength * TexelColor.rgb;
float3 Diffuse = LightDistanceIntensity * DiffuseIntensity * DiffuseStrength * LightOrShadow * (TexelColor.rgb * LightColor.rgb);
float3 Specular = LightDistanceIntensity * SpecularIntensity * SpecularStrength * LightOrShadow *(TexelColor.rgb * LightColor.rgb);
float3 FinalColor = Ambient + Diffuse + Specular;
return float4(FinalColor, 1.0f);
}