In my shader I already have a special variable that has the entire content of previously rendered screen. It is stored in
uniform sampler2D _GrabTexture;
Which it's content should be:
(As a side note, I'm using Unity's GrabPass{} to get the entire screen. Also please ignore Unity's GUI)
Now how can I render one more pass, using _GrabTexture as a texture for my plane model, so the result is exactly the same as my _GrabTexture?
(The point is, I can apply some effects like blur,sharpen,etc to that screen texture before render one more pass so the plane's texture is now stylized.)
I'm trying this in the final pass. The variable is declared in both Vertex & Fragment Shader.
uniform sampler2D _GrabTexture;
varying vec4 v_Position;
Vertex Shader :
void main()
{
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
v_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
}
Store the screen coordinate of each model's vertex as varying, to be used in Fragment Shader.
Fragment Shader :
void main()
{
gl_FragColor = texture2D(_GrabTexture,vec2(v_Position));
}
Now use that stored varying position to access the _GrabTexture screen texture. Since it's entire screen my v_Position which is already in screen coordinate should correctly got the right pixel.
But the result is
As you can see the plane's texture is 'sorts of' showing previously rendered screen but the coordinate is not right. How can I fix it so the result is the same as first image?
You're thinking too complicated. OpenGL tells you the on-screen fragment position in the fragment shader built in variable gl_FragCoord.
With GLSL-1.30 or newer you have texelFetch which you can give gl_FragCoord as source coordinate directly. Or you use translate gl_FragCoord into texture space coordinates, see https://stackoverflow.com/a/5879551/524368
Related
I have the following very basic shaders.
Vertex shader:
attribute vec4 a_foo;
varying vec4 v_foo;
void main()
{
v_foo = a_foo;
gl_Position = a_foo;
}
Fragment shader:
varying vec4 v_foo;
uniform sampler2D u_texture;
void main()
{
gl_FragColor = texture2D(u_texture, v_foo.xy);
}
The attribute a_foo I provide as a vector for each point. It is passed to the fragment shader as v_foo.
When my mesh consists of only single points (GL_POINTS) it is clear that I can expect v_foo to match a_foo. But what happens in case of having a triangle (GL_TRIANGLES) consisting of three points, when I have much more fragments (texels?) than points?
Will a_foo get interpolated for fragments between the fragments of the points?
Does this happen for all types of varying that I can pass between vertex and fragment shader?
Each primitive is rasterized so every "visible" (not clipped) pixel of your triangle will invoke a fragment shader and pass values interpolated (because you used varying) from the 3 triangle control points based on fragment relative position to the 3 control points.
The interpolation might be linear or perspective corrected linear depends on your OpenGL pipeline settings.
For more info about rasterization of convex polygons see:
how to rasterize rotated rectangle in 2d
However gfx cards use barycentric coordinates and test all pixels inside BBOX if inside polygon or not by simple winding rule test to take advantage of parallelism...
how do you make a cube with a texture mapped, display a different texture inside and outside?
By mapping the texture in the cube, I see both from without and from within the cube the same texture and I need to be different textures.
Working with OpenGL 3.3 or higher and C ++.
Render the cube twice, the second time around with a different texture and the opposite glFrontFace().
There is a built-in gl_FrontFacing variable in the fragment shader, which allows you to test if the currently rendered triangle is front facing. You can use a different texture depending on this value. The relevant pieces of the fragment shader can look like this:
uniform sampler2D FrontTex;
uniform sampler2D BackTex;
in vec2 TexCoord;
out FragColor;
void main() {
if (gl_FrontFacing) {
FragColor = texture(FrontTex, TexCoord);
} else {
FragColor = texture(BackTex, TexCoord);
}
}
In your C++ code, you bind the two textures to different texture units, and set the sampler uniforms accordingly.
I am using GLSL to render a basic cube (made from GL_QUADS surfaces). I would like to pass the gl_Vertex content from the vertex into the fragment shader. Everything works, if I am using gl_FrontColor (vertex shader) and gl_Color (fragment shader) for this, but it doesn't work, when using a plain varying (see code & image below). It appears the varying is not interpolated across the surface for some reason. Any idea what could cause this in OpenGL ?
glShadeModel is set to GL_SMOOTH - I can't think of anything else that could cause this effect right now.
Vertex Shader:
#version 120
varying vec4 frontSideValue;
void main() {
frontSideValue = gl_Vertex;
gl_Position = transformPos;
}
Fragment Shader:
#version 120
varying vec4 frontSideValue;
void main() {
gl_FragColor = frontSideValue;
}
The result looks just like you are not using values in the range [0,1] for the color vector. You basically use the untransformed vertex position, which might be well outside this range. Your cube seems centered around the origin, so you are seeing the small transition where the values are actually in the range [0,1] as that unsharp band.
With the builin gl_FrontColor, the value seems to get clamped before the interpolation.
I have written a fragment shader which i would like to change the color of the fragment. for example I would like if the color it receives is black then it should change it to a blue.
This is the shader that I am using:
uniform sampler2D mytex;
layout (pixel_center_integer) in vec4 gl_FragCoord;
uniform sampler2D texture1;
void main ()
{
ivec2 screenpos = ivec2 (gl_FragCoord.xy);
vec4 color = texelFetch (mytex, screenpos, 0);
if (color == vec4 (0.0,0.0,0.0,1.0)) {
color = (0.0,0.0,0.0,0.0);
}
gl_FragColor = texture2D (texture1, gl_TexCoord[0].st);
}
And here is the log that I am getting from it:
WARNING: -1:65535: 'GL_ARB_explicit_attrib_location' : extension is not available in current GLSL version
WARNING: 0:1: 'texelFetch' : function is not available in current GLSL version
I am aware of the warning- but shouldn't it compile anyways?
The shader is not doing what i would like it to do, can someone explain why?
For one thing, you are using functions that are not available in your GLSL implementation. The result of calling these will be undefined.
However, the kicker here is that gl_FragColor has absolutely NOTHING to do with the value of color in this shader. So even if your texelFetch (...) logic actually did work correctly, changing the value of color does nothing to the final output. A smart compiler will see this as a no-op and effectively strip your shader down to this:
uniform sampler2D texture1;
void main ()
{
gl_FragColor = texture2D (texture1, gl_TexCoord[0].st);
}
If that were not enough, texelFetch (...) is completely unnecessary in this shader. If you want to lookup the texel that corresponds to the current fragment in your shader and the texture has the same dimensions as the viewport you are drawing into you can actually use texture2D (texture1, gl_FragCoord.xy); This is because the default behaviour in GLSL is to have gl_FragCoord supply the coordinate of the fragment's center (x+0.5, y+0.5) - this is also the center of the corresponding texel in your texture (if it is the same resolution), so you can do a traditional texture lookup without worrying that texture filtering will alter your sampled result.
texelFetch (...) lets you fetch an explicit texel in a texture without using normalized coordinates, it is sort of like a "grownup" rectangle texture :) It is generally useful if you are using a multisample texture and want a specific sample, or if you want to bypass texture filtering (which includes mipmap level selection). In this case, it is not needed at all.
This is probably what you really want (OpenGL 3.2):
#version 150
uniform sampler2D mytex;
uniform sampler2D texture1;
layout (location=0) out vec4 frag_color;
layout (location=1) out vec4 mytex_color;
void main ()
{
mytex_color = texture2D (mytex, gl_FragCoord.xy);
// This is not black->blue like you explained in your question...
// ... This is generally opaque->transparent, assuming 4th component = alpha
if (mytex_color == vec4 (0.0,0.0,0.0,1.0)) {
mytex_color = vec4 (0.0);
}
frag_color = texture2D (texture1, gl_TexCoord[0].st);
}
In older GLSL versions, you will have to use glBindFragDataLocation (...) and set the data locations manually or use gl_FragData[n] instead of out variables.
Now the real problem here is that you seem to be wanting to change the color of the texture you are sampling from. That will not work, at best you will have to use two fragment data outputs. Writing into the same texture you are sampling from can be done under some very controlled circumstances, but generally what you would do is ping-pong between textures. In other words, you would fetch from one texture, write to another texture and all subsequent render passes that reference to the original texture should be swapped with the one you just wrote to.
See "Fragment Data Location" for more information on Multiple Render Target drawing.
I am learning WebGL, and would like to do the following:
Create a 3D quad with a square hole in it using a fragment shader.
It looks like I need to set gl_FragColor based on gl_FragCoord appropriately.
So should I:
a) Convert gl_FragCoord from window coordinates to model coordinates, do the appropriate geometry check, and set color.
OR
b) Somehow pass the hole information from the vertex shader to the fragment shader. Maybe use a texture coordinate. I am not clear on this part.
I am fuzzy about implementing either of the above, so I'd appreaciate some coding hints on either.
My background is that of an OpenGL old timer who has not kept up with the new shading language paradigm, and is now trying to catch up...
Edit (27/03/2011):
I have been able to successfully implement the above based on the tex coord hint. I've written up this example at the link below:
Quads with holes - example
The easiest way would be with texture coords. Simply supply the corrds as an extra attribute array then pass through to the fragment shader using a varying. The shaders should contain something like:
vertex:
attribute vec3 aPosition;
attribute vec2 aTexCoord;
varying vec2 vTexCoord;
void main(){
vTexCoord=aTexCoord;
.......
}
fragment:
varying vec2 vTexCoord;
void main(){
if(vTexCoord.x>{lower x limit} && vTexCoord.x<{upper x limit} && vTexCoord.y>{lower y limit} && vTexCoord.y<{upper y limit}){
discard; //this tell GFX to discard this fragment entirly
}
.....
}