public void setupSprites(SInstancedSpriteData instanceData) { var numElements = Math.Max(_rects.Length, _scales.Length); _spriteSlotIdxs = instanceData.requestSlots(numElements); for (int i = 0; i < _rects.Length; ++i) { instanceData.writeRect(_spriteSlotIdxs[i], _rects [i]); } for (int i = 0; i < _scales.Length; ++i) { instanceData.writeMasterScale(_spriteSlotIdxs [i], _scales [i]); } }
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); }