I need to do some heavy optimizations in my game and I was thinking since we can pass a vec4 color to the shader packed to only one float, is there a way to pass the vec2 texture coordinates too? For example in the following code can I pass the 2 texture coords(its always 1 and 0) as only one element,in the same way as its happening in the color element.
public void point(float x,float y,float z,float size,float color){
float hsize=size/2;
if(index>vertices.length-7)return;
vertices[index++]=x-hsize;
vertices[index++]=y-hsize;
vertices[index++]=color;
vertices[index++]=0;
vertices[index++]=0;
vertices[index++]=x+hsize;
vertices[index++]=y-hsize;
vertices[index++]=color;
vertices[index++]=1;
vertices[index++]=0;
vertices[index++]=x+hsize;
vertices[index++]=y+hsize;
vertices[index++]=color;
vertices[index++]=1;
vertices[index++]=1;
vertices[index++]=x-hsize;
vertices[index++]=y+hsize;
vertices[index++]=color;
vertices[index++]=0;
vertices[index++]=1;
num++;
}
{
mesh=new Mesh(false,COUNT*20, indices.length,
new VertexAttribute(Usage.Position, 2,"a_position"),
new VertexAttribute(Usage.ColorPacked, 4,"a_color"),
new VertexAttribute(Usage.TextureCoordinates, 2,"a_texCoord0")
);
}
frag shader
varying vec4 v_color;
varying vec2 v_texCoords;
uniform sampler2D u_texture;
void main() {
vec4 color=v_color * texture2D(u_texture, v_texCoords);
gl_FragColor = color;
}
vert shader
attribute vec4 a_position;
attribute vec4 a_color;
attribute vec2 a_texCoord0;
uniform mat4 u_projTrans;
varying vec4 v_color;
varying vec2 v_texCoords;
void main() {
v_color = a_color;
v_texCoords = a_texCoord0;
gl_Position = u_projTrans * a_position;
}
I know this will not make a big difference in the performance but I am just willing to spend some extra hours here and there to make this small optimizations in order to make my game run faster.
I haven't tried this but I think it will work. Simply use Usage.ColorPacked for your texture coordinates. I don't think you can send anything smaller than 4 bytes, so you may as well use the already defined packed color. You will only be saving one byte per vertex. You can put your coordinates into the first two elements and ignore the second two elements.
mesh = new Mesh(false,COUNT*20, indices.length,
new VertexAttribute(Usage.Position, 2,"a_position"),
new VertexAttribute(Usage.ColorPacked, 4,"a_color"),
new VertexAttribute(Usage.ColorPacked, 4,"a_texCoord0")
);
I don't think the usage parameter of VertexAttribute is actually used by anything in Libgdx. If you look at the source, it only checks if the usage is ColorPacked or not, and from that decides whether to use a single byte per component versus 4.
And in your vertex shader:
attribute vec4 a_position;
attribute vec4 a_color;
attribute vec4 a_texCoord0; //note using vec4
uniform mat4 u_projTrans;
varying vec4 v_color;
varying vec2 v_texCoords;
void main() {
v_color = a_color;
v_texCoords = a_texCoord0.xy; //using the first two elements
gl_Position = u_projTrans * a_position;
}
To translate the texture coordinate correctly:
final Color texCoordColor = new Color(0, 0, 0, 0);
//....
texCoordColor.r = texCoord.x;
texCoordColor.g = texCoord.y;
float texCoord = texCoordColor.toFloatBits();
Related
I have a project of castle and i send one light and one material to shaders. I want to add one more light and texture, but i don't know how to do it in shaders.
This is my fragment shader:
#version 130
out vec4 pixelColor;
in vec4 l;
in vec4 n;
in vec4 v;
uniform sampler2D textureMap0, textureMap1;
in vec2 iTexCoord;
in vec2 iTexCoord2;
uniform vec4 dragi1;
uniform vec4 dragi2;
uniform vec4 dragi3;
uniform float polysk;
uniform vec4 Light0ambient;
uniform vec4 Light0diffuse;
uniform vec4 Light0specular;
uniform vec4 Light0position;
uniform vec4 Material0emission;
uniform vec4 Material0ambient;
uniform vec4 Material0diffuse;
uniform vec4 Material0specular;
uniform float Material0shininess;
void main(void) {
vec4 ml=normalize(l);
vec4 mn=normalize(n);
vec4 mv=normalize(v);
vec4 mr=reflect(-ml,mn);
float nl=max(dot(ml,mn),0);
float rv=pow(max(dot(mr,mv),0),Material0shininess);
pixelColor=Light0ambient*Material0ambient+Light0diffuse*Md*vec4(nl,nl,nl,1)+Light0specular*Material0specular*vec4(rv,rv,rv,0);
}
And this is my vertex shader:
#version 130
uniform mat4 P;
uniform mat4 V;
uniform mat4 M;
in vec4 vertex;
in vec4 normal;
in vec2 texCoord;
out vec4 l;
out vec4 n;
out vec4 v;
out vec2 iTexCoord;
out vec2 iTexCoord2;
uniform vec4 Light0position;
void main(void) {
gl_Position=P*V*M*vertex;
l=normalize(V*(Light0position-M*vertex));
n=normalize(V*M*normal);
v=normalize(vec4(0,0,0,1)-V*M*vertex);
iTexCoord = texCoord;
iTexCoord2 = (n.xy + 1)/2;
}
It is simple to do?
And one more question, how to create a spotlight? Can i do this in simple way?
When you want to use multiple lights in your shaders you generally store all your light and material data in arrays and process each of those in one large for-loop with or without GLSL functions.
For example, you could create a light and a material struct and create a uniform array of those structs like this:
struct Light {
vec4 position;
vec4 ambient;
vec4 diffuse;
vec4 specular;
};
struct Material {
vec4 ambient;
vec4 diffuse;
vec4 specular;
vec4 emission;
float shininess;
};
uniform Light lights[4]; // Use 4 lights
uniform Material materials[2]; // Use 2 materials
Then the structure of your fragment shader could look something like this:
out vec4 color;
void main()
{
// define an output color value
vec3 output;
// calculate lighting value per light source
for(int i = 0; i < 4; i++)
outout += someFunctionToCalculateLight(lights[i], materials[0]);
color = vec4(output, 1.0);
}
In this case a function was created to calculate the resulting lighting color per light source and added to the final output color. This is generally how you work with multiple lights. Note that this is a very basic example.
Also, if you want to know how to create a spotlight, you're better off following tutorials on that subject of which there are plenty to be found online instead of asking that around here.
A few tutorials:
http://www.mbsoftworks.sk/index.php?page=tutorials&series=1&tutorial=20
http://www.lighthouse3d.com/tutorials/glsl-core-tutorial/spotlights/
http://www.learnopengl.com/#!Lighting/Light-casters
I want to darken the corners of my little quad in my program. I have the following vertex shader:
#version 130
varying vec4 v_color;
varying vec2 v_texcoord;
void main()
{
v_color = gl_Color.rgba;
v_texcoord = gl_MultiTexCoord0.xy;
gl_FrontColor = vec4(v_color.r, v_color.g, v_color.b, 1.0f);
gl_Position = ftransform();
}
And my fragment shader:
#version 130
uniform sampler2D u_texture;
varying vec4 v_color;
varying vec2 v_texcoord;
void main()
{
gl_FragColor = v_color * texture2D(u_texture, v_texcoord);
}
I read somewhere that gl_FrontColor could be used to "color" vertices, but no matter what I change the values to, it always seems to stay the same.
My question is, what function can I use to set the color of my vertices? I want the vertices to be slightly darker than the rest of the quad so it looks a little "nicer".
You output to both v_color (your varying), and gl_FrontColor (GLSL builtin). But, in fragment shader, you only use v_color, so anything that is in gl_FrontColor is being ignored.
You should use only one of these. Either
// vertex
#version 130
#define SCALE_FACTOR 0.5
varying vec4 v_color;
varying vec2 v_texcoord;
void main()
{
v_color = vec4(gl_Color.rgb * SCALE_FACTOR, 1.0);
v_texcoord = gl_MultiTexCoord0.xy;
gl_Position = ftransform();
}
// fragment
#version 130
uniform sampler2D u_texture;
varying vec4 v_color;
varying vec2 v_texcoord;
void main()
{
gl_FragColor = v_color * texture2D(u_texture, v_texcoord);
}
Or use gl_FrontColor in vertex and gl_Color in fragment shader, instead of your v_color (and remove this varying as it no longer needed).
Of course vertex gl_Color attribute comes from glColorPointer, - if you changed that colors, it would be changed in shader too.
(Edit): The original code I posted was for both gouraud and phong shading options. I've changed it so it is just phong shading and posted below. The mesh is too big to describe here, as it is generated from a Bezier Patch.
I'm having some problems with flat and phong shading in Open GL 3 Mesa 9. It seems no matter what I do I get flat shaded figures, with tiny facets (planes) and I cannot get Blinn-Phong shading to work.
Here are my shaders:
(Vertex Shader)
//material parameters
uniform vec4 AmbientProduct, DiffuseProduct, SpecularProduct;
uniform float Shininess;
attribute vec4 vPosition;
//attribute vec4 vColor;
attribute vec4 vNormal;
attribute vec4 vControlColor;
attribute vec2 texcoord;
uniform mat4 model_view;
uniform mat4 projection;
uniform int flag;
uniform int phong_flag;
uniform vec4 eye_position;
//lighting parameters
uniform vec4 light_1; //light 1 position
uniform vec4 light_2; //light 2 position
varying vec4 control_color;
varying vec4 color;
varying vec4 position;
varying vec4 normal;
varying vec2 st;
void
main()
{
control_color = vControlColor;
position = vPosition;
normal = vNormal;
tex_coords = texcoord;
st = texcoord;
gl_Position = projection*model_view*vPosition;
}
And my fragment shader:
//material parameters
uniform vec4 AmbientProduct, DiffuseProduct, SpecularProduct;
uniform float Shininess;
uniform vec4 eye_position;
uniform int phong_flag;
//lighting parameters
uniform vec4 light_1; //light 1 position
uniform vec4 light_2; //light 2 position
varying vec4 light_2_transformed; //light 2 transformed position
uniform int Control_Point_Flag;
uniform sampler2D texMap;
varying vec4 color;
varying vec4 position;
varying vec4 normal;
varying vec4 control_color;
varying vec2 st;
void
main()
{
vec4 N = normalize(normal);
vec4 E = normalize(eye_position - position);
vec4 L1 = normalize(light_1 - position);
vec4 L2 = normalize(light_2 - position);
vec4 H1 = normalize( L1 + E);
vec4 H2 = normalize( L2 + E);
//calculate ambient component
vec4 ambient = AmbientProduct;
//calculate diffuse componenent
float k_d_1 = max(dot(L1,N), 0.0);
float k_d_2 = max(dot(L2,N), 0.0);
vec4 diffuse1 = k_d_1*DiffuseProduct;
vec4 diffuse2 = k_d_2*DiffuseProduct;
//calculate specular componenent
float k_s_1 = pow(max(dot(N, H1), 0.0), Shininess);
float k_s_2 = pow(max(dot(N, H2), 0.0), Shininess);
vec4 specular1 = k_s_1*SpecularProduct;
vec4 specular2 = k_s_2*SpecularProduct;
//if specular color is behind the camera, discard it
if (dot(L1, N) < 0.0) {
specular1 = vec4(0.0, 0.0, 0.0, 1.0);
}
if (dot(L2, N) < 0.0) {
specular2 = vec4(0.0, 0.0, 0.0, 1.0);
}
vec4 final_color = ambient + diffuse1 + diffuse2 + specular1 + specular2;
final_color.a = 1.0;
/* gl_FragColor = final_color; */
gl_FragColor = final_color*texture2D(texMap, st);
}
Does everything look ok for my shaders?
Things worth noting:
You have variables for a ModelView in your vertex shader, but you never use it in calculating position. Your vertex "position"s are thus whatever is passed from your OpenGL application and are not affected by any transformations you may be trying to do, though they are physically placed correctly because you use the matrices for gl_Position.
You aren't passing a Normal matrix to your shader. The Normal matrix is calculated by taking the transpose inverse of the ModelView matrix. Calculate this outside of the shader and pass it in. If you don't multiply your normals by the Normal matrix, you'll still be able to transform your model, but the normals will all still be facing the same way, so your lighting will be incorrect.
However, your normal vectors on the OpenGL side are may likely be the culprit. See this question for a good explanation of a possible source of unwanted flat shading.
As a side note, both of your shaders seem more complicated than they should be. That is to say, they have too many variables that aren't used and too much stuff that you could condense into fewer lines. It's just housekeeping, but it will make keeping track of your code easier.
How to scrolling a texture on a plane?
So I have a plane with a texture, can I use a shader to scroll left from right (infinite) the texture on it?
Setup the texture wrapping mode using
glTexParameteri(TextureID, L_TEXTURE_WRAP_S, GL_REPEAT)
Add the float uniform named Time to your texturing shader
Use something like texture2D(sampler, u + Time, v) while fetching texture sample.
Update the Time uniform using some timer in your code.
Here's a GLSL shader:
/*VERTEX_PROGRAM*/
in vec4 in_Vertex;
in vec4 in_TexCoord;
uniform mat4 ModelViewMatrix;
uniform mat4 ProjectionMatrix;
out vec2 TexCoord;
void main()
{
gl_Position = ProjectionMatrix * ModelViewMatrix * in_Vertex;
TexCoord = vec2( in_TexCoord );
}
/*FRAGMENT_PROGRAM*/
in vec2 TexCoord;
uniform sampler2D Texture0;
/// Updated in external code
uniform float Time;
out vec4 out_FragColor;
void main()
{
/// "u" coordinate is altered
out_FragColor = texture( Texture0, vec2(TexCoord.x + Time, TexCoord.y) );
}
Hi i'm new to GLSL and i'm having a few problems.
I'm trying to create a pair of GLSL Shaders to either use color or texture but i must be doing something wrong.
The problem is that if set uUseTexture to 0 (which should indicate color) it doesn't work (object is not colored). I know the coloring code works separately, any hints why it does not work using the if statement?
Here is the code:
// Fragment
precision mediump float;
uniform int uUseTexture;
uniform sampler2D uSampler;
varying vec4 vColor;
varying vec2 vTextureCoord;
void main(void) {
if(uUseTexture == 1) {
gl_FragColor = texture2D(uSampler, vec2(vTextureCoord.s, vTextureCoord.t));
} else {
gl_FragColor = vColor;
}
}
// Vertex
attribute vec3 aVertexPosition;
attribute vec4 aVertexColor;
attribute vec2 aTextureCoord;
uniform int uUseTexture;
uniform mat4 uMVMatrix;
uniform mat4 uPMatrix;
varying vec4 vColor;
varying vec2 vTextureCoord;
void main(void) {
gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);
if(uUseTexture == 1) {
vTextureCoord = aTextureCoord;
} else {
vColor = aVertexColor;
}
Nothing springs to mind immediately glancing over your code, but I'd like to take a moment and point out that this use case can be covered without needing an if statement. For example, let's treat uUseTexture as a float instead of an int (you could cast it in the shader but this is more interesting):
// Vertex
attribute vec3 aVertexPosition;
attribute vec4 aVertexColor;
attribute vec2 aTextureCoord;
uniform mat4 uMVMatrix;
uniform mat4 uPMatrix;
varying vec4 vColor;
varying vec2 vTextureCoord;
void main(void) {
gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);
// It may actually be faster to just assign both of these anyway
vTextureCoord = aTextureCoord;
vColor = aVertexColor;
}
// Fragment
uniform float uUseTexture;
uniform sampler2D uSampler;
varying vec4 vColor;
varying vec2 vTextureCoord;
void main(void) {
// vTextureCoord is already a vec2, BTW
vec4 texColor = texture2D(uSampler, vTextureCoord) * uUseTexture;
vec4 vertColor = vColor * (1.0 - uUseTexture);
gl_FragColor = texColor + vertColor;
}
Now uUseTexture simply acts as a modulator for how much of each color source you want to use. And it's more flexible in that you could set it to 0.5 and get half texture/half vertex color too!
The thing that may surprise you is that there's a good likelihood that this is what the shader compiler is doing behind the scenes anyway when you use an if statement like that. It's typically more efficient for the hardware that way.