The following breakdown is based on my own guesses and how I understand the game from the textures and meshes I have watched. I can't tell you exactly if I'm right or wrong since I'm not a developer of the game. However, I believe I'm rational enough to think that most of what I say is close to what the developers have done. The purpose of this breakdown is educational and the work presented here belongs to its respective authors.
The Anvil Engine is a proprietary game engine used by Ubisoft's game projects for a few years now (the first game using it came out in 2007). We can call the Anvil Engine a next-gen engine since games for the previous console generation (like the Playstation 2) were using the Jade Engine at Ubisoft. The first project using this engine was the first Assassin's Creed game. Its initial engine name was Scimitar (before the release of the first game). Today, eight games are using this engine.
The engine has since been updated with Assassin's creed III under the name 'AnvilNext'. Mostly to support the new game challenges and configurations that we have today and probably to be ready with the future game consoles coming along.
As with every open world and/or huge city, you have to deal with a very high number of resources. Mostly to keep the player in a fresh world and avoid repetitions. Games over the years have used various techniques to get past this problem. One of them is to reuse any resources that you have created. Creating a texture for only one object in this type of environment can be a problem in term of memory footprint. So reusing a texture will allow you to keep you memory low in size. Pretty obvious, however it's a hard balance that you have to deal with: diversity versus quantity.
The size of the memory is not the only problem that you will meet; the number of drawcalls is also very important. As a reminder, a drawcall is a call to the API (the functions of the GPU to draw a set of primitives). For each frame that you render, you have a certain number of drawcalls. Each time you call the API to draw something it takes a given time, regardless of what you want to draw. So you want to be sure to reduce these calls to avoid any loss of performance (taking too much time to draw a frame will reduce your number of frames per second).
Each time you change a mesh for a new one you will create a new drawcall, because for the engine it's not the same geometry. This rule applies for the shaders too. If you change the shader, you don't render the same thing, so you have to change the way you render it. This means a new API call.
A common solution to this is to batch your calls. 'Batching' means to group some meshes together before calling the API to draw them. This is why it takes less time to render a big mesh than multiple small meshes. How to batch these meshes if chosen by the engine, there is no best rule for this and it depends a lot of what you want to draw. In the case of the Anvil engine, you are focused on drawing large and open spaces. The best way to improve the performance in this case is probably to batch per shader. So each geometry using the same shader will be sent together to be rendered. This way, reusing textures will allow you to batch a lot of things and gain a lot of time.
Since we evolve in cities, some houses are often similar, it is logical to find the same design multiple times. Which means that reusing a texture would not shock the player. It will even help for the visual consistency of the level. However, I believe that the engine was not perfect and due to some performance problems (maybe because of the dynamic lighting) they limited the number of textures. In Venice for example, you have an average of 1500/2000 textures in memory (including everything: sky, water, normal maps, shadows, characters and so on).
What do the textures look like exactly? In this game, textures for the walls are often around 512 x 512 pixels. Details, ornaments, water use 256 x 256 pixels most of the time. For example, the roof texture is only 256 x 256, but the tilling is so well made that it doesn't gene at all.
However, these textures being very tiny, the developers used vertex painting to blend details and break the repetition. Since there are almost no specular reflections in the game (probably to strengthen the feeling of the walls are made of bricks and dirt) the vertex painting masks are stored in the alpha channel of the diffuse texture. As you can see in the second screenshot below, the alpha mask uses very defined greyscales, probably because they separate each level of grey as a separate filter.
The textures are very bright, and we feel that in-game: the overall lighting is itself very luminous.
Dealing with an open world means dealing with a very long view distance. Therefore, the farther you see, the more you need to draw. Unfortunately you are limited by the hardware (especially on consoles) and you will have to use some LODs (level of detail). The developers have chosen to let the LODs 'pop'; this means no blending transitions between them, which is visually ugly since you notice the change.
The environment collisions are dissociated from the visuals mesh. Probably because you can more quickly hide/disable the collisions of the environment since they are not visually displayed on the screen. This explains why forcing the LODs of the environment allows you to... climb the void!
On the PC version, you can increase the minimum distance for when the environment starts to blend (which is something like 40/50 meters if you blend at the furthest possible distance). It's also interesting to note that some props like barrels, crates and other little things are independent of the global LOD distance. It seems that some props are linked to the LOD of the building mostly because they are at the roof level, while props in the street have their own blend distance.
Pedestrians in Assassin's Creed are based on modular characters. The developers use a set of heads which are combined with hands and different clothes. While the hand and heads have their own details and colours, the clothes are just a totally grey shared texture (except for the letter) and coloured in the shader to add variety in the game. They also add a detail texture to break the linearity of the clothes and bring up some fine details. Characters have also their own LODs.
During a presentation at GDC 2008 about the first Assassin's Creed, Francois Levesque (a technical director on the game) explained their pipeline to produce a lot of different characters without losing too much time. They used a base head which blends to fit to the high-res character. This way they automatically get the LOD mesh at the same time since the meshes always shared the same topology. The only update to do was for the position of the bones on the top of the vertex to keep their skin deformation.
Since meshes and UVs are similar, it's easier to manage and create a crowd dynamically. So there are maybe 5–10 different clothes and then the game dynamically creates a character to add it in the game scene. In the first Assassin's Creed, characters had 2 LODs, which meant 3 meshes per character. In Assassin's Creed II it's the same thing. However it seems that the clothes and the head don't blend at the same time. Probably because they don't have the same space occupied on the screen. So the heads go to their first LOD mesh sooner.
You can see some examples on zBrushCentral with the base mesh topology and also the topology of some bodies used by the game.
The Anvil engine is an engine developed to mostly show open environments. With the development on this second opus, they wanted to add a day-and-night cycle. To achieve this they naturally chose the cascaded shadow maps technique (more exactly, Parallel-Split Shadow Maps as described in a GameDev.net forum thread) which even today is the best way to draw a unified shadow on such big environments.
There is no Global illumination at all, it's mostly only a main directional light (the Sun) combined with an ambient colour which evolves during the day. Some interiors like the tombs present localised point lights; there are also some point lights which are enabled during the night.
However, regarding the performance, they were obliged to use a very low resolution and a blend distance. This explains why you see a lot of blurred pixels on the ground/walls for the shadow. This is also why you so clearly see the blending of the shadow from one level to another.
Some shaders use the Fresnel term to enhance the looking of the character clothes a bit, but most of the time they simply use direct lighting without complex shaders (again, because it was very expensive). There is no fake sub-surface scattering (SSS) for the characters, even during the cinematics. The SSS only comes in with Assassin's Creed: Revelations and will be improved for Assassin's Creed III.
Assassin's Creed II was a really good improvement compared to the first game, however it looks like the engine faced a lot of new constraints which were not totally well handled. The way the LODs appear and the nice but still limited quality of the lighting are good examples of that. Even on modern computers today the game gets some slow-down in certain places.
The engine was improved for the next game iterations and increased the amount of details and the quality of its lighting to finally show beautiful cities as we can see in Assassin's Creed III today.