private void OnValidate() { if (Application.isPlaying) { NBodyC.SetParams(gravConstant, blackHoleCombineDistance); } }
public void ResetTrails(bool forceReset = false) { if (!forceReset && _onlyResetWhenComplete) { _trailResetQueued = true; } else { _trailResetQueued = false; if (_trailState != null) { NBodyC.DestroyGalaxy(_trailState); _trailState = null; } _trailState = NBodyC.Clone(mainState); _trails.Clear(); unsafe { BlackHole *src = mainState->blackHoles; for (int i = 0; i < mainState->numBlackHoles; i++, src++) { _trails[src->id] = new TrailRecord(); } } } }
private void stepSimulation() { float deltaTime = timescale / REFERENCE_FRAMERATE; simulationTime += deltaTime; while (mainState->time < simulationTime) { //Simulate black holes { NBodyC.CopyGalaxy(mainState, prevState); NBodyC.StepGalaxy(mainState); } //Update trails { // When the mainState matches a trail entry, we can remove that trail entry // (These are _future_ trails, not past trails :P) foreach (var pair in _trails) { if (mainState->frames > pair.Value.startFrame && pair.Value.queue.Count > 0) { pair.Value.queue.PopFront(); } } } //Simulate stars { updateShaderConstants(); nextPos.DiscardContents(); Graphics.Blit(null, nextPos, simulateMat, 0); var tmp = prevPos; prevPos = currPos; currPos = nextPos; nextPos = tmp; simulateMat.SetTexture("_PrevPositions", prevPos); simulateMat.SetTexture("_CurrPositions", currPos); } if (_limitStepsPerFrame) { if (mainState->time < simulationTime) { simulationTime = mainState->time; } break; } } if (OnStep != null) { OnStep(); } }
private void OnDisable() { if (mainState != null) { NBodyC.DestroyGalaxy(mainState); mainState = null; } if (prevState != null) { NBodyC.DestroyGalaxy(prevState); prevState = null; } if (_trailState != null) { NBodyC.DestroyGalaxy(_trailState); _trailState = null; } }
private IEnumerator Start() { NBodyC.SetParams(gravConstant, blackHoleCombineDistance); _trailMesh = new Mesh(); _trailMesh.MarkDynamic(); _trailPropertyBlock = new MaterialPropertyBlock(); prevPos.Create(); currPos.Create(); nextPos.Create(); prevPos.DiscardContents(); currPos.DiscardContents(); nextPos.DiscardContents(); ResetSimulation(); yield return(null); yield return(null); ResetSimulation(); }
private void Update() { if (Input.GetKeyDown(resetKeycode)) { ResetSimulation(); } if ((loop && mainState->time > loopTime) || respawnMode) { ResetSimulation(); return; } Random.InitState(Time.frameCount); _seed = Random.Range(int.MinValue, int.MaxValue); if (simulate) { stepSimulation(); } if (_enableTrails) { using (new ProfilerSample("Simulate Trails")) { if (_profileTrails) { var stopwatch = new System.Diagnostics.Stopwatch(); stopwatch.Reset(); stopwatch.Start(); const int FRAMES_TO_TEST = 1000; for (int i = 0; i < FRAMES_TO_TEST; i++) { NBodyC.StepGalaxy(_trailState); } double seconds = stopwatch.ElapsedTicks / (double)System.Diagnostics.Stopwatch.Frequency; double framesPerSecond = FRAMES_TO_TEST / seconds; _trailFramerate = framesPerSecond; Debug.Log("#####: " + _trailFramerate); } else { int simTime = 0; while (_trailState->frames < mainState->frames + _maxTrailLength) { NBodyC.StepGalaxy(_trailState); unsafe { BlackHole * src = _trailState->blackHoles; TrailRecord trail; for (int j = 0; j < _trailState->numBlackHoles; j++, src++) { if (!_trails.TryGetValue(src->id, out trail)) { trail = new TrailRecord() { startFrame = _trailState->frames }; _trails[src->id] = trail; } trail.queue.PushBack(src->position); } } simTime++; if (simTime >= _trailUpdateRate) { break; } } } } //Build and display trail mesh //but only if it's already reached its max length if (_trailState->frames - mainState->frames >= _trailShowLength) { using (new ProfilerSample("Display Trails")) { _trailVerts.Clear(); _trailIndices.Clear(); using (new ProfilerSample("Build Vertex List")) { foreach (var pair in _trails) { for (int i = 0; i < pair.Value.queue.Count; i++) { if (i != 0) { _trailIndices.Add(_trailVerts.Count); _trailIndices.Add(_trailVerts.Count - 1); } _trailVerts.Add(pair.Value.queue[i]); } } } int[] indexArray; using (new ProfilerSample("Build Index Array")) { indexArray = ArrayPool <int> .Spawn(_trailIndices.Count); for (int i = 0; i < _trailIndices.Count; i++) { indexArray[i] = _trailIndices[i]; } for (int i = _trailIndices.Count; i < indexArray.Length; i++) { indexArray[i] = 0; } } using (new ProfilerSample("Upload Mesh")) { _trailMesh.Clear(); _trailMesh.SetVertices(_trailVerts); _trailMesh.SetIndices(indexArray, MeshTopology.Lines, 0); ArrayPool <int> .Recycle(indexArray); indexArray = null; } if (_trailResetQueued) { ResetTrails(forceReset: true); } } } _trailPropertyBlock.SetColor("_Color", _trailColor); Graphics.DrawMesh(_trailMesh, galaxyRenderer.displayAnchor.localToWorldMatrix, _trailMaterial, 0, null, 0, _trailPropertyBlock); } //Render the black holes themselves unsafe { BlackHole *prevSrc = prevState->blackHoles; BlackHole *mainSrc = mainState->blackHoles; float fraction = Mathf.InverseLerp(prevState->time, mainState->time, simulationTime); for (int j = 0; j < mainState->numBlackHoles; j++, prevSrc++, mainSrc++) { Vector3 position = Vector3.Lerp(prevSrc->position, mainSrc->position, fraction); galaxyRenderer.DrawBlackHole(position); } } }
public unsafe void ResetSimulation() { if (mainState != null) { NBodyC.DestroyGalaxy(mainState); mainState = null; } if (prevState != null) { NBodyC.DestroyGalaxy(prevState); prevState = null; } if (_trailState != null) { NBodyC.DestroyGalaxy(_trailState); _trailState = null; } _trails.Clear(); _trailMesh.Clear(); simulationTime = 0; mainState = NBodyC.CreateGalaxy(blackHoleCount); mainState->time = 0; mainState->frames = 0; _initialBlackHoleCount = blackHoleCount; { Random.InitState(_seed); BlackHole *dst = mainState->blackHoles; int nextId = 1; for (int i = 0; i < blackHoleCount; i++, dst++) { Vector3 position = Random.onUnitSphere * blackHoleSpawnRadius; *dst = new BlackHole() { position = position, velocity = Vector3.Slerp(Vector3.zero - position, Random.onUnitSphere, initialDirVariance).normalized *blackHoleVelocity, mass = Random.Range(1 - blackHoleMassVariance, 1 + blackHoleMassVariance), id = nextId, rotation = Random.rotationUniform }; nextId = nextId << 1; } } Texture2D tex = new Texture2D(2048, 1, TextureFormat.RFloat, mipmap: false, linear: true); for (int i = 0; i < tex.width; i++) { float t = 1 - i / 2047f; t = Mathf.Pow(t, pow); tex.SetPixel(i, 0, new Color(t, 0, 0, 0)); //tex.SetPixel(i, 0, new Color(radiusDistribution.Evaluate(i / 2048.0f), 0, 0, 0)); } tex.Apply(); tex.filterMode = FilterMode.Bilinear; tex.wrapMode = TextureWrapMode.Clamp; simulateMat.SetTexture("_RadiusDistribution", tex); updateShaderConstants(); { BlackHole *src = mainState->blackHoles; for (int i = 0; i < mainState->numBlackHoles; i++, src++) { _vectorArray[i] = src->velocity; } simulateMat.SetVectorArray("_PlanetVelocities", _vectorArray); } { BlackHole *src = mainState->blackHoles; _floatArray.Fill(0); for (int i = 0; i < mainState->numBlackHoles; i++, src++) { _floatArray[i] = Mathf.Lerp(1, src->mass, blackHoleMassAffectsDensity); } simulateMat.SetFloatArray("_PlanetDensities", _floatArray); simulateMat.SetFloat("_TotalDensity", _floatArray.Query().Fold((a, b) => a + b)); } { BlackHole *src = mainState->blackHoles; for (int i = 0; i < mainState->numBlackHoles; i++, src++) { _floatArray[i] = Mathf.Lerp(1, src->mass, blackHoleMassAffectsSize); } simulateMat.SetFloatArray("_PlanetSizes", _floatArray); } GL.LoadPixelMatrix(0, 1, 0, 1); prevPos.DiscardContents(); currPos.DiscardContents(); RenderBuffer[] buffer = new RenderBuffer[2]; buffer[0] = prevPos.colorBuffer; buffer[1] = currPos.colorBuffer; Graphics.SetRenderTarget(buffer, prevPos.depthBuffer); simulateMat.SetPass(1); GL.Begin(GL.QUADS); GL.TexCoord2(0, 0); GL.Vertex3(0, 0, 0); GL.TexCoord2(1, 0); GL.Vertex3(1, 0, 0); GL.TexCoord2(1, 1); GL.Vertex3(1, 1, 0); GL.TexCoord2(0, 1); GL.Vertex3(0, 1, 0); GL.End(); prevState = NBodyC.Clone(mainState); prevState->time = mainState->time - 1.0f / REFERENCE_FRAMERATE; ResetTrails(forceReset: true); if (OnReset != null) { OnReset(); } }