/// <summary> /// emits the specified particle object according to the emit type. /// </summary> /// <param name="obj">a particle object</param> protected void EmitParticle(ref ParticleObject obj) { float massRange = 0.0f; Matrix mtx1 = Matrix.Identity; float rnd1 = 0.0f, rnd2 = 0.0f; obj.state = (uint)(ParticleObject.States.Enable | ParticleObject.States.Fired | ParticleObject.States.FirstTime); obj.time = 0.0f; obj.posInterval = Info.PositionUpdateInterval; obj.scaleInterval = Info.ScaleUpdateInterval; obj.textureSequenceInterval = 0.0f; massRange = Info.MassMax - Info.MassMin; obj.mass = Info.MassMin + (HelperMath.RandomNormal() * massRange); obj.gravity = Vector3.Zero; obj.posRandomInterval = Info.PositionRandomInterval; switch (Info.EmitType) { // CONE type : changes tje direction randomly // from the default EmitDirection. case ParticleInfo.EmitObjectType.Cone: { rnd1 = HelperMath.RandomNormal2() * Info.EmitAngle; rnd2 = HelperMath.RandomNormal2() * Info.EmitAngle; mtx1 = Matrix.CreateFromAxisAngle(emitRight, MathHelper.ToRadians(rnd1)); mtx1 = mtx1 * Matrix.CreateFromAxisAngle(emitUp, MathHelper.ToRadians(rnd2)); obj.emitDir = Vector3.TransformNormal(Info.EmitDirection, mtx1); obj.startPos = Info.EmitPosition; } break; // SPHERE type : make the emit direction to the total random direction. case ParticleInfo.EmitObjectType.Sphere: { obj.emitDir = HelperMath.RandomVector2(); obj.emitDir.Normalize(); obj.startPos = Info.EmitPosition; } break; // Disk type: basically same as the cone, // (however, except the rotation around the EmitUpVector as the axis) // it makes the direction which is randomly turned // as the UpVector as the axis. case ParticleInfo.EmitObjectType.Disk: { rnd1 = HelperMath.RandomNormal2() * Info.EmitAngle; mtx1 = Matrix.CreateFromAxisAngle(emitRight, MathHelper.ToRadians(rnd1)); mtx1 = mtx1 * Matrix.CreateFromAxisAngle(Info.UpVector, HelperMath.RandomNormal() * 2.0f * MathHelper.Pi); obj.emitDir = Vector3.TransformNormal(Info.EmitDirection, mtx1); obj.startPos = Info.EmitPosition; } break; // RECT_PLANE type : The EmitAngle will follow the size // of a square area, not an angle. // The EmitDirection is always constant. case ParticleInfo.EmitObjectType.RectPlane: { obj.emitDir = Info.EmitDirection; rnd1 = (HelperMath.RandomNormal2() * 0.5f) * Info.EmitAngle; rnd2 = (HelperMath.RandomNormal2() * 0.5f) * Info.EmitAngle; obj.pos[0] = upRight * rnd1; obj.pos[0] += upAt * rnd2; obj.startPos = obj.pos[0] + Info.EmitPosition; } break; // CIRCLE_PLANE type : The circular area whose radius is the EmitAngle. case ParticleInfo.EmitObjectType.CirclePlane: { obj.emitDir = Info.EmitDirection; rnd1 = HelperMath.RandomNormal() * Info.EmitAngle; rnd2 = HelperMath.RandomNormal() * MathHelper.Pi * 2.0f; obj.pos[0] = upRight * rnd1; // Scaling mtx1 = Matrix.CreateFromAxisAngle(Info.UpVector, rnd2); obj.pos[0] = Helper3D.TransformCoord(obj.pos[0], mtx1); obj.startPos = obj.pos[0] + Info.EmitPosition; } break; } if (refEnable) { obj.startPos = Helper3D.TransformCoord(obj.startPos, (Matrix)refMatrix); obj.emitDir = Vector3.TransformNormal(obj.emitDir, (Matrix)refMatrix); } obj.pos[0] = obj.startPos; obj.scale = Vector3.Zero; obj.posRandom = 1.0f + ((HelperMath.RandomNormal2() * 0.5f) * Info.PositionInitialRandomFactor); obj.scaleRandom = 1.0f + ((HelperMath.RandomNormal2() * 0.5f) * Info.ScaleInitialRandomFactor); obj.rotateRandom = HelperMath.RandomNormal2(); switch (Info.ParticleType) { case ParticleInfo.ParticleObjectType.AnchorBillboard: { obj.pos[1] = obj.pos[0]; } break; case ParticleInfo.ParticleObjectType.Scene: { obj.rotateDir = HelperMath.RandomVector2(); } break; } { for (int i = 0; i < posArgCount; i++) obj.posArg[i] = Info.PositionInit[i]; for (int i = 0; i < scaleArgCount; i++) obj.scaleArg[i] = Info.ScaleInit[i]; obj.rotateAccm = Info.RotateInit + (HelperMath.RandomNormal2() * Info.RotateRandomFactor); } }
/// <summary> /// by using the particle information, a particle object is created /// and initialized. /// </summary> public void Create() { // Initialize Particle Information Info.Initialize(); Name = sequenceInfo.Name; sceneRoot.RemoveAllChild(false); if (sequenceInfo.TextureFileName.Length > 0) { string resourceFullPath = Path.Combine(resourcePath, sequenceInfo.TextureFileName); GameResourceTexture2D resource = FrameworkCore.ResourceManager.LoadTexture(resourceFullPath); // Set to texture Texture = resource.Texture2D; // Set to texture in TextureSequence if (TextureSequence != null) TextureSequence.SetTexture(Texture); } enableRotate = false; switch (Info.ParticleType) { // PointSprite case ParticleInfo.ParticleObjectType.PointSprite: { scenePointSprite = new GamePointSprite(); scenePointSprite.Create(Info.MaxObjectCount, Texture, RenderingSpace.World, false); scenePointSprite.AlphaBlendEnable = sequenceInfo.AlphaBlendEnable; scenePointSprite.DepthBufferEnable = sequenceInfo.DepthBufferEnable; scenePointSprite.SourceBlend = sequenceInfo.SourceBlend; scenePointSprite.DestinationBlend = sequenceInfo.DestinationBlend; scenePointSprite.BlendFunction = sequenceInfo.BlendFunction; scenePointSprite.DepthBufferEnable = true; scenePointSprite.DepthBufferWriteEnable = false; scenePointSprite.DepthBufferFunction = CompareFunction.Less; scenePointSprite.AlphaFunction = CompareFunction.Greater; scenePointSprite.CullMode = CullMode.None; sceneRoot.AddChild(scenePointSprite); } break; // Sprite3D case ParticleInfo.ParticleObjectType.Sprite: { sceneSprite3D = new GameSprite3D(); sceneSprite3D.Create(Info.MaxObjectCount, Texture, RenderingSpace.World, false); sceneSprite3D.AlphaBlendEnable = sequenceInfo.AlphaBlendEnable; sceneSprite3D.DepthBufferEnable = sequenceInfo.DepthBufferEnable; sceneSprite3D.SourceBlend = sequenceInfo.SourceBlend; sceneSprite3D.DestinationBlend = sequenceInfo.DestinationBlend; sceneSprite3D.BlendFunction = sequenceInfo.BlendFunction; sceneSprite3D.DepthBufferEnable = true; sceneSprite3D.DepthBufferWriteEnable = false; sceneSprite3D.DepthBufferFunction = CompareFunction.Less; sceneSprite3D.AlphaFunction = CompareFunction.Greater; sceneSprite3D.CullMode = CullMode.None; sceneRoot.AddChild(sceneSprite3D); enableRotate = true; // Possible to rotation } break; // Billboard case ParticleInfo.ParticleObjectType.AnchorBillboard: case ParticleInfo.ParticleObjectType.Billboard: { sceneBillboard = new GameBillboard(); sceneBillboard.Create(Info.MaxObjectCount, Texture, RenderingSpace.World, false); sceneBillboard.AlphaBlendEnable = sequenceInfo.AlphaBlendEnable; sceneBillboard.DepthBufferEnable = sequenceInfo.DepthBufferEnable; sceneBillboard.SourceBlend = sequenceInfo.SourceBlend; sceneBillboard.DestinationBlend = sequenceInfo.DestinationBlend; sceneBillboard.BlendFunction = sequenceInfo.BlendFunction; sceneBillboard.DepthBufferEnable = true; sceneBillboard.DepthBufferWriteEnable = false; sceneBillboard.DepthBufferFunction = CompareFunction.Less; sceneBillboard.AlphaFunction = CompareFunction.Greater; sceneBillboard.CullMode = CullMode.None; sceneRoot.AddChild(sceneBillboard); } break; // Mesh case ParticleInfo.ParticleObjectType.Scene: { if( Info.MeshData != null) { int vertextCount = Info.MeshData.Position.Count; int indexCount = 0; if (Info.MeshData.Index != null) indexCount = Info.MeshData.Index.Count; sceneMesh = new GameMesh(); sceneMesh.Create(vertextCount, indexCount, Texture); sceneMesh.AlphaBlendEnable = sequenceInfo.AlphaBlendEnable; sceneMesh.DepthBufferEnable = sequenceInfo.DepthBufferEnable; sceneMesh.SourceBlend = sequenceInfo.SourceBlend; sceneMesh.DestinationBlend = sequenceInfo.DestinationBlend; sceneMesh.BlendFunction = sequenceInfo.BlendFunction; sceneMesh.DepthBufferEnable = true; sceneMesh.DepthBufferWriteEnable = false; sceneMesh.DepthBufferFunction = CompareFunction.Less; sceneMesh.AlphaFunction = CompareFunction.Greater; sceneMesh.CullMode = CullMode.None; // Has position data if (Info.MeshData.HasPosition ) { sceneMesh.SetPositionData( Info.MeshData.Position.ToArray()); } // Has color data if (Info.MeshData.HasColor ) { sceneMesh.SetColorData( Info.MeshData.Color.ToArray()); } // Has texture coordinate data if (Info.MeshData.HasTextureCoord ) { sceneMesh.SetTextureCoordData( Info.MeshData.TextureCoord.ToArray()); } // Has index data if (Info.MeshData.HasIndex ) { sceneMesh.SetIndexData(Info.MeshData.Index.ToArray()); } // Use VB and IB if (sceneMesh.userPrimitive == false) { sceneMesh.BindVertexBuffer(); sceneMesh.BindIndexBuffer(); } sceneRoot.AddChild(sceneMesh); } enableRotate = true; // can rotate } break; } SetSceneEnable(false); // Particle Object particleObjectList.Clear(); for (int i = 0; i < Info.MaxObjectCount; i++) { ParticleObject obj = new ParticleObject(); particleObjectList.Add(obj); } // Emit Right & Up Vector { Matrix mtx = Helper3D.MakeMatrixWithAt(Info.EmitDirection, Info.UpVector); emitRight = mtx.Right; emitUp = mtx.Up; } // Up Right & At Vector { Matrix mtx = Helper3D.MakeMatrixWithUp(Info.UpVector, Matrix.Identity.Forward); upRight = mtx.Right; upAt = mtx.Forward; } posArgCount = 0; for (int i = ParticleInfo.FuncCount - 1; i >= 0; i--) { if (Info.PositionFunc[i] != ParticleInfo.FuncType.None) { posArgCount = i + 1; break; } } scaleArgCount = 0; for (int i = ParticleInfo.FuncCount - 1; i >= 0; i--) { if (Info.ScaleFunc[i] != ParticleInfo.FuncType.None) { scaleArgCount = i + 1; break; } } if( Info.IsPositionStyle( ParticleInfo.ParamStyles.Interpolate)) positionInterpolate = KeyFrameTable.Interpolation.Lerp; else positionInterpolate = KeyFrameTable.Interpolation.None; if (Info.IsScaleStyle(ParticleInfo.ParamStyles.Interpolate)) scaleInterpolate = KeyFrameTable.Interpolation.Lerp; else scaleInterpolate = KeyFrameTable.Interpolation.None; if (Info.IsColorStyle(ParticleInfo.ParamStyles.Interpolate)) colorInterpolate = KeyFrameTable.Interpolation.Lerp; else colorInterpolate = KeyFrameTable.Interpolation.None; rObjectLifeTime = 1.0f / Info.ObjectLifeTime; isStarting = false; isStopping = false; }