private void SaveDataOcclusion()
    {
        OcclusionData d = new OcclusionData();

        d.occlusion     = occlusion.vars;
        d.blurOcclusion = blurOcclusion.vars;
        WriteParams(d, assetName, "Occlusion.xml");
    }
Esempio n. 2
0
        public byte[] GetOcclusionBytes(OcclusionData occlusionData)
        {
            if (occlusionData == null)
            {
                return(new byte[0x10]);
            }

            return(occlusionData.ToByteArray());
        }
 private void LoadDataOcclusion()
 {
     if (File.Exists(GetSavePath(assetName) + "Occlusion.xml"))
     {
         OcclusionData d = ReadParams <OcclusionData>(assetName, "Occlusion.xml");
         occlusion.SetPara(d.occlusion);
         blurOcclusion.SetPara(d.blurOcclusion);
     }
     else
     {
         occlusion.ResetPara();
         blurOcclusion.ResetPara();
     }
 }
Esempio n. 4
0
        public OcclusionData GetOcclusionData()
        {
            if (gameplayHeader.occlusionPointer == 0)
            {
                return(null);
            }

            byte[] headBlock         = ReadBlock(fileStream, gameplayHeader.occlusionPointer, 0x10);
            OcclusionDataHeader head = new OcclusionDataHeader(headBlock);

            byte[]        occlusionBlock = ReadBlock(fileStream, gameplayHeader.occlusionPointer + 0x10, head.totalCount * 0x08);
            OcclusionData data           = new OcclusionData(occlusionBlock, head);


            return(data);
        }
    public void UpdateOcclusion(IList<SceneNode> nodes, RenderContext context)
    {
      // Measures the visibility of the light source by drawing a screen-aligned quad
      // using an occlusion query. The query result is used in the next frame.

      ThrowIfDisposed();

      if (nodes == null)
        throw new ArgumentNullException("nodes");
      if (context == null)
        throw new ArgumentNullException("context");

      context.Validate(_basicEffect);
      context.ThrowIfCameraMissing();

      // Occlusion queries require HiDef profile.
      var graphicsDevice = context.GraphicsService.GraphicsDevice;
      if (graphicsDevice.GraphicsProfile == GraphicsProfile.Reach)
        return;

      int numberOfNodes = nodes.Count;
      if (nodes.Count == 0)
        return;

      // Camera properties
      var cameraNode = context.CameraNode;
      var cameraPose = cameraNode.PoseWorld;
      Vector3 cameraRight = cameraPose.Orientation.GetColumn(0);    // 1st column vector
      Vector3 cameraUp = cameraPose.Orientation.GetColumn(1);       // 2nd column vector
      Vector3 cameraForward = -cameraPose.Orientation.GetColumn(2); // 3rd column vector (negated)
      Matrix view = cameraNode.View;
      Matrix projection = cameraNode.Camera.Projection;
      bool isOrthographic = (projection.M33 != 0);

      // The following factors are used to estimate the size of a quad in screen space.
      // (The equation is described in GraphicsHelper.GetScreenSize().)
      float xScale = Math.Abs(projection.M00 / 2);
      float yScale = Math.Abs(projection.M11 / 2);

      var viewport = graphicsDevice.Viewport;

      // Lens flares of directional lights are rendered directly on the screen.
      // --> Set up projection transformation for rendering in screen space.
      var orthographicProjection = Matrix.CreateOrthographicOffCenter(0, viewport.Width, viewport.Height, 0, 0, 1);

      // Set render states for rendering occlusion query geometry (quad).
      var savedRenderState = new RenderStateSnapshot(graphicsDevice);
      graphicsDevice.BlendState = GraphicsHelper.BlendStateNoColorWrite;
      graphicsDevice.DepthStencilState = DepthStencilState.DepthRead;
      graphicsDevice.RasterizerState = RasterizerState.CullCounterClockwise;

      for (int i = 0; i < numberOfNodes; i++)
      {
        var node = nodes[i] as LensFlareNode;
        if (node == null)
          continue;

        object dummy;
        cameraNode.ViewDependentData.TryGetValue(node, out dummy);
        var renderData = dummy as OcclusionData;
        if (renderData == null)
        {
          renderData = new OcclusionData();
          cameraNode.ViewDependentData[node] = renderData;
        }

        if (renderData.OcclusionQuery != null)
        {
          // Wait until previous occlusion query has completed.
          if (!renderData.OcclusionQuery.IsComplete)
            continue;

          // ----- Read result of previous occlusion query.
          int visiblePixels = renderData.OcclusionQuery.PixelCount;

          // OcclusionData.TotalPixels is only an approximation.
          // --> Clamp pixel count to [0, TotalPixels].
          if (visiblePixels > renderData.TotalPixels)
            visiblePixels = renderData.TotalPixels;

          renderData.VisiblePixels = visiblePixels;
        }

        // ----- Run new occlusion query.
        var lensFlare = node.LensFlare;

        // The user can disable the lens flare by setting LensFlare.Intensity to 0.
        float intensity = node.Intensity * lensFlare.Intensity;
        if (intensity < MinIntensity)
        {
          renderData.VisiblePixels = 0;
          continue;
        }

        float querySize;
        if (lensFlare.IsDirectional)
        {
          // ----- Directional lights

          // Ignore directional lights if camera has orthographic projection.
          // (The light source is infinitely far way and the camera frustum has only 
          // limited width and height. It is very unlikely that camera catches the 
          // directional light.
          if (isOrthographic)
          {
            renderData.VisiblePixels = 0;
            continue;
          }

          // Directional lights are positioned at infinite distance and are not affected
          // by the position of the camera.
          Vector3 lightDirectionWorld = -node.PoseWorld.Orientation.GetColumn(2);  // 3rd column vector (negated)
          Vector3 lightDirectionView = cameraPose.ToLocalDirection(lightDirectionWorld);
          if (lightDirectionView.Z < 0)
          {
            // Light comes from behind camera.
            renderData.VisiblePixels = 0;
            continue;
          }

          // Project position to viewport.
          Vector3 screenPosition = viewport.ProjectToViewport(-lightDirectionView, projection);

          // LensFlare.QuerySize is the size relative to viewport.
          querySize = lensFlare.QuerySize * viewport.Height;
          renderData.TotalPixels = (int)(querySize * querySize);
          if (renderData.TotalPixels < MinPixelSize)
          {
            // Cull small light sources.
            renderData.VisiblePixels = 0;
            continue;
          }

          // Draw quad in screen space.
          querySize /= 2;
          _queryGeometry[0].Position = new Vector3(screenPosition.X - querySize, screenPosition.Y - querySize, -1);
          _queryGeometry[1].Position = new Vector3(screenPosition.X + querySize, screenPosition.Y - querySize, -1);
          _queryGeometry[2].Position = new Vector3(screenPosition.X - querySize, screenPosition.Y + querySize, -1);
          _queryGeometry[3].Position = new Vector3(screenPosition.X + querySize, screenPosition.Y + querySize, -1);

          _basicEffect.World = Matrix.Identity;
          _basicEffect.View = Matrix.Identity;
          _basicEffect.Projection = orthographicProjection;
          _basicEffect.CurrentTechnique.Passes[0].Apply();

          if (renderData.OcclusionQuery == null)
            renderData.OcclusionQuery = new OcclusionQuery(graphicsDevice);

          renderData.OcclusionQuery.Begin();
          graphicsDevice.DrawUserPrimitives(PrimitiveType.TriangleStrip, _queryGeometry, 0, 2);
          renderData.OcclusionQuery.End();
        }
        else
        {
          // ----- Local lights

          // Determine planar distance to camera.
          Vector3 position = node.PoseWorld.Position;
          Vector3 cameraToNode = position - cameraPose.Position;
          float distance = Vector3.Dot(cameraToNode, cameraForward);
          if (distance < cameraNode.Camera.Projection.Near)
          {
            // Light is behind near plane.
            renderData.VisiblePixels = 0;
            continue;
          }

          Debug.Assert(
            node.ScaleWorld.X > 0 && node.ScaleWorld.Y > 0 && node.ScaleWorld.Z > 0,
            "Assuming that all scale factors are positive.");

          // LensFlare.QuerySize is the size in world space.
          querySize = node.ScaleWorld.LargestComponent * node.LensFlare.QuerySize;

          // Estimate screen space size of query geometry.
          float screenSizeX = viewport.Width * querySize * xScale;
          float screenSizeY = viewport.Height * querySize * yScale;
          if (!isOrthographic)
          {
            float oneOverDistance = 1 / distance;
            screenSizeX *= oneOverDistance;
            screenSizeY *= oneOverDistance;
          }

          renderData.TotalPixels = (int)(screenSizeX * screenSizeY);
          if (renderData.TotalPixels < MinPixelSize)
          {
            // Cull small light sources.
            renderData.VisiblePixels = 0;
            continue;
          }

          // Draw screen-aligned quad in world space.
          querySize /= 2;
          Vector3 upVector = querySize * cameraUp;
          Vector3 rightVector = querySize * cameraRight;

          // Offset quad by half its size towards the camera. Otherwise, the geometry 
          // of the light source could obstruct the query geometry.
          position -= querySize * cameraToNode.Normalized;
          _queryGeometry[0].Position = (Vector3)(position - rightVector - upVector);
          _queryGeometry[1].Position = (Vector3)(position - rightVector + upVector);
          _queryGeometry[2].Position = (Vector3)(position + rightVector - upVector);
          _queryGeometry[3].Position = (Vector3)(position + rightVector + upVector);

          _basicEffect.World = Matrix.Identity;
          _basicEffect.View = (Matrix)view;
          _basicEffect.Projection = (Matrix)projection;
          _basicEffect.CurrentTechnique.Passes[0].Apply();

          if (renderData.OcclusionQuery == null)
            renderData.OcclusionQuery = new OcclusionQuery(graphicsDevice);

          renderData.OcclusionQuery.Begin();
          graphicsDevice.DrawUserPrimitives(PrimitiveType.TriangleStrip, _queryGeometry, 0, 2);
          renderData.OcclusionQuery.End();
        }
      }

      savedRenderState.Restore();
    }
