Using Defold game engine and it forces textures in the atlas to be a power of 2 (384x216 -> 512x256).
Defold doesn't have support for parallax background and only options are:
Managing multiple sprite positioning with code
Manage it with shader on a single sprite.
The first option is not an elegant and optimized way to do, so I go with option Nr.2.
I have a pretty simple shader code that takes the scale and offset of the initial sprite. It works if the sprite is in size of power of 2. But I have practically no knowledge more than this, so I don't know how to tile part of the texture (original not a power of 2). I can calculate and give a uniform that has proportions vec2(384/512, 216/256).
varying mediump vec2 var_texcoord0;
uniform lowp sampler2D texture_sampler;
uniform lowp vec4 tint;
uniform lowp vec4 scale;
uniform lowp vec4 offset;
void main()
{
// Pre-multiply alpha since all runtime textures already are
lowp vec2 uv = vec2(var_texcoord0.x *scale.x +offset.x, var_texcoord0.y *scale.y +offset.y);
gl_FragColor = tint * texture2D( texture_sampler, uv);
}
I expect to get tiled background but it has empty space because of forced power of 2.
So I got help in Defold community and ended up with fragment shader like this:
varying mediump vec2 var_texcoord0;
uniform lowp sampler2D texture_sampler;
uniform lowp vec4 tint;
uniform lowp vec4 size; //actually vec2 of pecentage (x,y)
uniform lowp vec4 scale;
uniform lowp vec4 offset;
void main()
{
lowp vec2 uv = vec2(var_texcoord0.x *scale.x +offset.x, var_texcoord0.y *scale.y +offset.y);
uv = vec2(mod(uv.x, size.x), mod(uv.y, size.y));
gl_FragColor = tint * texture2D( texture_sampler, uv);
}
Related
I'm trying to change texture colors inside the GLSL context - doing so before the beginning of the OpenGL pipeline is not an option.
I have tried the following approach:
Vertex Shader
attribute highp vec2 a_TexCoord;
uniform highp mat3 u_TextureMatrix;
varying highp vec2 v_TexCoord;
highp vec4 calculatePosition();
void main()
{
gl_Position = calculatePosition();
v_TexCoord = (u_TextureMatrix * vec3(a_TexCoord,1.0)).xy;
}
attribute highp vec2 a_Vertex;
uniform highp mat3 u_TransformMatrix;
uniform highp mat3 u_ProjectionMatrix;
highp vec4 calculatePosition() {
return vec4(u_ProjectionMatrix * u_TransformMatrix * vec3(a_Vertex.xy, 1.0), 1.0);
}
Fragment Shader
uniform lowp float u_Opacity;
lowp vec4 calculatePixel();
void main()
{
gl_FragColor = calculatePixel();
gl_FragColor.a *= u_Opacity;
}
varying mediump vec2 v_TexCoord;
uniform lowp vec4 u_Color;
uniform sampler2D u_Tex0;
lowp vec4 calculatePixel() {
vec4 tex = texture2D(u_Tex0, v_TexCoord);
tex.xyz -= (100.0 / 255.0);
if (tex.x < 0.0) { tex.x += 1.0; }
if (tex.y < 0.0) { tex.y += 1.0; }
if (tex.z < 0.0) { tex.z += 1.0; }
return tex * u_Color;
}
This code works EXCEPT for the cases when Interpolation is applied (GL_LINEAR_MIPMAP_LINEAR), when things start to look really bad because the filtering happens before the Fragment Shader so I don't get to change the colors PRIOR when it's reliable to do so.
I'm developing a game that has as requirement supporting really old hardware (from as early as 2008) and that's why I'm using really obsolete GLSL code (version 120 compatible).
Is there a way to change Texture colors anywhere in the pipeline BEFORE the rasterization kicks in?
I'm very new to GLSL and started with a simple greyscale shade. I used the code of GamesFromScratch's tutorial:
vertexshader:
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;
}
Fragmentshader:
#ifdef GL_ES
precision mediump float;
#endif
varying vec4 v_color;
varying vec2 v_texCoords;
uniform sampler2D u_texture;
uniform mat4 u_projTrans;
void main() {
vec3 color = texture2D(u_texture, v_texCoords).rgb;
float gray = (color.r + color.g + color.b) / 3.0;
vec3 grayscale = vec3(gray);
gl_FragColor = vec4(grayscale, 1.0);
}
The effect and the problem: Everything is rendered in grayscale only, but transparent parts of the textures become white. For example: A simple filled circle is usually drawn as a circle. Now its a circle within a white box. Next to the removed transparent parts also changes on the alpha are not visible.
The problem is in your fragment shader. You create a vec3 color imagine (r,g,b) then you set gl_FragColor to a vec4 (r,g,b,a). Use use the first three from grayscale and then set the "a" to a hard coded alpha value of 1, removing any transparency.
You could get the rgba from the sampler and use its alpha in the final vec4.
Also if you are looking for a more true grayscale conversion the general standard is
color = 0.299 * r + 0.587 * g + 0.114 * b
https://en.wikipedia.org/wiki/Grayscale
I think these changes will help you.
vec4 color = texture2D(u_texture, v_texCoords);
float gray = dot(color.rgb, vec3(0.299, 0.587, 0.114));
gl_FragColor = vec4(grayscale, color.a);
In my changes, I read color with alpha from texture and apply it to output.
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();
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
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) );
}