VertexPositionColorTexture generates an error when using a Texture2D

Aug 19, 2009 at 1:19 PM

Hey all,

Maybe anybody have tried to do this also before, but i couldn't find the answer to this problem :(.

My problem is that i am creating a list of vertices that are being rendered as a trianglestrip, but then with a texture applied to it with the use of a matrialshader.

This was rendering all fine when using a VertexPositionTexture struct. But then i wanted to change the alpha to some of the elements, so i made a custom struct >>

struct CustomVertex
    {
        public Vector3 Position;
        public Vector3 Normal;
        public Color Color;
        public Vector2 TextureCoordinate;

        //constructor
        public CustomVertex(Vector3 position, Color color, Vector2 textureCoordinate,  Vector3 normal)
        {
            this.Position = position;
            this.Normal = normal;
            this.Color = color;
            this.TextureCoordinate = textureCoordinate;
        }
    }

I also tried it with VertexPositionColorTexture struct, but that also generates a error (same as with the custom struct). The error is as follows:

Object reference not set to an instance of an object. (NullReference) >> CameraControl.cs (Line 3790) >>

int[] arr = vertexShader.Tag as int[];  (It seems that the vertexshader == null)

I am setting up my verts like this:

vertPoints.Enqueue(new CustomVertex(position, Color.LightPink, new Vector2(0f, 0f), Vector3.UnitZ));

 

Does anybody know what i can do about this?

Many thanks in advance!

Aug 19, 2009 at 3:40 PM

It seems so that when i just use everything as described above, but without the following line:

material.UseVertexColour = true;   (The materialshader)

its rendering just fine with the texture. But when i enable that, because i want to use alpha for my texture, it generates the null reference.

Tracing that line that generates the error:

UseVertexColour = true;  >> vertexShader.Tag = null

also

void IShaderSystem.SetShaders(
            Microsoft.Xna.Framework.Graphics.VertexShader vertexShader,    == null
            Microsoft.Xna.Framework.Graphics.PixelShader pixelShader)    == null
        {

So the function doesn't receive any shader data at all.

 

UseVertexColour = false;  >> Both the shaders inside that function have data provided.

I just cant figure it out :(.

Aug 20, 2009 at 9:33 PM

I would need to have a better view when you create and initialize your Geometry using you custom vertex but I think you are creating it too soon in the overall Application workflow.

try putting your Geometry creation inside your LoadContent method and see what happens then.

Aug 20, 2009 at 10:22 PM

Thanks for replying, but i cannot create my geometry inside the LoadContent method as all the geometry is dynamically added as time goes by.

But the strange part is that when i load in the texture and set it to the material. And set the UseVertexColour to false, it all works perfectly. But when i turn that one on, it crashes :S.

http://www.soolstyle.com/images/AITester%202009-08-21%2000-19-18-10.png   << Here you can see it in action only without the texture use and UseVertexColour set to true.

As you can see that all works just fine :) expect the texture....

Aug 20, 2009 at 11:43 PM

Hmmm... some more code on how and when you generate your geometry would certainly help.

Err... I read that you are using vertPoints.Enqueue method?

Why don't you use the Vertices<VertexType> generic class?

Aug 21, 2009 at 5:44 AM

Ok here comes some more code and maybe this will clear some things out then :). I am using the queue because i use it for FIFO, as you can see in the picture the ships are moving forward and on the position of the ship the geometry is being created. Now when the geometry hits a certain max value, the last geometries are removed (thus the first one's that where inserted).

Here is the full class:

http://pastebin.com/m1daad26f

Aug 21, 2009 at 9:42 AM

Even this simple test is generating the error:

http://pastebin.com/m1920ad77

This one should be easy to follow and to implement yourself to test if you like.

Coordinator
Aug 21, 2009 at 12:02 PM

Hi vinnepin.

I've looked into this and I can reproduce the error - and I can see why it's happening. It's a fairly complex issue deep within some of the shader features used by material shader. It's going to be quite tricky to fix up.
Unfortunately, you've caught this at the worst time possible. I've just moved to the UK and I've only just got into Cambridge - so it'll be a while before I'm up and running again. I don't have Internet (this is through my phone), a console, a TV, etc.

The problem is quite tricky. Internally, Material shader has tonnes of combinations. So it creates a set of Shader classes for all the possible vertex shaders, and another set for all the pixel shaders.. Then it merges them at runtime based on which will have the lower overhead.
On top of that, it also does some inheritance with the shaders, so shaders that use the same constants (but, for instance, might use fewer lights) inherit from the same root shader. It's all to reduce code bloat from the combinations.
The problem is, when setting a texture on a newly created shader (for example) a bug can occur where it doesn't warm the shader properly first (it only calls the root parent static warm method, not the inherited class's method). Long and the short of it, the inherited class doesn't create it's VS/PS objects. So you get the error.

A work around, for now, is possible. In MaterialShader.cs, there is a class called 'ShaderMerge' which does all the funky stuff to pick the best two shader classes to merge for the appropriate combination of VS/PS. This is done in the 'GetShader()' method.
Manually warming the shader before it's returned will (hopefully) fix this problem. However, a merged shader cannot be warmed.. So it's a tad tricky...

There is a line that looks like this:

	if (...)
	{
		// huge chunk of logic to determine combination...
	}
	else
		shader = BaseShader.Merge((BaseShader)vshader, (BaseShader)pshader);

The changes need to occur around that area...

it needs to change to something like:

	if (...)
	{
		// huge chunk of logic to determine combination...

		((BaseShader)shader).Warm(state);
	}
	else
	{
		((BaseShader)vshader).Warm(state);
		((BaseShader)pshader).Warm(state);
		shader = BaseShader.Merge((BaseShader)vshader, (BaseShader)pshader);
	}

I know. It's not a small change, but it should help prevent this error until I can make a proper fix deep within the shader processing tool...
Note this will not totally prevent the problem. It could still occur after a device reset, etc.

Aug 21, 2009 at 12:45 PM
Edited Aug 21, 2009 at 1:07 PM

Many thanks StatusUnknown for that quick fix for the time being :). It's working properly for now, this way i can continue with it. You have made my day! :D

Results

Or with some funky texture