Je crée le moteur de terrain de type MC, et j'ai pensé que l'éclairage le rendrait beaucoup plus agréable Le problème est que les blocs ne sont pas allumés correctement lorsqu'un bloc émettant de la lumière est placé (voir les captures d'écran en bas) sur la page.
Jusqu'à présent, je veux mettre en œuvre l'éclairage "en bloc" de minecraft. J'ai donc créé un VertexFormat:
struct VertexPositionTextureLight
{
Vector3 position;
Vector2 textureCoordinates;
float light;
public readonly static VertexDeclaration VertexDeclaration = new VertexDeclaration
(
new VertexElement(0, VertexElementFormat.Vector3, VertexElementUsage.Position, 0),
new VertexElement(sizeof(float) * 3, VertexElementFormat.Vector2, VertexElementUsage.TextureCoordinate, 0),
new VertexElement(sizeof(float) * 5, VertexElementFormat.Single, VertexElementUsage.TextureCoordinate, 1)
);
public VertexPositionTextureLight(Vector3 position, Vector3 normal, Vector2 textureCoordinate, float light)
{
// I don't know why I included normal data :)
this.position = position;
this.textureCoordinates = textureCoordinate;
this.light = light;
}
}
Je suppose que si je veux implémenter l'éclairage, je dois spécifier une lumière pour chaque sommet ... Et maintenant, dans mon fichier d'effet, je veux pouvoir prendre cette valeur et éclairer le sommet en conséquence:
float4x4 World;
float4x4 Projection;
float4x4 View;
Texture Texture;
sampler2D textureSampler = sampler_state {
Texture = <Texture>;
MipFilter = Point;
MagFilter = Point;
MinFilter = Point;
AddressU = Wrap;
AddressV = Wrap;
};
struct VertexToPixel {
float4 Position : POSITION;
float4 TexCoords : TEXCOORD0;
float4 Light : TEXCOORD01;
};
struct PixelToFrame {
float4 Color : COLOR0;
};
VertexToPixel VertexShaderFunction(float4 inPosition : POSITION, float4 inTexCoords : TEXCOORD0, float4 light : TEXCOORD01) {
VertexToPixel Output = (VertexToPixel)0;
float4 worldPos = mul(inPosition, World);
float4 viewPos = mul(worldPos, View);
Output.Position = mul(viewPos, Projection);
Output.TexCoords = inTexCoords;
Output.Light = light;
return Output;
}
PixelToFrame PixelShaderFunction(VertexToPixel PSIn) {
PixelToFrame Output = (PixelToFrame)0;
float4 baseColor = 0.086f;
float4 textureColor = tex2D(textureSampler, PSIn.TexCoords);
float4 colorValue = pow(PSIn.Light / 16.0f, 1.4f) + baseColor;
Output.Color = textureColor;
Output.Color.r *= colorValue;
Output.Color.g *= colorValue;
Output.Color.b *= colorValue;
Output.Color.a = 1;
return Output;
}
technique Block {
pass Pass0 {
VertexShader = compile vs_2_0 VertexShaderFunction();
PixelShader = compile ps_2_0 PixelShaderFunction();
}
}
VertexToPixel VertexShaderBasic(float4 inPosition : POSITION, float4 inTexCoords : TEXCOORD0) {
VertexToPixel Output = (VertexToPixel)0;
float4 worldPos = mul(inPosition, World);
float4 viewPos = mul(worldPos, View);
Output.Position = mul(viewPos, Projection);
Output.TexCoords = inTexCoords;
return Output;
}
PixelToFrame PixelShaderBasic(VertexToPixel PSIn) {
PixelToFrame Output = (PixelToFrame)0;
Output.Color = tex2D(textureSampler, PSIn.TexCoords);
return Output;
}
technique Basic {
pass Pass0 {
VertexShader = compile vs_2_0 VertexShaderBasic();
PixelShader = compile ps_2_0 PixelShaderBasic();
}
}
Et ceci est un exemple sur la façon dont j'applique l'éclairage:
case BlockFaceDirection.ZDecreasing:
light = world.GetLight((int)(backNormal.X + pos.X), (int)(backNormal.Y + pos.Y), (int)(backNormal.Z + pos.Z));
SolidVertices.Add(new VertexPositionTextureLight(bottomRightBack, backNormal, bottomLeft, light));
SolidVertices.Add(new VertexPositionTextureLight(bottomLeftBack, backNormal, bottomRight, light));
SolidVertices.Add(new VertexPositionTextureLight(topRightBack, backNormal, topLeft, light));
SolidVertices.Add(new VertexPositionTextureLight(topLeftBack, backNormal, topRight, light));
AddIndices(0, 2, 3, 3, 1, 0);
break;
Et enfin, voici l'algorythim qui calcule tout:
public void AddCubes(Vector3 location, float light)
{
AddAdjacentCubes(location, light);
Blocks = new List<Vector3>();
}
public void Update(World world)
{
this.world = world;
}
public void AddAdjacentCubes(Vector3 location, float light)
{
if (light > 0 && !CubeAdded(location))
{
world.SetLight((int)location.X, (int)location.Y, (int)location.Z, (int)light);
Blocks.Add(location);
// Check ajacent cubes
for (int x = -1; x <= 1; x++)
{
for (int y = -1; y <= 1; y++)
{
for (int z = -1; z <= 1; z++)
{
// Make sure the cube checked it not the centre one
if (!(x == 0 && y == 0 && z == 0))
{
Vector3 abs_location = new Vector3((int)location.X + x, (int)location.Y + y, (int)location.Z + z);
// Light travels on transparent block ie not solid
if (!world.GetBlock((int)location.X + x, (int)location.Y + y, (int)location.Z + z).IsSolid)
{
AddAdjacentCubes(abs_location, light - 1);
}
}
}
}
}
}
}
public bool CubeAdded(Vector3 location)
{
for (int i = 0; i < Blocks.Count; i++)
{
if (location.X == Blocks[i].X &&
location.Y == Blocks[i].Y &&
location.Z == Blocks[i].Z)
{
return true;
}
}
return false;
}
Toute suggestion et aide serait très appréciée
CAPTURES D'ÉCRAN Remarquez les artefacts en haut sur le terrain et comment seule la partie gauche est éclairée en particulier ... Pour une raison quelconque, seuls certains côtés du cube sont éclairés et il n'éclaire pas le sol
Compris mon problème! Je ne vérifiais pas si ce bloc était déjà allumé et si oui dans quelle mesure (s'il est plus faible, il est plus haut)
public void DoLight(int x, int y, int z, float light)
{
Vector3 xDecreasing = new Vector3(x - 1, y, z);
Vector3 xIncreasing = new Vector3(x + 1, y, z);
Vector3 yDecreasing = new Vector3(x, y - 1, z);
Vector3 yIncreasing = new Vector3(x, y + 1, z);
Vector3 zDecreasing = new Vector3(x, y, z - 1);
Vector3 zIncreasing = new Vector3(x, y, z + 1);
if (light > 0)
{
light--;
world.SetLight(x, y, z, (int)light);
Blocks.Add(new Vector3(x, y, z));
if (world.GetLight((int)yDecreasing.X, (int)yDecreasing.Y, (int)yDecreasing.Z) < light &&
world.GetBlock((int)yDecreasing.X, (int)yDecreasing.Y, (int)yDecreasing.Z).BlockType == BlockType.none)
DoLight(x, y - 1, z, light);
if (world.GetLight((int)yIncreasing.X, (int)yIncreasing.Y, (int)yIncreasing.Z) < light &&
world.GetBlock((int)yIncreasing.X, (int)yIncreasing.Y, (int)yIncreasing.Z).BlockType == BlockType.none)
DoLight(x, y + 1, z, light);
if (world.GetLight((int)xDecreasing.X, (int)xDecreasing.Y, (int)xDecreasing.Z) < light &&
world.GetBlock((int)xDecreasing.X, (int)xDecreasing.Y, (int)xDecreasing.Z).BlockType == BlockType.none)
DoLight(x - 1, y, z, light);
if (world.GetLight((int)xIncreasing.X, (int)xIncreasing.Y, (int)xIncreasing.Z) < light &&
world.GetBlock((int)xIncreasing.X, (int)xIncreasing.Y, (int)xIncreasing.Z).BlockType == BlockType.none)
DoLight(x + 1, y, z, light);
if (world.GetLight((int)zDecreasing.X, (int)zDecreasing.Y, (int)zDecreasing.Z) < light &&
world.GetBlock((int)zDecreasing.X, (int)zDecreasing.Y, (int)zDecreasing.Z).BlockType == BlockType.none)
DoLight(x, y, z - 1, light);
if (world.GetLight((int)zIncreasing.X, (int)zIncreasing.Y, (int)zIncreasing.Z) < light &&
world.GetBlock((int)zIncreasing.X, (int)zIncreasing.Y, (int)zIncreasing.Z).BlockType == BlockType.none)
DoLight(x, y, z + 1, light);
}
}
A travers les travaux ci-dessus, quelqu'un pourrait-il savoir comment je le rendrais plus performant?