It really bugs me when my first post in any community I join has to be a request for help, so I have tried to hold off asking for assistance - but now this is holding up my development.

I have been having a headache over this for 2 weeks. There are plenty of examples and topics on the internet demonstrating this using primitives, and plenty that imply you want to use a content processor, but hardly any that ( none that I could find ) that shows how to implement this correctly when you want to copy vertices and indices from and existing model... and being fairly new to XNA ( specifically 3D programming ) , i have been losing sleep over only one and one particular issue: Geometry Instancing.

To begin - I started my implementation using the examples Here and Here, but with two notable differences:

- A: I did not need the "atlas texture" thing.
- B: I dont want to use generated geometry prrimitives, but instead copy the vertices from an existing model.

The MSDN Instanced Geometry Example doesnt help because the so called "instanced mesh" class mentioned in the article cannot be found.

In my particular project I need to check individual sub meshes ( + transforms ) to the camera's view frustum - so as a result - I want to maintain each individual mesh part in their own seperate vertexbuffers ( only examples I found that copy existing meshdata combines all meshparts into a single vertex buffer, making it impossible to manage individual mesh parts seperatly ).

In my project I have created the following classes:

OSModel

OSModelMesh

OSModelMeshPart

I want OSModelMeshPart to contain my VertexBuffer / InstanceBuffer, as this would be initialized from an existing ModelMeshPart, and this is how I have written it.

At runtime, my entire draw routine passes through (during step through debugging) without raising any exceptions - however nothing displays. One of those issues where theres is nothing telling me what isnt working. VertexBuffers appear full ( and all copied data matches lengths and types of the original sources ). Its driving me nuts.

So I tried the following:

Test: Forcing all instanced positions into the view frustum:Result: FPS drops as if all positions in my instance buffer are being drawn, but they seem completly invisible.

Test: Alternate positioning by sending only a matrix to use as position transformResult: Failed

Test: Tried using Generated Geometry ( manually typed in cube ).. as in the examples:Result: It worked - which is why I believe Im copying existing model data incorrectly...

Test: A none instanced version of my shader:Result: Passed - and renders correctly

In the attached images - all None-Instanced tests - all my positions are working - and my shaders are working, frustum checks are working, but I need this same result with Instancing, because I can maintain 20000+ ships in the game world, but I cannot put more than a few hundred of them inside my view frustum because I hit my batch limit ( too many draw calls ). I need to be able to put 2000 ships in my view frustum, in which some of these would be huge titans, I intend to LOD and Frustum Occlude each individual mesh part.

But when initializing these same models ( Skybox, Planets, and ships ) using the below instancing code, they do not render.

After banging my head against the wall a few times I figured the problem must be originating from the areas that differ from the examples:

Either I am copying Initializing my VertexBuffer, and IndexBuffer, for each OSModelMeshPart when copying from a ModelMeshPart incorrectly... or....

Maybe the extra elements ( currently only a vector 4, I removed others ) are not being passes to the shader correctly ( which I doubt since It appears the positions are working correctly ? )

My goal:

I want to maintain seperate draw lists for every mesh part in the end, therefore seperate instancebuffers for each meshpart - each meshpart is tested against the cameras view frustum on update - and the final instance buffer would contain only those visible in the view frustum.

DrawStates are controlled by OSModelMesh, and are ordered by OSModel (Opaque meshes are stored in a seperate lists from Alpha and additive meshes )

For it to actually work.

My entire instancing takes place in OSModelMeshPart - which I wanted to attach instead of making my post too long, but it appears .VB files are not permitted....

This is the curent state of my OSModelMeshPart object in my framework: RenderHelper contains StateManagement and Frustum Checks, etc...

