Lumberyard
Guía del usuario (Version 1.19)

Combinación de sondas de entorno

Puede utilizar el componente Sonda de entorno para conseguir la calidad visual adecuada en un espacio. Las sondas de entorno ayudan a determinar los reflejos, los valores de difuminado del entorno y las partículas y los colores de las sombras adecuados.

Cada sonda de entorno de una escena representa la información de iluminación ambiental. Los datos de la sonda no cambian incluso cuando otras luces de la escena se mueven o cambian de brillo. Esto puede generar una apariencia antinatural. Por ejemplo, el sol se pone, pero los objetos siguen intensamente iluminados por un entorno de sonda que se utiliza para la iluminación diurna.

Para conseguir transiciones convincentes en la iluminación:

  • Cree varias sondas de entorno que representen diferentes condiciones de iluminación.

  • Escriba un script que los combine y los sincronice con la iluminación dinámica de la escena.

Por ejemplo, cuando el sol pasa del mediodía al anochecer, un script toma las sondas de entorno más brillantes y las combina progresivamente para oscurecer las sondas de entorno. Un ciclo de día-noche completo realista puede requerir ocho o más sondas.

Las sondas de entorno tienen la propiedad Probe Fade (Desvanecer sonda) que desvanece la sonda de entorno. Puede cambiar la propiedad Probe Fade (Desvanecer sonda) con Script Canvas, Lua y Editor Track View. Para esta propiedad, puede especificar un valor entre 0.0 y 1.0, lo que representa un porcentaje de la iluminación ambiental. Por ejemplo, en un escenario con dos sondas de entorno superpuestas, la sonda de mayor prioridad (sonda A) normalmente oculta la sonda de menor prioridad (sonda B). Solo la sonda A ilumina los objetos de esa zona. Sin embargo, si establece el valor de Probe Fade (Desvanecer sonda) de la sonda A en 0.5, el 50 % de la luz ambiental procede de la sonda A y el resto de la sonda B.

Para añadir una sonda de entorno a la escena, consulte Uso de componentes y Sonda de entorno. También puede encontrar instrucciones detalladas en Iluminación del entorno en la Guía de introducción a Amazon Lumberyard.

Ejemplo de atenuador y luz nocturna

En el siguiente escenario de ejemplo, se muestra cómo atenuar una lámpara. La habitación tiene una lámpara con atenuador y una luz nocturna. Cuando la lámpara se atenúa, la luz ambiental que proporcionan las sondas de entorno debe atenuarse también. La habitación no se oscurece por completo debido a la luz nocturna.


                Escena de atenuador y luz nocturna de ejemplo con componentes Environment Probe (Sonda de entorno).

