2
votes

I am using GLSL shaders in a small Java OpenGL project I am making, and I am trying to come up with a well-written object-oriented way of organising my code. So far, I have a class called Model, which can contain multiple meshes, each of which has its own texture and material (a material being a set of parameters to describe ambient, diffuse, specular, blending, etc.). In order to achieve this, I understand that I could pass uniform variables to the shader every time I need to change material. However, the drawing takes place in the model's draw() method. Does that mean that each instance of the Model class needs to have a particular shader associated with it?

Also, I have a Camera class, which produces a matrix that will transform vertices simulate the camera's pitch, yaw, and position. This matrix then needs to uploaded to the shader as the view matrix. Doesn't that mean that I need to upload this matrix to every shader that I use? So if each Model can have its own shader, how can I upload the camera's view matrix to all of them? And even so, isn't it inefficient for every single model to have its own shader? If you wanted to draw a certain model lots of times, then you would be use()ing the shader and uploading a matrix to the shader every time you drew it.

I'm really struggling to come up with an object-oriented solution that links multiple shaders, multiple objects and multiple materials. Any help is appreciated.

2

2 Answers

2
votes

Modern OpenGL requires you to write vert/frag shaders in order to render anything, so it would be a safe bet to have the Material stored with the Model object. You could perhaps have a Default Material if none was linked with a model object - kind of like missing textures or models.

Rendering engine architecture is a big concept in general and I don't fully understand some things myself, but so far I quite like how THREE.js went about it structuring it. Of course it's made in javascript, but the ideas are quite translatable to other languages. You should look into it.

scene = new THREE.Scene();

camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 1, 10000 );
camera.position.z = 1000;

geometry = new THREE.BoxGeometry( 200, 200, 200 );
material = new THREE.MeshBasicMaterial( { color: 0xff0000, wireframe: true } );

mesh = new THREE.Mesh( geometry, material );
scene.add( mesh );

renderer = new THREE.CanvasRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
2
votes

To answer your second question, yes you need to be able to access Camera's view matrix for every shader you use. You probably need to make it accessible to whatever object does the rendering.

Each Model can have its own shader, but since shader changes are among the most costly state-switching operations, many engines batch rendering by shader. So (hopefully) you don't have too many different shaders in use.