Imports OS.Graphics.RenderHelper
Namespace Graphics
Public Class OSModelMeshPart
Inherits OS.iGameObject
Friend m_VertexDeclaration As VertexDeclaration, _
_
m_GeometryBuffer As VertexBuffer,
m_IndexBuffer As IndexBuffer,
_
m_InstanceBuffer As VertexBuffer
Friend m_Bindings As VertexBufferBinding()
Friend m_VertexStreamElements As VertexElement()
Private m_Owner As OSModelMesh
Friend m_Vertices As VertexPositionTexture()
Friend m_VertexCount As Integer,
m_VertexOffset As Integer,
m_IndexCount As Integer,
m_PrimitiveCount As Integer,
_
m_Last_InstanceCount As Integer = 0
Private m_BoundingSphere As BoundingSphere,
m_BoundingBox_FromSphere As BoundingBox,
m_BoundingBox_FromVertices As BoundingBox
Private m_Cache_LastPositions As ModelPositionInfo()
' instance list ( we TRIM/ ADD per cycle - do not CLEAR - optimization )
Private m_Instances As New List(Of InstanceInfo)
Private m_ListIDCap As Integer = -1
' weather we have anything to draw:
Private m_CanDraw As Boolean = False
' bounds for each instance per cycle:
Friend m_Cache_Instances_BoundingSpheres As BoundingSphere() = {}
Friend m_Cache_Instances_BoundingBoxes As BoundingBox() = {}
''' <summary>
''' Returns Bounding Spheres for this mesh part for all previous instances passed.
''' Bounding spheres are returned for all instanced regardless of View Frustum visibility.
''' EG: Length of array will always metch the positioninfo list length.
''' </summary>
''' <value></value>
''' <returns></returns>
''' <remarks></remarks>
ReadOnly Property Get_Last_Instance_BoundingSpheres As BoundingSphere()
Get
Return m_Cache_Instances_BoundingSpheres
End Get
End Property
''' <summary>
''' Returns all instance boundingboxes for this meshpart from the last instance positions list passed .
''' Bounding spheres are returned for all instanced regardless of View Frustum visibility.
''' EG: Length of array will always metch the positioninfo list length.
''' </summary>
''' <value></value>
''' <returns></returns>
''' <remarks></remarks>
ReadOnly Property Get_Last_Instance_BoundingBoxes As BoundingBox()
Get
Return m_Cache_Instances_BoundingBoxes
End Get
End Property
ReadOnly Property Owner_Mesh As OSModelMesh
Get
Return m_Owner
End Get
End Property
ReadOnly Property Owner_Model As OSModel
Get
Return m_Owner.Owner_Model
End Get
End Property
'Private Structure InstanceInfo
' Public World As Vector4
' Public TeamColor_1 As Vector4 ' for meshes that support TeamColor on RED regionmap channel
' Public TeamColor_2 As Vector4 ' for meshes that support TeamColor on GREEN region map channel
' Public TeamColor_3 As Vector4 ' for meshes that support TeamColor on BLUE region map channel
'End Structure
Private Structure InstanceInfo
Public World As Vector4
End Structure
Friend Sub New(Owner As OSModelMesh, Part As ModelMeshPart)
MyBase.New(Owner.Game)
m_Owner = Owner
_Initialize_VertexDeclaration(Part)
_Initialize_Geometry(Part)
_Initialize_BoundingSphere()
_Initialize_BoundingBox_From_BoundingSphere()
_Initialize_BoundingBox_From_Vertices()
#If DEBUG Then
'TODO: log stats containing information about this meshpart:
#End If
End Sub
Private Sub _Initialize_VertexDeclaration(Part As ModelMeshPart)
'0 = POSITION1 : Model Transforms per instance
'1 = COLOR1 : Per Instance Team Color1
'2 = COLOR2 : Per Instance Team Color2
'3 = COLOR3 : Per Instance Team Color3
' m_VertexStreamElements =
' {
' New VertexElement(0, VertexElementFormat.Vector4, VertexElementUsage.Position, 1)
'_
' New VertexElement(SizeOfVector4 * 4, VertexElementFormat.Vector4, VertexElementUsage.Color, 1),
' New VertexElement(SizeOfVector4 * 5, VertexElementFormat.Vector4, VertexElementUsage.Color, 2),
' New VertexElement(SizeOfVector4 * 6, VertexElementFormat.Vector4, VertexElementUsage.Color, 3)
'_
' }
m_VertexStreamElements =
{
New VertexElement(0, VertexElementFormat.Vector4, VertexElementUsage.Position, 1)
}
m_VertexDeclaration = New VertexDeclaration(m_VertexStreamElements)
End Sub
Private Sub _Initialize_Geometry(Part As ModelMeshPart)
Dim Result_Vertex As VertexPositionTexture() = {}
With Part
' Initialize Vertices
m_VertexCount = .PrimitiveCount * 3
m_VertexOffset = .VertexOffset
m_PrimitiveCount = .PrimitiveCount
Array.Resize(Result_Vertex, m_VertexCount)
.VertexBuffer.GetData(Of VertexPositionTexture)(Result_Vertex)
' execute the original vertexbuffer
.VertexBuffer.Dispose()
' Bake Bone transforms into vertices:
' NOTE: if animated / dynamic bones are needed - then this should be removed - and bone transforms would need to be supplied somehow per instance
g_ApplyBoneTransforms(Result_Vertex, Owner_Mesh.m_ParentBone)
m_GeometryBuffer = New VertexBuffer(Owner_Model.GraphicsDevice, VertexPositionTexture.VertexDeclaration, Result_Vertex.Length, BufferUsage.None)
' apply:
m_GeometryBuffer.SetData(Of VertexPositionTexture)(Result_Vertex)
' Indices:
m_IndexCount = .IndexBuffer.IndexCount
' ----------------------------------------
Dim Result_Indices As Short() = {}
Array.Resize(Result_Indices, m_IndexCount)
.IndexBuffer.GetData(Of Short)(Result_Indices, 0, Result_Indices.Length)
m_IndexBuffer = New IndexBuffer(Owner_Model.GraphicsDevice, Part.IndexBuffer.IndexElementSize, .IndexBuffer.IndexCount, BufferUsage.None)
' apply
m_IndexBuffer.SetData(Of Short)(Result_Indices)
' ----------------------------------------
End With
' a copy of vertices remains in memory because we create bounds from them for thsi meshpart:
m_Vertices = Result_Vertex
End Sub
' we dont have dynamic bones in our model structure ( we dont need them in the current game ) - so we will instead bake the bone transforms into the vertices
Private Sub g_ApplyBoneTransforms(ByRef Vertices As VertexPositionTexture(), Bone As ModelBone)
If Bone Is Nothing Then Return
For I = 0 To Vertices.Length - 1
Vertices(I).Position = Vector3.Transform(Vertices(I).Position, GetAbsoluteBoneTransform(Bone))
Next
End Sub
' get absolute bone transforms: ( which will be hardbaked into our model )
Private Function GetAbsoluteBoneTransform(Bone As ModelBone) As Matrix
If Bone Is Nothing Then Return Matrix.Identity
Return Bone.Transform * GetAbsoluteBoneTransform(Bone.Parent)
End Function
Private Sub _Initialize_BoundingSphere()
Dim R As Single = 0
' use bone transform
' vertices already have bone transformations applied...
Dim BoundingSpherePosition As Vector3 = Vector3.Transform(Vector3.Zero, GetAbsoluteBoneTransform(Owner_Mesh.m_ParentBone))
For I = 0 To m_Vertices.Length - 1
Dim D = System.Math.Abs(Vector3.Distance(BoundingSpherePosition, m_Vertices(I).Position))
If D > R Then R = D
Next
m_BoundingSphere = New BoundingSphere(BoundingSpherePosition, R)
End Sub
Private Sub _Initialize_BoundingBox_From_BoundingSphere()
m_BoundingBox_FromSphere = BoundingBox.CreateFromSphere(m_BoundingSphere)
End Sub
' vertices at this point only have bone transforms applied: bounding box represents all verticies with bone transforms
' - so world transforms would have to be applied seperatly ( in a cached instance list )
Private Sub _Initialize_BoundingBox_From_Vertices()
Dim MIN As Vector3 = Vector3.Zero
Dim MAX As Vector3 = Vector3.Zero
For I = 0 To m_Vertices.Length - 1
MIN = Vector3.Min(MIN, m_Vertices(I).Position)
MAX = Vector3.Max(MAX, m_Vertices(I).Position)
Next
m_BoundingBox_FromVertices = New BoundingBox(MIN, MAX)
End Sub
' Update cache list of boundingboxes for all instances (sphere too )
Private Sub Update_Instance_BoundingBox(Position As ModelPositionInfo, Index As Integer)
m_Cache_Instances_BoundingBoxes(Index) = New BoundingBox(
Vector3.Transform(m_BoundingBox_FromVertices.Min, Position.GetTransform),
Vector3.Transform(m_BoundingBox_FromVertices.Max, Position.GetTransform)
)
m_Cache_Instances_BoundingSpheres(Index) = New BoundingSphere(
Vector3.Transform(m_BoundingSphere.Center, Position.GetTransform),
m_BoundingSphere.Radius * Position.Scale
)
End Sub
Friend Sub Update_Instance_Information(Positions As ModelPositionInfo())
If Not m_Cache_LastPositions Is Nothing And Not Positions Is Nothing Then
If m_Cache_LastPositions.GetHashCode = Positions.GetHashCode Then
'OPTIMIZATION: nothing has changed - use previous instance information:
If Not m_InstanceBuffer Is Nothing Then Return
End If
End If
m_CanDraw = False
m_Last_InstanceCount = 0
If Positions Is Nothing Then Return
If Positions.Count < 1 Then Return
' bounding boxes lengths:
If m_Cache_Instances_BoundingSpheres.Length <> Positions.Length Then Array.Resize(m_Cache_Instances_BoundingSpheres, Positions.Length)
If m_Cache_Instances_BoundingBoxes.Length <> Positions.Length Then Array.Resize(m_Cache_Instances_BoundingBoxes, Positions.Length)
' make sure we are not repeatedly growing the list in the loop per instance:
If m_Instances.Capacity < Positions.Length Then m_Instances.Capacity = Positions.Length
Dim Visible As Integer = 0
Dim Index As Integer = 0 ' so we may scale our list:
Dim TrueIndex As Integer = 0
For Each P As ModelPositionInfo In Positions
If P.Enabled Then
' we only check with wour bounding sphere because the method has extra checks in case of bad accuracy:
If g_IsInViewOfCamera(P.Position, m_BoundingSphere, Owner_Model.GameState.Camera) Then
' TODO: check LOD and determine weather to / or how to draw this meshpart Per Instance
Dim INSTANCE As New InstanceInfo With
{
.World = Vector4.Transform(Vector3.Zero, P.GetTransform)
}
If Owner_Mesh.IsBillboard Then
' TODO: Billboard Tranformation for this model instance ( must face camera )
End If
If m_ListIDCap < Index Then
' index does not exist in list yet:
m_Instances.Add(INSTANCE)
m_ListIDCap = Index
Else
' index exists : replace... ( avoid clearing list every cycle )
m_Instances(Index) = INSTANCE
End If
' done:
Index += 1
End If
End If
' finally - ensure we have a bounding box and bounding sphere for each instance:
' bounds are cached for ALL positions regardless of weather they are enabled, or in the view frustum
Update_Instance_BoundingBox(P, TrueIndex)
TrueIndex += 1
Next
' remove excess positions that are not drawn this time around
' ( extra instance information from a previous draw cycle ( eg: an instance is no longer in the view frustum) )
If m_Instances.Count >= Index Then
For I = Index To m_Instances.Count - 1
m_Instances.RemoveAt(I)
Next
End If
' check that we actually have vertices to send:
If m_Instances.Count < 1 Then
' nothing to draw:
m_InstanceBuffer = Nothing
m_CanDraw = False
m_Last_InstanceCount = 0
End If
' if not created:
If m_InstanceBuffer Is Nothing Then
m_InstanceBuffer = New VertexBuffer(Owner_Model.GraphicsDevice, m_VertexDeclaration, m_Instances.Count, BufferUsage.WriteOnly)
End If
' if count is extactly the same as previous cycle - then do not redeclare - simply replace the data:
'If m_InstanceBuffer.VertexCount <> m_Instances.Count Then
m_InstanceBuffer = New VertexBuffer(Owner_Model.GraphicsDevice, m_VertexDeclaration, m_Instances.Count, BufferUsage.WriteOnly)
' End If
' apply:
m_InstanceBuffer.SetData(m_Instances.ToArray)
' set draw information states:
m_CanDraw = True
m_Last_InstanceCount = m_Instances.Count
' hold a copy of previous positions list for hash comparison next cycle:
m_Cache_LastPositions = Positions
End Sub
' must be called from OSModelMesh.Draw() AFTER 'Update_Instance_Information()' is called
' returns total instances drawn:
Friend Function Draw() As Integer
' check is flag is set notifying that we have nothing to draw this time round:
If m_CanDraw = False Then Return 0
m_Bindings = Nothing
' prepare bindings:
m_Bindings = {
New VertexBufferBinding(m_GeometryBuffer),
New VertexBufferBinding(m_InstanceBuffer, 0, 1)
}
With Owner_Model.GraphicsDevice
.Indices = m_IndexBuffer
If Owner_Model.Effect.Shader.CurrentTechnique.Passes.Count = 1 Then
' single pass
Owner_Model.Effect.Shader.CurrentTechnique.Passes(0).Apply()
.SetVertexBuffers(m_Bindings)
.DrawInstancedPrimitives(PrimitiveType.TriangleList, 0, 0, m_VertexCount, 0, m_PrimitiveCount, m_Last_InstanceCount)
Else
' shader have multiple passes:
For Each P As EffectPass In Owner_Model.Effect.Shader.CurrentTechnique.Passes
P.Apply()
.SetVertexBuffers(m_Bindings)
.DrawInstancedPrimitives(PrimitiveType.TriangleList, 0, 0, m_VertexCount, 0, m_PrimitiveCount, m_Last_InstanceCount)
Next
End If
'.SetVertexBuffers(Nothing)
End With
Return m_Last_InstanceCount
End Function
End Class
End Namespace

