private void SaveDataOcclusion() { OcclusionData d = new OcclusionData(); d.occlusion = occlusion.vars; d.blurOcclusion = blurOcclusion.vars; WriteParams(d, assetName, "Occlusion.xml"); }
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(); } }
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(); }
//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; }
//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; }
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(); }