Jump to content


FS use tex or color?


31 replies to this topic

#1 Alienizer

    Member

  • Members
  • PipPipPipPip
  • 435 posts

Posted 21 July 2012 - 05:12 PM

In a fragment shader, how do you know when to use the texture color, or the solid color? Right now, I test if the texel is black, but that's not the right way..

  vec4 texel = texture2D(tex, gl_TexCoord[0].st);
  if (texel.rgb == vec3(0,0,0)) {...


#2 Reedbeta

    DevMaster Staff

  • Administrators
  • 5310 posts
  • LocationSanta Clara, CA

Posted 22 July 2012 - 03:43 AM

Well, what are you trying to do? You use a texture or a solid color, whichever is more appropriate for what you want the shader to do! :) Honestly this is like asking whether to use an int or an array.
reedbeta.com - developer blog, OpenGL demos, and other projects

#3 Alienizer

    Member

  • Members
  • PipPipPipPip
  • 435 posts

Posted 22 July 2012 - 04:13 AM

Here is what I do...

 
if there is a texture for this poly, then...
 
glBindTexture(GL_TEXTURE_2D, TextureList[j].texID);
glColor4f(1,1,1,1);
 
else
 
glBindTexture(GL_TEXTURE_2D, 0);
glColor4f(clr.r, clr.g, clr.b, clr.a);

Now, in the fragment shader, I want to know if I need to use the solid color, or the texture color... gl_FragColor = ?

#4 Reedbeta

    DevMaster Staff

  • Administrators
  • 5310 posts
  • LocationSanta Clara, CA

Posted 22 July 2012 - 05:11 AM

So some polygons have a texture, while others don't? Typically you'd then use two different shaders, one that uses the texture for the textured polygons, and one that uses the solid color, for the solid-colored ones. Alternatively, you could just make a 1x1 texture for each solid color.
reedbeta.com - developer blog, OpenGL demos, and other projects

#5 Stainless

    Member

  • Members
  • PipPipPipPip
  • 582 posts
  • LocationSouthampton

Posted 22 July 2012 - 09:53 AM

The easiest way is to create a small texture that is totally white, and bind that for un-textured polygons.

This saves the overhead of swapping shaders.

Then in the fragment shader you can do ...
vec4 texel = texture2D(tex,texcoord);
return texel * colour;


#6 TheNut

    Senior Member

  • Moderators
  • 1701 posts
  • LocationCyberspace

Posted 22 July 2012 - 11:00 AM

Both Stainless and Reed provide good answers. Try to separate your shaders if the logic varies a lot, or if in this particular case you may be able to get away with just assigning all your polygons a texture. Try to avoid any conditional logic in shaders if possible. It's best to have the GPU plow through fragments as quickly as possible and have the CPU do any preparation logic (ie: sort polygons by shader).

Also, why are you using glColor? You should be using VBOs. Also, you don't need to waste cycles by resetting the active texture to null. Best just to leave it at the last texture used and switch it when you're ready to use a new texture. Not a major performance boost, but gets you into the habit of reducing state switching.
http://www.nutty.ca - Being a nut has its advantages.

#7 Alienizer

    Member

  • Members
  • PipPipPipPip
  • 435 posts

Posted 22 July 2012 - 04:05 PM

Can I create a 1x1 texture and change the data in it for the color before binding it? or do I have to create a 1x1 texture for each color in the entire model?

#8 Alienizer

    Member

  • Members
  • PipPipPipPip
  • 435 posts

Posted 22 July 2012 - 04:10 PM

View PostTheNut, on 22 July 2012 - 11:00 AM, said:

why are you using glColor? You should be using VBOs

hmmm, I don't know! It's just what I've been learning to do!

How can I use VBO to do this instead? I mean, don't I have to creat a VBO the size of the viewport and fill it with the pixel color? That would take too long!

#9 TheNut

    Senior Member

  • Moderators
  • 1701 posts
  • LocationCyberspace

