Recomendo que você leia a documentação oficial detalhada do Angular para escopos. Comece na seção 'Hierarquias de escopo':
https://docs.angularjs.org/guide/scope
Essencialmente, $ rootScope e $ scope identificam partes específicas do DOM dentro das quais
- Operações angulares são realizadas
- variáveis declaradas como parte de $ rootScope ou $ scope estão disponíveis
Qualquer coisa que pertença ao $ rootScope está disponível globalmente em seu aplicativo Angular, enquanto qualquer coisa que pertença a um $ escopo está disponível na parte do DOM à qual esse escopo se aplica.
O $ rootScope é aplicado ao elemento DOM que é o elemento raiz do aplicativo Angular (daí o nome $ rootScope). Quando você adiciona a diretiva ng-app a um elemento do DOM, ele se torna o elemento raiz do DOM dentro do qual $ rootScope está disponível. Em outras palavras, propriedades etc. de $ rootScope estarão disponíveis em todo o seu aplicativo Angular.
Um escopo $ Angular (e todas as suas variáveis e operações) está disponível para um subconjunto específico do DOM em seu aplicativo. Especificamente, o escopo $ para qualquer controlador específico está disponível para a parte do DOM ao qual esse controlador específico foi aplicado (usando a diretiva ng-controller). Observe, porém, que certas diretivas, por exemplo, ng-repeat, quando aplicadas dentro de uma parte do DOM onde o controlador foi aplicado, podem criar escopos filho do escopo principal - dentro do mesmo controlador - um controlador não contém necessariamente apenas um escopo.
Se você olhar o HTML gerado ao executar seu aplicativo Angular, poderá ver facilmente quais elementos DOM 'contêm' um escopo, pois o Angular adiciona a classe ng-scope em qualquer elemento ao qual um escopo foi aplicado (incluindo o elemento raiz do aplicativo, que tem o $ rootScope).
A propósito, o sinal '$' no início de $ scope e $ rootScope é simplesmente um identificador no Angular para coisas reservadas pelo Angular.
Observe que usar $ rootScope para compartilhar variáveis etc. entre módulos e controladores geralmente não é considerado a melhor prática. Os desenvolvedores de JavaScript falam sobre como evitar a 'poluição' do escopo global compartilhando variáveis lá, uma vez que pode haver conflitos mais tarde se uma variável com o mesmo nome for usada em outro lugar, sem que o desenvolvedor perceba que ela já está declarada no $ rootScope. A importância disso aumenta com o tamanho do aplicativo e com a equipe que o está desenvolvendo. O ideal é que $ rootScope conterá apenas constantes ou variáveis estáticas, que devem ser consistentes o tempo todo no aplicativo. Uma maneira melhor de compartilhar coisas entre os módulos pode ser usar serviços e fábricas, que é outro tópico!