public void preRenderUpdate(float timeElapsed) { var mParams = missile.parameters as SSpaceMissileVisualParameters; bodyObj.Pos = missile.displayPosition; bodyObj.Orient(missile.visualDirection, missile.up); bool ejection = missile.state == SSpaceMissileVisualData.State.Ejection; float smokeFrequency = Interpolate.Lerp( mParams.smokeEmissionFrequencyMin, mParams.smokeEmissionFrequencyMax, missile.visualSmokeAmmount); float sizeMin = ejection ? mParams.ejectionSmokeSizeMin : mParams.flameSmokeSizeMin; float sizeMax = ejection ? mParams.ejectionSmokeSizeMax : mParams.flameSmokeSizeMax; float smokeSize = Interpolate.Lerp(sizeMin, sizeMax, (float)SSpaceMissilesVisualSimulation.rand.NextDouble()); //flameSmokeEmitter.velocity = -missile.velocity; flameSmokeEmitter.center = missile.jetPosition(); flameSmokeEmitter.up = -missile.visualDirection; flameSmokeEmitter.emissionInterval = 1f / smokeFrequency; flameSmokeEmitter.componentScale = new Vector3(smokeSize); flameSmokeEmitter.effectorMask = (ushort) (ejection ? ParticleEffectorMasks.EjectionSmoke : ParticleEffectorMasks.FlameToSmoke); var vel = missile.velocity.LengthFast; flameSmokeEmitter.velocityFromCenterMagnitudeMin = ejection ? -vel / 2f : (-vel / 8f); flameSmokeEmitter.velocityFromCenterMagnitudeMax = ejection ? vel / 2f : (vel / 5f); flameSmokeEmitter.life = ejection ? mParams.ejectionSmokeDuration : mParams.flameSmokeDuration; if (missile.state == SSpaceMissileData.State.FadingOut) { float fadeFactor = 1f - (missile.timeSinceLaunch - missile.fadeTime) / mParams.fadeDuration; var color = bodyObj.MainColor; color.A = fadeFactor; bodyObj.MainColor = color; flameSmokeEmitter.life = flameSmokeEmitter.lifeMax * fadeFactor; } #if MISSILE_DEBUG RectangleF clientRect = OpenTKHelper.GetClientRect(); var xy = OpenTKHelper.WorldToScreen( missile.displayPosition, ref debugRays.viewProjMat, ref clientRect); debugCountdown.Pos = new Vector3(xy.X, xy.Y, 0f); debugCountdown.Label = Math.Floor(missile.timeToHit).ToString(); //debugCountdown.Label = missile.losRate.ToString("G3") + " : " + missile.losRateRate.ToString("G3"); debugRays.renderState.visible = mParams.debuggingAid; debugCountdown.renderState.visible = mParams.debuggingAid; #endif }
public void updateSprites(SInstancedSpriteData instanceData, ref RectangleF clientRect, ref Vector3 cameraPos, ref Matrix4 camera3dView, ref Matrix4 camera3dProj) { Matrix4 camera3dViewProjMat = camera3dView * camera3dProj; if (_sunDiskOccObj != null) { Matrix4 viewInverted = _sunDiskOccScene.renderConfig.invCameraViewMatrix.Inverted(); Vector3 viewRight = Vector3.Transform(Vector3.UnitX, viewInverted).Normalized(); Vector3 viewUp = Vector3.Transform(Vector3.UnitY, viewInverted).Normalized(); _sunDiskOccPos = OpenTKHelper.WorldToScreen(_sunDiskOccObj.Pos, ref camera3dViewProjMat, ref clientRect); float bbFullEstimate; // note that it is assumed that the sun object is fully symmertircal when it is in view if (_sunDiskOccObj.renderState.matchScaleToScreenPixels) { _sunDiskScreenSize = 2f * _sunDiskOccObj.Scale.Xy; bbFullEstimate = (float)Math.PI * _sunDiskOccObj.Scale.X * _sunDiskOccObj.Scale.Y; } else { Vector3 occRightMost = _sunDiskOccObj.Pos + viewRight * _sunDiskOccObj.Scale.X; Vector3 occTopMost = _sunDiskOccObj.Pos + viewUp * _sunDiskOccObj.Scale.Y; Vector2 occRightMostPt = OpenTKHelper.WorldToScreen(occRightMost, ref camera3dViewProjMat, ref clientRect); Vector2 occTopMostPt = OpenTKHelper.WorldToScreen(occTopMost, ref camera3dViewProjMat, ref clientRect); _sunDiskScreenSize = 2f * new Vector2(occRightMostPt.X - _sunDiskOccPos.X, _sunDiskOccPos.Y - occTopMostPt.Y); bbFullEstimate = (float)Math.PI * (float)_sunDiskScreenSize.X * (float)_sunDiskScreenSize.Y / 4f; } _sunDiskOccIntensity = Math.Min((float)_sunDiskOccObj.OcclusionQueueryResult / bbFullEstimate, 1f); } int numElements = _spriteSlotIdxs.Length; if (_sunDiskOccIntensity <= 0f) { // hide all sprites for (int i = 0; i < numElements; ++i) { instanceData.writePosition(_spriteSlotIdxs [i], new Vector2(float.NaN)); // hide all sprites } } else { Vector2 compScale = new Vector2(Math.Max(_sunDiskScreenSize.X, _sunDiskScreenSize.Y) * Math.Min(1.5f, 1f / (1f - _sunDiskOccIntensity))); Vector2 center = new Vector2(clientRect.X, clientRect.Y) + new Vector2(clientRect.Width, clientRect.Height) / 2f; Vector2 towardsCenter = center - _sunDiskOccPos; var color4 = _sunDiskOccObj.MainColor; color4.A = _sunDiskOccIntensity; for (int i = 0; i < numElements; ++i) { int writeIdx = _spriteSlotIdxs [i]; instanceData.writeComponentScale(writeIdx, compScale); instanceData.writeColor(writeIdx, color4); Vector2 spriteCenter = _sunDiskOccPos + towardsCenter * 2.5f / (float)numElements * (float)i; instanceData.writePosition(_spriteSlotIdxs[i], spriteCenter); } } }
public void updateSprites(SInstancedSpriteData instanceData, ref RectangleF clientRect, ref Vector3 cameraPos, ref Matrix4 camera3dView, ref Matrix4 camera3dProj) { var beam = _laser.beam(_beamId); var ray = beam.rayWorld(); var laserParams = _laser.parameters; var beamSrcInViewSpace = Vector3.Transform(beam.startPosWorld, camera3dView); bool hideSprites = true; Vector3 intersectPt3d; if (beamSrcInViewSpace.Z < 0f) { Matrix4 cameraViewProjMat3d = camera3dView * camera3dProj; // extract a near plane from the camera view projection matrix // https://www.opengl.org/discussion_boards/showthread.php/159332-Extract-clip-planes-from-projection-matrix SSPlane3d nearPlane = new SSPlane3d() { A = cameraViewProjMat3d.M14 + cameraViewProjMat3d.M13, B = cameraViewProjMat3d.M24 + cameraViewProjMat3d.M23, C = cameraViewProjMat3d.M34 + cameraViewProjMat3d.M33, D = cameraViewProjMat3d.M44 + cameraViewProjMat3d.M43 }; if (nearPlane.intersects(ref ray, out intersectPt3d)) { #if false Console.WriteLine("camera at world pos = " + cameraPos); Console.WriteLine("camera in screen pos = " + OpenTKHelper.WorldToScreen( cameraPos, ref cameraViewProjMat3d, ref clientRect)); Console.WriteLine("screen hit at world pos = " + intersectPt3d); #endif float lengthToIntersectionSq = (intersectPt3d - beam.startPosWorld).LengthSquared; float beamLengthSq = beam.lengthSqWorld(); if (lengthToIntersectionSq < beamLengthSq) { hideSprites = false; Vector2 drawScreenPos = OpenTKHelper.WorldToScreen( intersectPt3d - ray.dir * 1f, ref cameraViewProjMat3d, ref clientRect); //Console.WriteLine("screen hit at screen pos = " + drawScreenPos); float intensity = _laser.envelopeIntensity * beam.periodicIntensity; Vector2 drawScale = new Vector2(laserParams.hitFlareSizeMaxPx * (float)Math.Exp(intensity)); for (int i = 0; i < _spriteSlotIdxs.Length; ++i) { int writeIdx = _spriteSlotIdxs [i]; instanceData.writePosition(writeIdx, drawScreenPos); instanceData.writeComponentScale(writeIdx, drawScale); instanceData.writeOrientationZ(writeIdx, intensity * 2f * (float)Math.PI); } Color4 backgroundColor = laserParams.backgroundColor; backgroundColor.A = intensity; instanceData.writeColor(_spriteSlotIdxs[(int)SpriteId.coronaBackground], backgroundColor); Color4 overlayColor = laserParams.overlayColor; //overlayColor.A = intensity / _laser.parameters.intensityEnvelope.sustainLevel; overlayColor.A = Math.Min(intensity * 2f, 1f); instanceData.writeColor(_spriteSlotIdxs[(int)SpriteId.coronaOverlay], overlayColor); //System.Console.WriteLine("overlay.alpha == " + overlayColor.A); Color4 ring1Color = laserParams.overlayColor; //ring1Color.A = (float)Math.Pow(intensity, 5.0); ring1Color.A = 0.1f * intensity; instanceData.writeComponentScale(_spriteSlotIdxs[(int)SpriteId.ring1], drawScale * (float)Math.Exp(intensity)); instanceData.writeColor(_spriteSlotIdxs[(int)SpriteId.ring1], ring1Color); //instanceData.writeColor(_spriteSlotIdxs[(int)SpriteId.ring1], Color4.LimeGreen); Color4 ring2Color = laserParams.backgroundColor; //ring2Color.A = (float)Math.Pow(intensity, 10.0); ring2Color.A = intensity * 0.1f; instanceData.writeColor(_spriteSlotIdxs[(int)SpriteId.ring2], ring2Color); //instanceData.writeColor(_spriteSlotIdxs[(int)SpriteId.ring2], Color4.Magenta); } } } if (hideSprites) { // hide sprites for (int i = 0; i < _spriteSlotIdxs.Length; ++i) { instanceData.writeComponentScale(_spriteSlotIdxs[i], Vector2.Zero); } } //System.Console.WriteLine("beam id " + _beamId + " hitting screen at xy " + hitPosOnScreen); }
public void updateSprites(SInstancedSpriteData instanceData, ref RectangleF screenClientRect, ref Vector3 cameraPos, ref Matrix4 camera3dView, ref Matrix4 camera3dProj) { float occDiskScreenAreaUsed = (float)_occDiskObj.OcclusionQueueryResult; if (occDiskScreenAreaUsed <= 0f) { // hide all sprites var nanVec = new Vector2(float.NaN); instanceData.writePosition(_backgroundSpriteIdx, nanVec); instanceData.writePosition(_overlaySpriteIdx, nanVec); return; } var laserParams = _laser.parameters; var beam = _laser.beam(_beamId); float beamIntensity = _laser.envelopeIntensity * beam.periodicIntensity; // position sprites at the beam start in screen space Matrix4 camera3dViewProjMat = camera3dView * camera3dProj; var beamStartScreen = OpenTKHelper.WorldToScreen(beam.startPosWorld, ref camera3dViewProjMat, ref screenClientRect); instanceData.writePosition(_backgroundSpriteIdx, beamStartScreen); instanceData.writePosition(_overlaySpriteIdx, beamStartScreen); // compute screen space needed to occupy the area where the start of the middle's crossbeam // would be displayed Matrix4 viewInverted = camera3dView.Inverted(); Vector3 viewRight = Vector3.Transform(Vector3.UnitX, viewInverted).Normalized(); Vector3 occRightMost = _occDiskObj.Pos + viewRight * laserParams.middleBackgroundWidth; Vector2 occRightMostPt = OpenTKHelper.WorldToScreen(occRightMost, ref camera3dViewProjMat, ref screenClientRect); Vector2 occCenterPt = OpenTKHelper.WorldToScreen(_occDiskObj.Pos, ref camera3dViewProjMat, ref screenClientRect); float crossBeamRadiusScreenPx = Math.Abs(occRightMostPt.X - occCenterPt.X); // write sprite size big enough to cover up the starting section of the cross beam (middle) float scale = Math.Max(laserParams.emissionFlareScreenSizeMin, crossBeamRadiusScreenPx * 2.5f) * beamIntensity; instanceData.writeMasterScale(_backgroundSpriteIdx, scale * 1.2f); instanceData.writeMasterScale(_overlaySpriteIdx, scale * 1f); // add some variety to orientation to make the sprites look less static instanceData.writeOrientationZ(_backgroundSpriteIdx, beamIntensity * 1f * (float)Math.PI); instanceData.writeOrientationZ(_overlaySpriteIdx, beamIntensity * 1f * (float)Math.PI); // color intensity: depends on the dot product between to-camera vector and beam direction; // also depends on how of the occlusion disk area is visible float maxScreenArea = (float)Math.PI * laserParams.emissionOccDiskRadiusPx * laserParams.emissionOccDiskRadiusPx; float occDiskAreaRatio = occDiskScreenAreaUsed / maxScreenArea; //System.Console.WriteLine("occDiskAreaRatio = " + occDiskAreaRatio); Vector3 toCamera = (cameraPos - beam.startPosWorld).Normalized(); float dot = Math.Max(0f, Vector3.Dot(toCamera, beam.directionWorld())); //System.Console.WriteLine("dot = " + dot); var alpha = occDiskAreaRatio * 1.2f * (float)Math.Pow(beamIntensity, 0.1) * (float)Math.Pow(dot, 0.1); alpha = Math.Min(alpha, 1f); // finish background color var backgroundColor = laserParams.backgroundColor; backgroundColor.A = alpha; instanceData.writeColor(_backgroundSpriteIdx, backgroundColor); // finish overlay color var overlayColor = laserParams.overlayColor; overlayColor.A = alpha; instanceData.writeColor(_overlaySpriteIdx, overlayColor); }
public void preRenderUpdate(float timeElapsed) { bool visible = (targetObj != null); _outline.renderState.visible = visible; _labelBelow.renderState.visible = visible; _labelAbove.renderState.visible = visible; if (!visible) { return; } RectangleF clientRect = OpenTKHelper.GetClientRect(); var targetRc = _targetObj3dScene.renderConfig; Matrix4 targetViewProj = targetRc.invCameraViewMatrix * targetRc.projectionMatrix; // outline Quaternion viewRotOnly = targetRc.invCameraViewMatrix.ExtractRotation(); Quaternion viewRotInverted = viewRotOnly.Inverted(); Vector3 viewRight = Vector3.Transform(Vector3.UnitX, viewRotInverted).Normalized(); Vector3 viewUp = Vector3.Transform(Vector3.UnitY, viewRotInverted).Normalized(); Vector2 targetScreenPos = OpenTKHelper.WorldToScreen(targetObj.Pos, ref targetViewProj, ref clientRect); targetScreenPos.X = (float)Math.Round(targetScreenPos.X); // fixes off-by-one pixel jitter targetScreenPos.Y = (float)Math.Round(targetScreenPos.Y); // animate outline line stipple _outline.enableLineStipple = this.isSelected; if (_outline.enableLineStipple) { ushort stipplePattern = _outline.lineStipplePattern; _stippleTimeAccumulator += timeElapsed; while (_stippleTimeAccumulator >= stippleStepInterval) { ushort firstBit = (ushort)((uint)stipplePattern & 0x1); stipplePattern >>= 1; stipplePattern |= (ushort)((uint)firstBit << 15); _outline.lineStipplePattern = stipplePattern; _stippleTimeAccumulator -= stippleStepInterval; } } float outlineHalfWidth; float outlineHalfHeight; if (fixedSizeTargets) { outlineHalfWidth = outlineMinPixelSz; outlineHalfHeight = outlineMinPixelSz; } else { // assumes target is a convential SSObject without billboarding, match scale to screen, etc. var size = targetObj.worldBoundingSphereRadius; Vector3 targetRightMost = targetObj.Pos + viewRight * size; Vector3 targetTopMost = targetObj.Pos + viewUp * size; Vector2 screenRightMostPt = OpenTKHelper.WorldToScreen(targetRightMost, ref targetViewProj, ref clientRect); Vector2 screenTopMostPt = OpenTKHelper.WorldToScreen(targetTopMost, ref targetViewProj, ref clientRect); outlineHalfWidth = 2f * (screenRightMostPt.X - targetScreenPos.X); outlineHalfWidth = Math.Max(outlineHalfWidth, outlineMinPixelSz); outlineHalfHeight = 2f * (targetScreenPos.Y - screenTopMostPt.Y); outlineHalfHeight = Math.Max(outlineHalfHeight, outlineMinPixelSz); } Vector3 targetViewPos = Vector3.Transform(targetObj.Pos, targetRc.invCameraViewMatrix); _targetViewDepth = targetViewPos.Z; bool targetIsInFront = _targetViewDepth < 0f; float lineWidth = targetIsInFront ? outlineWidthWhenInFront : outlinelineWidthWhenBehind; bool above, below, left, right; if (targetIsInFront) { left = targetScreenPos.X + outlineHalfWidth < 0f; right = !left && targetScreenPos.X - outlineHalfWidth > clientRect.Width; above = targetScreenPos.Y + outlineHalfHeight < 0f; below = !above && targetScreenPos.Y + outlineHalfHeight > clientRect.Height; } else // target is behind { float halfScrWidth = clientRect.Width / 2f; float halfScrHeight = clientRect.Height / 2f; float quartScrWidth = halfScrWidth / 2f; float quartScrHeight = halfScrHeight / 2f; right = targetScreenPos.X < quartScrWidth; left = !right && targetScreenPos.X > halfScrWidth + quartScrWidth; below = targetScreenPos.Y < quartScrHeight; above = !below && targetScreenPos.Y > halfScrHeight + quartScrHeight; } int orientIdx = (above ? 1 : 0) + (below ? 2 : 0) + (left ? 4 : 0) + (right ? 8 : 0); bool inTheCenter = (orientIdx == 0); if (!inTheCenter) { outlineHalfWidth = outlineMinPixelSz; outlineHalfHeight = outlineMinPixelSz; if (left) { targetScreenPos.X = outlineHalfWidth; } else if (right) { targetScreenPos.X = clientRect.Width - outlineHalfWidth - lineWidth * 2f; } if (above) { targetScreenPos.Y = outlineHalfHeight + _labelAbove.getGdiSize.Height; } else if (below) { targetScreenPos.Y = clientRect.Height - outlineHalfHeight - _labelBelow.getGdiSize.Height; } } _outline.Mesh = inTheCenter ? (targetIsInFront ? hudRectLinesMesh : hudCircleMesh) : hudTriMesh; _outline.Scale = new Vector3(outlineHalfWidth, outlineHalfHeight, 1f); _outline.Orient(outlineOrients [orientIdx]); _outline.Pos = new Vector3(targetScreenPos.X, targetScreenPos.Y, +1f); // labels _labelBelow.Label = fetchTextBelow(targetObj); var labelBelowPos = targetScreenPos; if (left) { labelBelowPos.X = 0f; } else if (right) { labelBelowPos.X = clientRect.Width - _labelBelow.getGdiSize.Width - 10f; } else { labelBelowPos.X -= _labelBelow.getGdiSize.Width / 2f; } labelBelowPos.Y += outlineHalfHeight; if ((left || right) && !below) { labelBelowPos.Y += outlineHalfHeight; } _labelBelow.Pos = new Vector3(labelBelowPos.X, labelBelowPos.Y, 0f); _labelAbove.Label = fetchTextAbove(targetObj); var labelAbovePos = targetScreenPos; if (left) { labelAbovePos.X = 0f; } else if (right) { labelAbovePos.X = clientRect.Width - _labelAbove.getGdiSize.Width - 10f; } else { labelAbovePos.X -= _labelAbove.getGdiSize.Width / 2f; } if ((left || right) && !above) { labelAbovePos.Y -= outlineHalfHeight; } labelAbovePos.Y -= (outlineHalfHeight + _labelAbove.getGdiSize.Height); _labelAbove.Pos = new Vector3(labelAbovePos.X, labelAbovePos.Y, 0f); Color4 color = fetchColor(targetObj); _outline.MainColor = color; _labelBelow.MainColor = color; _labelAbove.MainColor = color; _outlineScreenRect = new Rectangle( (int)(targetScreenPos.X - outlineHalfWidth), (int)(targetScreenPos.Y - outlineHalfHeight), (int)(outlineHalfWidth * 2f), (int)(outlineHalfHeight * 2f) ); }