Posted 22 July 2012 - 04:50 PM

The minimum texture size in OpenGL is 64x64. I have seen cases where you can go lower, but it depends on the video driver devs wanting to support such resolutions.

Alienizer said:

or do I have to create a 1x1 texture for each color in the entire model?
The idea that was presented here is that, for whatever reason, if you have one object that is textured and another object that is not, you can render both objects using the same shader by giving the object without a texture a simple white texture. If looks like in your case that you want to support both vertex colours and textures. With vertex colouring, you supply a separate buffer just like you do with vertex, UVs, and normals. Your vertex shader will pass the colour attribute to the fragment shader in a varying variable, where it will be interpolated across the polygon. In your fragment shader, you typically assign the fragment colour as vertex_colour * texture_colour. The default vertex colour should be set to white to maintain the colour of any textures you apply to the polygon. When supplying a white texture, you can modify the output colour by adjusting the vertex colour. If you wanted to supply a material colour for the whole object, you could more easily create a uniform vec4 colour variable in your fragment shader. I would not use this as a substitute for setting each polygon's colour in a loop though. A vertex colour buffer is better suited for that and allows you to render the whole geometry in one direct shot.

To understand this better, you need to learn about VBOs, or vertex buffer objects. I'm rather surprised you don't already know this if you're working with shaders. I find it bizarre that any learning material on shaders would still be using classic OpenGL rendering routines. You can google for topics on this, but I would recommend reading the specification guides at OpenGL.org to avoid learning deprecated APIs.
http://www.nutty.ca - Being a nut has its advantages.

#10 Alienizer

    Member

  • Members
  • PipPipPipPip
  • 435 posts

Posted 22 July 2012 - 05:40 PM

What I have is many objects of different colors, and other objects with textures. Some textures have transparency like PNG images. Objects with colors only can also have transparencies.

I'm learning from this board and from docs found on google, but it seems that I'm getting more and more confused. Some tutorials tells you to do it "this way" and other "that way". When I try one way and finally make it somewhat work, and then use something I need from another tutorial requiring #version 130 or something, then everything I've done before gives me a bunch of deprecated messages, so I have to redo everything from scratch, and don't know how to start!

Now I'm looking at the PDF from http://www.khronos.org/opengl/ and in the deprecated section E, looks like everything is deprecated!!?? So I'm lost, very very lost.

Where do you guys turn to when you need to lookup some references? What docs should I read to get in the right direction and be on the same wavelength as you guys?

#11 Alienizer

    Member

  • Members
  • PipPipPipPip
  • 435 posts

Posted 22 July 2012 - 05:50 PM

Now I'm looking at http://www.opengl.or...k/docs/manglsl/ and under Built-in Variables, there is only a handfull. gl_FrontColor is gone, gl_Color too etc. Am I reading this correctly? I don't know what to use anymore :blink:

#12 TheNut

    Senior Member

  • Moderators
  • 1701 posts
  • LocationCyberspace

Posted 22 July 2012 - 08:54 PM

Mostly nowadays I refer to official documentation, such as you found on OpenGL's website. I only read websites that are 6 months to 1 year old tops, with some exceptions for older material. Even then, I'm only interested in the theory and not the code. The core and GLSL ref docs on the Khronos website will provide accurate support documentation for the platform you want to target. It won't give you examples, but you can search for those online and reference the doc to follow along. You can download their latest version 4.20, although I would personally lean more towards 2.X documentation as that platform is widely supported and is quite capable at making games. I would also avoid any built-in or global parameters. Use only the mathematical routines provided by the lowest GLSL version you want to support and do the rest yourself. Those built-in vars were to cater to old-school devs that continued to use GL 1.X functions, which has all but phased out now (thank god).

Vertex colouring + texturing will definitely give you what you want. FYI you can pass in any vertex colouring format, including RGBA data in byte, short, or floating point format. Your shader should look something like this.

