2

I want to be able to (in fragment shader) add one texture to another. Right now I have projective texturing and want to expand on that.

Here is what I have so far :

Im also drawing the viewfrustum along which the blue/gray test image is projected onto the geometry that is in constant rotation.

My vertex shader:

    ProjTexCoord = ProjectorMatrix * ModelTransform * raw_pos;

My Fragment Shader:

vec4 diffuse = texture(texture1, vs_st);
vec4 projTexColor = textureProj(texture2, ProjTexCoord);
vec4 shaded = diffuse; // max(intensity * diffuse, ambient); -- no shadows for now
    if (ProjTexCoord[0] > 0.0 || 
        ProjTexCoord[1] > 0.0 ||
        ProjTexCoord[0] < ProjTexCoord[2] || 
        ProjTexCoord[1] < ProjTexCoord[2]){
        diffuse = shaded;
    }else if(dot(n, projector_aim) < 0 ){
        diffuse = projTexColor;
    }else{
        diffuse = shaded;
    }

What I want to achieve:

When for example - the user presses a button, I want the blue/gray texture to be written to the gray texture on the sphere and rotate with it. Imagine it as sort of "taking a picture" or painting on top of the sphere so that the blue/gray texture spins with the sphere after a button is pressed.

As the fragment shader operates on each pixel it should be possible to copy pixel-by-pixel from one texture to the other, but I have no clue how, I might be googling for the wrong stuff.

How can I achieve this technically? What method is most versatile? Suggestions are very much appreciated, please let me know If more code is necessary.

jozxyqk
  • 16,424
  • 12
  • 91
  • 180
mike
  • 194
  • 1
  • 2
  • 18
  • Is a frame buffer object along the lines of what you want? http://www.songho.ca/opengl/gl_fbo.html – BlamKiwi Nov 24 '14 at 22:37
  • @MorphingDragon I have never used FBO's before. So the idea is then that the FBO becomes final output texture for the sphere? sort of like a cached texture which I modify constantly? – mike Nov 24 '14 at 22:54
  • Pretty much. This would be the GPU only route anyway. – BlamKiwi Nov 24 '14 at 23:09
  • For a direct copy from texture to texture, you can use `glBlitFramebuffer()`. Otherwise, set the target texture as an FBO attachment, and render to it. – Reto Koradi Nov 25 '14 at 03:37

2 Answers2

2

Just to be clear, you'd like to bake decals into your sphere's grey texture.

The trouble with writing to the grey texture while drawing another object is it's not one to one. You may be writing twice or more to the same texel, or a single fragment may need to write to many texels in your grey texture. It may sound attractive as you already have the coordinates of everything in the one place, but I wouldn't do this.

I'd start by creating a texture containing the object space position of each texel in your grey texture. This is key, so that when you click you can render to your grey texture (using an FBO) and know where each texel is in your current view or your projective texture's view. There may be edge cases where the same bit of texture appears on multiple triangles. You could do this by rendering your sphere to the grey texture using the texture coordinates as your vertex positions. You probably need a floating point texture for this, and the following image probably isn't the sphere's texture mapping, but it'll do for demonstration :P.

enter image description here

So when you click, you render a full screen quad to your grey texture with alpha blending enabled. Using the grey texture object space positions, each fragment computes the image space position within the blue texture's projection. Discard the fragments that are outside the texture and sample/blend in those that are inside.

enter image description here

jozxyqk
  • 16,424
  • 12
  • 91
  • 180
  • I have implemented this on the CPU, the result is as follows: [Link to results](http://imgur.com/yxnPGZF) - It takes a substantial time to do so I want to implement it on the GPU. **Question:** How would I go about doing that? What I mean is: I have never worked with FBO's before and find it quite difficult to understand the concept - Do I create a whole separate vert/frag shader pipeline for the render-to-FBO? What I have is the standard glUseProgram("myShader"); /*pass uniforms etc*/ glUseProgram(0); imageProject(). Where (how) in the code do I do the FBO rendering? – mike Dec 17 '14 at 16:18
  • Oh and also, as I wasnt able to figure out the FBO rendering, I tried doing it via compute shader (which doesnt seem to work either for now): [Other Stack-question](http://stackoverflow.com/q/27494768/2579996) – mike Dec 17 '14 at 16:21
-2

I think you are overcomplicating things.

  • Writes to textures inside classic shaders (i.e. not compute shader) are only implemented for latest hardware and very latest OpenGL versions and extensions.
  • It could be terribly slow if used wrong. It's so easy to introduce pipeline stalls and CPU-GPU sync points
  • Pixel shader could become a terribly slow unmaintainable mess of branches and texture fetches.
  • And all this mess will be done for every single pixel every single frame

Solution: KISS

  • Just update your texture on CPU side.
  • Write to texture, replacing parts of it with desired content
  • Update is only need to be done once and only when you need this. Data persists until you rewrite it (not even once per frame, but only once per change request)
  • Pixel shader is dead brain simple: no branching, one texture
  • To get target pixels, implement ray-picking (you will need it anyway for any non-trivial interactive 3D-graphics program)

P.S. "Everything should be made as simple as possible, but not simpler." Albert Einstein.

Ivan Aksamentov - Drop
  • 12,860
  • 3
  • 34
  • 61
  • Writes to textures have been supported since OpenGL3, hardly the latest version and extensions. I suggest updating your answer for factual accuracy. – BlamKiwi Nov 24 '14 at 23:10
  • @Drop: Actually I am restricted to core profile 440 and above so Im not much concerned with backward capability. But, doing it on CPU side would be a bit messy too right? It seems to me I would have to do the projection CPU-side to then update the texture? I have never heard of ray-picking before, ill look it up. thanks – mike Nov 24 '14 at 23:18
  • @mike why don't you have a try at both. Getting comfortable with mixing GPU and CPU data and GPU only programming is a big plus for a 3D programmer. – BlamKiwi Nov 24 '14 at 23:24
  • @MorphingDragon We are talking about something like [`Image load/store`](https://www.opengl.org/wiki/Image_Load_Store), not about `rendering to texture`, right? – Ivan Aksamentov - Drop Nov 25 '14 at 06:08
  • @mike I think that f you have "the user presses a button" scenario (like mouse button?) than you will need to do CPU unprojection (get `raw_pos`) with any rendering method. – Ivan Aksamentov - Drop Nov 25 '14 at 06:13
  • @Drop I don't see anything about this problem that would *require* full Image load/save support. – BlamKiwi Nov 25 '14 at 09:14
  • @MorphingDragon I didn't said it is required. Reading the question I was thinking that mike asks for how to use texture load/store (maybe I was wrong here). Anyway, my solution seems to be correct and mainstream method (at least at commercial gamedev environment) of implementing desired result. – Ivan Aksamentov - Drop Nov 25 '14 at 11:07