public ModelVertexMapping GetVertexMappingToGPU(Model modelAsset, IEffect effectAsset) { switch (effectAsset.Name) { case "effect.BuiltinSurface:TextureNormalSkinned": case "effect.BuiltinSurface:TextureNormalSpecColDefSkinned": case "effect.BuiltinSurface:TextureNormalSpecColConSkinned": case "effect.BuiltinSurface:TextureNormalSpecColMapSkinned": return(ModelVertexMapping.Create( src => new VertexPositionNormalBinormalTangentTextureBlendable( src.Position ?? Vector3.Zero, src.Normal ?? Vector3.Zero, src.BiTangent ?? Vector3.Zero, src.Tangent ?? Vector3.Zero, (src.TexCoordsUV != null && src.TexCoordsUV.Length >= 1) ? src.TexCoordsUV[0] : Vector2.Zero, src.BoneWeights ?? Vector4.Zero, src.BoneIndices ?? new Byte4(0, 0, 0, 0)))); case "effect.BuiltinSurface:TextureSkinned": return(ModelVertexMapping.Create( src => new VertexPositionNormalTextureBlendable( src.Position ?? Vector3.Zero, src.Normal ?? Vector3.Zero, (src.TexCoordsUV != null && src.TexCoordsUV.Length >= 1) ? src.TexCoordsUV[0] : Vector2.Zero, src.BoneWeights ?? Vector4.Zero, src.BoneIndices ?? new Byte4(0, 0, 0, 0)))); case "effect.BuiltinSurface:ColorSkinned": return(ModelVertexMapping.Create( src => new VertexPositionNormalColorBlendable( src.Position ?? Vector3.Zero, src.Normal ?? Vector3.Zero, (src.Colors != null && src.Colors.Length >= 1) ? src.Colors[0]: new Color(), src.BoneWeights ?? Vector4.Zero, src.BoneIndices ?? new Byte4(0, 0, 0, 0)))); case "effect.BuiltinSurface:DiffuseSkinned": return(ModelVertexMapping.Create( src => new VertexPositionNormalBlendable( src.Position ?? Vector3.Zero, src.Normal ?? Vector3.Zero, src.BoneWeights ?? Vector4.Zero, src.BoneIndices ?? new Byte4(0, 0, 0, 0)))); case "effect.BuiltinSurface:TextureNormal": case "effect.BuiltinSurface:TextureNormalSpecColDef": case "effect.BuiltinSurface:TextureNormalSpecColCon": case "effect.BuiltinSurface:TextureNormalSpecColMap": return(ModelVertexMapping.Create( src => new VertexPositionNormalBinormalTangentTexture( src.Position ?? Vector3.Zero, src.Normal ?? Vector3.Zero, src.BiTangent ?? Vector3.Zero, src.Tangent ?? Vector3.Zero, (src.TexCoordsUV != null && src.TexCoordsUV.Length >= 1) ? src.TexCoordsUV[0] : Vector2.Zero))); case "effect.BuiltinSurface:Texture": return(ModelVertexMapping.Create( src => new VertexPositionNormalTexture( src.Position ?? Vector3.Zero, src.Normal ?? Vector3.Zero, (src.TexCoordsUV != null && src.TexCoordsUV.Length >= 1) ? src.TexCoordsUV[0] : Vector2.Zero))); case "effect.BuiltinSurface:Color": return(ModelVertexMapping.Create( src => new VertexPositionNormalColor( src.Position ?? Vector3.Zero, src.Normal ?? Vector3.Zero, (src.Colors != null && src.Colors.Length >= 1) ? src.Colors[0] : new Color()))); case "effect.BuiltinSurface:Diffuse": return(ModelVertexMapping.Create( src => new VertexPositionNormal( src.Position ?? Vector3.Zero, src.Normal ?? Vector3.Zero))); case "effect.PointLight": return(ModelVertexMapping.Create( src => new VertexPosition(src.Position ?? Vector3.Zero))); default: return(null); } }
/// <summary> /// Creates a render request for the model using the specified transform. /// </summary> /// <param name="renderContext"> /// The render context. /// </param> /// <param name="effect"></param> /// <param name="effectParameterSet"></param> /// <param name="transform"> /// The transform. /// </param> public IRenderRequest CreateRenderRequest(IRenderContext renderContext, IEffect effect, IEffectParameterSet effectParameterSet, Matrix transform) { if (Vertexes.Length == 0 && Indices.Length == 0) { throw new InvalidOperationException( "This model does not have any vertexes or indices. It's most " + "likely been imported from an FBX file that only contains hierarchy, " + "in which case there isn't anything to render."); } LoadBuffers(renderContext.GraphicsDevice); VertexBuffer vertexBuffer; if (_cachedVertexBuffers.ContainsKey(effect)) { vertexBuffer = _cachedVertexBuffers[effect]; } else { // Find the vertex mapping configuration for this model. if (_cachedModelVertexMapping == null) { _cachedModelVertexMapping = _modelRenderConfigurations.Select(x => x.GetVertexMappingToGPU(this, effect)) .FirstOrDefault(x => x != null); if (_cachedModelVertexMapping == null) { throw new InvalidOperationException( "No implementation of IModelRenderConfiguration could provide a vertex " + "mapping for this model. You must implement IModelRenderConfiguration " + "and bind it in the dependency injection system, so that the engine is " + "aware of how to map vertices in models to parameters in effects."); } } var mappedVerticies = Array.CreateInstance(_cachedModelVertexMapping.VertexType, Vertexes.Length); for (var i = 0; i < Vertexes.Length; i++) { var vertex = _cachedModelVertexMapping.MappingFunction(Vertexes[i]); mappedVerticies.SetValue(vertex, i); } float maxX = 0f, maxY = 0f, maxZ = 0f; foreach (var vert in this.Vertexes) { if (vert.Position.HasValue) { if (Math.Abs(vert.Position.Value.X) > maxX) { maxX = Math.Abs(vert.Position.Value.X); } if (Math.Abs(vert.Position.Value.Y) > maxY) { maxY = Math.Abs(vert.Position.Value.Y); } if (Math.Abs(vert.Position.Value.Z) > maxZ) { maxZ = Math.Abs(vert.Position.Value.Z); } } } var radius = new Vector3(maxX, maxY, maxZ).Length() * 2; _localisedBoundingRegion = new LocalisedBoundingRegion(radius); vertexBuffer = new VertexBuffer( renderContext.GraphicsDevice, _cachedModelVertexMapping.VertexDeclaration, Vertexes.Length, BufferUsage.WriteOnly); vertexBuffer.GetType().GetMethods().First(x => x.Name == "SetData" && x.GetParameters().Length == 1).MakeGenericMethod(_cachedModelVertexMapping.VertexType).Invoke( vertexBuffer, new[] { mappedVerticies }); _cachedVertexBuffers[effect] = vertexBuffer; } if (effectParameterSet.HasSemantic <IBonesEffectSemantic>()) { var bonesEffectSemantic = effectParameterSet.GetSemantic <IBonesEffectSemantic>(); foreach (var bone in _flattenedBones) { if (bone.ID == -1) { continue; } bonesEffectSemantic.Bones[bone.ID] = bone.GetFinalMatrix(); } } // Create the render request. return(_renderBatcher.CreateSingleRequestFromState( renderContext, effect, effectParameterSet, vertexBuffer, IndexBuffer, PrimitiveType.TriangleList, renderContext.World * transform, (m, vb, ib) => { var mappedVerticies = Array.CreateInstance(_cachedModelVertexMapping.VertexType, Vertexes.Length * m.Count); var mappedIndicies = new int[Indices.Length * m.Count]; for (var im = 0; im < m.Count; im++) { for (var i = 0; i < Vertexes.Length; i++) { var vertex = _cachedModelVertexMapping.MappingFunction(Vertexes[i].Transform(m[im])); mappedVerticies.SetValue(vertex, im * Vertexes.Length + i); } for (var i = 0; i < Indices.Length; i++) { mappedIndicies[im * Vertexes.Length + i] = Indices[i] + Vertexes.Length * im; } } vb.GetType().GetMethods().First(x => x.Name == "SetData" && x.GetParameters().Length == 1).MakeGenericMethod(_cachedModelVertexMapping.VertexType).Invoke( vb, new[] { mappedVerticies }); ib.SetData(mappedIndicies); }, _localisedBoundingRegion)); }