private RasterInkStroke CreateDryStrokeFromRasterBrush(DecodedRasterInkBuilder decodedRasterInkBuilder, RasterBrush rasterBrush, Stroke stroke) { var result = decodedRasterInkBuilder.AddWholePath(stroke.Spline.Data, rasterBrush.Spacing, stroke.Layout); List <float> points = new List <float>(result.Addition); uint channelMask = (uint)decodedRasterInkBuilder.SplineInterpolator.InterpolatedSplineLayout.ChannelMask; ParticleList particleList = new ParticleList(); particleList.Assign(points, channelMask); ParticleBrush particleBrush = new ParticleBrush { FillTexture = mGraphics.CreateTexture(Task.Run(async() => await Utils.GetPixelDataAsync(rasterBrush.FillTexture)).Result), FillTileSize = new Size(rasterBrush.FillWidth, rasterBrush.FillHeight), RotationMode = (ParticleRotationMode)rasterBrush.RotationMode, Scattering = rasterBrush.Scattering, ShapeTexture = mGraphics.CreateTexture(Task.Run(async() => await Utils.GetPixelDataAsync(rasterBrush.ShapeTextures[0])).Result) }; RasterInkStroke dryStroke = new RasterInkStroke(stroke, rasterBrush, particleList, particleBrush); return(dryStroke); }
internal override void Update(GameTime gameTime) { float now = (float)gameTime.TotalGameTime.TotalMilliseconds; for (int i = ParticleList.Count - 1; i >= 0; i--) { Particle particle = ParticleList[i]; float timeAlive = now - this.BirthTime; if (timeAlive > this.MaxAge) { ParticleList.RemoveAt(i); } else { float relAge = timeAlive / this.MaxAge; particle.Position = 0.5f * particle.Accelaration * relAge * relAge + particle.Direction * relAge + this.Position; //particle.OrginalPosition; float invAge = 1.0f - relAge; particle.Color = new Color(new Vector4(invAge, invAge, invAge, invAge)); Vector2 positionFromCenter = particle.Position - this.Position; //particle.OrginalPosition; float distance = positionFromCenter.Length(); particle.Scale = ((50.0f + distance) / 200.0f) * this.Size; ParticleList[i] = particle; } } }
public InstantObject GetParticleEffect(ParticleList type) { Queue <InstantObject> container = null; GameObject prefab = null; switch (type) { case ParticleList.Explosion: container = _explosionEffect; prefab = GameData.PrefabExplosion; break; case ParticleList.HitEffectA: container = _hitEffectA; prefab = GameData.PrefabHitEffectA; break; } if (container.Count == 0) { AddToContainer(prefab, container); } InstantObject rv = container.Dequeue(); rv.gameObject.SetActive(true); return(rv); }
protected override void StoreCurrentStroke(string pointerDeviceType) { var allData = mInkBuilder.SplineInterpolator.AllData; var points = new List <float>(); if (allData != null) { for (int i = 0; i < allData.Count; i++) { points.Add(allData[i]); } if (points.Count > 0) { uint channelMask = (uint)mInkBuilder.SplineInterpolator.InterpolatedSplineLayout.ChannelMask; ParticleList path = new ParticleList(); path.Assign(points, channelMask); mDryStrokes.Add(new DryStroke(path, mStartRandomSeed, mStrokeConstants.Clone(), mInkBuilder.Brush)); } } mRenderingContext.SetTarget(mAllStrokesLayer); mRenderingContext.DrawLayer(mCurrentStrokeLayer, null, Ink.Rendering.BlendMode.SourceOver); mRenderingContext.SetTarget(mCurrentStrokeLayer); mRenderingContext.ClearColor(Colors.Transparent); mDirtyRectManager.Reset(); mSerializer.EncodeCurrentStroke(pointerDeviceType, mInkBuilder, mStrokeConstants, mStartRandomSeed); }
public void AddParticleP1(Particle.ParticleInfo info, ParticleList inList) { Particle useParticle = (ParticleSystemRoss.Instance()).GetNextFreeParticleP1(inList, "hmm"); if (particle != null) { switch (info.type) { case ParticleType.kParticle_WaterSparkle: useParticle.Launch_WaterSparkle(info); break; case ParticleType.kParticle_WaterLine: useParticle.Launch_WaterLine(info); break; case ParticleType.kParticle_PondBlob: useParticle.Launch_PondBlob(info); break; default: Globals.Assert(false); break; } } }
public void UpdateList(ParticleList listType) { int listHead; listHead = usedListHead[(int)listType]; int i = listHead; while (i != -1) { bool flagToRemove = false; if ((particle[i]).Update()) { flagToRemove = true; } int prevI = i; i = (particle[i]).next; if (flagToRemove) { particle[prevI].myAtlasBillboard.StopRender(); this.RemoveFromListP1(listType, prevI); this.AddToFreeList(prevI); } } }
public RasterInkStroke(RasterInkBuilder inkBuilder, PointerDeviceType pointerDeviceType, List <float> points, uint seed, RasterBrush rasterBrush, ParticleBrush particleBrush, StrokeConstants StrokeParams, Identifier sensorDataId) { Id = Identifier.FromNewGuid(); PointerDeviceType = pointerDeviceType; uint channelMask = (uint)inkBuilder.SplineInterpolator.InterpolatedSplineLayout.ChannelMask; Path = new ParticleList(); Path.Assign(points, channelMask); RandomSeed = seed; StrokeConstants = StrokeParams; SensorDataId = sensorDataId; RasterBrush = rasterBrush; ParticleBrush = particleBrush; // Cloning is needed, otherwise the spatial data is corrupted Spline = inkBuilder.SplineProducer.AllData.Clone(); Layout = inkBuilder.Layout; }
public DryStroke(ParticleList path, uint seed, StrokeConstants StrokeParams, ParticleBrush particleBrush) { Path = path; RandomSeed = seed; StrokeConstants = StrokeParams; ParticleBrush = particleBrush; }
internal override void AddParticle(GameTime gameTime) { Particle particle = new Particle(); //particle.OrginalPosition = Position; particle.Position = Position; // particle.OrginalPosition; //particle.Rotation = rotation; ////particle.BirthTime = (float)gameTime.TotalGameTime.TotalMilliseconds; ////particle.MaxAge = MaxAge; particle.Scale = 1f; particle.Color = Color.White; //float particleDistance = (float)Manager.Random.NextDouble() * this.Spread; //Size; //Vector2 displacement = new Vector2(particleDistance, 0); //float angle = MathHelper.ToRadians(Manager.Random.Next(360)); //displacement = Vector2.Transform(displacement, Matrix.CreateRotationZ(angle)); //particle.Direction = displacement * 2.0f; //particle.Accelaration = -particle.Direction; Vector2 direction = this.Position - this.aimAt.ToVector2(); direction.Normalize(); particle.Direction = direction; particle.Accelaration = new Vector2(-3f, -3f); ParticleList.Add(particle); }
// Update is called once per frame void Update() { int NumToSpawn = rate; if (spawnerTime < 0.0f) { playing = false; } spawnerTime -= Time.deltaTime; while (currParticles < maxParticles && NumToSpawn > 0 && playing) { //spawn GameObject currPart = Instantiate(particle, this.GetComponent <Transform>()); ParticleList currlist = currPart.GetComponent <ParticleList>(); currlist.position = new Vector3(Random.Range(minRangePos.x, maxRangePos.x), Random.Range(minRangePos.y, maxRangePos.y), Random.Range(minRangePos.z, maxRangePos.z)); //custom spawners: if (ringSpawner) { Vector3 offset = new Vector3(Random.Range(-1.0f, 1.0f), Random.Range(-1.0f, 1.0f), 0.0f); offset.Normalize(); currlist.position += offset * Random.Range(ringRadius, circleRadius); } currlist.velocity = new Vector3(Random.Range(minInitialVel.x, maxInitialVel.x), Random.Range(minInitialVel.y, maxInitialVel.y), 0.0f) * Random.Range(rangeVel.x, rangeVel.y); currlist.size = lerpSize.x; currlist.alpha = lerpAlpha.x; currlist.age = 0.0f; currlist.lifetime = Random.Range(rangeLifetime.x, rangeLifetime.y); currlist.mass = mass; currlist.gravity = gravity; currlist.lerpAlpha = lerpAlpha; currlist.LerpSize = lerpSize; currlist.noiseStrength = noiseStrength; currlist.noiseFrequency = noiseFrequency; currlist.useNoise = noiseOn; currParticles++; NumToSpawn--; } if (play) { play = false; playing = true; spawnerTime = spawnTime; } if (parse) { parse = false; OnParse(); } }
public override void _Ready() { var size = GetViewportRect().Size; var list = new ParticleList() { Position = new Vector2(size.x / 2, size.y / 4) }; AddChild(list); }
public Particle GetNextFreeParticleP1(ParticleList inList, string debugName) { if (freeListHead == -1) { return(null); } int oldHead = freeListHead; this.RemoveFromFreeList(oldHead); this.AddToListP1(inList, oldHead); return(particle[oldHead]); }
/// <summary> /// Updates the Unity Particle System with the generated particle data. /// </summary> void UpdateShuriken() { if (Renderers == null) { return; } foreach (GameObject g in Renderers) { ParticleSystem system = g.GetComponent <ParticleSystem>(); system?.SetParticles(ParticleList.Select(p => Particle.ConvertToParticleSystem(p, m_prefab.TextureSheetPow)).ToArray(), m_particleList.Length); } CalculateBounds(); }
public void UpdateParticles(GameTime gameTime) { EmittedNewParticle = false; if (gameTime.ElapsedGameTime.TotalMilliseconds > 0) { if (Active) { timeSinceLastEmission += gameTime.ElapsedGameTime.Milliseconds; if (emitterFrequency == 0 || timeSinceLastEmission >= emitterFrequency) { emitterFrequency = emitterHelper.RandomizedDouble(RandomEmissionInterval); if (emitterFrequency == 0) { throw new Exception("emitter frequency cannot be below 0.1d !!"); } for (int i = 0; i < Math.Round(timeSinceLastEmission / emitterFrequency); i++) { EmitParticle(); } timeSinceLastEmission = 0; } } else { emitterFrequency = 0; } foreach (Particle particle in ParticleList.ToArray()) { float y = -1 * ((float)Math.Cos(MathHelper.ToRadians(particle.Direction))) * particle.Speed; float x = (float)Math.Sin(MathHelper.ToRadians(particle.Direction)) * particle.Speed; particle.TotalLifetime += gameTime.ElapsedGameTime.Milliseconds; particle.Position += new Vector2(x, y); particle.Rotation += particle.RotationSpeed; ParticleScaler.Scale(particle, ParticleLifeTime); particle.Fade = ParticleFader.Fade(particle, ParticleLifeTime); particle.Color = new Color(particle.Fade, particle.Fade, particle.Fade, particle.Fade); if (particle.TotalLifetime > ParticleLifeTime) { ParticleList.Remove(particle); } } } }
private void EmitParticle() { if (i > TextureList.Count - 1) { i = 0; } Particle particle = new Particle(TextureList[i], Position, (float)emitterHelper.RandomizedDouble(ParticleSpeed), (float)emitterHelper.RandomizedDouble(ParticleDirection), MathHelper.ToRadians((float)emitterHelper.RandomizedDouble(ParticleRotation)), (float)emitterHelper.RandomizedDouble(RotationSpeed), Opacity); ParticleList.Add(particle); EmittedNewParticle = true; LastEmittedParticle = particle; i++; }
public void RemoveFromListP1(ParticleList listType, int whichObject) { numActiveParticles--; int listHead = usedListHead[(int)listType]; if (whichObject == listHead) { usedListHead[(int)listType] = (particle[whichObject]).next; return; } int item = listHead; while ((particle[item]).next != whichObject) { item = (particle[item]).next; } ; (particle[item]).SetNext((particle[whichObject]).next); }
public RasterInkStroke(Stroke stroke, RasterBrush rasterBrush, ParticleList particleList, ParticleBrush particleBrush) { Id = stroke.Id; Path = particleList; RandomSeed = stroke.Style.RandomSeed; RasterBrush = rasterBrush; ParticleBrush = particleBrush; PathPointProperties ppp = stroke.Style.PathPointProperties; StrokeConstants = new StrokeConstants { Color = MediaColor.FromArgb( ppp.Alpha.HasValue ? (byte)(ppp.Alpha * 255.0f) : byte.MinValue, ppp.Red.HasValue ? (byte)(ppp.Red * 255.0f) : byte.MinValue, ppp.Green.HasValue ? (byte)(ppp.Green * 255.0f) : byte.MinValue, ppp.Blue.HasValue ? (byte)(ppp.Blue * 255.0f) : byte.MinValue) }; SensorDataId = stroke.SensorDataId; Spline = stroke.Spline; Layout = stroke.Layout; }
// Play the type of particle on the container // if called with the same type that is being played. do nothing. // if currently played particle is different type, stop and play the new type. public GameObject Play(ParticleList type, Transform container) { GameObject particlePrefab = null; GameObject particle = null; int instanceId = container.GetInstanceID(); if (playingParticles.ContainsKey(container.GetInstanceID())) { ParticleWithType playingParticle = playingParticles[instanceId]; if (playingParticle.type == type) { return(playingParticle.particle); } else { Stop(container); } } particlePrefab = particleDictionary[type]; particle = Instantiate(particlePrefab, container, false) as GameObject; playingParticles[instanceId] = new ParticleWithType(type, particle); return(particle); }
private DryStroke CreateDryStrokeFromRasterBrush(DecodedRasterInkBuilder decodedRasterInkBuilder, RasterBrush rasterBrush, Stroke stroke) { var result = decodedRasterInkBuilder.AddWholePath(stroke.Spline.Data, rasterBrush.Spacing, stroke.Layout); List <float> points = new List <float>(result.Addition); uint channelMask = (uint)decodedRasterInkBuilder.SplineInterpolator.InterpolatedSplineLayout.ChannelMask; ParticleList particleList = new ParticleList(); particleList.Assign(points, channelMask); PathPointProperties ppp = stroke.Style.PathPointProperties; StrokeConstants strokeConstants = new StrokeConstants { Color = MediaColor.FromArgb( ppp.Alpha.HasValue ? (byte)(ppp.Alpha * 255.0f) : byte.MinValue, ppp.Red.HasValue ? (byte)(ppp.Red * 255.0f) : byte.MinValue, ppp.Green.HasValue ? (byte)(ppp.Green * 255.0f) : byte.MinValue, ppp.Blue.HasValue ? (byte)(ppp.Blue * 255.0f) : byte.MinValue) }; ParticleBrush particleBrush = new ParticleBrush { FillTexture = mGraphics.CreateTexture(Utils.GetPixelData(rasterBrush.FillTexture)), FillTileSize = new Size(rasterBrush.FillWidth, rasterBrush.FillHeight), RotationMode = (ParticleRotationMode)rasterBrush.RotationMode, Scattering = rasterBrush.Scattering, ShapeTexture = mGraphics.CreateTexture(Utils.GetPixelData(rasterBrush.ShapeTextures[0])) }; DryStroke dryStroke = new DryStroke(particleList, stroke.Style.RandomSeed, strokeConstants, particleBrush); return(dryStroke); }
/// <inheritdoc /> public override unsafe void PatchVertexBuffer(ref ParticleBufferState bufferState, Vector3 invViewX, Vector3 invViewY, ref ParticleList sorter) { // If you want, you can integrate the base builder here and not call it. It should result in slight speed up base.PatchVertexBuffer(ref bufferState, invViewX, invViewY, ref sorter); var colorField = sorter.GetField(ParticleFields.Color); if (!colorField.IsValid()) { return; } var colAttribute = bufferState.GetAccessor(VertexAttributes.Color); if (colAttribute.Size <= 0) { return; } foreach (var particle in sorter) { // Set the vertex color attribute to the particle's color field var color = (uint)(*(Color4 *)particle[colorField]).ToRgba(); bufferState.SetAttributePerSegment(colAttribute, (IntPtr)(&color)); bufferState.NextSegment(); } bufferState.StartOver(); }
public override int BuildVertexBuffer(ref ParticleBufferState bufferState, Vector3 invViewX, Vector3 invViewY, ref Vector3 spaceTranslation, ref Quaternion spaceRotation, float spaceScale, ref ParticleList sorter) { return 0; }
/// <inheritdoc /> public override unsafe int BuildVertexBuffer(ref ParticleBufferState bufferState, Vector3 invViewX, Vector3 invViewY, ref Vector3 spaceTranslation, ref Quaternion spaceRotation, float spaceScale, ref ParticleList sorter, ref Matrix viewProj) { // Update the curve samplers if required base.BuildVertexBuffer(ref bufferState, invViewX, invViewY, ref spaceTranslation, ref spaceRotation, spaceScale, ref sorter, ref viewProj); // Get all required particle fields var positionField = sorter.GetField(ParticleFields.Position); if (!positionField.IsValid()) { return(0); } var lifeField = sorter.GetField(ParticleFields.Life); var sizeField = sorter.GetField(ParticleFields.Size); var rotField = sorter.GetField(ParticleFields.Quaternion); var hasRotation = rotField.IsValid() || (SamplerRotation != null); // Check if the draw space is identity - in this case we don't need to transform the position, scale and rotation vectors var trsIdentity = (spaceScale == 1f); trsIdentity = trsIdentity && (spaceTranslation.Equals(new Vector3(0, 0, 0))); trsIdentity = trsIdentity && (spaceRotation.Equals(Quaternion.Identity)); var renderedParticles = 0; var posAttribute = bufferState.GetAccessor(VertexAttributes.Position); var texAttribute = bufferState.GetAccessor(bufferState.DefaultTexCoords); foreach (var particle in sorter) { var centralPos = GetParticlePosition(particle, positionField, lifeField); var particleSize = GetParticleSize(particle, sizeField, lifeField); var unitX = new Vector3(1, 0, 0); var unitY = new Vector3(0, 0, 1); if (hasRotation) { var particleRotation = GetParticleRotation(particle, rotField, lifeField); particleRotation.Rotate(ref unitX); particleRotation.Rotate(ref unitY); } // The TRS matrix is not an identity, so we need to transform the quad if (!trsIdentity) { spaceRotation.Rotate(ref centralPos); centralPos = centralPos * spaceScale + spaceTranslation; particleSize *= spaceScale; spaceRotation.Rotate(ref unitX); spaceRotation.Rotate(ref unitY); } // Use half size to make a Size = 1 result in a Billboard of 1m x 1m unitX *= (particleSize * 0.5f); unitY *= (particleSize * 0.5f); var particlePos = centralPos - unitX + unitY; var uvCoord = new Vector2(0, 0); // 0f 0f bufferState.SetAttribute(posAttribute, (IntPtr)(&particlePos)); bufferState.SetAttribute(texAttribute, (IntPtr)(&uvCoord)); bufferState.NextVertex(); // 1f 0f particlePos += unitX * 2; uvCoord.X = 1; bufferState.SetAttribute(posAttribute, (IntPtr)(&particlePos)); bufferState.SetAttribute(texAttribute, (IntPtr)(&uvCoord)); bufferState.NextVertex(); // 1f 1f particlePos -= unitY * 2; uvCoord.Y = 1; bufferState.SetAttribute(posAttribute, (IntPtr)(&particlePos)); bufferState.SetAttribute(texAttribute, (IntPtr)(&uvCoord)); bufferState.NextVertex(); // 0f 1f particlePos -= unitX * 2; uvCoord.X = 0; bufferState.SetAttribute(posAttribute, (IntPtr)(&particlePos)); bufferState.SetAttribute(texAttribute, (IntPtr)(&uvCoord)); bufferState.NextVertex(); renderedParticles++; } var vtxPerShape = 4 * QuadsPerParticle; return(renderedParticles * vtxPerShape); }
/// <inheritdoc /> public override unsafe int BuildVertexBuffer(ref ParticleBufferState bufferState, Vector3 invViewX, Vector3 invViewY, ref Vector3 spaceTranslation, ref Quaternion spaceRotation, float spaceScale, ref ParticleList sorter, ref Matrix viewProj) { // Step 1 - get all required fields to build the particle shapes. Some fields may not exist if no initializer or updater operates on them // In that case we just decide on a default value for that field and skip the update var positionField = sorter.GetField(ParticleFields.Position); if (!positionField.IsValid()) { return(0); // We can't display the particles without position. All other fields are optional } var sizeField = sorter.GetField(ParticleFields.Size); var angleField = sorter.GetField(ParticleFields.Angle); var hasAngle = angleField.IsValid(); var rectField = sorter.GetField(CustomParticleFields.RectangleXY); var isRectangle = rectField.IsValid(); // In case of Local space particles they are simulated in local emitter space, but drawn in world space // If the draw space is identity (i.e. simulation space = draw space) skip transforming the particle's location later var trsIdentity = (spaceScale == 1f); trsIdentity = trsIdentity && (spaceTranslation.Equals(new Vector3(0, 0, 0))); trsIdentity = trsIdentity && (spaceRotation.Equals(new Quaternion(0, 0, 0, 1))); // Custom feature - fix the Y axis to always point up in world space rather than screen space if (FixYAxis) { invViewY = new Vector3(0, 1, 0); invViewX.Y = 0; invViewX.Normalize(); } var renderedParticles = 0; var posAttribute = bufferState.GetAccessor(VertexAttributes.Position); var texAttribute = bufferState.GetAccessor(bufferState.DefaultTexCoords); foreach (var particle in sorter) { var centralPos = particle.Get(positionField); var particleSize = sizeField.IsValid() ? particle.Get(sizeField) : 1f; if (!trsIdentity) { spaceRotation.Rotate(ref centralPos); centralPos = centralPos * spaceScale + spaceTranslation; particleSize *= spaceScale; } var unitX = invViewX * particleSize; var unitY = invViewY * particleSize; if (isRectangle) { var rectSize = particle.Get(rectField); unitX *= rectSize.X; unitY *= rectSize.Y; } // Particle rotation. Positive value means clockwise rotation. if (hasAngle) { var rotationAngle = particle.Get(angleField); var cosA = (float)Math.Cos(rotationAngle); var sinA = (float)Math.Sin(rotationAngle); var tempX = unitX * cosA - unitY * sinA; unitY = unitY * cosA + unitX * sinA; unitX = tempX; } var particlePos = centralPos - unitX + unitY; var uvCoord = new Vector2(0, 0); // 0f 0f bufferState.SetAttribute(posAttribute, (IntPtr)(&particlePos)); bufferState.SetAttribute(texAttribute, (IntPtr)(&uvCoord)); bufferState.NextVertex(); // 1f 0f particlePos += unitX * 2; uvCoord.X = 1; bufferState.SetAttribute(posAttribute, (IntPtr)(&particlePos)); bufferState.SetAttribute(texAttribute, (IntPtr)(&uvCoord)); bufferState.NextVertex(); // 1f 1f particlePos -= unitY * 2; uvCoord.Y = 1; bufferState.SetAttribute(posAttribute, (IntPtr)(&particlePos)); bufferState.SetAttribute(texAttribute, (IntPtr)(&uvCoord)); bufferState.NextVertex(); // 0f 1f particlePos -= unitX * 2; uvCoord.X = 0; bufferState.SetAttribute(posAttribute, (IntPtr)(&particlePos)); bufferState.SetAttribute(texAttribute, (IntPtr)(&uvCoord)); bufferState.NextVertex(); renderedParticles++; } // Return the number of updated vertices var vtxPerShape = 4 * QuadsPerParticle; return(renderedParticles * vtxPerShape); }
/// <inheritdoc /> public override unsafe int BuildVertexBuffer(ref ParticleBufferState bufferState, Vector3 invViewX, Vector3 invViewY, ref Vector3 spaceTranslation, ref Quaternion spaceRotation, float spaceScale, ref ParticleList sorter) { // Step 1 - get all required fields to build the particle shapes. Some fields may not exist if no initializer or updater operates on them // In that case we just decide on a default value for that field and skip the update var positionField = sorter.GetField(ParticleFields.Position); if (!positionField.IsValid()) return 0; // We can't display the particles without position. All other fields are optional var sizeField = sorter.GetField(ParticleFields.Size); var angleField = sorter.GetField(ParticleFields.Angle); var hasAngle = angleField.IsValid(); var rectField = sorter.GetField(CustomParticleFields.RectangleXY); var isRectangle = rectField.IsValid(); // In case of Local space particles they are simulated in local emitter space, but drawn in world space // If the draw space is identity (i.e. simulation space = draw space) skip transforming the particle's location later var trsIdentity = (spaceScale == 1f); trsIdentity = trsIdentity && (spaceTranslation.Equals(new Vector3(0, 0, 0))); trsIdentity = trsIdentity && (spaceRotation.Equals(new Quaternion(0, 0, 0, 1))); // Custom feature - fix the Y axis to always point up in world space rather than screen space if (FixYAxis) { invViewY = new Vector3(0, 1, 0); invViewX.Y = 0; invViewX.Normalize(); } var renderedParticles = 0; var posAttribute = bufferState.GetAccessor(VertexAttributes.Position); var texAttribute = bufferState.GetAccessor(bufferState.DefaultTexCoords); foreach (var particle in sorter) { var centralPos = particle.Get(positionField); var particleSize = sizeField.IsValid() ? particle.Get(sizeField) : 1f; if (!trsIdentity) { spaceRotation.Rotate(ref centralPos); centralPos = centralPos * spaceScale + spaceTranslation; particleSize *= spaceScale; } var unitX = invViewX * particleSize; var unitY = invViewY * particleSize; if (isRectangle) { var rectSize = particle.Get(rectField); unitX *= rectSize.X; unitY *= rectSize.Y; } // Particle rotation. Positive value means clockwise rotation. if (hasAngle) { var rotationAngle = particle.Get(angleField); var cosA = (float)Math.Cos(rotationAngle); var sinA = (float)Math.Sin(rotationAngle); var tempX = unitX * cosA - unitY * sinA; unitY = unitY * cosA + unitX * sinA; unitX = tempX; } var particlePos = centralPos - unitX + unitY; var uvCoord = new Vector2(0, 0); // 0f 0f bufferState.SetAttribute(posAttribute, (IntPtr)(&particlePos)); bufferState.SetAttribute(texAttribute, (IntPtr)(&uvCoord)); bufferState.NextVertex(); // 1f 0f particlePos += unitX * 2; uvCoord.X = 1; bufferState.SetAttribute(posAttribute, (IntPtr)(&particlePos)); bufferState.SetAttribute(texAttribute, (IntPtr)(&uvCoord)); bufferState.NextVertex(); // 1f 1f particlePos -= unitY * 2; uvCoord.Y = 1; bufferState.SetAttribute(posAttribute, (IntPtr)(&particlePos)); bufferState.SetAttribute(texAttribute, (IntPtr)(&uvCoord)); bufferState.NextVertex(); // 0f 1f particlePos -= unitX * 2; uvCoord.X = 0; bufferState.SetAttribute(posAttribute, (IntPtr)(&particlePos)); bufferState.SetAttribute(texAttribute, (IntPtr)(&uvCoord)); bufferState.NextVertex(); renderedParticles++; } // Return the number of updated vertices var vtxPerShape = 4 * QuadsPerParticle; return renderedParticles * vtxPerShape; }
/// <inheritdoc /> public unsafe override void BuildUVCoordinates(ref ParticleBufferState bufferState, ref ParticleList sorter, AttributeDescription texCoordsDescription) { var lifeField = sorter.GetField(ParticleFields.RemainingLife); if (!lifeField.IsValid()) { return; } var texAttribute = bufferState.GetAccessor(texCoordsDescription); if (texAttribute.Size == 0 && texAttribute.Offset == 0) { return; } var texDefault = bufferState.GetAccessor(bufferState.DefaultTexCoords); if (texDefault.Size == 0 && texDefault.Offset == 0) { return; } foreach (var particle in sorter) { var normalizedTimeline = 1f - *(float *)(particle[lifeField]); Vector4 uvTransform = Vector4.Lerp(StartFrame, EndFrame, normalizedTimeline); uvTransform.Z -= uvTransform.X; uvTransform.W -= uvTransform.Y; bufferState.TransformAttributePerSegment(texDefault, texAttribute, this, ref uvTransform); bufferState.NextSegment(); } bufferState.StartOver(); }
/// <inheritdoc /> public override unsafe int BuildVertexBuffer(ref ParticleBufferState bufferState, Vector3 invViewX, Vector3 invViewY, ref Vector3 spaceTranslation, ref Quaternion spaceRotation, float spaceScale, ref ParticleList sorter, ref Matrix viewProj) { // Update the curve samplers if required base.BuildVertexBuffer(ref bufferState, invViewX, invViewY, ref spaceTranslation, ref spaceRotation, spaceScale, ref sorter, ref viewProj); // Get all the required particle fields var positionField = sorter.GetField(ParticleFields.Position); if (!positionField.IsValid()) { return(0); } var lifeField = sorter.GetField(ParticleFields.Life); var sizeField = sorter.GetField(ParticleFields.Size); var angleField = sorter.GetField(ParticleFields.Angle); var hasAngle = angleField.IsValid() || (SamplerRotation != null); // Check if the draw space is identity - in this case we don't need to transform the position, scale and rotation vectors var trsIdentity = (spaceScale == 1f); trsIdentity = trsIdentity && (spaceTranslation.Equals(Vector3.Zero)); trsIdentity = trsIdentity && (spaceRotation.Equals(Quaternion.Identity)); var renderedParticles = 0; var posAttribute = bufferState.GetAccessor(VertexAttributes.Position); var texAttribute = bufferState.GetAccessor(bufferState.DefaultTexCoords); foreach (var particle in sorter) { var centralPos = GetParticlePosition(particle, positionField, lifeField); var particleSize = GetParticleSize(particle, sizeField, lifeField); if (!trsIdentity) { spaceRotation.Rotate(ref centralPos); centralPos = centralPos * spaceScale + spaceTranslation; particleSize *= spaceScale; } // Use half size to make a Size = 1 result in a Billboard of 1m x 1m var unitX = invViewX * (particleSize * 0.5f); var unitY = invViewY * (particleSize * 0.5f); // Particle rotation. Positive value means clockwise rotation. if (hasAngle) { var rotationAngle = GetParticleRotation(particle, angleField, lifeField); var cosA = (float)Math.Cos(rotationAngle); var sinA = (float)Math.Sin(rotationAngle); var tempX = unitX * cosA - unitY * sinA; unitY = unitY * cosA + unitX * sinA; unitX = tempX; } var particlePos = centralPos - unitX + unitY; var uvCoord = Vector2.Zero; // 0f 0f bufferState.SetAttribute(posAttribute, (IntPtr)(&particlePos)); bufferState.SetAttribute(texAttribute, (IntPtr)(&uvCoord)); bufferState.NextVertex(); // 1f 0f particlePos += unitX * 2; uvCoord.X = 1; bufferState.SetAttribute(posAttribute, (IntPtr)(&particlePos)); bufferState.SetAttribute(texAttribute, (IntPtr)(&uvCoord)); bufferState.NextVertex(); // 1f 1f particlePos -= unitY * 2; uvCoord.Y = 1; bufferState.SetAttribute(posAttribute, (IntPtr)(&particlePos)); bufferState.SetAttribute(texAttribute, (IntPtr)(&uvCoord)); bufferState.NextVertex(); // 0f 1f particlePos -= unitX * 2; uvCoord.X = 0; bufferState.SetAttribute(posAttribute, (IntPtr)(&particlePos)); bufferState.SetAttribute(texAttribute, (IntPtr)(&uvCoord)); bufferState.NextVertex(); renderedParticles++; } var vtxPerShape = 4 * QuadsPerParticle; return(renderedParticles * vtxPerShape); }
/// <inheritdoc /> public unsafe override int BuildVertexBuffer(ref ParticleBufferState bufferState, Vector3 invViewX, Vector3 invViewY, ref Vector3 spaceTranslation, ref Quaternion spaceRotation, float spaceScale, ref ParticleList sorter) { // Update the curve samplers if required base.BuildVertexBuffer(ref bufferState, invViewX, invViewY, ref spaceTranslation, ref spaceRotation, spaceScale, ref sorter); // Get all the required particle fields var positionField = sorter.GetField(ParticleFields.Position); if (!positionField.IsValid()) return 0; var lifeField = sorter.GetField(ParticleFields.Life); var sizeField = sorter.GetField(ParticleFields.Size); var directionField = sorter.GetField(ParticleFields.Direction); // Check if the draw space is identity - in this case we don't need to transform the position, scale and rotation vectors var trsIdentity = (spaceScale == 1f); trsIdentity = trsIdentity && (spaceTranslation.Equals(new Vector3(0, 0, 0))); trsIdentity = trsIdentity && (spaceRotation.Equals(Quaternion.Identity)); var renderedParticles = 0; var posAttribute = bufferState.GetAccessor(VertexAttributes.Position); var texAttribute = bufferState.GetAccessor(bufferState.DefaultTexCoords); Vector3 invViewZ; Vector3.Cross(ref invViewX, ref invViewY, out invViewZ); invViewZ.Normalize(); foreach (var particle in sorter) { var centralPos = GetParticlePosition(particle, positionField, lifeField); var centralOffset = (directionField.IsValid()) ? particle.Get(directionField) : new Vector3(0, 1, 0); var particleSize = GetParticleSize(particle, sizeField, lifeField); if (!trsIdentity) { spaceRotation.Rotate(ref centralPos); centralPos = centralPos * spaceScale + spaceTranslation; spaceRotation.Rotate(ref centralOffset); centralOffset = centralOffset * spaceScale; particleSize *= spaceScale; } var unitX = invViewX; var unitY = invViewY; { var centralAxis = centralOffset; float dotZ; Vector3.Dot(ref centralAxis, ref invViewZ, out dotZ); centralAxis -= invViewZ*dotZ; centralAxis.Normalize(); float dotX; Vector3.Dot(ref centralAxis, ref unitX, out dotX); float dotY; Vector3.Dot(ref centralAxis, ref unitY, out dotY); unitX = unitX*dotY - unitY*dotX; unitX.Normalize(); unitY = centralOffset; } // Use half size to make a Size = 1 result in a Billboard of 1m x 1m unitX *= (particleSize * 0.5f); if (ScaleLength) { unitY *= (LengthFactor * particleSize * 0.5f); } else { unitY *= (LengthFactor * 0.5f); } var particlePos = centralPos - unitX + unitY; var uvCoord = new Vector2(0, 0); // 0f 0f bufferState.SetAttribute(posAttribute, (IntPtr)(&particlePos)); bufferState.SetAttribute(texAttribute, (IntPtr)(&uvCoord)); bufferState.NextVertex(); // 1f 0f particlePos += unitX * 2; uvCoord.X = 1; bufferState.SetAttribute(posAttribute, (IntPtr)(&particlePos)); bufferState.SetAttribute(texAttribute, (IntPtr)(&uvCoord)); bufferState.NextVertex(); // 1f 1f particlePos -= unitY * 2; uvCoord.Y = 1; bufferState.SetAttribute(posAttribute, (IntPtr)(&particlePos)); bufferState.SetAttribute(texAttribute, (IntPtr)(&uvCoord)); bufferState.NextVertex(); // 0f 1f particlePos -= unitX * 2; uvCoord.X = 0; bufferState.SetAttribute(posAttribute, (IntPtr)(&particlePos)); bufferState.SetAttribute(texAttribute, (IntPtr)(&uvCoord)); bufferState.NextVertex(); renderedParticles++; } var vtxPerShape = 4 * QuadsPerParticle; return renderedParticles * vtxPerShape; }
public override unsafe void PatchVertexBuffer(ref ParticleBufferState bufferState, Vector3 invViewX, Vector3 invViewY, ref ParticleList sorter) { // If you want, you can integrate the base builder here and not call it. It should result in slight speed up base.PatchVertexBuffer(ref bufferState, invViewX, invViewY, ref sorter); // Update the non-default coordinates first, because they update off the default ones if (UVBuilder1 != null) { UVBuilder1.BuildUVCoordinates(ref bufferState, ref sorter, texCoord1); } // Update the default coordinates last if (UVBuilder0 != null) { UVBuilder0.BuildUVCoordinates(ref bufferState, ref sorter, texCoord0); } // If the particles have color field, the base class should have already passed the information if (HasColorField) { return; } // If there is no color stream we don't need to fill anything var colAttribute = bufferState.GetAccessor(VertexAttributes.Color); if (colAttribute.Size <= 0) { return; } // Since the particles don't have their own color field, set the default color to white var color = 0xFFFFFFFF; bufferState.StartOver(); foreach (var particle in sorter) { bufferState.SetAttributePerParticle(colAttribute, (IntPtr)(&color)); bufferState.NextParticle(); } bufferState.StartOver(); }
public override unsafe void PatchVertexBuffer(ref ParticleBufferState bufferState, Vector3 invViewX, Vector3 invViewY, ref ParticleList sorter) { // If you want, you can integrate the base builder here and not call it. It should result in slight speed up base.PatchVertexBuffer(ref bufferState, invViewX, invViewY, ref sorter); // Update the non-default coordinates first, because they update off the default ones if (UVBuilder1 != null) UVBuilder1.BuildUVCoordinates(ref bufferState, ref sorter, texCoord1); // Update the default coordinates last if (UVBuilder0 != null) UVBuilder0.BuildUVCoordinates(ref bufferState, ref sorter, texCoord0); // If the particles have color field, the base class should have already passed the information if (HasColorField) return; // If there is no color stream we don't need to fill anything var colAttribute = bufferState.GetAccessor(VertexAttributes.Color); if (colAttribute.Size <= 0) return; // Since the particles don't have their own color field, set the default color to white var color = 0xFFFFFFFF; bufferState.StartOver(); foreach (var particle in sorter) { bufferState.SetAttributePerParticle(colAttribute, (IntPtr)(&color)); bufferState.NextParticle(); } bufferState.StartOver(); }
/// <summary> /// Builds the actual vertex buffer for the current frame using the particle data /// </summary> /// <param name="bufferState">Target particle buffer state, used to populate the assigned vertex buffer</param> /// <param name="invViewX">Unit vector X (right) in camera space, extracted from the inverse view matrix</param> /// <param name="invViewY">Unit vector Y (up) in camera space, extracted from the inverse view matrix</param> /// <param name="spaceTranslation">Translation of the target draw space in regard to the particle data (world or local)</param> /// <param name="spaceRotation">Rotation of the target draw space in regard to the particle data (world or local)</param> /// <param name="spaceScale">Uniform scale of the target draw space in regard to the particle data (world or local)</param> /// <param name="sorter">Particle enumerator which can be iterated and returns sported particles</param> /// <returns></returns> public abstract int BuildVertexBuffer(ref ParticleBufferState bufferState, Vector3 invViewX, Vector3 invViewY, ref Vector3 spaceTranslation, ref Quaternion spaceRotation, float spaceScale, ref ParticleList sorter);
public void Load(RTSRenderer renderer, ParticleOptions o) { // Create Bullet System plBullets = new ParticleList<BulletParticle, VertexBulletInstance>(renderer, o.BulletMaxCount, ParticleType.Bullet); using(var fs = File.OpenRead(o.BulletModel)) { LoadBulletModel(renderer, fs, ParsingFlags.ConversionOpenGL); } LoadBulletTexture(renderer, o.BulletTexture); // Create Fire System plFires = new ParticleList<FireParticle, VertexFireInstance>(renderer, o.FireMaxCount, ParticleType.Fire); BuildFireModel(renderer, o.FireDetail); LoadFireShader(renderer, o.FireNoise, o.FireColor, o.FireAlpha); // Create Lightning System plBolts = new ParticleList<LightningParticle, VertexLightningInstance>(renderer, o.LightningMaxCount, ParticleType.Lightning); BuildLightningModel(renderer); LoadLightningShader(renderer, o.LightningImage, o.LightningNumTypes); // Create Alert System plAlerts = new ParticleList<AlertParticle, VertexAlertInstance>(renderer, o.AlertMaxCount, ParticleType.Alert); BuildAlertModel(renderer); tAlert = renderer.LoadTexture2D(o.AlertImage); // Create Blood System plBloods = new ParticleList<BloodParticle, VertexAlertInstance>(renderer, o.BloodMaxCount, ParticleType.Blood); BuildBloodModel(renderer); tBlood = renderer.LoadTexture2D(o.BloodImage); }
/// <summary> /// Enhances or animates the texture coordinates using already existing base coordinates of (0, 0, 1, 1) or similar /// (base texture coordinates may differ depending on the actual shape) /// </summary> /// <param name="bufferState">The particle buffer state which is used to build the assigned vertex buffer</param> /// <param name="sorter"><see cref="ParticleSorter"/> to use to iterate over all particles drawn this frame</param> /// <param name="texCoordsDescription">Attribute description of the texture coordinates in the current vertex layout</param> public abstract void BuildUVCoordinates(ref ParticleBufferState bufferState, ref ParticleList sorter, AttributeDescription texCoordsDescription);
/// <summary> /// Patch the particle's vertex buffer which was already built by the <see cref="ShapeBuilders.ShapeBuilder"/> /// This involes animating hte uv coordinates and filling per-particle fields, such as the color field /// </summary> /// <param name="bufferState">The particle buffer state which is used to build the assigned vertex buffer</param> /// <param name="invViewX">Unit vector X (right) in camera space, extracted from the inverse view matrix</param> /// <param name="invViewY">Unit vector Y (up) in camera space, extracted from the inverse view matrix</param> /// <param name="sorter">Particle enumerator which can be iterated and returns sported particles</param> public virtual void PatchVertexBuffer(ref ParticleBufferState bufferState, Vector3 invViewX, Vector3 invViewY, ref ParticleList sortedList) { }
public override int BuildVertexBuffer(ref ParticleBufferState bufferState, Vector3 invViewX, Vector3 invViewY, ref Vector3 spaceTranslation, ref Quaternion spaceRotation, float spaceScale, ref ParticleList sorter, ref Matrix viewProj) { return(0); }
/// <inheritdoc /> public override unsafe int BuildVertexBuffer(ref ParticleBufferState bufferState, Vector3 invViewX, Vector3 invViewY, ref Vector3 spaceTranslation, ref Quaternion spaceRotation, float spaceScale, ref ParticleList sorter) { // Update the curve samplers if required base.BuildVertexBuffer(ref bufferState, invViewX, invViewY, ref spaceTranslation, ref spaceRotation, spaceScale, ref sorter); // Get all required particle fields var positionField = sorter.GetField(ParticleFields.Position); if (!positionField.IsValid()) return 0; var sizeField = sorter.GetField(ParticleFields.Size); var lifeField = sorter.GetField(ParticleFields.Life); var angleField = sorter.GetField(ParticleFields.Angle); var hasAngle = angleField.IsValid() || (SamplerRotation != null); // Check if the draw space is identity - in this case we don't need to transform the position, scale and rotation vectors var trsIdentity = (spaceScale == 1f); trsIdentity = trsIdentity && (spaceTranslation.Equals(new Vector3(0, 0, 0))); trsIdentity = trsIdentity && (spaceRotation.Equals(Quaternion.Identity)); var renderedParticles = 0; var posAttribute = bufferState.GetAccessor(VertexAttributes.Position); var texAttribute = bufferState.GetAccessor(bufferState.DefaultTexCoords); foreach (var particle in sorter) { var centralPos = GetParticlePosition(particle, positionField, lifeField); var particleSize = GetParticleSize(particle, sizeField, lifeField); if (!trsIdentity) { spaceRotation.Rotate(ref centralPos); centralPos = centralPos * spaceScale + spaceTranslation; particleSize *= spaceScale; } // Use half size to make a Size = 1 result in a Billboard of 1m x 1m var unitX = invViewX * (particleSize * 0.5f); var unitY = invViewY * (particleSize * 0.5f); // Particle rotation. Positive value means clockwise rotation. if (hasAngle) { var rotationAngle = GetParticleRotation(particle, angleField, lifeField); var cosA = (float)Math.Cos(rotationAngle); var sinA = (float)Math.Sin(rotationAngle); var tempX = unitX * cosA - unitY * sinA; unitY = unitY * cosA + unitX * sinA; unitX = tempX; } // vertex.Size = particleSize; const float Sqrt3Half = 0.86602540378f; unitY *= Sqrt3Half; var halfX = unitX * 0.5f; var particlePos = centralPos - halfX + unitY; var uvCoord = new Vector2(0.25f, 0.5f - Sqrt3Half * 0.5f); // Upper half // 0f 0f bufferState.SetAttribute(posAttribute, (IntPtr)(&particlePos)); bufferState.SetAttribute(texAttribute, (IntPtr)(&uvCoord)); bufferState.NextVertex(); // 1f 0f particlePos += unitX; uvCoord.X = 0.75f; bufferState.SetAttribute(posAttribute, (IntPtr)(&particlePos)); bufferState.SetAttribute(texAttribute, (IntPtr)(&uvCoord)); bufferState.NextVertex(); // 1f 1f particlePos += halfX; particlePos -= unitY; uvCoord.X = 1; uvCoord.Y = 0.5f; bufferState.SetAttribute(posAttribute, (IntPtr)(&particlePos)); bufferState.SetAttribute(texAttribute, (IntPtr)(&uvCoord)); bufferState.NextVertex(); // 0f 1f particlePos -= unitX * 2; uvCoord.X = 0; bufferState.SetAttribute(posAttribute, (IntPtr)(&particlePos)); bufferState.SetAttribute(texAttribute, (IntPtr)(&uvCoord)); bufferState.NextVertex(); // Upper half // 0f 0f bufferState.SetAttribute(posAttribute, (IntPtr)(&particlePos)); bufferState.SetAttribute(texAttribute, (IntPtr)(&uvCoord)); bufferState.NextVertex(); // 1f 0f particlePos += unitX * 2; uvCoord.X = 1; bufferState.SetAttribute(posAttribute, (IntPtr)(&particlePos)); bufferState.SetAttribute(texAttribute, (IntPtr)(&uvCoord)); bufferState.NextVertex(); // 1f 1f particlePos -= halfX; particlePos -= unitY; uvCoord.X = 0.75f; uvCoord.Y = 1; bufferState.SetAttribute(posAttribute, (IntPtr)(&particlePos)); bufferState.SetAttribute(texAttribute, (IntPtr)(&uvCoord)); bufferState.NextVertex(); // 0f 1f particlePos -= unitX; uvCoord.X = 0.25f; bufferState.SetAttribute(posAttribute, (IntPtr)(&particlePos)); bufferState.SetAttribute(texAttribute, (IntPtr)(&uvCoord)); bufferState.NextVertex(); renderedParticles++; } var vtxPerShape = 4 * QuadsPerParticle; return renderedParticles * vtxPerShape; }
/// <inheritdoc /> public override unsafe int BuildVertexBuffer(ref ParticleBufferState bufferState, Vector3 invViewX, Vector3 invViewY, ref Vector3 spaceTranslation, ref Quaternion spaceRotation, float spaceScale, ref ParticleList sorter, ref Matrix viewProj) { // Update the curve samplers if required base.BuildVertexBuffer(ref bufferState, invViewX, invViewY, ref spaceTranslation, ref spaceRotation, spaceScale, ref sorter, ref viewProj); // Get all the required particle fields var positionField = sorter.GetField(ParticleFields.Position); if (!positionField.IsValid()) { return(0); } var lifeField = sorter.GetField(ParticleFields.Life); var sizeField = sorter.GetField(ParticleFields.Size); var directionField = sorter.GetField(ParticleFields.Direction); // Check if the draw space is identity - in this case we don't need to transform the position, scale and rotation vectors var trsIdentity = (spaceScale == 1f); trsIdentity = trsIdentity && (spaceTranslation.Equals(new Vector3(0, 0, 0))); trsIdentity = trsIdentity && (spaceRotation.Equals(Quaternion.Identity)); var renderedParticles = 0; var posAttribute = bufferState.GetAccessor(VertexAttributes.Position); var texAttribute = bufferState.GetAccessor(bufferState.DefaultTexCoords); // TODO Use viewProj Vector3 invViewZ; Vector3.Cross(ref invViewX, ref invViewY, out invViewZ); invViewZ.Normalize(); foreach (var particle in sorter) { var centralPos = GetParticlePosition(particle, positionField, lifeField); var centralOffset = (directionField.IsValid()) ? particle.Get(directionField) : new Vector3(0, 1, 0); var particleSize = GetParticleSize(particle, sizeField, lifeField); if (!trsIdentity) { spaceRotation.Rotate(ref centralPos); centralPos = centralPos * spaceScale + spaceTranslation; spaceRotation.Rotate(ref centralOffset); centralOffset = centralOffset * spaceScale; particleSize *= spaceScale; } var unitX = invViewX; var unitY = invViewY; { var centralAxis = centralOffset; float dotZ; Vector3.Dot(ref centralAxis, ref invViewZ, out dotZ); centralAxis -= invViewZ * dotZ; centralAxis.Normalize(); float dotX; Vector3.Dot(ref centralAxis, ref unitX, out dotX); float dotY; Vector3.Dot(ref centralAxis, ref unitY, out dotY); unitX = unitX * dotY - unitY * dotX; unitX.Normalize(); unitY = centralOffset; } // Use half size to make a Size = 1 result in a Billboard of 1m x 1m unitX *= (particleSize * 0.5f); if (ScaleLength) { unitY *= (LengthFactor * particleSize * 0.5f); } else { unitY *= (LengthFactor * 0.5f); } var particlePos = centralPos - unitX + unitY; var uvCoord = new Vector2(0, 0); // 0f 0f bufferState.SetAttribute(posAttribute, (IntPtr)(&particlePos)); bufferState.SetAttribute(texAttribute, (IntPtr)(&uvCoord)); bufferState.NextVertex(); // 1f 0f particlePos += unitX * 2; uvCoord.X = 1; bufferState.SetAttribute(posAttribute, (IntPtr)(&particlePos)); bufferState.SetAttribute(texAttribute, (IntPtr)(&uvCoord)); bufferState.NextVertex(); // 1f 1f particlePos -= unitY * 2; uvCoord.Y = 1; bufferState.SetAttribute(posAttribute, (IntPtr)(&particlePos)); bufferState.SetAttribute(texAttribute, (IntPtr)(&uvCoord)); bufferState.NextVertex(); // 0f 1f particlePos -= unitX * 2; uvCoord.X = 0; bufferState.SetAttribute(posAttribute, (IntPtr)(&particlePos)); bufferState.SetAttribute(texAttribute, (IntPtr)(&uvCoord)); bufferState.NextVertex(); renderedParticles++; } var vtxPerShape = 4 * QuadsPerParticle; return(renderedParticles * vtxPerShape); }
/// <inheritdoc /> public unsafe override void PatchVertexBuffer(ref ParticleBufferState bufferState, Vector3 invViewX, Vector3 invViewY, ref ParticleList sorter) { // If you want, you can implement the base builder here and not call it. It should result in slight speed up base.PatchVertexBuffer(ref bufferState, invViewX, invViewY, ref sorter); // The UV Builder, if present, animates the basic (0, 0, 1, 1) uv coordinates of each billboard UVBuilder?.BuildUVCoordinates(ref bufferState, ref sorter, bufferState.DefaultTexCoords); bufferState.StartOver(); // If the particles have color field, the base class should have already passed the information if (HasColorField) return; // If the particles don't have color field but there is no color stream either we don't need to fill anything var colAttribute = bufferState.GetAccessor(VertexAttributes.Color); if (colAttribute.Size <= 0) return; // Since the particles don't have their own color field, set the default color to white var color = 0xFFFFFFFF; // TODO: for loop. Remove IEnumerable from sorter foreach (var particle in sorter) { bufferState.SetAttributePerParticle(colAttribute, (IntPtr)(&color)); bufferState.NextParticle(); } bufferState.StartOver(); }
/// <inheritdoc /> public override unsafe int BuildVertexBuffer(ref ParticleBufferState bufferState, Vector3 invViewX, Vector3 invViewY, ref Vector3 spaceTranslation, ref Quaternion spaceRotation, float spaceScale, ref ParticleList sorter) { // Get all the required particle fields var positionField = sorter.GetField(ParticleFields.Position); if (!positionField.IsValid()) return 0; var sizeField = sorter.GetField(ParticleFields.Size); var orderField = sorter.GetField(ParticleFields.Order); // Check if the draw space is identity - in this case we don't need to transform the position, scale and rotation vectors // ReSharper disable once CompareOfFloatsByEqualityOperator var trsIdentity = (spaceScale == 1f); trsIdentity = trsIdentity && (spaceTranslation.Equals(new Vector3(0, 0, 0))); trsIdentity = trsIdentity && (spaceRotation.Equals(Quaternion.Identity)); var ribbonizer = new Ribbonizer(this, currentTotalParticles, currentQuadsPerParticle); var renderedParticles = 0; bufferState.StartOver(); uint oldOrderValue = 0; foreach (var particle in sorter) { if (orderField.IsValid()) { var orderValue = (*((uint*)particle[orderField])); if ((orderValue >> SpawnOrderConst.GroupBitOffset) != (oldOrderValue >> SpawnOrderConst.GroupBitOffset)) { ribbonizer.Ribbonize(ref bufferState, invViewX, invViewY, QuadsPerParticle); ribbonizer.RibbonSplit(); } oldOrderValue = orderValue; } var centralPos = particle.Get(positionField); var particleSize = sizeField.IsValid() ? particle.Get(sizeField) : 1f; if (!trsIdentity) { spaceRotation.Rotate(ref centralPos); centralPos = centralPos * spaceScale + spaceTranslation; particleSize *= spaceScale; } ribbonizer.AddParticle(ref centralPos, particleSize); renderedParticles++; } ribbonizer.Ribbonize(ref bufferState, invViewX, invViewY, QuadsPerParticle); ribbonizer.Free(); var vtxPerShape = 4 * QuadsPerParticle; return renderedParticles * vtxPerShape; }
private void InkBuilder_LayoutUpdated(object sender, EventArgs e) { mAddedInterpolatedSpline = new ParticleList(); mPredictedInterpolatedSpline = new ParticleList(); }
/// <inheritdoc /> public unsafe override void PatchVertexBuffer(ref ParticleBufferState bufferState, Vector3 invViewX, Vector3 invViewY, ref ParticleList sorter) { // If you want, you can implement the base builder here and not call it. It should result in slight speed up base.PatchVertexBuffer(ref bufferState, invViewX, invViewY, ref sorter); // The UV Builder, if present, animates the basic (0, 0, 1, 1) uv coordinates of each billboard UVBuilder?.BuildUVCoordinates(ref bufferState, ref sorter, bufferState.DefaultTexCoords); bufferState.StartOver(); // If the particles have color field, the base class should have already passed the information if (HasColorField) { return; } // If the particles don't have color field but there is no color stream either we don't need to fill anything var colAttribute = bufferState.GetAccessor(VertexAttributes.Color); if (colAttribute.Size <= 0) { return; } // Since the particles don't have their own color field, set the default color to white var color = 0xFFFFFFFF; // TODO: for loop. Remove IEnumerable from sorter foreach (var particle in sorter) { bufferState.SetAttributePerParticle(colAttribute, (IntPtr)(&color)); bufferState.NextParticle(); } bufferState.StartOver(); }
/// <inheritdoc /> public unsafe override int BuildVertexBuffer(ref ParticleBufferState bufferState, Vector3 invViewX, Vector3 invViewY, ref Vector3 spaceTranslation, ref Quaternion spaceRotation, float spaceScale, ref ParticleList sorter) { // Update the curve samplers if required base.BuildVertexBuffer(ref bufferState, invViewX, invViewY, ref spaceTranslation, ref spaceRotation, spaceScale, ref sorter); // Get all required particle fields var positionField = sorter.GetField(ParticleFields.Position); if (!positionField.IsValid()) return 0; var lifeField = sorter.GetField(ParticleFields.Life); var sizeField = sorter.GetField(ParticleFields.Size); var rotField = sorter.GetField(ParticleFields.Quaternion); var hasRotation = rotField.IsValid() || (SamplerRotation != null); // Check if the draw space is identity - in this case we don't need to transform the position, scale and rotation vectors var trsIdentity = (spaceScale == 1f); trsIdentity = trsIdentity && (spaceTranslation.Equals(new Vector3(0, 0, 0))); trsIdentity = trsIdentity && (spaceRotation.Equals(Quaternion.Identity)); var renderedParticles = 0; var posAttribute = bufferState.GetAccessor(VertexAttributes.Position); var texAttribute = bufferState.GetAccessor(bufferState.DefaultTexCoords); foreach (var particle in sorter) { var centralPos = GetParticlePosition(particle, positionField, lifeField); var particleSize = GetParticleSize(particle, sizeField, lifeField); var unitX = new Vector3(1, 0, 0); var unitY = new Vector3(0, 0, 1); if (hasRotation) { var particleRotation = GetParticleRotation(particle, rotField, lifeField); particleRotation.Rotate(ref unitX); particleRotation.Rotate(ref unitY); } // The TRS matrix is not an identity, so we need to transform the quad if (!trsIdentity) { spaceRotation.Rotate(ref centralPos); centralPos = centralPos * spaceScale + spaceTranslation; particleSize *= spaceScale; spaceRotation.Rotate(ref unitX); spaceRotation.Rotate(ref unitY); } // Use half size to make a Size = 1 result in a Billboard of 1m x 1m unitX *= (particleSize * 0.5f); unitY *= (particleSize * 0.5f); var particlePos = centralPos - unitX + unitY; var uvCoord = new Vector2(0, 0); // 0f 0f bufferState.SetAttribute(posAttribute, (IntPtr)(&particlePos)); bufferState.SetAttribute(texAttribute, (IntPtr)(&uvCoord)); bufferState.NextVertex(); // 1f 0f particlePos += unitX * 2; uvCoord.X = 1; bufferState.SetAttribute(posAttribute, (IntPtr)(&particlePos)); bufferState.SetAttribute(texAttribute, (IntPtr)(&uvCoord)); bufferState.NextVertex(); // 1f 1f particlePos -= unitY * 2; uvCoord.Y = 1; bufferState.SetAttribute(posAttribute, (IntPtr)(&particlePos)); bufferState.SetAttribute(texAttribute, (IntPtr)(&uvCoord)); bufferState.NextVertex(); // 0f 1f particlePos -= unitX * 2; uvCoord.X = 0; bufferState.SetAttribute(posAttribute, (IntPtr)(&particlePos)); bufferState.SetAttribute(texAttribute, (IntPtr)(&uvCoord)); bufferState.NextVertex(); renderedParticles++; } var vtxPerShape = 4 * QuadsPerParticle; return renderedParticles * vtxPerShape; }
/// <inheritdoc /> public override unsafe int BuildVertexBuffer(ref ParticleBufferState bufferState, Vector3 invViewX, Vector3 invViewY, ref Vector3 spaceTranslation, ref Quaternion spaceRotation, float spaceScale, ref ParticleList sorter) { // Get all the required particle fields var positionField = sorter.GetField(ParticleFields.Position); if (!positionField.IsValid()) { return(0); } var sizeField = sorter.GetField(ParticleFields.Size); var orderField = sorter.GetField(ParticleFields.Order); // Check if the draw space is identity - in this case we don't need to transform the position, scale and rotation vectors // ReSharper disable once CompareOfFloatsByEqualityOperator var trsIdentity = (spaceScale == 1f); trsIdentity = trsIdentity && (spaceTranslation.Equals(new Vector3(0, 0, 0))); trsIdentity = trsIdentity && (spaceRotation.Equals(Quaternion.Identity)); var ribbonizer = new Ribbonizer(this, currentTotalParticles, currentQuadsPerParticle); var renderedParticles = 0; bufferState.StartOver(); uint oldOrderValue = 0; foreach (var particle in sorter) { if (orderField.IsValid()) { var orderValue = (*((uint *)particle[orderField])); if ((orderValue >> SpawnOrderConst.GroupBitOffset) != (oldOrderValue >> SpawnOrderConst.GroupBitOffset)) { ribbonizer.Ribbonize(ref bufferState, invViewX, invViewY, QuadsPerParticle); ribbonizer.RibbonSplit(); } oldOrderValue = orderValue; } var centralPos = particle.Get(positionField); var particleSize = sizeField.IsValid() ? particle.Get(sizeField) : 1f; if (!trsIdentity) { spaceRotation.Rotate(ref centralPos); centralPos = centralPos * spaceScale + spaceTranslation; particleSize *= spaceScale; } ribbonizer.AddParticle(ref centralPos, particleSize); renderedParticles++; } ribbonizer.Ribbonize(ref bufferState, invViewX, invViewY, QuadsPerParticle); ribbonizer.Free(); var vtxPerShape = 4 * QuadsPerParticle; return(renderedParticles * vtxPerShape); }
/// <inheritdoc /> public override unsafe void PatchVertexBuffer(ref ParticleBufferState bufferState, Vector3 invViewX, Vector3 invViewY, ref ParticleList sorter) { // If you want, you can integrate the base builder here and not call it. It should result in slight speed up base.PatchVertexBuffer(ref bufferState, invViewX, invViewY, ref sorter); var colorField = sorter.GetField(ParticleFields.Color); if (!colorField.IsValid()) return; var colAttribute = bufferState.GetAccessor(VertexAttributes.Color); if (colAttribute.Size <= 0) return; foreach (var particle in sorter) { // Set the vertex color attribute to the particle's color field var color = (uint)(*(Color4*)particle[colorField]).ToRgba(); bufferState.SetAttributePerSegment(colAttribute, (IntPtr)(&color)); bufferState.NextSegment(); } bufferState.StartOver(); }