Para configurar las luces, las sondas de entorno y el script

  1. En Lumberyard Editor, haga lo siguiente:

    1. Cree una entidad denominada lamp.

    2. Añada el componente Point Light (Luz puntual) a la entidad.

    3. Para asignar un alto nivel de brillo, especifique los siguientes valores de propiedad:

      • Cast shadow spec (Arrojar valor especular de sombra): Low

      • Diffuse multiplier (Multiplicador de valor difuso): 4

      • Max Distance (Distancia máxima): 10

  2. Cree otra entidad denominada nightlight y haga lo siguiente:

    1. Añada el componente Point Light (Luz puntual) a la entidad.

    2. Para asignar un bajo nivel de brillo, especifique los siguientes valores de propiedad:

      • Cast shadow spec (Arrojar valor especular de sombra): Low

      • Diffuse multiplier (Multiplicador de valor difuso): 1

      • Max Distance (Distancia máxima): 10

  3. Cree dos sondas de entorno. Colóquelas en la misma ubicación y haga que sean del mismo tamaño. Llame a una probe_light y a la otra probe_dark.

    1. En probe_light, especifique la propiedad Sort Priority (Prioridad de clasificación) en 1. Esta es la sonda de entorno que aumenta de brillo y se desvanece.

    2. En probe_dark, mantenga el valor predeterminado de Sort Priority (Prioridad de clasificación). El valor debería ser 0.

  4. En el siguiente paso, tendrá que procesar la entidad probe_light. Procesar significa almacenar información sobre la iluminación en la sonda de entorno.

    Para procesar probe_light, haga lo siguiente:

    1. Seleccione la entidad probe_light.

    2. En el Entity Inspector, bajo Cubemap generation (Generación de mapeado cúbico), haga clic en Generate (Generar).

      Después de que se genere el mapeado cúbico, el botón Add Bounce (Añadir rebote) sustituye al botón Generate (Generar).

    3. Haga clic en Add Bounce (Añadir rebote) para volver a procesar la sonda con luz de rebote.

    4. Oculte la entidad probe_light. Con este método, se evita que la iluminación de la entidad probe_light se procese en la entidad probe_dark.

  5. Para procesar la entidad probe_dark, haga lo siguiente:

    1. Seleccione y oculte la entidad lamp. Con este método, se impide que la iluminación de la entidad lamp se procese en la entidad probe_dark.

    2. Seleccione la entidad probe_dark.

    3. En el Entity Inspector, bajo Cubemap generation (Generación de mapeado cúbico), haga clic en Generate (Generar).

      Después de que se genere el mapeado cúbico, el botón Add Bounce (Añadir rebote) sustituye al botón Generate (Generar).

    4. Haga clic en Add Bounce (Añadir rebote) para volver a procesar la sonda con luz de rebote.

  6. Muestre (deje de ocultar) las entidades probe_light y lamp.

  7. Cree una entidad y haga lo siguiente:

    1. Añada un componente Lua Script a la entidad.

    2. En el componente Lua Script, para la propiedad Script, haga clic en el icono (...) y luego busque y seleccione el archivo RoomLights.lua. Consulte RoomLights.lua.

    nota

    Para crear el archivo de script, copie y pegue el código en un archivo de texto. Cambie la extensión del archivo por .lua y guárdelo en el directorio del proyecto.

  8. En el componente Lua Script, para la propiedad LightEntity, haga clic en el icono de destino 
                            Target picker icon
                        y en la ventanilla, seleccione la entidad lamp. También puede utilizar Entity Outliner para seleccionar la entidad lamp.

    La entidad lamp aparece en el recuadro LightEntity.

  9. En el componente Lua Script, para la propiedad ProbeEntity, haga clic en el icono de destino 
                            Target picker icon
                        y en la ventanilla, seleccione la entidad probe_light.

    También puede utilizar Entity Outliner para seleccionar la entidad probe_light.

    El componente Lua Script debería ser similar al del siguiente ejemplo:

    
                        El componente Lua Script tiene LightEntity establecido en lamp y ProbeEntity establecido en probe_light.

ejemplo

Vea el siguiente script RoomLights.lua.

local RoomLights = { -- Defines properties that are exposed in the Entity Inspector window Properties = { Speed = 1.0, -- Use to modify the speed of the light cycle LightEntity = EntityId(), -- Set this to a Light component that will have its intensity changed ProbeEntity = EntityId(), -- Set this to an Environment Probe component that will be faded out in sync with the Light component } } function RoomLights:OnActivate() -- Subscribes to per-frame tick updates self.tickBusHandler = TickBus.Connect(self); -- Tracks the total number of seconds that the script has been running self.time = 0; -- The level at which the light starts is its max value. Light level is -- reduced periodically to dim the light, and then raised back to its max level. self.maxLightLevel = Light.Event.GetDiffuseMultiplier(self.Properties.LightEntity); end function RoomLights:OnDeactivate() self.tickBusHandler:Disconnect(); -- Restores entities to their default settings Light.Event.SetDiffuseMultiplier(self.Properties.LightEntity, self.maxLightLevel); Light.Event.SetProbeAttenuation(self.Properties.ProbeEntity, 1); end function RoomLights:OnTick(deltaTime, timePoint) self.time = self.time + deltaTime; -- Increases and decreases brightness between 0 and 1 as time passes local brightness = Math.LerpInverse(-1, 1, Math.Sin(self.time * self.Properties.Speed)); -- Sets the brightness of the light Light.Event.SetDiffuseMultiplier(self.Properties.LightEntity, brightness * self.maxLightLevel); -- Sets the fade value of the probe Light.Event.SetProbeFade(self.Properties.ProbeEntity, brightness); end return RoomLights

