Join 3 tables with where and sorting clauses
Still room for improvement. This is your last version, untangled, formatted and shortened with table aliases:

SELECT vm.id, v.name, vm.name, count(c.id) AS count 
FROM   vendors       v
JOIN   vendor_models vm ON vm.vendor_id = v.id 
JOIN   cameras       c  ON c.model_id = vm.id
GROUP  BY vm.id, v.name, vm.name
ORDER  BY v.name;


Remaining problems:


You have the name name twice in the result, which is unhelpful to say the least.
(A shining example why non-descriptive names like "name" are bad names.)
Sort order not fully deterministic.
Not as fast as it could be.


I suggest:

SELECT vm.id
     , v.name AS vendor, vm.name AS model  -- column aliases to disambiguate
     , c.camera_count
FROM   vendors       v
JOIN   vendor_models vm ON vm.vendor_id = v.id 
JOIN  (
   SELECT model_id, count(*) AS camera_count  -- count(*) slightly faster
   FROM   cameras
   GROUP  BY 1           -- aggregate first, join later
   ) c ON c.model_id = vm.id
ORDER  BY v.name, vm.name, vm.id; -- add "id" if the names are not unique


If you count cameras per model first, you have far fewer join operations and don't have to aggregate outer columns at all. Should be faster.

count(*) is a bit faster than count(expression) (separate implementation) while doing the same in the absence of NULL values.

Since columns from the outer tables (vendors, vendor_models) are not aggregated at all now, you can put any of these columns in the SELECT list at will - including vm.*.

Related:


Understanding multiple table join with aggregation
Slow queries related to subqueries using aggregation