Esempio n. 6
0
        //Engine file constructor
        public Level(string enginePath)
        {
            path = Path.GetDirectoryName(enginePath);

            // Engine elements
            using (EngineParser engineParser = new EngineParser(enginePath))
            {
                game = engineParser.GetGameType();

                //REMOVE THESE ASAP!!!!!111
                renderDefBytes   = engineParser.GetRenderDefBytes();
                collBytesEngine  = engineParser.GetCollisionBytes();
                billboardBytes   = engineParser.GetBillboardBytes();
                soundConfigBytes = engineParser.GetSoundConfigBytes();

                LOGGER.Debug("Parsing skybox...");
                skybox = engineParser.GetSkyboxModel();
                LOGGER.Debug("Success");

                LOGGER.Debug("Parsing moby models...");
                mobyModels = engineParser.GetMobyModels();
                LOGGER.Debug("Added {0} moby models", mobyModels.Count);

                LOGGER.Debug("Parsing tie models...");
                tieModels = engineParser.GetTieModels();
                LOGGER.Debug("Added {0} tie models", tieModels.Count);

                LOGGER.Debug("Parsing shrub models...");
                shrubModels = engineParser.GetShrubModels();
                LOGGER.Debug("Added {0} shrub models", shrubModels.Count);

                LOGGER.Debug("Parsing weapons...");
                gadgetModels = engineParser.GetGadgets();
                LOGGER.Debug("Added {0} weapons", gadgetModels.Count);

                LOGGER.Debug("Parsing textures...");
                textures = engineParser.GetTextures();
                LOGGER.Debug("Added {0} textures", textures.Count);

                LOGGER.Debug("Parsing ties...");
                ties = engineParser.GetTies(tieModels);
                LOGGER.Debug("Added {0} ties", ties.Count);

                LOGGER.Debug("Parsing Shrubs...");
                shrubs = engineParser.GetShrubs(shrubModels);
                LOGGER.Debug("Added {0} shrubs", shrubs.Count);

                LOGGER.Debug("Parsing Lights...");
                lights = engineParser.GetLights();
                LOGGER.Debug("Added {0} lights", lights.Count);

                LOGGER.Debug("Parsing terrain elements...");
                terrainEngine = engineParser.GetTerrainModel();
                LOGGER.Debug("Added {0} terrain elements", terrainEngine.fragments.Count);

                LOGGER.Debug("Parsing player animations...");
                playerAnimations = engineParser.GetPlayerAnimations((MobyModel)mobyModels[0]);
                LOGGER.Debug("Added {0} player animations", playerAnimations.Count);

                uiElements = engineParser.GetUiElements();
                LOGGER.Debug("Added {0} ui elements", uiElements.Count);

                lightConfig        = engineParser.GetLightConfig();
                textureConfigMenus = engineParser.GetTextureConfigMenu();

                collisionEngine = engineParser.GetCollisionModel();

                unk3 = engineParser.GetUnk3Bytes();
                unk4 = engineParser.GetUnk4Bytes();
                unk5 = engineParser.GetUnk5Bytes();
                unk8 = engineParser.GetUnk8Bytes();
                unk9 = engineParser.GetUnk9Bytes();
            }


            // Gameplay elements
            using (GameplayParser gameplayParser = new GameplayParser(game, path + @"/gameplay_ntsc"))
            {
                LOGGER.Debug("Parsing Level variables...");
                levelVariables = gameplayParser.GetLevelVariables();

                LOGGER.Debug("Parsing mobs...");
                mobs = gameplayParser.GetMobies(mobyModels);
                LOGGER.Debug("Added {0} mobs", mobs.Count);

                LOGGER.Debug("Parsing splines...");
                splines = gameplayParser.GetSplines();
                LOGGER.Debug("Added {0} splines", splines.Count);

                LOGGER.Debug("Parsing languages...");
                english   = gameplayParser.GetEnglish();
                ukenglish = gameplayParser.GetUkEnglish();
                french    = gameplayParser.GetFrench();
                german    = gameplayParser.GetGerman();
                spanish   = gameplayParser.GetSpanish();
                italian   = gameplayParser.GetItalian();
                japanese  = gameplayParser.GetJapanese();
                korean    = gameplayParser.GetKorean();

                LOGGER.Debug("Parsing other gameplay assets...");
                unk6  = gameplayParser.GetUnk6();
                unk7  = gameplayParser.GetUnk7();
                unk12 = gameplayParser.GetUnk12();
                unk13 = gameplayParser.GetUnk13();
                unk14 = gameplayParser.GetUnk14();
                unk16 = gameplayParser.GetUnk16();
                unk17 = gameplayParser.GetUnk17();
                unk18 = gameplayParser.GetUnk18();

                tieData   = gameplayParser.GetTieData(ties.Count);
                shrubData = gameplayParser.GetShrubData(shrubs.Count);

                tieGroupData   = gameplayParser.GetTieGroups();
                shrubGroupData = gameplayParser.GetShrubGroups();

                areasData = gameplayParser.GetAreasData();

                directionalLights = gameplayParser.GetDirectionalLights();
                type0Cs           = gameplayParser.GetType0Cs();
                spheres           = gameplayParser.GetSpheres();
                cylinders         = gameplayParser.GetCylinders();
                type4Cs           = gameplayParser.GetType4Cs();
                type7Cs           = gameplayParser.GetType7Cs();
                type80s           = gameplayParser.GetType80();
                type88s           = gameplayParser.GetType88s();
                type50s           = gameplayParser.GetType50s();
                type5Cs           = gameplayParser.GetType5Cs();

                pVars       = gameplayParser.GetPvars(mobs);
                cuboids     = gameplayParser.GetCuboids();
                gameCameras = gameplayParser.GetGameCameras();

                mobyIds       = gameplayParser.GetMobyIds();
                tieIds        = gameplayParser.GetTieIds();
                shrubIds      = gameplayParser.GetShrubIds();
                occlusionData = gameplayParser.GetOcclusionData();
            }

            terrainChunks   = new List <Terrain>();
            collisionChunks = new List <Model>();
            collBytesChunks = new List <byte[]>();

            for (int i = 0; i < 5; i++)
            {
                var chunkPath = Path.Join(path, @"chunk" + i + ".ps3");
                if (!File.Exists(chunkPath))
                {
                    continue;
                }

                using (ChunkParser chunkParser = new ChunkParser(chunkPath, game))
                {
                    terrainChunks.Add(chunkParser.GetTerrainModels());
                    collisionChunks.Add(chunkParser.GetCollisionModel());
                    collBytesChunks.Add(chunkParser.GetCollBytes());
                }
            }

            List <string> armorPaths = ArmorHeader.FindArmorFiles(game, enginePath);

            armorModels   = new List <Model>();
            armorTextures = new List <List <Texture> >();

            foreach (string armor in armorPaths)
            {
                LOGGER.Debug("Looking for armor data in {0}", armor);
                List <Texture> tex;
                MobyModel      model;
                using (ArmorParser parser = new ArmorParser(game, armor))
                {
                    tex   = parser.GetTextures();
                    model = parser.GetArmor();
                }

                string vram = armor.Replace(".ps3", ".vram");

                using (VramParser parser = new VramParser(vram))
                {
                    parser.GetTextures(tex);
                }

                if (model != null)
                {
                    armorModels.Add(model);
                }

                armorTextures.Add(tex);
            }

            string gadgetPath = GadgetHeader.FindGadgetFile(game, enginePath);

            gadgetTextures = new List <Texture>();

            if (gadgetPath != "")
            {
                LOGGER.Debug("Looking for gadget data in {0}", gadgetPath);
                using (GadgetParser parser = new GadgetParser(game, gadgetPath))
                {
                    gadgetModels.AddRange(parser.GetModels());
                    gadgetTextures.AddRange(parser.GetTextures());
                }

                using (VramParser parser = new VramParser(gadgetPath.Replace(".ps3", ".vram")))
                {
                    parser.GetTextures(gadgetTextures);
                }
            }

            List <string> missionPaths = MissionHeader.FindMissionFiles(game, enginePath);

            missions = new List <Mission>();

            for (int i = 0; i < missionPaths.Count; i++)
            {
                string missionPath = missionPaths[i];
                string vramPath    = missionPath.Replace(".ps3", ".vram");

                if (!File.Exists(vramPath))
                {
                    LOGGER.Warn("Could not find .vram file for {0}", missionPath);
                    continue;
                }

                LOGGER.Debug("Looking for mission data in {0}", missionPath);

                Mission mission = new Mission(i);

                using (MissionParser parser = new MissionParser(game, missionPath))
                {
                    mission.models   = parser.GetModels();
                    mission.textures = parser.GetTextures();
                }

                using (VramParser parser = new VramParser(vramPath))
                {
                    parser.GetTextures(mission.textures);
                }

                missions.Add(mission);
            }

            using (VramParser vramParser = new VramParser(path + @"/vram.ps3"))
            {
                vramParser.GetTextures(textures);
            }

            LOGGER.Info("Level parsing done");
            valid = true;
        }