Ejemplo del ciclo día-noche

El siguiente escenario es un ejemplo más complejo, pero que se utiliza habitualmente, para desarrollar un ciclo completo de día-noche. Este ejemplo utiliza un concepto similar al del atenuador de Ejemplo de atenuador y luz nocturna, pero en lugar de cambiar la intensidad de la bombilla, se cambia la posición del sol. Esto requiere la combinación de un gran número de sondas. Además, el amanecer y el anochecer requieren más sondas de mediodía y medianoche. Consulte el siguiente procedimiento y esquema de script para comenzar.

Para configurar las sondas y el script del ciclo de día-noche

  1. Cree un conjunto de entidades para representar las horas. Colóquelas en la misma ubicación y haga que sean del mismo tamaño.

  2. Ponga un nombre a las entidades de modo que se correspondan con una hora del reloj (por ejemplo, probe1200 para representar el mediodía).

    Por ejemplo, empiece con 0000, 0550, 0600, 0610, 1200, 1750, 1800 y 1810. No necesita otra sonda a las 2400, ya que es la misma que 0000. Observe que hay más sondas agrupada en torno al amanecer y el anochecer que el mediodía y la medianoche.

    nota

    Puede poner el nombre que quiera a estas sondas, pero deben acabar con la designación de horas de 4 dígitos. El script que se aplica más adelante en este procedimiento buscará entidades que terminen con los cuatro dígitos correspondientes a la hora.

  3. Añada un componente Sonda de entorno a cada entidad.

  4. Oculte las sondas de forma que su resultado no se capte en la iluminación procesada de unas y otras.

  5. Para procesar cada sonda, haga lo siguiente:

    1. Seleccione una sonda de entorno. No es necesario mostrarla (dejar de ocultarla) durante el proceso.

    2. Abra el editor Time Of Day (Hora del día).

    3. Establezca Current Time (Hora actual) en la hora que se corresponda con el nombre de la sonda. Cierre el editor Time of Day (Hora del día).

    4. Con la sonda seleccionada, haga clic en Generate (Generar) para generar el mapeado cúbico.

    5. (Opcional) Para simular rebotes de luz adicionales, muestre (deje de ocultar) la sonda de entorno y, a continuación, haga clic en Add Bounce (Añadir rebote).

    6. Si no está oculta ya, oculte la sonda y luego repita estos pasos para la siguiente sonda.

  6. Después de establecer la hora del día y generar (procesar) el mapeado cúbico para cada sonda, cree otra entidad denominada probe_set.

  7. Seleccione y mueva las sondas a la entidad probe_set.

    
                        Mueva todas las sondas de entorno a la entidad principal, probe_set.
  8. En el Entity Outliner, haga lo siguiente:

    1. Seleccione la entidad probe_set.

    2. Añada un componente Lua Script a la entidad.

    3. En el componente Lua Script, para la propiedad Script, haga clic en (...) y luego busque y seleccione el archivo ProbeBlending.lua. Consulte ProbeBlending.lua.

    nota

    Para crear el archivo de script, copie y pegue el código en un archivo de texto. Cambie la extensión del archivo por .lua y guárdelo en el directorio del proyecto.

  9. En el componente Lua Script, para Probes (Sondas), haga clic en + hasta que el número de ranuras de EntityId sea igual al número de sondas que tiene.

    
                        Cree ranuras EntityID que coincidan con el número de sondas de entorno del componente Lua Script.
  10. Asigne cada una de las sondas a una de las ranuras de sonda de EntityId del script. En el Entity Inspector, haga clic en el icono de destino 
                            Target picker icon
                        junto a una ranura vacía. En el Entity Outliner, seleccione una sonda. Repita hasta que se rellenen todas las ranuras.

    En el siguiente ejemplo, se rellenan todas las ranuras vacías. Los recuadros EntityId están en blanco cuando aún no están seleccionados.

    
                        Componente Lua Script con todas las sondas seleccionadas.

