PDA

View Full Version : Accessing multiple Materials and Textures in the FragmentShader



john_connor
05-12-2016, 04:01 PM
Hi, i'm trying to render many different meshes (created from .obj files) with a single shader program.
Until i decided to NOT using a draw call per material, it went pretty well. Now, i want to render a mesh which uses some different materials / textures. To decide which Material should be used per vertex i've setup a vertex attribute called "int materialID" = index of the material to use in the material array, specified & filled with data in the fragment shader.

That works well.


PROBLEM:

i cant access the correct textures which are used by some materials ...
because there's only a limited amount of textures (= 16) which i can acces in 1 shader stage, i decided to
give every material indices to the textures only IF they need any texture, if not they get a -1 (= which means not allowed to access any texture).

here's the material struct (fragment shader):

struct Material
{
vec3 Ambient;
vec3 Diffuse;
vec3 Specular;
float Shininess;
float Alpha;

// test
int textureindex_Ka;
int textureindex_Kd;
int textureindex_Ks;
int textureindex_Ns;
int textureindex_bump;
int textureindex_d;
};

now, every material "knows" what sampler2D to access:

uniform sampler2D textures[MAX_TEXTURES];


but ... it doesnt work. i assume that "int"s are not allowed in the fragment shader
so i tried to declare them "flat int textureindex_Ka", that also doesnt work (application crashes)
whats the "best" solution to use multiple textures within 1 draw call (glDrawArraysInstanced(...)) ??
would it be possible to pass those texture indices (or the whole used material) from the vertexshader to the fragmentshader ??


here are the complete shader sources:

Vertex Shader


#version 450

#define MAX_MODELS_COUNT 1000


layout (location = 0) in vec3 in_position;
layout (location = 1) in vec2 in_texcoords;
layout (location = 2) in vec3 in_normal;
layout (location = 3) in int in_materialID;


layout (packed, column_major) uniform Uniforms_Models
{
mat4 View;
mat4 Projection;
mat4 Models[MAX_MODELS_COUNT];
int ObjectIDs[MAX_MODELS_COUNT];
};


out VS_OUT
{
vec3 position;
vec2 texcoords;
vec3 normal;
vec4 objectidcolor;
flat int materialID;
} vs_out;


vec4 IntegerToColor(int i)
{
int r = (i & 0x000000FF) >> 0;
int g = (i & 0x0000FF00) >> 8;
int b = (i & 0x00FF0000) >> 16;
int a = (i & 0xFF000000) >> 24;
return vec4(r / 255.0, g / 255.0, b / 255.0, a / 255.0);
}


void main(void)
{
mat4 MVP = Projection * View * Models[gl_InstanceID];
gl_Position = MVP * vec4(in_position, 1);

vs_out.position = (Models[gl_InstanceID] * vec4(in_position, 1)).xyz;
vs_out.texcoords = in_texcoords;
vs_out.normal = (Models[gl_InstanceID] * vec4(in_normal, 0)).xyz;
vs_out.objectidcolor = IntegerToColor(ObjectIDs[gl_InstanceID]);
//vs_out.materialID = in_materialID;
vs_out.materialID = 0;
}




Fragment Shader:


#version 450

#define MAX_MODELS_COUNT 1000
#define GRAPHICS_MAX_LIGHTS 5


in VS_OUT
{
vec3 position;
vec2 texcoords;
vec3 normal;
vec4 objectidcolor;
flat int materialID;
} vs_out;


struct Material
{
vec3 Ambient;
vec3 Diffuse;
vec3 Specular;
float Shininess;
float Alpha;

// test
int textureindex_Ka;
int textureindex_Kd;
int textureindex_Ks;
int textureindex_Ns;
int textureindex_bump;
int textureindex_d;
};


struct Light
{
vec3 Position;
vec3 Ambient;
vec3 Diffuse;
vec3 Specular;
};


// ................................
#define MAX_MATERIALS 10
#define MAX_TEXTURES 16

uniform vec3 CameraPosition;
uniform Light light;
uniform Material materials[MAX_MATERIALS];

uniform sampler2D textures[MAX_TEXTURES];
// ambient
// diffuse
// specular
// shininess
// bump ...... HOW TO USE ???
// alpha
// ................................