Esempio n. 7
0
        //Engine file constructor
        public Level(string enginePath)
        {
            path = Path.GetDirectoryName(enginePath);

            // Engine elements
            using (EngineParser engineParser = new EngineParser(enginePath))
            {
                game = engineParser.DetectGame();

                //REMOVE THESE ASAP!!!!!111
                renderDefBytes   = engineParser.GetRenderDefBytes();
                collBytes        = engineParser.GetCollisionBytes();
                billboardBytes   = engineParser.GetBillboardBytes();
                soundConfigBytes = engineParser.GetSoundConfigBytes();

                Console.WriteLine("Parsing skybox...");
                skybox = engineParser.GetSkyboxModel();
                Console.WriteLine("Success");

                Console.WriteLine("Parsing moby models...");
                mobyModels = engineParser.GetMobyModels();
                Console.WriteLine("Added " + mobyModels.Count + " moby models");

                Console.WriteLine("Parsing tie models...");
                tieModels = engineParser.GetTieModels();
                Console.WriteLine("Added " + tieModels.Count + " tie models");

                Console.WriteLine("Parsing shrub models...");
                shrubModels = engineParser.GetShrubModels();
                Console.WriteLine("Added " + shrubModels.Count + " shrub models");

                Console.WriteLine("Parsing weapons...");
                weaponModels = engineParser.GetWeapons();
                Console.WriteLine("Added " + weaponModels.Count + " weapons");

                Console.WriteLine("Parsing textures...");
                textures = engineParser.GetTextures();
                Console.WriteLine("Added " + textures.Count + " textures");

                Console.WriteLine("Parsing ties...");
                ties = engineParser.GetTies(tieModels);
                Console.WriteLine("Added " + ties.Count + " ties");

                Console.WriteLine("Parsing Shrubs...");
                shrubs = engineParser.GetShrubs(shrubModels);
                Console.WriteLine("Added " + shrubs.Count + " Shrubs");

                Console.WriteLine("Parsing Lights...");
                lights = engineParser.GetLights();
                Console.WriteLine("Added " + lights.Count + " lights");

                Console.WriteLine("Parsing terrain elements...");
                terrains = engineParser.GetTerrainModels();
                Console.WriteLine("Added " + terrains?.Count + " terrain elements");

                Console.WriteLine("Parsing player animations...");
                playerAnimations = engineParser.GetPlayerAnimations((MobyModel)mobyModels[0]);
                Console.WriteLine("Added " + playerAnimations?.Count + " player animations");

                uiElements = engineParser.GetUiElements();
                Console.WriteLine("Added " + uiElements?.Count + " ui elements");

                lightConfig        = engineParser.GetLightConfig();
                textureConfigMenus = engineParser.GetTextureConfigMenu();
                collisionModel     = engineParser.GetCollisionModel();
            }


            // Gameplay elements
            using (GameplayParser gameplayParser = new GameplayParser(game, path + @"/gameplay_ntsc"))
            {
                Console.WriteLine("Parsing Level variables...");
                levelVariables = gameplayParser.GetLevelVariables();

                Console.WriteLine("Parsing mobs...");
                mobs = gameplayParser.GetMobies(game, mobyModels);
                Console.WriteLine("Added " + mobs?.Count + " mobs");

                Console.WriteLine("Parsing splines...");
                splines = gameplayParser.GetSplines();
                //Console.WriteLine("Added " + splines.Count + " splines");

                Console.WriteLine("Parsing languages...");
                english = gameplayParser.GetEnglish();
                lang2   = gameplayParser.GetLang2();
                french  = gameplayParser.GetFrench();
                german  = gameplayParser.GetGerman();
                spanish = gameplayParser.GetSpanish();
                italian = gameplayParser.GetItalian();
                lang7   = gameplayParser.GetLang7();
                lang8   = gameplayParser.GetLang8();

                Console.WriteLine("Parsing other gameplay assets...");
                unk6  = gameplayParser.GetUnk6();
                unk7  = gameplayParser.GetUnk7();
                unk13 = gameplayParser.GetUnk13();
                unk17 = gameplayParser.GetUnk17();
                unk14 = gameplayParser.GetUnk14();

                tieData   = gameplayParser.GetTieData(ties.Count);
                shrubData = gameplayParser.getShrubData(shrubs.Count);

                type04s = gameplayParser.GetType04s();
                type0Cs = gameplayParser.GetType0Cs();
                type64s = gameplayParser.GetType64s();
                type68s = gameplayParser.GetType68s();
                type7Cs = gameplayParser.GetType7Cs();
                type80s = gameplayParser.GetType80();
                type88s = gameplayParser.GetType88s();
                type50s = gameplayParser.GetType50s();
                type5Cs = gameplayParser.GetType5Cs();

                pVars       = gameplayParser.GetPvars(mobs);
                cuboids     = gameplayParser.GetCuboids();
                gameCameras = gameplayParser.GetGameCameras();

                mobyIds       = gameplayParser.GetMobyIds();
                tieIds        = gameplayParser.GetTieIds();
                shrubIds      = gameplayParser.GetShrubIds();
                occlusionData = gameplayParser.GetOcclusionData();
            }


            VramParser vramParser = new VramParser(path + @"/vram.ps3");

            if (!vramParser.valid)
            {
                valid = false;
                return;
            }

            vramParser.GetTextures(textures);
            vramParser.Close();


            Console.WriteLine("Level parsing done");
            valid = true;
        }