Attached Thumbnails

This quite a lot of code to inspect, especially since you use a "unpopular" language (no offence intended. On the contrary: I consider it quite nice. It's probably the first time I see someone using XNA with VB). Maybe translate it to C# with reflector or ILSpy, so more people can read it.

What you're trying to do is surely possible. Can't easily read the VB part but the shader caught my eye. I've seen troubles with using the POSITION1 semantic in some thread around here. Maybe you can't use it for instancing. Use a texcoord for a change (and make sure it doesn't collide with the geometry part).

Such troubles are best investigated with PIX (needs the DirectX June 2010 SDK) or a similar tool though. Problem is, with XNA you're probably not familiar with the underlying D3D9 calls, so not sure this will help.

Edit: Are you familiar with the Direct3D debug runtimes ?. I suspect another problem with your vertex declaration (I'm not sure one can use a COLOR2 semantic).

This quite a lot of code to inspect, especially since you use a "unpopular" language (no offence intended. On the contrary: I consider it quite nice. It's probably the first time I see someone using XNA with VB). Maybe translate it to C# with reflector or ILSpy, so more people can read it.

What you're trying to do is surely possible. Can't easily read the VB part but the shader caught my eye. I've seen troubles with using the POSITION1 semantic in some thread around here. Maybe you can't use it for instancing. Use a texcoord for a change (and make sure it doesn't collide with the geometry part).

Such troubles are best investigated with PIX (needs the DirectX June 2010 SDK) or a similar tool though. Problem is, with XNA you're probably not familiar with the underlying D3D9 calls, so not sure this will help.

Edit: Are you familiar with the Direct3D debug runtimes ?. I suspect another problem with your vertex declaration (I'm not sure one can use a COLOR2 semantic).

Teamcolor lines were commented out as well as all related code. I wanted to be able to pass instance spefic colors as well ( teamcolors,) Im looking into the debug runtimes now.

However. The instances are still not drawing ( and DirectXSDK is still downloading, so i cant try the utilities in there yet ) All the results I have again - are exactly as they were before. And no exceptions are being raised.

A TEXCOORD1 ( elementusage 1) already existed in the vertexdeclaration supplied by the original model, so I decided to leave it as it is by not replacing it ( just in case). This resulted in me having to begin my matrix elements at ElementUsage 2 ( TEXCOORD2 ).

In the attached images:

1: The original vertex elements array supplied by the original vertexdeclaration supplied by the model - see the second TextureCoordinate supplied by the original model.

2: My vertex elements, but offset so they are just added to the eisting elements without replacing or conflicting with existing texturecoordinate elements.

3: My completed stream elements

As a result I made a version of my shader that expects a TEXCOORD2 instead of TEXCOORD1 - because I am not replacing the original - but instead just adding more:

Attached Thumbnails

Look at the example you linked to more closely. If you send a full world matrix you need to transpose it, either beforehand when filling the instance stream or - as in the example - by transposing in the shader. This is because the mul(float4, matrix) needs the matrix layed out in column-major (For shader parameters like View/Projection this is happening automatically with the effect framework).

Why there's a second texcoord ? Well, if that mesh needs/has one, so be it. Could be for e.g. multitexturing. Anyway you made it right by offsetting so the semantics don't collide.

I had a look at the reflected XNA code. You should get exceptions if the drawing fails. Still, the debug runtimes gives more clues about the why.

Hmmm, what is FinalElements for ? I don't think you need to setup the combined declaration manually, at least not for XNA 4.0 since the VertexBufferBinding/VertexBuffers will take care of that for you (see here).

Then - when I ran it - I got the first image result attached. Holy hell, now we see something. But the model mesh is now broken in this geometry buffer obviously ( see the Fighter Model in the previously attached screenshots from the Non-Instanced draws ).

I managed to isolate the Draw call in pix after running it again to test using F12 capture.

I also tested this WITH my matrix transformation - which appears to be working ( the broken mesh data is now simply transformed... )

The results - . I dont know how to fix this, but now im convinced that I am definetly not copying my model's data corectly.

Look at the example you linked to more closely. If you send a full world matrix you need to transpose it, either beforehand when filling the instance stream or - as in the example - by transposing in the shader. This is because the mul(float4, matrix) needs the matrix layed out in column-major (For shader parameters like View/Projection this is happening automatically with the effect framework).

Why there's a second texcoord ? Well, if that mesh needs/has one, so be it. Could be for e.g. multitexturing. Anyway you made it right by offsetting so the semantics don't collide.

I had a look at the reflected XNA code. You should get exceptions if the drawing fails. Still, the debug runtimes gives more clues about the why.

Hmmm, what is FinalElements for ? I don't think you need to setup the combined declaration manually, at least not for XNA 4.0 since the VertexBufferBinding/VertexBuffers will take care of that for you (see here).

Sorry - I responded and didnt notice your response before I posted. In my own project I have corrected my shader now. However my geometry is now obviously broken before I send it to the GPU.

The reason I tried a combined Elementstream - was because the ROE example seems to be doing the same thing.

After reading your post I tested both by original elemenstream and the finalstream now that I can actually see something ( the broken geometry ) . Both results are exactly the same on display

That really helps. You said the original mesh has a second texcoord. Make sure you use an appropriate vertex struct ( VertexPositionTexture only has one texcoord). XNA probably does not come with a suitable struct, so you need to define one yourself.

Actually I wonder if you need to copy at all. You might as well bind the original buffers from the mesh part.

Edit: Nah, scratch that. I just realized you apply the bone transforms, not just copy.

- I wish I had known about PIX before. The only problem is what I "guessed" was my problem before, was only confirmed by pix... regarding my geometry.

Yeah - because I don't need animated bones, I applied them directly to the mesh when trying to copy.

Note - I was using the wrong ( simpler) model with the instanced test, but the results are the same regardless of what model I load into my OSModel heirachy.

I also tested with bone transforms call commented out - mesh is broken either way ( and I dont think I applied the transforms wrong anyhow ).

The following screenshots from pix are with the shader applying color from TEXCOORD0, in addition to using the InstanceTransform.

Also - see what Texcoord1 looks like in pix? , it's just a single float always evaluating to zero. D:? I can ignore this, but who knows when I may actually need that extra TEXCOORD.... ( this is when I am only sending my extra stream elements, however still with the offsets assuming that TEXCOORD1 is populated, which I will change later - I'm now just worried about the geometry problem )

The instancing streams looks bad, too (TEXCOORD5). I'd recommend inspecting the data you send manually from the VB side (log it in tabular form, so you can compare it easily with the PIX table). Also check if the stride (last paramter of SetStreamSource) matches the vertex struct size (in C# Marshal.SizeOf(typeof(VertexType))).

Also, in PIX you can inspect all states and resources by clicking on the "hyperlinks" (device, textures, buffers, declarations). Especially the buffers and the declarations are of interest. For the buffers you can first provide a HLSL-like definition to get it into the type-correct tabular form.

However, the second texture coordinate was evaluating to (0,0) for all instances, so I chose to replace it instead ( starting my World Transform matrix at TEXCOORD1 instead of TEXCOORD2 )

I can now also verify my world transforms are working, as each instance ( there are 1001 positions in this screenshot ), is positioned correction ( random scale applied o each instance, and random orientation )

Your help here has helped me step foreward considerably on this issue, so far. Thank m8.

All that remains now is figuring out why my geometry is broken. I now have a clear understanding of what was wrong with everything else except my broken geometry problem. =(

I'm hoping someone will know of an article that correctly explains how I should have initialized my geometry so the rat nests I am rendering now can be fixed - because it seems simply copying the Vertices and Indices doesn't work the way I expected it to.

Game Render:

Pix ( which doesn't show the skybox because my skybox uses a separate rendertarget )

Edit: You know what ? I'd actually go a step back and draw the model normally without instancing at all. Then inspect with PIX and check what declaration (and strides) you get. I actually wonder if one can have different declarations for different parts. Maybe that's a another problem.

Edit2: Hmmm, my suspicion might hold. Get the vertex buffer from the ModelMeshPart and inspect the VertexDeclaration thereof (and show us).

The trouble here is that on my model ( in the non instanced exampled seen in the opening post ) , I needed to use different blendstates (engine glow built into the model requires alpha ). I also would like to be able to access individual mesh parts when rendering because I want some of my ships to have a spinning gravity ring without having to load a seperate model just to do it. Also some of my models will be huge, ( so big they could potentially extend all the way up to the end of my camera's view distance ) - in which I intend to LOD/OccludeTest individual mesh parts of a model ( large portions of supercapital ship, would be outside the camera's view frustum if you get close to it ).

While unsure how to get VertexStride and other buffer related data ( besides just the buffers themselves ) out of PIX, heres a check of what things look like to pix with my non instances test gamestate:

Primary Rendertarget from the end of the Final Compositor's compositing stage:

Planets and Ships render to two seperate geometry buffers in my project ( planets require a much much larger draw distance )

What the fighter looks like in Pix:

What my Planet looks like in Pix:

Edit: Original Vertex Declaration

Edit: My Vertex declaration for comparison:

Not sure exaactly what it means, but I assume I should have manually specified a new vertex stride to accommodate my extra elements?

Im not exactly sure exactly what my Vertex Stride needs to be.

Edit: Also noticed now the positions of vertexes differ from the non instanced draw, as seen

Edit: This was being posted as your reply came in. Will try using VertexPositionNormalTexture

My semantics are getting scrambled. Vertex positions are mixing into the Normals and texture coordinate channels.... But why =([edit - i think I understand why ]

Edit: -------------------

The two different models I have tested with supply different elements ( also, the fighter above has 5 total mesh parts across 3 meshes, while the other only has one total)

The elements supplied by the first original fighter ModelMeshPart: (which should be the same across all mesh parts )

And elements from the other simpler model - the model were the strange extra texture coordinate was coming from:

Which I dont understand, because both were modelled in 3DSMax and exported using the exact same FBX Exporter configuration in 3DSMax.

However with both models I get the same anomoly were vertex positions are mixed into the other element channels, in addition to being mixed in with other ( not needed ) elements. ( I dont need binormals or that pesky extra texture coordinate in this project)

The solution to my problem is now figuring out how to fix this problem and get onlt Position, Normal and TextureCoordinate into the output vertex buffers and work exactly the same for all models that I supply as long as they have the 3 elements I need, while discarding all extra elements.

If I figure this piece out now - then my problem is 1000% solved,.

But yeah - your suggestion to use PIX - Im loving this utility already. Makes no sense why no one else has ever mentioned it to me before.

I can't help you with 3DSMax, but I'm not surprised a model can have different formats. Either you go further with this, meaning "force" it to have one format only on the API side by converting/copying, or alternatively use the buffers and formats as-is like already suggested. For the latter you need to provide an additional matrix for the bone (shader constant) and draw the subsets separately. Maybe actually a better idea: Sounds like the parts need different states (blending) and maybe even different shaders anyway.

The trouble though is thet the other model doesnt for some reason. I would like to eliminate Tangent and Binormal because none of my shaders actually use them ( while also eliminating the extra texturecoordinate the second model supplies ).

... with all of the original elements in a 1 dimensionall array, and coolecting only the Position, Normal, and TextureCoordinate from it, and discarding the rest. To completly replace the original elements.

this is under my understanding that using GetData to retrieve floats instead of structures will contain floats in this order :

so that regardless of how many elements a model loaded from FBX has declared, I would have replaced it with a vertex declaration that only contains the elements Position, Normal, TextureCoordinate, so that in the future if I encounter another model that defines unusual extra elements ( like a second texture Coordinate ), then It would have those stripped so that I can maintain an exact output element stream that is the same for all models.

EDIT:

The above worked exactly as I was hoping it would - by removing any elements manually that dont fit in VertexPositionNormalTexture, and fixed the errors in my VertexStream elements:

While there is probably a better way to do it, it at least allows me to prevent errors against models with variating element lengths - and ill probably need to improve on it:

Hmmm, yeah, VertexBuffer.GetData has some overloads, but one still needs some type (currently your float). Pity one can't work with the blob directly, with VertexDeclaration.VertexStride and the offsets from the elements one could do this generically (see here for something along those lines). You could probably use a GetData(Of Byte) and some marshalling tricks to achieve that, but I doubt it will be simpler/easier than what you're doing now.

Im pretty confident now I can start implementing and experimenting with new features and carry on by myself again ( after I commit my source code to my repository - in case I break it ) - in addition to looking at how I could implement LOD with instancing.

I am pretty curious about using COLOR1,COLOR2,COLOR3 on a per instance level as well ( which is what I originally intended ). I think I could perhaps have my effect objects notify models of extra elements they would expect - or something....

And I can now update my existing shaders to make use of the instancing.

It feels a bit wierd because up till now everything else in my framework was written without help. But getting feedback definetly has it's perks - especially if it gets me looking at things differently or using tools I never knew existed that end up saving my brain from melting into a puddle of radioactive glowing yellow goo..

Once again m8, thanks for the feedback.

Hopefully in a few weeks my next forum thread here will be me showing off basic game-play features. Writing my game framework is full of l learning experiences.