public void updateCamera(ref Matrix4 rendererWorldMat, ref Vector3 cameraPosLocal)
            {
                var laserParams = _laser.parameters;

                for (int i = 0; i < laserParams.numBeams; ++i)
                {
                    var beam         = _laser.beam(i);
                    var flashEmitter = _flashEmitters [i];
                    var smokeEmitter = _smokeEmitters [i];
                    // TODO need intersection location
                    if (beam.hitsAnObstacle)
                    {
                        var hitPosLocal   = Vector3.Transform(beam.endPosWorld, rendererWorldMat.Inverted());
                        var towardsCamera = (cameraPosLocal - hitPosLocal).Normalized();
                        flashEmitter.center = hitPosLocal;
                        flashEmitter.up     = towardsCamera;
                        flashEmitter.particlesPerEmissionMin = laserParams.flashParticlesPerEmissionMin;
                        flashEmitter.particlesPerEmissionMax = laserParams.flashParticlesPerEmissionMax;
                        smokeEmitter.center = hitPosLocal;
                        smokeEmitter.up     = towardsCamera;
                        smokeEmitter.particlesPerEmissionMin = laserParams.flameSmokeParticlesPerEmissionMin;
                        smokeEmitter.particlesPerEmissionMax = laserParams.flameSmokeParticlesPerEmissionMax;
                    }
                    else
                    {
                        // no hit = no particle emissions
                        flashEmitter.particlesPerEmission = 0;
                        smokeEmitter.particlesPerEmission = 0;
                    }
                }
                _flamesSmokeColorEffector.colorMask   = _laser.parameters.backgroundColor;
                _flamesSmokeColorEffector.colorMask.A = _laser.envelopeIntensity;

                _flashColorEffector.colorMask   = _laser.parameters.overlayColor;
                _flashColorEffector.colorMask.A = _laser.envelopeIntensity;
            }
        public override void Render(SSRenderConfig renderConfig)
        {
            var beam = _laser.beam(_beamId);

            if (beam == null)
            {
                return;
            }

            base.Render(renderConfig);

            // step: setup render settings
            SSShaderProgram.DeactivateAll();
            GL.ActiveTexture(TextureUnit.Texture0);
            GL.Enable(EnableCap.Texture2D);

            var laserParams = _laser.parameters;

            var startView  = Vector3.Transform(beam.startPosWorld, renderConfig.invCameraViewMatrix);
            var endView    = Vector3.Transform(beam.endPosWorld, renderConfig.invCameraViewMatrix);
            var middleView = (startView + endView) / 2f;

            // step: draw middle section:
            Vector3 diff                = endView - startView;
            float   diff_xy             = diff.Xy.Length;
            float   phi                 = -(float)Math.Atan2(diff.Z, diff_xy);
            float   theta               = (float)Math.Atan2(diff.Y, diff.X);
            Matrix4 backgroundOrientMat = Matrix4.CreateRotationY(phi) * Matrix4.CreateRotationZ(theta);
            Matrix4 middlePlacementMat  = backgroundOrientMat * Matrix4.CreateTranslation(middleView);
            //Matrix4 startPlacementMat = Matrix4.CreateTranslation (startView);

            float laserLength = diff.Length;
            float middleWidth = laserParams.middleBackgroundWidth * _laser.envelopeIntensity;

            Vector3 cameraDir = Vector3.Transform(
                -Vector3.UnitZ, _cameraScene.renderConfig.invCameraViewMatrix).Normalized();
            float dot = Vector3.Dot(cameraDir, beam.directionWorld());

            dot = Math.Max(dot, 0f);
            float interferenceWidth = middleWidth * laserParams.middleInterferenceScale;

            GL.Color4(1f, 1f, 1f, beam.periodicIntensity * beam.periodicIntensity);

            _updateMiddleMesh(laserLength, middleWidth);

                        #if true
            // stretched middle background sprite
            if (middleBackgroundSprite != null)
            {
                GL.Material(MaterialFace.Front, MaterialParameter.Emission, laserParams.backgroundColor);
                GL.BindTexture(TextureTarget.Texture2D, middleBackgroundSprite.TextureID);

                foreach (var oriX in xOrientationPresets)
                {
                    Matrix4 rotated = oriX * middlePlacementMat;
                    GL.LoadMatrix(ref rotated);
                    _middleMesh.renderMesh(renderConfig);
                }
            }
                        #endif
                        #if true
            // stretched middle overlay sprite
            if (middleOverlayTexture != null)
            {
                GL.Material(MaterialFace.Front, MaterialParameter.Emission, laserParams.overlayColor);
                GL.BindTexture(TextureTarget.Texture2D, middleOverlayTexture.TextureID);

                _middleMesh.renderMesh(renderConfig);

                foreach (var oriX in xOrientationPresets)
                {
                    Matrix4 rotated = oriX * middlePlacementMat;
                    GL.LoadMatrix(ref rotated);
                    _middleMesh.renderMesh(renderConfig);
                }
            }
                        #endif
                        #if true
            // interference sprite with a moving U-coordinate offset
            if (laserParams.middleInterferenceScale > 0f && interferenceTexture != null)
            {
                _updateInterfernenceVertices(laserLength, interferenceWidth);

                GL.Material(MaterialFace.Front, MaterialParameter.Emission, laserParams.middleInterferenceColor);
                //GL.BindTexture(TextureTarget.Texture2D, interferenceSprite.TextureID);
                GL.BindTexture(TextureTarget.Texture2D, interferenceTexture.TextureID);
                var scaleMat = Matrix4.CreateScale(laserLength + middleWidth / 2f, interferenceWidth, 1f);

                foreach (var oriX in xOrientationPresets)
                {
                    Matrix4 rotated = scaleMat * oriX * middlePlacementMat;
                    GL.LoadMatrix(ref rotated);
                    _interferenceMesh.renderMesh(renderConfig);
                }
            }
                        #endif
        }
Beispiel #3
0
        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);
        }