Esempio n. 8
0
        public void UpdateOcclusion(IList<SceneNode> nodes, RenderContext context)
        {
            // Measures the visibility of the light source by drawing a screen-aligned quad
              // using an occlusion query. The query result is used in the next frame.

              ThrowIfDisposed();

              if (nodes == null)
            throw new ArgumentNullException("nodes");
              if (context == null)
            throw new ArgumentNullException("context");

              context.Validate(_basicEffect);
              context.ThrowIfCameraMissing();

              // Occlusion queries require HiDef profile.
              var graphicsDevice = context.GraphicsService.GraphicsDevice;
              if (graphicsDevice.GraphicsProfile == GraphicsProfile.Reach)
            return;

              int numberOfNodes = nodes.Count;
              if (nodes.Count == 0)
            return;

              // Camera properties
              var cameraNode = context.CameraNode;
              var cameraPose = cameraNode.PoseWorld;
              Vector3F cameraRight = cameraPose.Orientation.GetColumn(0);    // 1st column vector
              Vector3F cameraUp = cameraPose.Orientation.GetColumn(1);       // 2nd column vector
              Vector3F cameraForward = -cameraPose.Orientation.GetColumn(2); // 3rd column vector (negated)
              Matrix44F view = cameraNode.View;
              Matrix44F projection = cameraNode.Camera.Projection;
              bool isOrthographic = (projection.M33 != 0);

              // The following factors are used to estimate the size of a quad in screen space.
              // (The equation is described in GraphicsHelper.GetScreenSize().)
              float xScale = Math.Abs(projection.M00 / 2);
              float yScale = Math.Abs(projection.M11 / 2);

              var viewport = graphicsDevice.Viewport;

              // Lens flares of directional lights are rendered directly on the screen.
              // --> Set up projection transformation for rendering in screen space.
              var orthographicProjection = Matrix.CreateOrthographicOffCenter(0, viewport.Width, viewport.Height, 0, 0, 1);

              // Set render states for rendering occlusion query geometry (quad).
              var savedRenderState = new RenderStateSnapshot(graphicsDevice);
              graphicsDevice.BlendState = GraphicsHelper.BlendStateNoColorWrite;
              graphicsDevice.DepthStencilState = DepthStencilState.DepthRead;
              graphicsDevice.RasterizerState = RasterizerState.CullCounterClockwise;

              for (int i = 0; i < numberOfNodes; i++)
              {
            var node = nodes[i] as LensFlareNode;
            if (node == null)
              continue;

            object dummy;
            cameraNode.ViewDependentData.TryGetValue(node, out dummy);
            var renderData = dummy as OcclusionData;
            if (renderData == null)
            {
              renderData = new OcclusionData();
              cameraNode.ViewDependentData[node] = renderData;
            }

            if (renderData.OcclusionQuery != null)
            {
              // Wait until previous occlusion query has completed.
              if (!renderData.OcclusionQuery.IsComplete)
            continue;

              // ----- Read result of previous occlusion query.
              int visiblePixels = renderData.OcclusionQuery.PixelCount;

              // OcclusionData.TotalPixels is only an approximation.
              // --> Clamp pixel count to [0, TotalPixels].
              if (visiblePixels > renderData.TotalPixels)
            visiblePixels = renderData.TotalPixels;

              renderData.VisiblePixels = visiblePixels;
            }

            // ----- Run new occlusion query.
            var lensFlare = node.LensFlare;

            // The user can disable the lens flare by setting LensFlare.Intensity to 0.
            float intensity = node.Intensity * lensFlare.Intensity;
            if (intensity < MinIntensity)
            {
              renderData.VisiblePixels = 0;
              continue;
            }

            float querySize;
            if (lensFlare.IsDirectional)
            {
              // ----- Directional lights

              // Ignore directional lights if camera has orthographic projection.
              // (The light source is infinitely far way and the camera frustum has only
              // limited width and height. It is very unlikely that camera catches the
              // directional light.
              if (isOrthographic)
              {
            renderData.VisiblePixels = 0;
            continue;
              }

              // Directional lights are positioned at infinite distance and are not affected
              // by the position of the camera.
              Vector3F lightDirectionWorld = -node.PoseWorld.Orientation.GetColumn(2);  // 3rd column vector (negated)
              Vector3F lightDirectionView = cameraPose.ToLocalDirection(lightDirectionWorld);
              if (lightDirectionView.Z < 0)
              {
            // Light comes from behind camera.
            renderData.VisiblePixels = 0;
            continue;
              }

              // Project position to viewport.
              Vector3F screenPosition = viewport.ProjectToViewport(-lightDirectionView, projection);

              // LensFlare.QuerySize is the size relative to viewport.
              querySize = lensFlare.QuerySize * viewport.Height;
              renderData.TotalPixels = (int)(querySize * querySize);
              if (renderData.TotalPixels < MinPixelSize)
              {
            // Cull small light sources.
            renderData.VisiblePixels = 0;
            continue;
              }

              // Draw quad in screen space.
              querySize /= 2;
              _queryGeometry[0].Position = new Vector3(screenPosition.X - querySize, screenPosition.Y - querySize, -1);
              _queryGeometry[1].Position = new Vector3(screenPosition.X + querySize, screenPosition.Y - querySize, -1);
              _queryGeometry[2].Position = new Vector3(screenPosition.X - querySize, screenPosition.Y + querySize, -1);
              _queryGeometry[3].Position = new Vector3(screenPosition.X + querySize, screenPosition.Y + querySize, -1);

              _basicEffect.World = Matrix.Identity;
              _basicEffect.View = Matrix.Identity;
              _basicEffect.Projection = orthographicProjection;
              _basicEffect.CurrentTechnique.Passes[0].Apply();

              if (renderData.OcclusionQuery == null)
            renderData.OcclusionQuery = new OcclusionQuery(graphicsDevice);

              renderData.OcclusionQuery.Begin();
              graphicsDevice.DrawUserPrimitives(PrimitiveType.TriangleStrip, _queryGeometry, 0, 2);
              renderData.OcclusionQuery.End();
            }
            else
            {
              // ----- Local lights

              // Determine planar distance to camera.
              Vector3F position = node.PoseWorld.Position;
              Vector3F cameraToNode = position - cameraPose.Position;
              float distance = Vector3F.Dot(cameraToNode, cameraForward);
              if (distance < cameraNode.Camera.Projection.Near)
              {
            // Light is behind near plane.
            renderData.VisiblePixels = 0;
            continue;
              }

              Debug.Assert(
            node.ScaleWorld.X > 0 && node.ScaleWorld.Y > 0 && node.ScaleWorld.Z > 0,
            "Assuming that all scale factors are positive.");

              // LensFlare.QuerySize is the size in world space.
              querySize = node.ScaleWorld.LargestComponent * node.LensFlare.QuerySize;

              // Estimate screen space size of query geometry.
              float screenSizeX = viewport.Width * querySize * xScale;
              float screenSizeY = viewport.Height * querySize * yScale;
              if (!isOrthographic)
              {
            float oneOverDistance = 1 / distance;
            screenSizeX *= oneOverDistance;
            screenSizeY *= oneOverDistance;
              }

              renderData.TotalPixels = (int)(screenSizeX * screenSizeY);
              if (renderData.TotalPixels < MinPixelSize)
              {
            // Cull small light sources.
            renderData.VisiblePixels = 0;
            continue;
              }

              // Draw screen-aligned quad in world space.
              querySize /= 2;
              Vector3F upVector = querySize * cameraUp;
              Vector3F rightVector = querySize * cameraRight;

              // Offset quad by half its size towards the camera. Otherwise, the geometry
              // of the light source could obstruct the query geometry.
              position -= querySize * cameraToNode.Normalized;
              _queryGeometry[0].Position = (Vector3)(position - rightVector - upVector);
              _queryGeometry[1].Position = (Vector3)(position - rightVector + upVector);
              _queryGeometry[2].Position = (Vector3)(position + rightVector - upVector);
              _queryGeometry[3].Position = (Vector3)(position + rightVector + upVector);

              _basicEffect.World = Matrix.Identity;
              _basicEffect.View = (Matrix)view;
              _basicEffect.Projection = (Matrix)projection;
              _basicEffect.CurrentTechnique.Passes[0].Apply();

              if (renderData.OcclusionQuery == null)
            renderData.OcclusionQuery = new OcclusionQuery(graphicsDevice);

              renderData.OcclusionQuery.Begin();
              graphicsDevice.DrawUserPrimitives(PrimitiveType.TriangleStrip, _queryGeometry, 0, 2);
              renderData.OcclusionQuery.End();
            }
              }

              savedRenderState.Restore();
        }