/// <summary>
        /// Sets a custom texture as input for an observation,
        /// replacing an agent camera.
        /// (Multiple agents can use the same texture ID. In that case,
        /// the corresponding textures are expected to be the same size.)
        /// Optionally matches the corresponding observation size to the
        /// texture size.
        /// </summary>
        /// <param name="agent">Agent.</param>
        /// <param name="id">Texture ID, must match inspector value.</param>
        /// <param name="texture">Texture2D.</param>
        /// <param name="autoSizeObservation">Defaults to false.</param>
        /// <returns>Dictionary length.</returns>
        public int SetCustomTexture(Agent agent,
                                    string id,
                                    Texture2D texture,
                                    bool autoSizeObservation = false)
        {
            if (HasObservations())
            {
                int i = 0;
                for (; i < observations.Length; i++)
                {
                    if (observations[i].textureID == id)
                    {
                        break;
                    }
                }
                if (i == observations.Length)
                {
                    throw new UnityAgentsException(string.Format(
                                                       "Texture ID {0} not found in observations.", id));
                }

                if (autoSizeObservation)
                {
                    observations[i].width  = texture.width;
                    observations[i].height = texture.height;

                    UpdateResolutions();

                    TextureHelper[] texHelpers = GetAgentTextureHelpers(agent);
                    texHelpers[i].CreateBuffer(observations[i]);
                }

                string key = id + agent.GetInstanceID();
                customTextures.Add(key, texture);
                return(customTextures.Count);
            }
            else
            {
                throw new UnityAgentsException(string.Format(
                                                   "Brain {0} has no visual observations.",
                                                   GetComponent <Brain>().gameObject.name));
            }
        }
        /// <summary>
        /// Called from Agent's SendInfoToBrain method.
        /// Populates the agent's info.visualObservations list with textures
        /// from the agent cameras, the camera buffers and optional custom
        /// textures, based on the Observation settings.
        /// </summary>
        /// <param name="agent">Agent.</param>
        /// <param name="agentVisualObservations">
        /// The agent's info.visualObservations list.</param>
        public void ApplyObservations(Agent agent,
                                      List <Texture2D> agentVisualObservations)
        {
            if (HasObservations())
            {
                Camera[] cameras = agent.agentParameters.agentCameras.ToArray();
                if (numCameras > cameras.Length)
                {
                    throw new UnityAgentsException(string.Format(
                                                       "Not enough cameras for agent {0}: Brain {1} expects at"
                                                       + " least {2} cameras but only {3} are present.",
                                                       agent.gameObject.name, agent.brain.gameObject.name,
                                                       numCameras, cameras.Length));
                }

                TextureHelper[] texHelpers = GetAgentTextureHelpers(agent);
                // Assuming agent's camera order matches observations order
                // in inspector.
                int camIndex = 0;
                for (int i = 0, n = observations.Length; i < n; i++)
                {
                    if (string.IsNullOrEmpty(observations[i].textureID))
                    {
                        Agent.ObservationToTexture(cameras[camIndex++],
                                                   observations[i].width,
                                                   observations[i].height,
                                                   ref texHelpers[i].input);
                    }
                    else
                    {
                        Texture2D tmp;
                        string    key = observations[i].textureID
                                        + agent.GetInstanceID();

                        if (customTextures.TryGetValue(key, out tmp))
                        {
                            if (tmp.width != observations[i].width ||
                                tmp.height != observations[i].height)
                            {
                                throw new UnityAgentsException(string.Format(
                                                                   "Custom texture size {0} x {1} does not match "
                                                                   + " observation size {2} x {3}.",
                                                                   tmp.width, tmp.height,
                                                                   observations[i].width, observations[i].height));
                            }

                            TextureHelper.CopyTexture(tmp, texHelpers[i].input);
                        }
                        else
                        {
                            throw new UnityAgentsException(string.Format(
                                                               "Custom texture {0} not found for agent {1}.",
                                                               observations[i].textureID,
                                                               agent.gameObject.name));
                        }
                    }

                    texHelpers[i].ApplyBuffer(observations[i],
                                              agentVisualObservations);
                }
            }
        }