// Vertex shader

attribute vec4 Vertex; // xyzw data from VBO
attribute vec2 Uv; // uv data from VBO
attribute vec4 Colour; // RGBA data from VBO

uniform mat4 ProjectionMatrix; // camera projection
uniform mat4 ViewMatrix; // camera transformation
uniform mat4 ModelMatrix; // object transformation

varying vec4 vertexColour; // Output to fragment shader
varying vec2 vertexUv; // Output to fragment shader

void main ()
{
	// Don't use ftransform() - assume everything is your responsibility
	gl_Position = ProjectionMatrix * ViewMatrix * ModelMatrix * Vertex;

	vertexColour = Colour
	vertexUv = Uv
}


// Fragment shader


uniform sampler2D MyTexture; // Set via C++. Objects without a texture will pass in a white texture by default.

// Inputs interpolated from vertex shader
varying vec4 vertexColour;
varying vec2 vertexUv;

void main ()
{
	gl_FragColor = vertexColour * texture2D(MyTexture, vertexUv);
}

http://www.nutty.ca - Being a nut has its advantages.

#13 Alienizer

    Member

  • Members
  • PipPipPipPip
  • 435 posts

Posted 22 July 2012 - 09:36 PM

oh! so you mean that ProjectionMatrix, ViewMatrix and ModelMatrix are passed from the main program?

So I see what you mean. Use glsl as computation only, and everything else camera(pos,dir), lights etc are all defined in the main program. So no need to use one or more of the 8 bilt-in lights anymore, but we have to do every shading, and that's what the fragment shader will do right?

What I'm not sure about your code example is the VBO part, then rest I understand fully, if I'm right about what I just said above.

So what is the VBO? Is it like a texture2d where we put in info to be passed to the vertex shader?

Thanks for the info and the time to explain! I appreciate it.

#14 TheNut

    Senior Member

  • Moderators
  • 1701 posts
  • LocationCyberspace

Posted 23 July 2012 - 02:45 AM

Alienizer said:

and that's what the fragment shader will do right?
Not just the fragment shader, but also the vertex shader, the tessellation shader (added in GL 4.X), and the geometry shader (added in GL 3.X). The freedom and programmability allows you to, for example, use a uniform variable in any one of these shaders. You could for instance access the ViewMatrix from the fragment shader if you wanted to. Often you spread out your uniforms to both vertex and fragment shaders. For example, you often process transformations in a vertex shader, but in a fragment shader I may pass in several lights to perform per-pixel lighting. I could optionally perform those computations at the vertex level if I wanted to improve performance at the expense of image quality. It's all up to the dev to decide what the shader does and what data it needs. The backend part (C++) will provide all that data in the form of attributes and uniforms, and a vertex shader can optionally send data to be interpolated by the time it reaches the fragment shader using varyings.

To understand VBOs, you have to rewind the clock a bit. It all started with glBegin, glVertex3f x 1000 calls and finally glEnd. At first this was simple and it just worked. Then better hardware came out and more polygons were being pushed. The function call overhead on the CPU was starting to become problematic and so they moved to vertex arrays. Instead of calling glVertex a couple thousand times, you now prepared an array of all your vertices, uvs, normals, etc. and made one call to render the whole thing in one shot. This was great for a while, but then hardware again improved and more polygons were being pushed. This time, the bottleneck was the bus between system memory and video memory. Sending tens of thousands of polygons every frame was creating New York city style traffic congestion, slowing everything down. To resolve this, they brought in VBOs. Like vertex arrays, except the geometry data is now optimally stored in video memory, like texture data. When it comes time to draw, instead of pushing all those polygons down the bus, the video card just accesses the data from it's own memory, which is blazing fast in comparison. It's like how every game developer sleeps on the company sofa. No need to waste time going home. Just wake up right at the office :D Booyah!

