I'd like to have a sort of floor with a programmaically created texture on it. I already created the vertices and the indexes needed for the work:
private VertexPositionNormalTexture[] verticiBase;
private short[] indici;
...
verticiBase = new VertexPositionNormalTexture[4];
verticiBase[0] = new VertexPositionNormalTexture(new Vector3(0.0f, 0.0f, 0.0f), Vector3.Up, new Vector2(0, 0));
verticiBase[1] = new VertexPositionNormalTexture(new Vector3(dimensioneVera.X, 0.0f, 0.0f), Vector3.Up, new Vector2(1, 0));
verticiBase[2] = new VertexPositionNormalTexture(new Vector3(0.0f, 0.0f, dimensioneVera.Y), Vector3.Up, new Vector2(0, 1));
verticiBase[3] = new VertexPositionNormalTexture(new Vector3(dimensioneVera.X, 0.0f, dimensioneVera.Y), Vector3.Up, new Vector2(1, 1));
graphics.GraphicsDevice.VertexDeclaration = new
VertexDeclaration(graphics.GraphicsDevice,
VertexPositionNormalTexture.VertexElements);
indici = new short[6];
indici[0] = 0;
indici[1] = 1;
indici[2] = 2;
indici[3] = 1;
indici[4] = 3;
indici[5] = 2;
Then I created the texture and the data which I'd like to show:
private Texture2D texture;
private Color[] textureData;
...
texture = new Texture2D(Game.GraphicsDevice, (int)dimensioneVera.X, (int)dimensioneVera.Y);
textureData = new Color[(int)dimensioneVera.X * (int)dimensioneVera.Y];
for (int x = 0; x < textureData.Length; x++)
textureData[x] = Color.Red;
texture.SetData(textureData);
And this is the code I used to draw:
private BasicEffect effetti;
...
effetti = new BasicEffect(graphics.GraphicsDevice, null);
...
public override void Draw(GameTime gameTime)
{
effetti.World = Matrix.Identity;
effetti.View = camera.view;
effetti.Projection = camera.projection;
effetti.TextureEnabled = true;
effetti.Texture = texture;
effetti.Begin();
effetti.EnableDefaultLighting();
effetti.CurrentTechnique.Passes[0].Begin();
graphics.GraphicsDevice.DrawUserIndexedPrimitives(PrimitiveType.TriangleList,
verticiBase, 0, verticiBase.Length, indici, 0, indici.Length / 3);
effetti.CurrentTechnique.Passes[0].End();
effetti.End();
base.Draw(gameTime);
}
The floor is displayed but the texture is all black. What's wrong?
Thanks for your time.
I suspect the problem is not that you've created the texture incorrectly. The problem is your lighting; you've called EnableDefaultLighting() but not provided any lights, so everything is completely dark (black). Try setting effetti.AmbientLightColor = Color.White and see if that helps.
Related
I'm making a 2.5D game with Monogame. I have 2D meshes in a 3D space, and I want them to shine. But if I activate default lighting, they're pitch black.
Here the render code:
BasicEffect effect = new BasicEffect(graphicsDevice);
VertexPositionTexture[] vertices =
{
new VertexPositionTexture(new Vector3(-.5f + Position.X, 0.5f + Position.Y, 0.0f), new Vector2(0, 0)),
new VertexPositionTexture(new Vector3(-.5f + Position.X, -.5f + Position.Y, 0.0f), new Vector2(0, 1)),
new VertexPositionTexture(new Vector3(0.5f + Position.X, 0.5f + Position.Y, 0.0f), new Vector2(1, 0)),
new VertexPositionTexture(new Vector3(0.5f + Position.X, -.5f + Position.Y, 0.0f), new Vector2(1, 1)),
};
graphicsDevice.BlendState = BlendState.AlphaBlend;
effect.EnableDefaultLighting();
effect.LightingEnabled = true;
//effect.AmbientLightColor = new Vector3(.75f, .75f, .75f);
effect.DirectionalLight0.DiffuseColor = new Vector3(.75f, .75f, .75f);
effect.DirectionalLight0.Direction = new Vector3(0, 0, -1);
effect.DirectionalLight0.SpecularColor = new Vector3(.75f, .60f, .60f);
effect.TextureEnabled = true;
effect.Texture = Subtexture;
effect.Projection = camera.Fov;
effect.View = camera.ViewMatrix;
effect.World = camera.WorldMatrix;
VertexBuffer buffer = new VertexBuffer(graphicsDevice, typeof(VertexPositionTexture), vertices.Length, BufferUsage.WriteOnly);
buffer.SetData(vertices);
graphicsDevice.SetVertexBuffer(buffer);
graphicsDevice.RasterizerState = RasterizerState.CullNone;
foreach (EffectPass pass in effect.CurrentTechnique.Passes)
{
pass.Apply();
graphicsDevice.DrawUserPrimitives(PrimitiveType.TriangleStrip, vertices, 0, 2);
}
I'm trying to draw a polygon of a solid color. I'm given a vector of 2D vectors, ordered such that there will be an edge from v0 to v1 to v2 to ... to vn to v0.
Does such a primitive exist?
Credit to Stefan Agartsson for the post this answer's code is based upon.
To describe the vertices as edges instead of triangles, You can use the PrimitiveType.LineStrip instead of PrimitiveType.TriangleList you have to adjust the index and counts as well since each vertex is used only once.
BasicEffect basicEffect = new BasicEffect(device);
basicEffect.Texture = myTexture;
basicEffect.TextureEnabled = true;
VertexPositionTexture[] vert = new VertexPositionTexture[4];
vert[0].Position = new Vector3(0, 0, 0); //These connect in order
vert[1].Position = new Vector3(100, 0, 0);
vert[2].Position = new Vector3(100, 100, 0);
vert[3].Position = new Vector3(0, 100, 0);
vert[0].TextureCoordinate = new Vector2(0, 0);
vert[1].TextureCoordinate = new Vector2(1, 0);
vert[2].TextureCoordinate = new Vector2(1, 1);
vert[3].TextureCoordinate = new Vector2(0, 1);
short[] ind = new short[n+1]; // the +1 is to close the shape
for(int i = 0; i < n; i++)
ind[i] = i;
ind[n] = 0; // return to start to close.
Then in your render loop you do this:
foreach (EffectPass effectPass in basicEffect.CurrentTechnique.Passes)
{
effectPass.Apply();
device.DrawUserIndexedPrimitives<VertexPositionTexture>(
PrimitiveType.LineStrip, vert, 0, vert.Length, ind, 0, ind.Length);
}
I want to change color for each line(element) just like in color switch. But my code is not working. Whats wrong with my code?
void Start()
{
lineGeneratorPrefab = new GameObject();
DrawLine();
}
private void DrawLine()
{
GameObject myLine = new GameObject();
myLine.transform.position = start;
myLine.AddComponent<LineRenderer>();
LineRenderer lr = myLine.GetComponent<LineRenderer>();
lr.positionCount = 4;
lr.SetPosition(0, new Vector3(-2, 0, 0));
lr.SetPosition(1, new Vector3(2, 0, 0));
lr.SetPosition(2, new Vector3(2, -2, 0));
lr.SetPosition(3, new Vector3(-2, -2, 0));
lr.materials[2].color = Color.blue;
lr.materials[3].color = Color.red;
}
Take at look here.
Instead of altering the various materials, you could instead change the gradient of the line renderer through the colorGradient property.
So in your case you could add the following:
gradient.SetKeys(
new GradientColorKey[] {
new GradientColorKey(Color.red,0.0f),
new GradientColorKey(Color.red, 0.25f),
new GradientColorKey(Color.blue, 0.5f),
new GradientColorKey(Color.blue, 1.0f)},
// Alpha key
);
If you want a more abrupt transition, you could add color keys at 0.49 and 0.51 for example.
I initially had a function that created a rectangular mesh given a specific height/width:
void BoxMesh(float width, float height)
{
MeshFilter mf = GetComponent<MeshFilter>();
Mesh mesh = new Mesh();
mf.mesh = mesh;
//Verticies
Vector3[] verticies = new Vector3[4]
{
new Vector3(0,0,0), new Vector3(0, height, 0), new Vector3(width, height, 0), new Vector3(width, 0, 0)
};
//Triangles
int[] tri = new int[6];
tri[0] = 0;
tri[1] = 1;
tri[2] = 3;
tri[3] = 1;
tri[4] = 2;
tri[5] = 3;
//normals
Vector3[] normals = new Vector3[4];
normals[0] = -Vector3.forward;
normals[1] = -Vector3.forward;
normals[2] = -Vector3.forward;
normals[3] = -Vector3.forward;
//UVs
Vector2[] uv = new Vector2[4];
uv[0] = new Vector2(0, 0);
uv[1] = new Vector2(0, 1);
uv[2] = new Vector2(1, 1);
uv[3] = new Vector2(1, 0);
//initialise
mesh.vertices = verticies;
mesh.triangles = tri;
mesh.normals = normals;
mesh.uv = uv;
//setting up collider
polyCollider.pathCount = 1;
Vector2[] path = new Vector2[4]
{
new Vector2(0,0), new Vector2(0, height), new Vector2(width, height), new Vector2(width, 0)
};
polyCollider.SetPath(0, path);
}
I then decided I wanted this mesh to have an outline so I edited the function so it is now:
void BoxMesh(float width, float height, float OLwidth)
{
MeshFilter mf = GetComponent<MeshFilter>();
Mesh mesh = new Mesh();
mf.mesh = mesh;
MeshFilter mfOL = GetComponent<MeshFilter>();
Mesh meshOL = new Mesh();
mfOL.mesh = meshOL;
//Verticies
Vector3[] verticies = new Vector3[4]
{
new Vector3(0,0,0), new Vector3(0, height, 0), new Vector3(width, height, 0), new Vector3(width, 0, 0)
};
//Verticies Outline
Vector3[] verticiesOL = new Vector3[4]
{
new Vector3(-OLwidth,-OLwidth,0), new Vector3(-OLwidth, height + OLwidth, 0), new Vector3(width + OLwidth, height + OLwidth, 0), new Vector3(width + OLwidth, -OLwidth, 0)
};
//Triangles
int[] tri = new int[6];
tri[0] = 0;
tri[1] = 1;
tri[2] = 3;
tri[3] = 1;
tri[4] = 2;
tri[5] = 3;
//normals
Vector3[] normals = new Vector3[4];
normals[0] = -Vector3.forward;
normals[1] = -Vector3.forward;
normals[2] = -Vector3.forward;
normals[3] = -Vector3.forward;
//UVs
Vector2[] uv = new Vector2[4];
uv[0] = new Vector2(0, 0);
uv[1] = new Vector2(0, 1);
uv[2] = new Vector2(1, 1);
uv[3] = new Vector2(1, 0);
//initialise
mesh.vertices = verticies;
mesh.triangles = tri;
mesh.normals = normals;
mesh.uv = uv;
meshOL.vertices = verticiesOL;
meshOL.triangles = tri;
meshOL.normals = normals;
meshOL.uv = uv;
//setting up collider
polyCollider.pathCount = 1;
Vector2[] path = new Vector2[4]
{
new Vector3(-OLwidth,-OLwidth,0), new Vector3(-OLwidth, height + OLwidth, 0), new Vector3(width + OLwidth, height + OLwidth, 0), new Vector3(width + OLwidth, -OLwidth, 0)
};
polyCollider.SetPath(0, path);
}
So i now have two meshes one outside the other. However I want the one on the outside to have a different material: so it looks like an outline.
I have these two materials in my mesh renderer, so how would I go about assigning one material to the outer mesh, and another to the inner mesh.
The concept you might be missing here is "SubMesh", each submesh of a mesh will be rendered using a material from the list at a given index.
To create a submesh you can call
mesh.SetTriangles(int[] triangles, int submesh);
You can re-use your vertexes, by specifying different faces basing on the same list of points. If you specify more submeshes than materials, remaining submeshes will be rendered solid magenta.
I'm having a problem with XNA 4.0 and couldn't even google it. It occurs in my main project as well as in my test project which is very plain version to reduce unnecessary code.
I need to use my own custom vertex declaration and use it to draw textured primitives (or why not models too).
Drawing and texturing works fine with BasicEffect and any built-in vertex declarations (like VertexPositionColorTexture)...but what on earth is wrong that textures aren't drawn properly if I use BasicEffect with my custom vertex declaration? I'd love to keep all combinations of built-in types in one VD. My only idea as a fix is that I should make a new vertex/pixel shader but would it help? And if it would, how should I do it?
I tried to upload images to describe but I'd need at least 10 reputation so I'll explain in words:
With my custom VD, textures of my square (and any other shape) object seems to be tiled instead of scaled/fit. Also, textures won't rotate when I rotate the object.
Here's my custom vertex declaration:
namespace WindowsGame2
{
public struct VertexPositionNormalColorTexture : IVertexType
{
public Vector3 Position;
public Vector3 Normal;
public Color Color;
public Vector2 TextureCoordinate;
VertexDeclaration IVertexType.VertexDeclaration
{
get { return VertexDeclaration; }
}
public readonly static VertexDeclaration VertexDeclaration =
new VertexDeclaration(
new VertexElement(0, VertexElementFormat.Vector3, VertexElementUsage.Position, 0),
new VertexElement(sizeof(float) * 3, VertexElementFormat.Vector3, VertexElementUsage.Normal, 0),
new VertexElement((sizeof(float) * 3) * 2, VertexElementFormat.Color, VertexElementUsage.Color, 0),
new VertexElement((sizeof(float) * 3) * 3, VertexElementFormat.Vector2, VertexElementUsage.TextureCoordinate, 0)
);
public VertexPositionNormalColorTexture(Vector3 p)
{
Position = p;
Normal = Vector3.Zero;
Color = Color.White;
TextureCoordinate = Vector2.Zero;
}
public VertexPositionNormalColorTexture(Vector3 p, Color c)
{
Position = p;
Normal = Vector3.Zero;
Color = c;
TextureCoordinate = Vector2.Zero;
}
public VertexPositionNormalColorTexture(Vector3 p, Vector2 t)
{
Position = p;
Normal = Vector3.Zero;
Color = Color.White;
TextureCoordinate = t;
}
public VertexPositionNormalColorTexture(Vector3 p, Color c, Vector2 t)
{
Position = p;
Normal = Vector3.Zero;
Color = c;
TextureCoordinate = t;
}
public VertexPositionNormalColorTexture(Vector3 p, Vector3 n, Color c)
{
Position = p;
Normal = n;
Color = c;
TextureCoordinate = Vector2.Zero;
}
public VertexPositionNormalColorTexture(Vector3 p, Vector3 n, Vector2 t)
{
Position = p;
Normal = n;
Color = Color.White;
TextureCoordinate = t;
}
public VertexPositionNormalColorTexture(Vector3 p, Vector3 n, Color c, Vector2 t)
{
Position = p;
Normal = n;
Color = c;
TextureCoordinate = t;
}
}
}
And the game class:
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
namespace WindowsGame2
{
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
ViewerManager viewer;
List<VertexPositionNormalColorTexture> vertices;
List<short> indices;
Texture2D thumbnail;
VertexBuffer vertexBuf;
IndexBuffer indexBuf;
RasterizerState rasterizerState;
BasicEffect basicEffect;
Matrix worldMatrix;
Matrix viewMatrix;
Matrix projectionMatrix;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
}
protected override void Initialize()
{
viewer = new ViewerManager(graphics, new Vector3(0.0f, 0.0f, 5.0f), new Vector3(0.0f, 0.0f, 0.0f), 500);
vertices = new List<VertexPositionNormalColorTexture>() {
new VertexPositionNormalColorTexture(new Vector3(-1, -1, 0), Color.Yellow, new Vector2(0, 1)),
new VertexPositionNormalColorTexture(new Vector3(-1, 1, 0), Color.Yellow, new Vector2(0, 0)),
new VertexPositionNormalColorTexture(new Vector3(1, 1, 0), Color.Yellow, new Vector2(1, 0)),
new VertexPositionNormalColorTexture(new Vector3(-1, -1, 0), Color.Yellow, new Vector2(0, 1)),
new VertexPositionNormalColorTexture(new Vector3(1, 1, 0), Color.Yellow, new Vector2(1, 0)),
new VertexPositionNormalColorTexture(new Vector3(1, -1, 0), Color.Yellow, new Vector2(1, 1)),
};
indices = new List<short>() {
0, 1, 2, 3, 4, 5
};
basicEffect = new BasicEffect(graphics.GraphicsDevice);
worldMatrix = Matrix.CreateTranslation(0.0f, 0.0f, 0.0f) * Matrix.CreateScale(3);
viewMatrix = Matrix.CreateLookAt(new Vector3(0.0f, 0.0f, 5.0f), new Vector3(0.0f, 0.0f, 0.0f), Vector3.Up);
projectionMatrix = Matrix.CreatePerspectiveFieldOfView(MathHelper.ToRadians(90), graphics.GraphicsDevice.Viewport.AspectRatio, 1f, 50f);
vertexBuf = new VertexBuffer(graphics.GraphicsDevice, VertexPositionNormalColorTexture.VertexDeclaration, 500, BufferUsage.WriteOnly);
indexBuf = new IndexBuffer(graphics.GraphicsDevice, IndexElementSize.SixteenBits, 500, BufferUsage.WriteOnly);
rasterizerState = new RasterizerState();
rasterizerState.CullMode = CullMode.None;
base.Initialize();
}
protected override void LoadContent()
{
spriteBatch = new SpriteBatch(GraphicsDevice);
thumbnail = this.Content.Load<Texture2D>("GameThumbnail");
}
protected override void UnloadContent()
{
this.Content.Unload();
}
protected override void Update(GameTime gameTime)
{
if (Keyboard.GetState().IsKeyDown(Keys.Escape))
this.Exit();
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
graphics.GraphicsDevice.RasterizerState = rasterizerState;
basicEffect.World = worldMatrix;
basicEffect.View = viewMatrix;
basicEffect.Projection = projectionMatrix;
basicEffect.VertexColorEnabled = true;
basicEffect.TextureEnabled = true;
basicEffect.Texture = thumbnail;
vertexBuf.SetData<VertexPositionNormalColorTexture>(vertices.ToArray());
indexBuf.SetData<short>(indices.ToArray());
graphics.GraphicsDevice.SetVertexBuffer(vertexBuf);
graphics.GraphicsDevice.Indices = indexBuf;
foreach (EffectPass pass in basicEffect.CurrentTechnique.Passes)
{
pass.Apply();
graphics.GraphicsDevice.DrawUserIndexedPrimitives(
PrimitiveType.TriangleList,
vertices.ToArray(),
0,
vertices.Count,
indices.ToArray(),
0,
2,
VertexPositionNormalColorTexture.VertexDeclaration);
}
graphics.GraphicsDevice.Indices = null;
graphics.GraphicsDevice.SetVertexBuffer(null);
base.Draw(gameTime);
}
}
}
I found out the problem. I allocated too much memory for a vertex which resulted in weird texturing. It's in this part of the vertex declaration:
new VertexElement((sizeof(float) * 3) * 2, VertexElementFormat.Color, VertexElementUsage.Color, 0),
new VertexElement((sizeof(float) * 3) * 3, VertexElementFormat.Vector2, VertexElementUsage.TextureCoordinate, 0)
Size of type Color isn't actually float/int but byte. Therefore I had to put it like this:
new VertexElement((sizeof(float) * 3) * 2 + 4, VertexElementFormat.Vector2, VertexElementUsage.TextureCoordinate, 0)