Thanks again all, I think I'm starting to get it now.
I think the heart of my problem is that I'm not encapsulating the details of the renderer, so for example my Terrain class doesn't have a simple Material and Geometry but instead has much lower level information, such as:
// The Vertex and Index Buffers describing a tile ID3D11Buffer* m_TerrainVB; ID3D11Buffer* m_TerrainIB; ID3D11Buffer* m_SeaVB; ID3D11Buffer* m_SeaIB; ID3D11Buffer* m_BoxVB; ID3D11Buffer* m_BoxIB; ID3D11VertexShader* m_TerrainVS; ID3D11PixelShader* m_TerrainPS; ID3D11VertexShader* m_SeaVS; ID3D11PixelShader* m_SeaPS; ID3D11VertexShader* m_BoxVS; ID3D11PixelShader* m_BoxPS; // The input layout for terrain vertices ID3D11InputLayout* m_TerrainInputLayout; ID3D11InputLayout* m_SeaInputLayout; // Constant Buffers ID3D11Buffer* m_PerFrameCB; // Per frame constant buffer ID3D11Buffer* m_TerrainObjectCB; // Per object constant buffer
I guess I need to better encapsulate these, so that I just have higher level Material and Geometry classes, and then I can use the above advice to just send the Material and Geometry to the renderer.
It's all starting to make sense, and should help to simplify and tidy up the code too (I hate messy code, so I've not been happy with this for a while now).