As for the buffers themselves, it's up to you to decide how you want to craft them. The vertex shader accesses this data via the attribute variables. Some people create one massive array and stride the data. Others may create several buffers, one to store each component of the geometry. For example, one buffer for vertices, one for UVs, another for colour. This is how I often organize my data because sometimes I may want to update a VBO, but not have to resend the entire geometry back to the video card. For example, with particle engines you will update the vertex coordinates of each particle using something called a dynamic VBO. You don't need to reupload UV data, so it's much more efficient to just update the vertex buffer and leave the others alone. The only drawback is that instead of activating a single VBO, you have to activate several for each object before you render it. As you can see, it starts to add a little function overhead, but from my tests it's quite negligible. To each their own.
http://www.nutty.ca - Being a nut has its advantages.

#15 Alienizer

    Member

  • Members
  • PipPipPipPip
  • 435 posts

Posted 23 July 2012 - 03:44 AM

Thank you TheNut, that explanation is very well understood. Now it makes more sense to me. I know why my terrain with a tank on it runs at 0.01 FPS.

So we don't need to use any of the gl_* built-in variables anymore? Or do we still need to use gl_Vertex, gl_Normal, gl_FragColor and others? But none of the gl_Lights and stuff?

What about...
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;

do we still need this if everything is in the VBO?

I don't know how to access the VBO from a shader. Is it via the uniform? Something like...
glBindBufferARB(GL_ARRAY_BUFFER_ARB, FragmentsVBO);

Could you guide me to a good site, or have, a skeleton in C++ on how to use the VBO for the basic stuff? I understand clearly your explanation, but now I just need a little kick start to know the layout of the c++ code and how the VBOs are accessed in the shaders. Sorry if I'm so demanding, but I really want to do it right this time and come out of the cave I'm in right now!

#16 Alienizer

    Member

  • Members
  • PipPipPipPip
  • 435 posts

Posted 23 July 2012 - 04:14 AM

aaaaaaaaah I'm getting more confused again...

http://www.opengl.or...-_just_examples

why is it deprecated??? or am I worrying for nothing?

#17 TheNut

    Senior Member

  • Moderators
  • 1701 posts
  • LocationCyberspace

Posted 23 July 2012 - 10:48 AM

Alienizer said:

So we don't need to use any of the gl_* built-in variables anymore?
Generally yes, but with some exceptions. Every shader requires output data. A vertex shader must set the gl_Position vector. Without this, the card won't be able to render the triangle. Fragment shaders must set the gl_Fragment vector to actually colour the pixel. You can optionally access the fragment's current coordinates (and depth) by using the gl_FragCoord input vector, which is essentially the interpolated window coordinates from the gl_Position vector you provided in the vertex shader. Geometry shaders are a bit different. It's like executing a vertex shader as many times as you want. For each new vertex you wish to create, you supply the gl_Position + any varyings (normals, uvs, etc.) and then call EmitVertex(). You then call EndPrimitive() to complete the polygon and either continue or exit the shader when you're done. For a complete list of inputs and outputs of each shader, see chapter 7 "Built-in Variables" in the 4.20 GLSL Shader Language core doc. Any section in that doc that says "Compatibility Profile" you should really ignore. That's all the 1.X fixed stuff like gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0. That's the kind of GLSL programming you should steer away from. gl_TextureMatrix for example is set when you switch the OpenGL projection state to GL_TEXTURE and then call glLoadMatrix() (or optionally glMultMatrix). This kind of behaviour is no longer necessary. If you want to upload a texture matrix, just create a uniform matrix variable in your shader and upload the texture matrix values. Except for the mandatory outputs from each shader, you're responsible for all the inputs.


Alienizer said:

I don't know how to access the VBO from a shader. Is it via the uniform? Something like...
The VBO data is accessed from the attributes, once for each vertex. Uniforms are like your function parameters. Where the attributes will change for each new vertex you process, the uniforms will remain the same throughout each vertex. I can't seem to find any up-to-date decent site explaining this, so I'll just jot down the steps. Here's a simple VBO containing only the vertex data, from start to finish.

