I'm using the tutorials on http://arcsynthesis.org/gltut/ to learn OpenGL, it's required, I have to use it. Mostly I want to apply the textures from Tutorial 15 onto objects in tutorial 7 (world with UBO).
For now it seemed like the textures only work when mipmaps are turned on. This comes with a downside: The only mipmap used is the one with an index of zero, and that's the 1 colored 1x1 pixel one. I tried setting the minimum level of a mipmap higher or turning off mipmaps entirely, but even that doesn't fix thing, because then everything turns pitch black. Now I'll list the most important parts of my program
EDIT: I guess I'll add more details...
The vertex shader has something like this:
#version 330
layout(location = 0) in vec4 position;
layout(location = 1) in vec4 color;
layout(location = 2) in vec3 normal;
//Added these later
layout(location = 5) in vec2 texCoord;
out vec2 colorCoord;
smooth out vec4 interpColor;
out vec3 vertexNormal;
out vec3 modelSpacePosition;
out vec3 cameraSpacePosition;
uniform mat4 worldToCameraMatrix;
uniform mat4 modelToWorldMatrix;
uniform mat3 normalModelToCameraMatrix;
uniform vec3 dirToLight;
uniform vec4 lightIntensity;
uniform vec4 ambientIntensity;
uniform vec4 baseColor;
uniform mat4 cameraToClipMatrix;
void main()
{
vertexNormal = normal;
vec3 normCamSpace = normalize(normalModelToCameraMatrix * vertexNormal);
cameraSpacePosition = normCamSpace;
float cosAngIncidence = dot(normCamSpace, dirToLight);
cosAngIncidence = clamp(cosAngIncidence, 0, 1);
modelSpacePosition.x = position.x;
modelSpacePosition.y = position.y;
modelSpacePosition.z = position.z;
vec4 temp = modelToWorldMatrix * position;
temp = worldToCameraMatrix * temp;
gl_Position = cameraToClipMatrix * temp;
interpColor = ((lightIntensity * cosAngIncidence) + (ambientIntensity)) * baseColor;
colorCoord= texCoord ;
}
The fragment shader like this:
#version 330
in vec3 vertexNormal;
in vec3 modelSpacePosition;
smooth in vec4 interpColor;
uniform vec3 modelSpaceLightPos;
uniform vec4 lightIntensity2;
uniform vec4 ambientIntensity2;
out vec4 outputColor;
//Added later
in vec2 colorCoord;
uniform sampler2D colorTexture;
void main()
{
vec3 lightDir2 = normalize(modelSpacePosition - modelSpaceLightPos);
float cosAngIncidence2 = dot(normalize(vertexNormal), lightDir2);
cosAngIncidence2 = clamp(cosAngIncidence2, 0, 1);
float light2DistanceSqr = dot(modelSpacePosition - modelSpaceLightPos, modelSpacePosition - modelSpaceLightPos);
//added
vec4 texture2 = texture(colorTexture, colorCoord);
outputColor = ((ambientIntensity2 + (interpColor*2))/4) +
((((interpColor) * lightIntensity2/200 * cosAngIncidence2) + (ambientIntensity2* interpColor ))
/( ( sqrt(light2DistanceSqr) + light2DistanceSqr)/200 ));
//No outputColor for texture testing
outputColor = texture2 ;
}
}
Those were both shaders. And here are the parts added to the .cpp:
#include <glimg/glimg.h>
#include "../framework/directories.h"
[...]
const int g_colorTexUnit = 0;
GLuint g_checkerTexture = 0;
And here's the loader for the texture:
void LoadCheckerTexture()
{
try
{
std::string filename(LOCAL_FILE_DIR);
filename += "checker.dds";
std::auto_ptr<glimg::ImageSet>
pImageSet(glimg::loaders::dds::LoadFromFile(filename.c_str()));
glGenTextures(1, &g_checkerTexture);
glBindTexture(GL_TEXTURE_2D, g_checkerTexture);
glimg::SingleImage image = pImageSet->GetImage(0, 0, 0);
glimg::Dimensions dims = image.GetDimensions();
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, dims.width, dims.height, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, image.GetImageData());
glBindTexture(GL_TEXTURE_2D, 0);
}
catch(std::exception &e)
{
printf("%s\n", e.what());
throw;
}
}
Naturally I've got this in void init():
LoadCheckerTexture();
And then when rendering the object:
glActiveTexture(GL_TEXTURE0 + g_colorTexUnit);
glBindTexture(GL_TEXTURE_2D,g_checkerTexture);
g_pLeftMesh->Render();
glBindSampler(g_colorTexUnit, 0);
glBindTexture(GL_TEXTURE_2D, 0);
With all of this, I get put pitch black for everything, however when I change the outputColor equation into "texture + outputColor;", everything looks normal. I have no idea what I'm doing wrong here. A friend tried to help me, we removed some unnecessairy stuff, but we got nothing running.
Ok guys, I've worked on this whole thing, and did manage to somehow get it running. First off I had to add samplers:
GLuint g_samplers;
//Add Later
void CreateSamplers()
{
glGenSamplers(1, &g_samplers);
glSamplerParameteri(g_samplers, GL_TEXTURE_WRAP_S, GL_REPEAT);
glSamplerParameteri(g_samplers, GL_TEXTURE_WRAP_T, GL_REPEAT);
//Linear mipmap Nearest
glSamplerParameteri(g_samplers, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glSamplerParameteri(g_samplers, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
}
I also added this to the file thing:
glimg::OpenGLPixelTransferParams xfer = glimg::GetUploadFormatType(pImageSet->GetFormat(), 0);
glimg::SingleImage image = pImageSet->GetImage(0, 0, 0);
glimg::Dimensions dims = image.GetDimensions();
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, dims.width, dims.height, 0,
xfer.format, xfer.type, image.GetImageData());
The xfer variable does get the format and type adjusted to the dds.
Also the render code got turned into this:
//Added necessary
glActiveTexture(GL_TEXTURE0 + g_colorTexUnit);
glBindTexture(GL_TEXTURE_2D,g_checkerTexture);
glBindSampler(g_colorTexUnit, g_samplers);
g_pLeftMesh->Render();
glBindSampler(g_colorTexUnit, 0);
glBindTexture(GL_TEXTURE_2D, 0);
And of course at the end of init() I needed to add the CreateSamplers thing:
//Added this later
LoadCheckerTexture();
CreateSamplers();
I'm sorry for all the trouble with all this, but guess OpenGL really is just this confusing and it was just dumb luck that I got it right. Just posting this so that people know
Your fail to add textures may be caused by:
Have you add texture coordinates to objects? (this is the most probable cause, because you are adding textures to non textured tutorial), add textures to VAO.
Did you add uniform textureunit (Sampler2D)? (it must be uniform, else texturing will not work properly)
Is your texture loaded,binded,enabled (GL_TEXTURE_2D) ?
Is your active texture unit - 0? if not change layout/multitexture coords or set active texture 0
This two codes are simple texturing shaders (texture unit 0) no special things (like light,blend,bump,...):
tm_l2g is transformation local obj space -> world space (Modelview)
tm_g2s is transformation world space -> screen space (Projection)
pos are vertex coordinates
txt are texture coordinates
col are colors
Do not forget to change uniform names and layout locations to yours.
Vertex:
//------------------------------------------------------------------
#version 420 core
//------------------------------------------------------------------
uniform mat4x4 tm_l2g;
uniform mat4x4 tm_g2s;
layout(location=0) in vec3 pos;
layout(location=1) in vec4 col;
layout(location=2) in vec2 txr;
out smooth vec4 pixel_col;
out smooth vec2 pixel_txr;
//------------------------------------------------------------------
void main(void)
{
vec4 p;
p.xyz=pos;
p.w=1.0;
p=tm_l2g*p;
p=tm_g2s*p;
gl_Position=p;
pixel_col=col;
pixel_txr=txr;
}
//------------------------------------------------------------------
fragment:
//------------------------------------------------------------------
#version 420 core
//------------------------------------------------------------------
in smooth vec4 pixel_col;
in smooth vec2 pixel_txr;
uniform sampler2D txr_texture0;
out layout(location=0) vec4 frag_col;
//------------------------------------------------------------------
void main(void)
{
vec4 col;
col=texture(txr_texture0,pixel_txr.st);
frag_col=col*pixel_col;
}
//------------------------------------------------------------------
[edit1] CPU old style OpenGL render code (initializations are not included its only render code they can be found here)
//------------------------------------------------------------------
// set modelview,projection,textures,bind GLSL programs...
GLfloat a=10.0,z=0.0;
glColor3f(1.0,1.0,1.0);
glBegin(GL_QUADS);
// textured quad
glTexCoord2f(0.0,0.0); glVertex3f(-a,-a,z);
glTexCoord2f(0.0,1.0); glVertex3f(-a,+a,z);
glTexCoord2f(1.0,1.0); glVertex3f(+a,+a,z);
glTexCoord2f(1.0,0.0); glVertex3f(+a,-a,z);
// reverse order quad to be shore that at least one passes by CULL_FACE
glTexCoord2f(1.0,0.0); glVertex3f(+a,-a,z);
glTexCoord2f(1.0,1.0); glVertex3f(+a,+a,z);
glTexCoord2f(0.0,1.0); glVertex3f(-a,+a,z);
glTexCoord2f(0.0,0.0); glVertex3f(-a,-a,z);
glEnd();
//------------------------------------------------------------------
[edit2] ok here goes VAO/VBO render code,...
//------------------------------------------------------------------------------
// enum of VBO locations (it is also your layout location) I use enums for simple in code changes
enum _vbo_enum
{
_vbo_pos=0, // glVertex
_vbo_col, // glColor
_vbo_tan, // glNormal
_vbo_unused0, // unused (at least i dont see anything at this location in your code)
_vbo_unused1, // unused (at least i dont see anything at this location in your code)
_vbo_txr, // glTexCoord
_vbos
};
//------------------------------------------------------------------------------
// 'global' names and size for OpenGL mesh in VAO/VBO ... similar ot texture names/handles
GLuint vao[1],vbo[_vbos],num_pnt=0;
//------------------------------------------------------------------------------
void VAO_init_cube() // call this before VAO use,...but after OpenGL init !
{
//[1] first you need some model to render (mesh), here is a simple cube
// size,position of cube - change it that it is visible in your scene
const GLfloat a=1.0,x=0.0,y=0.0,z=0.0;
// cube points 3f x,y,z
GLfloat mesh_pos[]=
{
x-a,y-a,z-a,x-a,y+a,z-a,x+a,y+a,z-a,x+a,y-a,z-a,
x-a,y-a,z+a,x-a,y+a,z+a,x+a,y+a,z+a,x+a,y-a,z+a,
x-a,y-a,z-a,x-a,y-a,z+a,x+a,y-a,z+a,x+a,y-a,z-a,
x-a,y+a,z-a,x-a,y+a,z+a,x+a,y+a,z+a,x+a,y+a,z-a,
x-a,y-a,z-a,x-a,y+a,z-a,x-a,y+a,z+a,x-a,y-a,z+a,
x+a,y-a,z-a,x+a,y+a,z-a,x+a,y+a,z+a,x+a,y-a,z+a,
};
// cube colors 3f r,g,b
GLfloat mesh_col[]=
{
0.0,0.0,0.0,0.0,1.0,0.0,1.0,1.0,0.0,1.0,0.0,0.0,
0.0,0.0,1.0,0.0,1.0,1.0,1.0,1.0,1.0,1.0,0.0,1.0,
0.0,0.0,0.0,0.0,0.0,1.0,1.0,0.0,1.0,1.0,0.0,0.0,
0.0,1.0,0.0,0.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,0.0,
0.0,0.0,0.0,0.0,1.0,0.0,0.0,1.0,1.0,0.0,0.0,1.0,
1.0,0.0,0.0,1.0,1.0,0.0,1.0,1.0,1.0,1.0,0.0,1.0,
};
// cube normals 3f x,y,z
GLfloat mesh_tan[]=
{
-0.6,-0.6,-0.6,-0.6,+0.6,-0.6,+0.6,+0.6,-0.6,+0.6,-0.6,-0.6,
-0.6,-0.6,+0.6,-0.6,+0.6,+0.6,+0.6,+0.6,+0.6,+0.6,-0.6,+0.6,
-0.6,-0.6,-0.6,-0.6,-0.6,+0.6,+0.6,-0.6,+0.6,+0.6,-0.6,-0.6,
-0.6,+0.6,-0.6,-0.6,+0.6,+0.6,+0.6,+0.6,+0.6,+0.6,+0.6,-0.6,
-0.6,-0.6,-0.6,-0.6,+0.6,-0.6,-0.6,+0.6,+0.6,-0.6,-0.6,+0.6,
+0.6,-0.6,-0.6,+0.6,+0.6,-0.6,+0.6,+0.6,+0.6,+0.6,-0.6,+0.6,
};
// cube texture coords 2f s,t
GLfloat mesh_txr[]=
{
0.0,0.0,0.0,1.0,1.0,1.0,1.0,0.0,
0.0,0.0,0.0,1.0,1.0,1.0,1.0,0.0,
0.0,0.0,0.0,1.0,1.0,1.0,1.0,0.0,
0.0,0.0,0.0,1.0,1.0,1.0,1.0,0.0,
0.0,0.0,0.0,1.0,1.0,1.0,1.0,0.0,
0.0,0.0,0.0,1.0,1.0,1.0,1.0,0.0,
};
// init VAO/VBO
glGenVertexArrays(1,vao); // allocate 1 x VAO
glGenBuffers(_vbos,vbo); // allocate _vbos x VBO
// copy mesh to VAO/VBO ... after this you do not need the mesh anymore
GLint i,sz,n; // n = number of numbers per 1 entry
glBindVertexArray(vao[0]);
num_pnt=sizeof(mesh_pos)/(sizeof(GLfloat)*3); // num of all points in mesh
i=_OpenGLVAOgfx_pos; n=3; sz=sizeof(GLfloat)*n;
glBindBuffer(GL_ARRAY_BUFFER,vbo[i]);
glBufferData(GL_ARRAY_BUFFER,sz*num_pnt,mesh_pos,GL_STATIC_DRAW);
glEnableVertexAttribArray(i);
glVertexAttribPointer(i,n,GL_FLOAT,GL_FALSE,0,0);
i=_OpenGLVAOgfx_col; n=3; sz=sizeof(GLfloat)*n;
glBindBuffer(GL_ARRAY_BUFFER,vbo[i]);
glBufferData(GL_ARRAY_BUFFER,sz*num_pnt,mesh_col,GL_STATIC_DRAW);
glEnableVertexAttribArray(i);
glVertexAttribPointer(i,n,GL_FLOAT,GL_FALSE,0,0);
i=_OpenGLVAOgfx_tan; n=3; sz=sizeof(GLfloat)*n;
glBindBuffer(GL_ARRAY_BUFFER,vbo[i]);
glBufferData(GL_ARRAY_BUFFER,sz*num_pnt,mesh_tan,GL_STATIC_DRAW);
glEnableVertexAttribArray(i);
glVertexAttribPointer(i,n,GL_FLOAT,GL_FALSE,0,0);
i=_OpenGLVAOgfx_txr; n=2; sz=sizeof(GLfloat)*n;
glBindBuffer(GL_ARRAY_BUFFER,vbo[i]);
glBufferData(GL_ARRAY_BUFFER,sz*num_pnt,mesh_txr,GL_STATIC_DRAW);
glEnableVertexAttribArray(i);
glVertexAttribPointer(i,n,GL_FLOAT,GL_FALSE,0,0);
glBindVertexArray(0);
}
//------------------------------------------------------------------------------
void VAO_draw() // call this to draw your mesh,... need to enable and bind textures,... before use
{
glDisable(GL_CULL_FACE);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
glBindVertexArray(vao[0]);
glEnableVertexAttribArray(_vbo_pos);
glEnableVertexAttribArray(_vbo_col);
glEnableVertexAttribArray(_vbo_tan);
glDisableVertexAttribArray(_vbo_unused0);
glEnableVertexAttribArray(_vbo_txr);
glDrawArrays(GL_QUADS,0,num_pnt);
glDisableVertexAttribArray(_vbo_pos);
glDisableVertexAttribArray(_vbo_col);
glDisableVertexAttribArray(_vbo_tan);
glDisableVertexAttribArray(_vbo_unused0);
glDisableVertexAttribArray(_vbo_unused1);
glDisableVertexAttribArray(_vbo_txr);
glBindVertexArray(0);
}
//------------------------------------------------------------------------------
void VAO_exit() // clean up ... call this when you do not need VAO/VBO anymore
{
glDisableVertexAttribArray(_vbo_pos);
glDisableVertexAttribArray(_vbo_col);
glDisableVertexAttribArray(_vbo_tan);
glDisableVertexAttribArray(_vbo_unused0);
glDisableVertexAttribArray(_vbo_unused1);
glDisableVertexAttribArray(_vbo_txr);
glBindVertexArray(0);
glDeleteVertexArrays(1,vao);
glDeleteBuffers(_vbos,vbo);
}
//------------------------------------------------------------------------------
[edit3] if you are win32/64 user you can try my IDE for GLSL
It is very simple and easy to use, but cannot change texture/attrib locations. Press [F1] for help,... [F9] for run [F10] for return to normal OpenGL mode. Also txt-editor is little buggy sometimes but it is enough for my purpose.
GLSL IDE
I have OpenGL program that I want to texture sphere with bitmap of earth. I prepared mesh in Blender and exported it to OBJ file. Program loads appropriate mesh data (vertices, uv and normals) and bitmap properly- I have checked it texturing cube with bone bitmap.
My program is texturing sphere, but incorrectly (or in the way I don't expect). Each triangle of this sphere includes deformed copy of this bitmap. I've checked bitmap and uv seems to be ok. I've tried many sizes of bitmap (powers of 2, multiples of 2 etc).
Here's the texture:
Screenshot of my program (like It would ignore my UV coords):
Mappings of UVs in Blender I've done in this way:
Code setting texture after loading it (apart from code adding texture to VBO- I think it's ok):
GLuint texID;
glGenTextures(1,&texID);
glBindTexture(GL_TEXTURE_2D,texID);
glTexImage2D(GL_TEXTURE_2D,0,GL_RGB,width,height,0,GL_BGR,GL_UNSIGNED_BYTE,(GLvoid*)&data[0]);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP);
Is there needed any extra code to map this texture properly?
[Edit]
Initializing textures (earlier presented code is in LoadTextureBMP_custom() function)
bool Program::InitTextures(string texturePath)
{
textureID = LoadTextureBMP_custom(texturePath);
GLuint TBO_ID;
glGenBuffers(1,&TBO_ID);
glBindBuffer(GL_ARRAY_BUFFER,TBO_ID);
glBufferData(GL_ARRAY_BUFFER,uv.size()*sizeof(vec2),&uv[0],GL_STATIC_DRAW);
return true;
}
My main loop:
bool Program::MainLoop()
{
bool done = false;
mat4 projectionMatrix;
mat4 viewMatrix;
mat4 modelMatrix;
mat4 MVP;
Camera camera;
shader.SetShader(true);
while(!done)
{
if( (glfwGetKey(GLFW_KEY_ESC)))
done = true;
if(!glfwGetWindowParam(GLFW_OPENED))
done = true;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Tutaj przeksztalcenia macierzy
camera.UpdateCamera();
modelMatrix = mat4(1.0f);
viewMatrix = camera.GetViewMatrix();
projectionMatrix = camera.GetProjectionMatrix();
MVP = projectionMatrix*viewMatrix*modelMatrix;
// Koniec przeksztalcen
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D,textureID);
shader.SetShaderParameters(MVP);
SetOpenGLScene(width,height);
glEnableVertexAttribArray(0); // Udostepnienie zmiennej Vertex Shadera => vertexPosition_modelspace
glBindBuffer(GL_ARRAY_BUFFER,VBO_ID);
glVertexAttribPointer(0,3,GL_FLOAT,GL_FALSE,0,(void*)0);
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER,TBO_ID);
glVertexAttribPointer(1,2,GL_FLOAT,GL_FALSE,0,(void*)0);
glDrawArrays(GL_TRIANGLES,0,vert.size());
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
glfwSwapBuffers();
}
shader.SetShader(false);
return true;
}
VS:
#version 330
layout(location = 0) in vec3 vertexPosition;
layout(location = 1) in vec2 vertexUV;
out vec2 UV;
uniform mat4 MVP;
void main()
{
vec4 v = vec4(vertexPosition,1.0f);
gl_Position = MVP*v;
UV = vertexUV;
}
FS:
#version 330
in vec2 UV;
out vec4 color;
uniform sampler2D texSampler; // Uchwyt tekstury
void main()
{
color = texture(texSampler, UV);
}
I haven't done any professional GL programming, but I've been working with 3D software quite a lot.
your UVs are most likely bad
your texture is a bad fit to project on a sphere
considering UVs are bad, you might want to check your normals as well
consider an ISOSPHERE instead of a regular one to make more efficient use of polygons
You are currently using a flat texture with flat mapping, which may give you very ugly results, since you will have very low resolution in the "outer" perimeter and most likely a nasty seam artifact where the two projections meet if you like... rotate the planet or something.
Note that you don't have to have any particular UV map, it just needs to be correct with the geometry, which it doesn't look like it is right now. The spherical mapping will take care for the rest. You could probably get away with a cylindrical map as well, since most Earth textures are in a suitable projection.
Finally, I've got the answer. Error was there:
bool Program::InitTextures(string texturePath)
{
textureID = LoadTextureBMP_custom(texturePath);
// GLuint TBO_ID; _ERROR_
glGenBuffers(1,&TBO_ID);
glBindBuffer(GL_ARRAY_BUFFER,TBO_ID);
glBufferData(GL_ARRAY_BUFFER,uv.size()*sizeof(vec2),&uv[0],GL_STATIC_DRAW);
}
There is the part of Program class declaration:
class Program
{
private:
Shader shader;
GLuint textureID;
GLuint VAO_ID;
GLuint VBO_ID;
GLuint TBO_ID; // Member covered with local variable declaration in InitTextures()
...
}
I've erroneously declared local TBO_ID that covered TBO_ID in class scope. UVs were generated with crummy precision and seams are horrible, but they weren't problem.
I have to admit that information I've supplied is too small to enable help. I should have put all the code of Program class. Thanks everybody who tried to.