ejemplo

Vea el siguiente script ProbeBlending.lua.

-- This script connects a set of probes to the time-of-day cycle and blends between them as time progresses. -- It supports an arbitrary number of probes. This means that you can use as many or as few as you need. -- A minimum of two environment probes are required. You likely need more to get convincing results, particularly around dawn and -- dusk when lighting conditions change dramatically. -- This script is provided as an example to help you get started. It is not an official feature, and is -- therefore not guaranteed to address every need or be completely free from defects. local ProbeBlending = { Properties = { Probes = { default = { EntityId(),EntityId() } }, -- Each probe entity's name must end in a 24-hour time code such as "envProbe1830" for a probe at 6:30pm ShowDebugOutput = false, -- If true, on every frame the script dumps the blend values for all probes to the console output Blend = true, -- If false, pops between probes rather than blending between them (mostly for demonstration purposes) UseToD = true, -- If true, progression is based on Time of Day (ToD). If false, an internal timer. Turning this off can be useful for testing purposes. CycleTime = 10 -- If UseToD = false, this is the number of seconds in one full cycle }, MAX_TIME = 24.0, ProbeData = {} -- Will be filled with entries {Probe=, Time=) sorted by time. Or nil if something went wrong. } -- Function for sorting probes by time function ProbeBlending.ProbeLessThan(a, b) return EntityId.IsValid(a.Probe) and EntityId.IsValid(b.Probe) and a.Time < b.Time or EntityId.IsValid(a.Probe) and not EntityId.IsValid(b.Probe); end -- Extracts a floating point 24-hour time value from a probe entity name. The last four characters of the probe -- name should be a 24 hour clock time value. For example, "1830" means "6:30pm" and returns a value of 18.5. -- Returns -1 if there is a problem function ProbeBlending.ExtractTimeValue(probeName) if probeName:len() < 4 then return -1; elseif probeName:len() == 4 and nil == probeName:sub(-4,-1):find("%d%d%d%d") then -- if only 4 characters, they must all be digits return -1 elseif probeName:len() > 4 and nil == probeName:sub(-5,-1):find("[^%d]%d%d%d%d") then -- the number of time code digits shall be 4, no more, no less return -1 else local hour = probeName:sub(-4,-3); local minutes = probeName:sub(-2,-1); return tonumber(hour) + tonumber(minutes)/60.0; end end -- This function is called upon activation to prepare self.ProbeData for processing function ProbeBlending:ValidateAndSortProbeData() self.ProbeData = nil; if(#self.Properties.Probes < 2) then Debug.Error(false, "Script requires at least 2 Probes"); return; end if(self.Properties.CycleTime <= 0 and not self.Properties.UseToD) then Debug.Error(false, "CycleTime must be > 0"); return; end -- Copies the probe data into a different table where it can be easily sorted. local probeDataTable = {}; for i=0,#self.Properties.Probes,1 do local probe = self.Properties.Probes[i]; if(EntityId.IsValid(probe)) then local currentProbeName = GameEntityContextRequestBus.Broadcast.GetEntityName(probe); local probeTime = ProbeBlending.ExtractTimeValue(currentProbeName); if(probeTime < 0) then Debug.Error(false, "Probe Entity name '" .. currentProbeName .. "' does not end with a four-digit timecode"); return; end probeDataTable[i] = {Probe=probe, Time=probeTime}; end end -- Sorts the probes according to their time codes table.sort(probeDataTable, ProbeBlending.ProbeLessThan); -- Further validates the data for i=1,#probeDataTable,1 do local currentProbe = probeDataTable[i].Probe; local currentProbeTime = probeDataTable[i].Time; if(currentProbeTime < 0 or currentProbeTime > self.MAX_TIME) then Debug.Error(false, "Probe time is out of range [0," .. self.MAX_TIME .. "]"); return; end if(i > 1) then local prevProbe = probeDataTable[i-1].Probe; local prevProbeTime = probeDataTable[i-1].Time; if(prevProbeTime >= currentProbeTime) then Debug.Error(false, "Time values must increase"); return; end end end -- Saves data after it has been validated self.ProbeData = probeDataTable; end function ProbeBlending:OnActivate() -- Subscribes to per-frame tick updates self.tickBusHandler = TickBus.Connect(self); self:ValidateAndSortProbeData(); self.time = 0; end function ProbeBlending:OnDeactivate() self.tickBusHandler:Disconnect(); end -- Per-frame updates are processed here function ProbeBlending:OnTick(deltaTime, timePoint) local numProbes = #self.ProbeData; if(numProbes < 2) then return end local currentTime = 0; -- Updates currentTime if(self.Properties.UseToD) then currentTime = TimeOfDay.GetTime(); else local rate = 1.0 / self.Properties.CycleTime; self.time = self.time + deltaTime * rate; currentTime = (self.time % 1.0) * self.MAX_TIME; end -- Finds pair of probes that surround currentTime local probeIndexA = -1; local probeIndexB = -1; for i=1,numProbes,1 do local currentProbe = self.ProbeData[i].Probe; local currentProbeTime = self.ProbeData[i].Time; if(currentTime < currentProbeTime) then probeIndexB = i; if i == 1 then probeIndexA = numProbes; else probeIndexA = probeIndexB-1; end break; end end if(self.ProbeData[numProbes].Time <= currentTime) then probeIndexA = numProbes; probeIndexB = 1; end -- This first sets all attenuation values to 0 before blending in the relevant two. for i=1,numProbes,1 do Light.Event.SetProbeFade(self.ProbeData[i].Probe, 0); end -- Calculates the blend between the two bordering probes, such that the final color should be something like -- probeA * (1-blend) + probeB * blend local blend = 1.0; if(probeIndexA < probeIndexB) then blend = Math.LerpInverse(self.ProbeData[probeIndexA].Time, self.ProbeData[probeIndexB].Time, currentTime); elseif(probeIndexB < probeIndexA) then local passedTime = 0; timeBetweenProbes = self.ProbeData[probeIndexB].Time + (self.MAX_TIME - self.ProbeData[probeIndexA].Time); if(0 <= currentTime and currentTime <= self.ProbeData[probeIndexB].Time) then passedTime = currentTime + (self.MAX_TIME - self.ProbeData[probeIndexA].Time); else passedTime = currentTime - self.ProbeData[probeIndexA].Time; end blend = passedTime / timeBetweenProbes; end -- Applies the blend by setting probe fades for the two relevant probes if(self.Properties.Blend) then local priorityA = Light.Event.GetProbeSortPriority(self.ProbeData[probeIndexA].Probe); local priorityB = Light.Event.GetProbeSortPriority(self.ProbeData[probeIndexB].Probe); if(priorityA == priorityB) then -- Time-adjacent probes must have different priorities in order to know which one to fade out. We'll force one to be higher Light.Event.SetProbeSortPriority(self.ProbeData[probeIndexB].Probe, priorityB+1); end if (priorityA > priorityB) then Light.Event.SetProbeFade(self.ProbeData[probeIndexA].Probe, 1-blend); Light.Event.SetProbeFade(self.ProbeData[probeIndexB].Probe, 1); else Light.Event.SetProbeFade(self.ProbeData[probeIndexA].Probe, 1); Light.Event.SetProbeFade(self.ProbeData[probeIndexB].Probe, blend); end else Light.Event.SetProbeFade(self.ProbeData[probeIndexA].Probe, 1); Light.Event.SetProbeFade(self.ProbeData[probeIndexB].Probe, 0); end -- Generates debug output if self.Properties.ShowDebugOutput then local debugInfo = "Fades> "; for i=1,numProbes,1 do local currentProbe = self.ProbeData[i].Probe; local blendFactor = Light.Event.GetProbeFade(currentProbe); local currentProbeName = GameEntityContextRequestBus.Broadcast.GetEntityName(currentProbe); debugInfo = debugInfo .. string.format("%s: %.2f | ", currentProbeName, blendFactor) end Debug.Log(debugInfo); end end return ProbeBlending