layout (location = 0) out vec4 FragmentColor0;
layout (location = 1) out vec4 FragmentColor1;


void main(void)
{
// texture indices
int textureindex_Ka = materials[vs_out.materialID].textureindex_Ka;
int textureindex_Kd = materials[vs_out.materialID].textureindex_Kd;
int textureindex_Ks = materials[vs_out.materialID].textureindex_Ks;
int textureindex_Ns = materials[vs_out.materialID].textureindex_Ns;
int textureindex_bump = materials[vs_out.materialID].textureindex_bump;
int textureindex_d = materials[vs_out.materialID].textureindex_d;


vec3 SurfaceNormal = normalize(vs_out.normal);
vec3 LightToSurface = normalize(vs_out.position - light.Position);
vec3 EyeToSurface = normalize(vs_out.position - CameraPosition);
vec3 ReflectedDirection = reflect(-LightToSurface, SurfaceNormal);
float DiffuseFactor = max(0, dot(-LightToSurface, SurfaceNormal));
float SpecularFactor = pow(max(0, dot(EyeToSurface, ReflectedDirection)), materials[vs_out.materialID].Shininess);
//if (textureindex_Ns != -1)
// SpecularFactor = texture(textures[textureindex_Ns], vs_out.texcoords).r;

// read material data
vec3 MaterialAmbient = materials[vs_out.materialID].Ambient;
vec3 MaterialDiffuse = materials[vs_out.materialID].Diffuse;
vec3 MaterialSpecular = materials[vs_out.materialID].Specular;

// use textures if present ...
if (textureindex_Ka != -1)
MaterialAmbient = texture(textures[textureindex_Ka], vs_out.texcoords).rgb;
if (textureindex_Kd != -1)
MaterialDiffuse = texture(textures[textureindex_Kd], vs_out.texcoords).rgb;
if (textureindex_Ks != -1)
MaterialSpecular = texture(textures[textureindex_Ks], vs_out.texcoords).rgb;

vec3 Ambient = light.Ambient * MaterialAmbient;
vec3 Diffuse = light.Diffuse * DiffuseFactor * MaterialDiffuse;
vec3 Specular = light.Specular * SpecularFactor * MaterialSpecular;

// resulting color ...
vec3 Color = Ambient + Diffuse + Specular;

// resulting transparency ... 0 = transparent, 1 = opaque ...
float alpha = materials[vs_out.materialID].Alpha;
if (textureindex_d != -1)
alpha = texture(textures[textureindex_d], vs_out.texcoords).r;
// make sure that transparency doesnt make the fragment invisible
if (alpha < 0.2f)
alpha = 0.2f;

// draw object into color attachment 0 and its ID in color attachment 1 ...
FragmentColor0 = vec4(Color, alpha);
FragmentColor1 = vs_out.objectidcolor;
}

GClements
05-12-2016, 06:01 PM
Arrays of samplers are allowed, so long as the index expression is dynamically uniform (in the fragment shader, that means that it's constant for all fragments within a given triangle, but can vary between triangles).

The other option is to use array textures. This is more restrictive in that each layer must have the same format and dimensions, and sampling parameters (filter/wrap modes, etc) apply to the entire texture rather than to a layer, but the layer index doesn't need to be dynamically uniform (it can vary between fragments).

Saying that it "doesn't work" doesn't tell us much. Do you get any warnings from compilation or linking? Does glGetError() report any errors?

john_connor
05-13-2016, 05:41 AM
Arrays of samplers are allowed, so long as the index expression is dynamically uniform (in the fragment shader, that means that it's constant for all fragments within a given triangle, but can vary between triangles).
The other option is to use array textures. This is more restrictive in that each layer must have the same format and dimensions, and sampling parameters (filter/wrap modes, etc) apply to the entire texture rather than to a layer, but the layer index doesn't need to be dynamically uniform (it can vary between fragments).

ok that means i'm on a wrong way ... so i'll try to use 3D texture samplers this time, thx 4 your help!



Saying that it "doesn't work" doesn't tell us much. Do you get any warnings from compilation or linking? Does glGetError() report any errors?

i've checked now the compilation log directly after shader compilation, it says:


0(71) : error C7561: OpenGL requires 'in/out' with 'flat'

nevermind ^^