/// <summary> /// Create the material from another material instance. /// </summary> /// <param name="other">Other material to clone.</param> public SkinnedMaterial(SkinnedMaterial other) { _effect = other._effect.Clone() as SkinnedEffect; MaterialAPI asBase = this; other.CloneBasics(ref asBase); }
/// <summary> /// Draw this model. /// </summary> /// <param name="worldTransformations">World transformations to apply on this entity (this is what you should use to draw this entity).</param> public override void DoEntityDraw(ref Matrix worldTransformations) { // call base draw entity base.DoEntityDraw(ref worldTransformations); // reset last radius _lastRadius = 0f; float scaleLen = worldTransformations.Scale.Length(); // iterate model meshes foreach (var mesh in Model.Meshes) { // iterate over mesh effects and apply them (set world matrix etc) foreach (var effect in mesh.Effects) { Materials.MaterialAPI material = effect.GetMaterial(); material.Apply(ref worldTransformations, ref _lastBoundingSphere); } // update last radius _lastRadius = System.Math.Max(_lastRadius, mesh.BoundingSphere.Radius * scaleLen); // draw the mesh itself mesh.Draw(); } }
/// <summary> /// Add array of vertices to the combined mesh. /// </summary> /// <param name="vertices">Vertices array to add.</param> /// <param name="indexes">Draw order / indexes array.</param> /// <param name="material">Material to use with the vertices.</param> public void AddVertices(VertexType[] vertices, ushort[] indexes, Materials.MaterialAPI material) { // sanity check - if build was called assert if (_wasBuilt) { throw new Exceptions.InvalidActionException("Cannot add vertices to Combined Mesh Entity after it was built!"); } // get the combined chunk to add these vertices to CombinedMeshesPart combinedPart = GetCombinedPart(material); // add vertices to combined part combinedPart.Vertices.AddRange(vertices); foreach (var vertex in vertices) { _allPoints.Add(GetPosition(vertex)); } // set indexes combinedPart.PushIndexes(indexes); // increase index offset in combined part combinedPart.IndexOffset += vertices.Length; // update primitives count combinedPart.PrimitiveCount += indexes.Length / 3; }
/// <summary> /// Create the material from another material instance. /// </summary> /// <param name="other">Other material to clone.</param> public BasicMaterial(BasicMaterial other) { _effect = other._effect.Clone() as BasicEffect; MaterialAPI asBase = this; other.CloneBasics(ref asBase); }
/// <summary> /// Create the material from another material instance. /// </summary> /// <param name="other">Other material to clone.</param> public SkyboxMaterial(SkyboxMaterial other) { _effect = other._effect.Clone() as BasicEffect; MaterialAPI asBase = this; other.CloneBasics(ref asBase); FlipYZ = other.FlipYZ; }
/// <summary> /// Draw this model. /// </summary> /// <param name="worldTransformations">World transformations to apply on this entity (this is what you should use to draw this entity).</param> public override void DoEntityDraw(ref Matrix worldTransformations) { // call base draw entity base.DoEntityDraw(ref worldTransformations); // decompose transformations Vector3 position; Quaternion rotation; Vector3 scale; worldTransformations.Decompose(out scale, out rotation, out position); // add position offset position += PositionOffset; // create a new world matrix for the billboard Matrix newWorld; // if facing camera, create billboard world matrix if (FaceCamera) { // set rotation based on camera with locked axis if (LockedAxis != null) { newWorld = Matrix.CreateScale(scale) * Matrix.CreateConstrainedBillboard(position, GraphicsManager.ActiveCamera.Position, LockedAxis.Value, null, null); } // set rotation based on camera without any locked axis else { newWorld = Matrix.CreateScale(scale) * Matrix.CreateBillboard(position, GraphicsManager.ActiveCamera.Position, Vector3.Up, null); } } // if not facing camera, just use world transformations else { newWorld = worldTransformations; } // update per-entity override properties Materials.MaterialAPI material = MaterialOverride.Apply(Material); // setup material material.Apply(ref newWorld, ref _lastBoundingSphere); // draw sprite // draw the cube vertices material.IterateEffectPasses((EffectPass pass) => { GraphicsManager.GraphicsDevice.DrawUserIndexedPrimitives <VertexPositionNormalTexture>( PrimitiveType.TriangleList, _spritesheetStep.Vertices, 0, 4, _spritesheetStep.Indexes, 0, 2); }); }
/// <summary> /// Create the material from another material instance. /// </summary> /// <param name="other">Other material to clone.</param> public AlphaTestMaterial(AlphaTestMaterial other) { _effect = other._effect.Clone() as AlphaTestEffect; MaterialAPI asBase = this; other.CloneBasics(ref asBase); AlphaFunction = other.AlphaFunction; ReferenceAlpha = other.ReferenceAlpha; }
/// <summary> /// Create the material from another material instance. /// </summary> /// <param name="other">Other material to clone.</param> public LitMaterial(LitMaterial other) { // clone effect and set defaults _effect = other._effect.Clone(); MaterialAPI asBase = this; other.CloneBasics(ref asBase); // init light params InitLightParams(); }
/// <summary> /// Create the sprite entity. /// </summary> /// <param name="spritesheet">Spritesheet for this sprite.</param> /// <param name="material">Material to use for this sprite.</param> public SpriteEntity(SpriteSheet spritesheet, Materials.MaterialAPI material) : base() { // store spritesheet and material Spritesheet = spritesheet; _material = material; // set default rendering queue RenderingQueue = RenderingQueue.Billboards; // set default step _spritesheetStep = spritesheet.GetStep(0); }
/// <summary> /// Clone all the basic properties of a material. /// </summary> /// <param name="cloned">Cloned material to copy properties into.</param> protected void CloneBasics(ref MaterialAPI cloned) { cloned.World = World; cloned.TextureEnabled = TextureEnabled; cloned.Texture = Texture; cloned.Alpha = Alpha; cloned.DiffuseColor = DiffuseColor; cloned.SpecularColor = SpecularColor; cloned.SpecularPower = SpecularPower; cloned.AmbientLight = AmbientLight; cloned.EmissiveLight = EmissiveLight; cloned.SamplerState = SamplerState; }
/// <summary> /// Apply all custom render properties on a given material, and return either the given material or a clone of it, if needed. /// This will not do anything if there are no custom properties currently used. /// </summary> /// <param name="material">Effect to set properties.</param> /// <returns>Either the input material or a clone of it with applied properties.</returns> public Materials.MaterialAPI Apply(Materials.MaterialAPI material) { // if there's nothing to do just return the original material if (!UsingOverrideProperties) { _materialsCahce.Clear(); return(material); } // we need to apply custom properties. get the cached material with properties or create a new one Materials.MaterialAPI original = material; if (!_materialsCahce.TryGetValue(material, out material)) { material = original.Clone(); _materialsCahce[original] = material; } // if got override diffuse color, set it if (DiffuseColor != null) { material.DiffuseColor = DiffuseColor.Value; } // if got override specular color, set it if (SpecularColor != null) { material.SpecularColor = SpecularColor.Value; } // if got override emissive color, set it if (EmissiveLight != null) { material.EmissiveLight = EmissiveLight.Value; } // if got override alpha, set it if (Alpha != null) { material.Alpha = Alpha.Value; } // if got override texture, set it if (Texture != null) { material.Texture = Texture; material.TextureEnabled = true; } // return the cloned material return(material); }
/// <summary> /// Add a model to the combined mesh. /// </summary> /// <param name="model">Model to add.</param> /// <param name="transform">World transformations.</param> /// <param name="material">Optional material to use instead of the model default materials.</param> public void AddModel(Model model, Matrix transform, Materials.MaterialAPI material = null) { // sanity check - if build was called assert if (_wasBuilt) { throw new Exceptions.InvalidActionException("Cannot add model to Combined Mesh Entity after it was built!"); } // iterate model meshes and add them foreach (var mesh in model.Meshes) { AddModelMesh(mesh, transform, material); } }
/// <summary> /// Get combined mesh part from material. /// </summary> /// <param name="material">Material to get combined part for.</param> /// <returns>Combined mesh part.</returns> private CombinedMeshesPart GetCombinedPart(Materials.MaterialAPI material) { // try to get from existing parts and if not found create it CombinedMeshesPart combinedPart; if (!_parts.TryGetValue(material, out combinedPart)) { combinedPart = new CombinedMeshesPart(); _parts[material] = combinedPart; } // return combined part return(combinedPart); }
/// <summary> /// Return a list with all materials in model. /// Note: if alternative materials are set, will return them. /// Note2: prevent duplications, eg if even if more than one part uses the same material it will only return it once. /// </summary> /// <returns>List of materials.</returns> public List <Materials.MaterialAPI> GetMaterials() { List <Materials.MaterialAPI> ret = new List <Materials.MaterialAPI>(); foreach (var mesh in Model.Meshes) { for (int i = 0; i < mesh.MeshParts.Count; ++i) { Materials.MaterialAPI material = GetMaterial(mesh.Name, i); if (!ret.Contains(material)) { ret.Add(material); } } } return(ret); }
/// <summary> /// Apply all new properties on the material effect. /// Call this whenever you want to draw using this material. /// </summary> /// <param name="worldMatrix">The world transformations of the currently rendered entity.</param> /// <param name="boundingSphere">The bounding sphere (should be already transformed) of the rendered entity.</param> public void Apply(ref Matrix worldMatrix, ref BoundingSphere boundingSphere) { // set world matrix World = worldMatrix; // apply sampler state ApplySamplerState(); // update view if needed if (_viewMatrixVersion != _globalViewMatrixVersion) { UpdateView(ref _view); _viewMatrixVersion = _globalViewMatrixVersion; } // update projection if needed if (_projectionMatrixVersion != _globalProjectionMatrixVersion) { UpdateProjection(ref _projection); _projectionMatrixVersion = _globalProjectionMatrixVersion; } // if support light get lights and set them if (LightingEnabled && UseDefaultLightsManager) { // get lights in rendering range var lightsManager = GraphicsManager.ActiveLightsManager; var lights = lightsManager.GetLights(this, ref boundingSphere, MaxLights); AmbientLight = lightsManager.AmbientLight; ApplyLights(lights, ref worldMatrix, ref boundingSphere); } // set effect tag to point on self, and call the per-effect specific apply if (Effect.Tag == null) { Effect.Tag = this; } MaterialSpecificApply(_lastMaterialApplied == this); // set last material applied to self _lastMaterialApplied = this; // clear flags _dirtyFlags = 0; }
/// <summary> /// Return a list with all materials in model. /// Note: if alternative materials are set, will return them. /// Note2: prevent duplications, eg if even if more than one part uses the same material it will only return it once. /// </summary> /// <returns>List of materials.</returns> public List <Materials.MaterialAPI> GetMaterials() { List <Materials.MaterialAPI> ret = new List <Materials.MaterialAPI>(); foreach (DictionaryEntry entry in _meshes) { MeshEntity mesh = entry.Value as MeshEntity; for (int i = 0; i < mesh.Mesh.MeshParts.Count; ++i) { Materials.MaterialAPI material = mesh.GetMaterial(i); if (!ret.Contains(material)) { ret.Add(material); } } } return(ret); }
/// <summary> /// Draw this model. /// </summary> /// <param name="worldTransformations">World transformations to apply on this entity (this is what you should use to draw this entity).</param> public override void DoEntityDraw(ref Matrix worldTransformations) { // call base draw entity base.DoEntityDraw(ref worldTransformations); // reset last radius _lastRadius = 0f; float scaleLen = Utils.ExtendedMath.GetScale(ref worldTransformations).Length(); // iterate model meshes foreach (var mesh in Model.Meshes) { // check if in this mesh we have shared materials, eg same effects used for several mesh parts bool gotSharedEffects = mesh.Effects.Count != mesh.MeshParts.Count; // iterate over mesh parts int index = 0; foreach (var meshPart in mesh.MeshParts) { // get material for this mesh and effect index Materials.MaterialAPI material = GetMaterial(mesh.Name, index); // no material found? skip. // note: this can happen if user set alternative materials array with less materials than original mesh file if (material == null) { break; } // update per-entity override properties material = MaterialOverride.Apply(material); // if we don't have shared effects, eg every mesh part has its own effect, update material transformations if (!gotSharedEffects) { material.Apply(ref worldTransformations, ref _lastBoundingSphere); } // apply material effect on the mesh part. note: we first store original effect in mesh part's tag. meshPart.Tag = meshPart.Effect; meshPart.Effect = material.Effect; // next index. ++index; } // if we have shared effects, eg more than one mesh part with the same effect, we apply all materials here // this is to prevent applying the same material more than once if (gotSharedEffects) { foreach (var effect in mesh.Effects) { effect.GetMaterial().Apply(ref worldTransformations, ref _lastBoundingSphere); } } // update last radius _lastRadius = System.Math.Max(_lastRadius, mesh.BoundingSphere.Radius * scaleLen); // iterate mesh parts if (ProcessMeshParts) { foreach (ModelMeshPart part in mesh.MeshParts) { // call the before-drawing-mesh-part callback BeforeDrawingMeshPart(part); } } // draw the mesh itself mesh.Draw(); // restore original effect to mesh parts foreach (var meshPart in mesh.MeshParts) { meshPart.Effect = meshPart.Tag as Effect; meshPart.Tag = null; } } }
/// <summary> /// Set alternative material for a specific mesh id. /// </summary> /// <param name="material">Material to set.</param> /// <param name="meshId">Mesh name. If empty string is provided, this material will be used for all meshes.</param> public void SetMaterial(Materials.MaterialAPI material, string meshId = "") { _materials[meshId] = new Materials.MaterialAPI[] { material }; }
/// <summary> /// Add array of vertices to the combined mesh. /// </summary> /// <param name="vertices">Vertices array to add.</param> /// <param name="indexes">Draw order / indexes array.</param> /// <param name="transform">World transformations.</param> /// <param name="material">Material to use with the vertices.</param> public void AddVertices(VertexPositionNormalTexture[] vertices, ushort[] indexes, Matrix transform, Materials.MaterialAPI material) { // sanity check - if build was called assert if (_wasBuilt) { throw new Exceptions.InvalidActionException("Cannot add vertices to Combined Mesh Entity after it was built!"); } // if transform is identity skip everything here if (transform == Matrix.Identity) { AddVertices(vertices, indexes, material); return; } // transform all vertices from array int i = 0; VertexPositionNormalTexture[] processed = new VertexPositionNormalTexture[vertices.Length]; foreach (var vertex in vertices) { // get current vertex VertexPositionNormalTexture curr = vertex; // apply transformations curr.Position = Vector3.Transform(curr.Position, transform); curr.Normal = Vector3.Normalize(Vector3.TransformNormal(curr.Normal, transform)); processed[i++] = curr; } // add processed vertices AddVertices(processed, indexes, material); }
/// <summary> /// Prepare material to draw this model. /// </summary> /// <param name="material">Material to prepare.</param> /// <param name="world">World transformations.</param> protected void PrepareMaterial(Materials.MaterialAPI material, Matrix world) { // set world / view / projection matrix of the effect material.World = world; }
/// <summary> /// Set first alternative material for this mesh (useful for meshes with one effect). /// </summary> /// <param name="material">Material to set.</param> public void SetMaterial(Materials.MaterialAPI material) { _materials = new Materials.MaterialAPI[] { material }; }
/// <summary> /// Add a model mesh to the combined mesh. /// </summary> /// <param name="mesh">Mesh to add.</param> /// <param name="transform">World transformations.</param> /// <param name="material">Optional material to use instead of the mesh default materials.</param> public void AddModelMesh(ModelMesh mesh, Matrix transform, Materials.MaterialAPI material = null) { // sanity check - if build was called assert if (_wasBuilt) { throw new Exceptions.InvalidActionException("Cannot add meshes to Combined Mesh Entity after it was built!"); } // did we get material override to set? bool externalMaterial = material != null; // iterate mesh parts foreach (var meshPart in mesh.MeshParts) { // if we didn't get external material to use, get material from mesh part. if (!externalMaterial) { material = meshPart.GetMaterial(); } // get the combined chunk to add this meshpart to CombinedMeshesPart combinedPart = GetCombinedPart(material); // make sure its not readonly if (meshPart.VertexBuffer.BufferUsage == BufferUsage.WriteOnly || meshPart.IndexBuffer.BufferUsage == BufferUsage.WriteOnly) { throw new Exceptions.InvalidValueException("Cannot add mesh with write-only buffers to Combined Mesh!"); } // make sure vertex buffer uses position-normal-texture if (meshPart.VertexBuffer.VertexDeclaration.VertexStride < 8) { throw new Exceptions.InvalidValueException("Combined meshes can only use vertex buffers with position, normal and texture!"); } // get vertex buffer parameters int vertexStride = meshPart.VertexBuffer.VertexDeclaration.VertexStride; int vertexBufferSize = meshPart.NumVertices * vertexStride; // get vertex data as float float[] vertexData = new float[vertexBufferSize / sizeof(float)]; meshPart.VertexBuffer.GetData <float>(vertexData); // iterate through vertices and add them int verticesInPart = 0; for (int i = 0; i < vertexBufferSize / sizeof(float); i += vertexStride / sizeof(float)) { // get curr position with transformations Vector3 currPosition = Vector3.Transform(new Vector3(vertexData[i], vertexData[i + 1], vertexData[i + 2]), transform); // get other vertex properties based on type and add to vertices buffer switch (_vtype) { case VertexTypes.VertexPosition: { // add to buffer var vertexToAdd = new VertexPosition(currPosition); combinedPart.Vertices.Add(ToVertexType(vertexToAdd)); break; } case VertexTypes.VertexPositionColor: { // get color Color currColor = new Color(vertexData[i + 3], vertexData[i + 4], vertexData[i + 5], vertexData[i + 6]); // add to buffer var vertexToAdd = new VertexPositionColor(currPosition, currColor); combinedPart.Vertices.Add(ToVertexType(vertexToAdd)); break; } case VertexTypes.VertexPositionNormalTexture: { // get normal Vector3 normal = new Vector3(vertexData[i + 3], vertexData[i + 4], vertexData[i + 5]); normal = Vector3.Normalize(Vector3.TransformNormal(normal, transform)); // get texture coords Vector2 textcoords = new Vector2(vertexData[i + 6], vertexData[i + 7]); // add to buffer var vertexToAdd = new VertexPositionNormalTexture(currPosition, normal, textcoords); combinedPart.Vertices.Add(ToVertexType(vertexToAdd)); break; } case VertexTypes.VertexPositionNormalTangentTexture: { // get normal Vector3 normal = new Vector3(vertexData[i + 3], vertexData[i + 4], vertexData[i + 5]); normal = Vector3.Normalize(Vector3.TransformNormal(normal, transform)); // get tangent Vector3 tangent = new Vector3(vertexData[i + 6], vertexData[i + 7], vertexData[i + 8]); // get binormal Vector3 binormal = new Vector3(vertexData[i + 9], vertexData[i + 10], vertexData[i + 11]); // get texture coords Vector2 textcoords = new Vector2(vertexData[i + 12], vertexData[i + 13]); // add to buffer var vertexToAdd = new VertexPositionNormalTangentTexture(currPosition, normal, textcoords, tangent, binormal); combinedPart.Vertices.Add(ToVertexType(vertexToAdd)); break; } case VertexTypes.VertexPositionTexture: { // get texture coords Vector2 textcoords = new Vector2(vertexData[i + 3], vertexData[i + 4]); // add to buffer var vertexToAdd = new VertexPositionTexture(currPosition, textcoords); combinedPart.Vertices.Add(ToVertexType(vertexToAdd)); break; } default: throw new Exceptions.InternalError("Forgot to implement type support?"); } // add to temp list of all points and increase vertices count _allPoints.Add(currPosition); verticesInPart++; } // set indexes ushort[] drawOrder = new ushort[meshPart.IndexBuffer.IndexCount]; meshPart.IndexBuffer.GetData <ushort>(drawOrder); combinedPart.PushIndexes(drawOrder); // increase indexes offset combinedPart.IndexOffset += verticesInPart; // increase primitives count combinedPart.PrimitiveCount += meshPart.PrimitiveCount; } }
/// <summary> /// Add array of vertices to the combined mesh. /// </summary> /// <param name="vertices">Vertices array to add.</param> /// <param name="indexes">Draw order / indexes array.</param> /// <param name="transform">World transformations.</param> /// <param name="material">Material to use with the vertices.</param> public void AddVertices(VertexType[] vertices, ushort[] indexes, Matrix transform, Materials.MaterialAPI material) { // sanity check - if build was called assert if (_wasBuilt) { throw new Exceptions.InvalidActionException("Cannot add vertices to Combined Mesh Entity after it was built!"); } // if transform is identity skip everything here if (transform == Matrix.Identity) { AddVertices(vertices, indexes, material); return; } // transform all vertices from array int i = 0; VertexType[] processed = new VertexType[vertices.Length]; foreach (var vertex in vertices) { // get current vertex VertexType curr = vertex; // apply transformations switch (_vtype) { case VertexTypes.VertexPosition: { var currVer = ToSpecificVertexType <VertexPosition>(curr); currVer.Position = Vector3.Transform(currVer.Position, transform); processed[i++] = ToVertexType(currVer); break; } case VertexTypes.VertexPositionColor: { var currVer = ToSpecificVertexType <VertexPositionColor>(curr); currVer.Position = Vector3.Transform(currVer.Position, transform); processed[i++] = ToVertexType(currVer); break; } case VertexTypes.VertexPositionNormalTexture: { var currVer = ToSpecificVertexType <VertexPositionNormalTexture>(curr); currVer.Position = Vector3.Transform(currVer.Position, transform); currVer.Normal = Vector3.Normalize(Vector3.TransformNormal(currVer.Normal, transform)); processed[i++] = ToVertexType(currVer); break; } case VertexTypes.VertexPositionNormalTangentTexture: { var currVer = ToSpecificVertexType <VertexPositionNormalTangentTexture>(curr); currVer.Position = Vector3.Transform(currVer.Position, transform); currVer.Normal = Vector3.Normalize(Vector3.TransformNormal(currVer.Normal, transform)); currVer.Tangent = Vector3.Normalize(Vector3.TransformNormal(currVer.Tangent, transform)); currVer.Binormal = Vector3.Normalize(Vector3.TransformNormal(currVer.Binormal, transform)); processed[i++] = ToVertexType(currVer); break; } case VertexTypes.VertexPositionTexture: { var currVer = ToSpecificVertexType <VertexPositionTexture>(curr); currVer.Position = Vector3.Transform(currVer.Position, transform); processed[i++] = ToVertexType(currVer); break; } } } // add processed vertices AddVertices(processed, indexes, material); }