/// <summary> /// Creates a new LineCirclePattern, duplicating an existing one /// </summary> /// <param name="CopyTarget">The LineCirclePattern to duplicate</param> public LineCirclePattern(LineCirclePattern CopyTarget) { Count = CopyTarget.Count; LineCount = CopyTarget.LineCount; LineScaleMultiplier = CopyTarget.LineScaleMultiplier; LineRotationMultiplier = CopyTarget.LineRotationMultiplier; SphericalCoordinates = CopyTarget.SphericalCoordinates; LineInterval = CopyTarget.LineInterval; AutoScaleLines = CopyTarget.AutoScaleLines; TimeStep = CopyTarget.TimeStep; TimeSpan = CopyTarget.TimeSpan; TimeOffset = CopyTarget.TimeOffset; DrawLines = CopyTarget.DrawLines; DrawFill = CopyTarget.DrawFill; LineColor = CopyTarget.LineColor; FillColor = CopyTarget.FillColor; SrcMode = CopyTarget.SrcMode; DstMode = CopyTarget.DstMode; Oscillators = new Oscillator[CopyTarget.Oscillators.Length]; for (int i = 0; i < Oscillators.Length; i++) { Oscillators[i] = new Oscillator(CopyTarget.Oscillators[i]); } TimeToZ = CopyTarget.TimeToZ; ZFade = CopyTarget.ZFade; }
/// <summary> /// Initialises a new LineCirclePattern which is the interpolation of two other LineCirclePatterns /// </summary> /// <param name="PatternA"></param> /// <param name="PatternB"></param> /// <param name="LerpFactor"></param> public LineCirclePattern(LineCirclePattern PatternA, LineCirclePattern PatternB, float LerpFactor) { Count = Mathf.RoundToInt(Mathf.Lerp(PatternA.Count, PatternB.Count, LerpFactor)); LineCount = Mathf.RoundToInt(Mathf.Lerp(PatternA.LineCount, PatternB.LineCount, LerpFactor)); LineScaleMultiplier = Mathf.Lerp(PatternA.LineScaleMultiplier, PatternB.LineScaleMultiplier, LerpFactor); LineRotationMultiplier = Mathf.Lerp(PatternA.LineRotationMultiplier, PatternB.LineRotationMultiplier, LerpFactor); SphericalCoordinates = LerpFactor < 0.5f ? PatternA.SphericalCoordinates : PatternB.SphericalCoordinates; LineInterval = Mathf.RoundToInt(Mathf.Lerp(PatternA.LineInterval, PatternB.LineInterval, LerpFactor)); AutoScaleLines = LerpFactor < 0.5f ? PatternA.AutoScaleLines : PatternB.AutoScaleLines; TimeStep = Mathf.Lerp(PatternA.TimeStep, PatternB.TimeStep, LerpFactor); TimeSpan = Mathf.Lerp(PatternA.TimeSpan, PatternB.TimeSpan, LerpFactor); TimeOffset = Mathf.Lerp(PatternA.TimeOffset, PatternB.TimeOffset, LerpFactor); DrawLines = LerpFactor < 0.5f ? PatternA.DrawLines : PatternB.DrawLines; DrawFill = LerpFactor < 0.5f ? PatternA.DrawFill : PatternB.DrawFill; LineColor = Color.Lerp(PatternA.LineColor, PatternB.LineColor, LerpFactor); FillColor = Color.Lerp(PatternA.FillColor, PatternB.FillColor, LerpFactor); SrcMode = LerpFactor < 0.5f ? PatternA.SrcMode : PatternB.SrcMode; DstMode = LerpFactor < 0.5f ? PatternA.DstMode : PatternB.DstMode; Oscillators = new Oscillator[PatternA.Oscillators.Length]; for (int i = 0; i < Oscillators.Length; i++) { Oscillators[i] = new Oscillator(PatternA.Oscillators[i], PatternB.Oscillators[i], LerpFactor); } TimeToZ = LerpFactor < 0.5f ? PatternA.TimeToZ : PatternB.TimeToZ; ZFade = LerpFactor < 0.5f ? PatternA.ZFade : PatternB.ZFade; }
/// <summary> /// Reusable code snippet to shuffle a given oscillator (used for angular oscillators that can be a sawtooth wave) /// </summary> /// <param name="index">Index of oscillator shuffler to target</param> /// <param name="pattern">Pattern to be mutated by this shuffle operation</param> private void RollShufflerLoopable(int index, ref LineCirclePattern pattern) { //check to see if we should be a sawtooth pattern.Oscillators[index].Type = Roll(SawtoothChance) ? OscillatorShape.Sawtooth : OscillatorShape.Sine; //do normal stuff RollShuffler(index, ref pattern); //if sawtooth, make sure we go from 0 to 2 pi (so one full revolution) if (pattern.Oscillators[index].Type != OscillatorShape.Sawtooth) { return; } OscillatorShuffler.EnforceTwoPi(ref pattern.Oscillators[index]); //Once we've done all this enforcing, we need to do one more pass on ensuring that the frequency isn't too high if (Shufflers[index].OverrideFrequency) { Shufflers[index].RandomiseFrequency(ref pattern.Oscillators[index]); } else { OscillatorShuffler.RandomiseFrequency(ref pattern.Oscillators[index], GlobalMinimumFrequency, GlobalMaximumFrequency); } Shufflers[index].EnforceMaxFrequency(ref pattern.Oscillators[index]); }
/// <summary> /// Reusable code snippet to shuffle a given oscillator /// </summary> /// <param name="index">Index of oscillator shuffler to target</param> /// <param name="pattern">Pattern to be mutated by this shuffle operation</param> private void RollShuffler(int index, ref LineCirclePattern pattern) { //check whether we should shuffle at all if (!Roll(GlobalShuffleChance)) { return; } //check whether we should freeze if (Roll(FreezeChance)) { Shufflers[index].RandomiseCenter(ref pattern.Oscillators[index]); pattern.Oscillators[index].Amplitude = 0; } else { Shufflers[index].RandomiseRange(ref pattern.Oscillators[index]); OscillatorShuffler.RandomisePhase(ref pattern.Oscillators[index]); //check whether we should use override frequency values if (Shufflers[index].OverrideFrequency) { Shufflers[index].RandomiseFrequency(ref pattern.Oscillators[index]); } else { OscillatorShuffler.RandomiseFrequency(ref pattern.Oscillators[index], GlobalMinimumFrequency, GlobalMaximumFrequency); } } Shufflers[index].EnforceMaxFrequency(ref pattern.Oscillators[index]); }
public void SetPattern(LineCirclePattern pattern) { Pattern = pattern; ResetBounds(); _maxPossibleBounds = Pattern.GetMaxPossibleBounds(); OnPatternChanged?.Invoke(this, new EventArgs()); if (pattern.Count != _setCount) { SetCount(pattern.Count); } }
/// <summary> /// Assign all Pattern values to the GPU to update its simulation /// </summary> /// <param name="pattern">The LineCirclePattern to push to the GPU</param> private void SetComputeValues(LineCirclePattern pattern) { //each of these has _type, _center, _amplitude, _period and _phase appended //just saves me writing tons of code! var prefixes = new[] { "circlePos_x", "circlePos_y", "circlePos_z", "circleRot_x", "circleRot_y", "circleRot_z", "circleRad", "lineRot_x", "lineRot_y", "lineRot_z", "lineLength", "colorRange", "colorOffset" }; for (var i = 0; i < pattern.Oscillators.Length; i++) { _snapshotCompute.SetInt(prefixes[i] + "_type", (int)pattern.Oscillators[i].Type); _snapshotCompute.SetFloat(prefixes[i] + "_center", pattern.Oscillators[i].Center); _snapshotCompute.SetFloat(prefixes[i] + "_amplitude", pattern.Oscillators[i].Amplitude); _snapshotCompute.SetFloat(prefixes[i] + "_period", pattern.Oscillators[i].Period); _snapshotCompute.SetFloat(prefixes[i] + "_phase", pattern.Oscillators[i].Phase); } _snapshotCompute.SetInt("_BufferCount", pattern.Count); _snapshotCompute.SetFloat("_TimeStep", pattern.TimeStep); _snapshotCompute.SetFloat("_TimeOffset", pattern.TimeOffset); _snapshotCompute.SetInt("_TimeSpan", (int)(pattern.TimeSpan / pattern.TimeStep)); _snapshotCompute.SetInt("_AutoScaleLines", pattern.AutoScaleLines ? 1 : 0); _snapshotCompute.SetInt("_IntervalOffset", (int)(pattern.TimeOffset / pattern.TimeStep)); _snapshotCompute.SetInt("_LineInterval", pattern.LineInterval); _vertexCompute.SetInt("_LineCount", pattern.LineCount); _vertexCompute.SetFloat("_TimeSpan", pattern.TimeSpan); _vertexCompute.SetInt("_Spherical", pattern.SphericalCoordinates ? 1 : 0); _vertexCompute.SetInt("_FirstIndex", (int)(pattern.TimeSpan / pattern.TimeStep)); _vertexCompute.SetFloat("_LineScaleMultiplier", pattern.LineScaleMultiplier); _vertexCompute.SetFloat("_LineRotationMultiplier", pattern.LineRotationMultiplier); _lineMat.SetInt("_LineCount", pattern.LineCount); _lineMat.SetFloat("_Alpha", pattern.LineColor.a * AlphaMultiplier); _lineMat.SetMatrix("_LocalToWorld", transform.localToWorldMatrix); _lineMat.SetMatrix("_WorldToLocal", transform.worldToLocalMatrix); _lineMat.SetFloat("_TimeToZ", pattern.TimeToZ); _lineMat.SetFloat("_ZFade", pattern.ZFade); _fillMat.SetInt("_LineCount", pattern.LineCount); _fillMat.SetFloat("_Alpha", pattern.FillColor.a * AlphaMultiplier); _fillMat.SetMatrix("_LocalToWorld", transform.localToWorldMatrix); _fillMat.SetMatrix("_WorldToLocal", transform.worldToLocalMatrix); _fillMat.SetFloat("_TimeToZ", pattern.TimeToZ); _fillMat.SetFloat("_ZFade", pattern.ZFade); // _lineMat.SetInt("_Spherical", pattern.SphericalCoordinates ? 1 : 0); // _lineMat.SetInt("_LineCount", pattern.LineCount); // _lineMat.SetColor("_Color", pattern.LineColor); // _lineMat.SetInt("_LineInterval", pattern.LineInterval); // _lineMat.SetInt("_IntervalOffset", (int)(pattern.TimeOffset / pattern.TimeStep)); // _lineMat.SetInt("_TimeSpan", (int)(pattern.TimeSpan / pattern.TimeStep)); // // _lineMat.SetVector("_Position", new Vector4(transform.position.x, transform.position.y, transform.position.z, 0)); // _lineMat.SetVector("_Rotation", new Vector4(transform.eulerAngles.x * Mathf.Deg2Rad, transform.eulerAngles.y * Mathf.Deg2Rad, transform.eulerAngles.z * Mathf.Deg2Rad, 0)); // _lineMat.SetVector("_Scale", new Vector4(transform.localScale.x, transform.localScale.y, transform.localScale.z, 0)); // // _lineMat.SetInt("_SrcMode", (int)pattern.SrcMode); // _lineMat.SetInt("_DstMode", (int)pattern.DstMode); // // _fillMat.SetInt("_Spherical", pattern.SphericalCoordinates ? 1 : 0); // _fillMat.SetInt("_LineCount", pattern.LineCount); // _fillMat.SetColor("_Color", pattern.FillColor); // _fillMat.SetInt("_TimeSpan", (int)(pattern.TimeSpan / pattern.TimeStep)); // // _fillMat.SetVector("_Position", new Vector4(transform.position.x, transform.position.y, transform.position.z, 0)); // _fillMat.SetVector("_Rotation", new Vector4(transform.eulerAngles.x * Mathf.Deg2Rad, transform.eulerAngles.y * Mathf.Deg2Rad, transform.eulerAngles.z * Mathf.Deg2Rad, 0)); // _fillMat.SetVector("_Scale", new Vector4(transform.localScale.x, transform.localScale.y, transform.localScale.z, 0)); // // _fillMat.SetInt("_SrcMode", (int)pattern.SrcMode); // _fillMat.SetInt("_DstMode", (int)pattern.DstMode); }
/// <summary> /// Generates a new LineCircle pattern, shuffling parameters of a previous pattern /// </summary> /// <param name="previousPattern">Previous pattern to use as shuffle base</param> /// <returns>A shuffled version of the previous pattern</returns> public LineCirclePattern GenerateNewPattern(LineCirclePattern previousPattern) { var newPattern = new LineCirclePattern(previousPattern); //first we decide whether we should be spherical or cartesian if (Roll(SphericalSwapChance)) { newPattern.SphericalCoordinates = true; //Shuffle X (aka radius) RollShuffler(ID.CirclePosX, ref newPattern); //Shuffle Y (aka theta) if in 3D mode if (!RestrictThirdDimension) { RollShufflerLoopable(ID.CirclePosY, ref newPattern); } else { //reset to make sure everything is in 2D var savedName = newPattern.Oscillators[ID.CirclePosY].Name; newPattern.Oscillators[ID.CirclePosY] = new Oscillator("CirclePosY", 0, 0, 0, 1, 0) { Name = savedName }; } //Shuffle Z (aka phi) RollShufflerLoopable(ID.CirclePosZ, ref newPattern); } else { newPattern.SphericalCoordinates = false; //Shuffle X and Y RollShuffler(ID.CirclePosX, ref newPattern); RollShuffler(ID.CirclePosY, ref newPattern); //Shuffle Z if in 3D mode if (!RestrictThirdDimension) { RollShuffler(ID.CirclePosZ, ref newPattern); } else { //reset to make sure everything is in 2D var savedName = newPattern.Oscillators[ID.CirclePosZ].Name; newPattern.Oscillators[ID.CirclePosZ] = new Oscillator("CirclePosZ", 0, 0, 0, 1, 0) { Name = savedName }; } } //Shuffle rotation about X and Y axes if in 3D mode if (!RestrictThirdDimension) { RollShufflerLoopable(ID.CircleRotX, ref newPattern); RollShufflerLoopable(ID.CircleRotY, ref newPattern); } else { //reset to make sure everything is in 2D var savedName = newPattern.Oscillators[ID.CircleRotX].Name; newPattern.Oscillators[ID.CircleRotX] = new Oscillator("CircleRotX", 0, 0, 0, 1, 0) { Name = savedName }; savedName = newPattern.Oscillators[ID.CircleRotY].Name; newPattern.Oscillators[ID.CircleRotY] = new Oscillator("CircleRotY", 0, 0, 0, 1, 0) { Name = savedName }; } //Shuffle rotation about Z axis RollShufflerLoopable(ID.CircleRotZ, ref newPattern); //Shuffle radius RollShuffler(ID.CircleRad, ref newPattern); //Shuffle offset about X and Y axes if in 3D mode if (!RestrictThirdDimension) { RollShufflerLoopable(ID.LineRotX, ref newPattern); RollShufflerLoopable(ID.LineRotY, ref newPattern); } else { //reset to make sure everything is in 2D var savedName = newPattern.Oscillators[ID.LineRotX].Name; newPattern.Oscillators[ID.LineRotX] = new Oscillator("LineRotX", 0, 0, 0, 1, 0) { Name = savedName }; savedName = newPattern.Oscillators[ID.LineRotY].Name; newPattern.Oscillators[ID.LineRotY] = new Oscillator("LineRotY", 0, 0, 0, 1, 0) { Name = savedName }; } //Shuffle offset about Z axis RollShufflerLoopable(ID.LineRotZ, ref newPattern); //custom - line length and colors //for line length we only randomise the total length if (Roll(GlobalShuffleChance)) { newPattern.Oscillators[ID.LineLength] = new Oscillator("LineLength", 0, Random.Range(Shufflers[ID.LineLength].AbsoluteMin, Shufflers[ID.LineLength].AbsoluteMax), 0, 1, 0) { Name = "Line Length" }; } //we keep amplitude for both color values at zero because otherwise the pattern is just a rainbow mess //mmm...rainbow mess if (Roll(GlobalShuffleChance)) { newPattern.Oscillators[ID.ColorRange].Amplitude = 0f; newPattern.Oscillators[ID.ColorRange].Center = Random.Range(0f, 1f); } if (Roll(GlobalShuffleChance)) { newPattern.Oscillators[ID.ColorOffset].Amplitude = 0f; newPattern.Oscillators[ID.ColorOffset].Center = Random.Range(0f, 1f); } //Shuffle line count if (Roll(GlobalShuffleChance)) { newPattern.LineCount = Random.Range(3, MaxLineCount + 1); } return(newPattern); }