// Create vertex buffer
int vboVertex;
glGenBuffers(1, vboVertex);
if ( vboVertex == 0 )
{ error! }

// Upload vertices to vertex buffer
float vertices[] = {x, y, z, x, y, z, x, y, z......};
glBindBuffer(GL_ARRAY_BUFFER, vboVertex);
glBufferData(GL_ARRAY_BUFFER, NumberOfVertices * sizeof(float), vertices, GL_STATIC_DRAW);

// You can optionally delete the vertices array at this point to save memory. The video card now has everything.

// Now set the shader attribute (assuming you compiled and loaded your shader)
int atribVertex = glGetAttribLocation(MyShaderProgramID, "Vertex"); // In vertex shader, you should have "attribute vec* Vertex", otherwise this function will return 0.
glEnableVertexAttribArray(atribVertex);

// Bind the vertex buffer to the attribute
glBindBuffer(GL_ARRAY_BUFFER, vboVertex);
glVertexAttribPointer(atribVertex, 3, GL_FLOAT, false, 0, 0);

// Draw
glDrawElements(...) or glDrawArrays(...)

That's the gist of it. Basically do this for each buffer, or create one massive buffer with everything and define the vertex stride parameter when you call glVertexAttribPointer. You'll note that I haven't suffixed any ARB extension to the end of these methods, as you will see many websites do. A long long time ago these were APIs introduced by the ARB to extend OpenGL. They have since become part of the core with OpenGL 2.X. Many people haven't caught on yet :)
http://www.nutty.ca - Being a nut has its advantages.

#18 Alienizer

    Member

  • Members
  • PipPipPipPip
  • 435 posts

Posted 23 July 2012 - 08:21 PM

Thank you again TheNut. I have it in without errors, but in the draw function, I have...

glDrawArrays(GL_TRIANGLES, 0, totPoly);

and in the vertex shader...

attribute vec3 Vertex;
void main(void)
{
  gl_Position = vec4(Vertex, 1);
}


and in the fragment shader...

void main(void) {
  gl_FragColor = vec4(0.1, 0.4, 0.9, 1.0);
}

But nothing is drawn, just the blue background set by glClearColor

Can you enlighten me a little more please?

#19 TheNut

    Senior Member

  • Moderators
  • 1701 posts
  • LocationCyberspace

Posted 23 July 2012 - 08:47 PM

I presume your vertex coordinates are already in clip space (clamped between -1.0 and 1.0)? You're not performing any transformations in your vertex shader, so if you're using actual 3D world coordinates then it's likely the polygons are getting clipped due to being outside the viewport. Otherwise I would suggest posting a bit more code. I'm not sure right off the bat what could be your problem. So far what you've done looks right, but there might be something else missing.

-- Edit
BTW, GLSL is quite formal in that you should declare any floating point values with a decimal notation. For example, vec4(Vertex, 1) is considered bad form and will throw errors on certain GLSL profiles. You should declare it as vec4(Vertex, 1.0). Make sure to check for compiler errors to avoid these sort of mishaps.
http://www.nutty.ca - Being a nut has its advantages.

#20 Alienizer

    Member

  • Members
  • PipPipPipPip
  • 435 posts

Posted 23 July 2012 - 09:28 PM

Yes, I did 1.0 as oppose to 1, thanks for poiting it out, I usually do this!

I also added glEnableClientState(GL_VERTEX_ARRAY); before glDrawArrays and glDisableClientState(GL_VERTEX_ARRAY); after it. Is this correct? Or I don't need to do this?

I did now I had to clamp my vertices to -1.0...1.0 I just passed them as they are. ow do you make them in this range? I mean, a scene bbox could be -100..1000 or even 500...600 !??





1 user(s) are reading this topic

0 members, 1 guests, 0 anonymous users