How to Manipulate Texture Content on the Fly

OpenGL: changing texture coordinates on the fly

If you need to modify the texture coordinates frequently, but the other vertex attributes remain unchanged, it can be beneficial to keep the texture coordinates in a separate VBO. While it's generally preferable to use interleaved attributes, this is one case where that's not necessarily the most efficient solution.

So you would have two VBOs, one for the positions, and one for the texture coordinates. Your setup code will look something like this:

GLuint vboIds[2];
glGenBuffers(2, vboIds);

// Load positions.
glBindBuffer(GL_ARRAY_BUFFER, vboIds[0]);
glBufferData(GL_ARRAY_BUFFER, sizeof(positions), positions, GL_STATIC_DRAW);

// Load texture coordinates.
glBindBuffer(GL_ARRAY_BUFFER, vboIds[1]);
glBufferData(GL_ARRAY_BUFFER, sizeof(texCoords), texCoords, GL_DYNAMIC_DRAW);

Note the different last argument to glBufferData(), which is a usage hint. GL_STATIC_DRAW suggests to the OpenGL implementation that the data will not be modified on a regular basis, while GL_DYNAMIC_DRAW suggests that it will be modified frequently.

Then, anytime your texture data changes, you can modify it with glBufferSubData():

glBindBuffer(GL_ARRAY_BUFFER, vboIds[1]);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(texCoords), texCoords);

Of course if only part of them change, you would only make the call for the part that changes.

You did not specify how exactly the texture coordinates change. If it's just something like a simple transformation, it would be much more efficient to apply that transformation in the shader code, instead of modifying the original texture coordinates.

For example, say you only wanted to shift the texture coordinates. You could have a uniform variable for the shift in your vertex shader, and then add it to the incoming texture coordinate attribute:

uniform vec2 TexCoordShift;
in vec2 TexCoord;
out vec2 FragTexCoord;
...
FragTexCoord = TexCoord + TexCoordShift;

and then in your C++ code:

// Once during setup, after linking program.
TexCoordShiftLoc = glGetUniformLocation(program, "TexCoordShift");

// To change transformation, after glUseProgram(), before glDraw*().
glUniform2f(TexCoordShiftLoc, xShift, yShift);

Changing textures for specific faces on the fly in three.js

I suggest you look into screen-space AO schemes, rather than baked maps. SSAO will be far more flexible if the geometry is changing. The simplest SSAO technique is to do an unsharp mask of the scene depth, and the original paper is here: http://www.cgmi.inf.uni-konstanz.de/publikationen/2006/unsharp_masking/Luft%20et%20al.%20--%20Image%20Enhancement%20by%20Unsharp%20Masking%20the%20Depth%20Buffer.pdf it is elegant and simple enough that I coded my first copy on a flight from San Francisco to New York with time for a nap.

Updating a texture in OpenGL with glTexImage2D

In modern OpenGL there are 4 different methods to update 2D textures:

  1. glTexImage2D - the slowest one, recreates internal data structures.

  2. glTexSubImage2D - a bit faster, but can't change the parameters (size, pixel format) of the image.

  3. Render-to-texture with FBO - update texture entirely on GPU, very fast. Refer to this answer for more details: https://stackoverflow.com/a/10702468/1065190

  4. Pixel Buffer Object PBO - for fast uploads from CPU to GPU, not supported (yet) on OpenGL ES.

Writing texture data onto depth buffer

The depth buffer is more obscured than you think in OpenGL ES; not only is glDrawPixels absent but gl_FragDepth has been removed from GLSL. So you can't write a custom fragment shader to spool values to the depth buffer as you might push colours.

The most obvious solution is to pack your depth information into a texture and to use a custom fragment shader that does a depth comparison between the fragment it generates and one looked up from a texture you supply. Only if the generated fragment is closer is it allowed to proceed. The normal depth buffer will catch other cases of occlusion and — in principle — you could use a framebuffer object to create the depth texture in the first place, giving you a complete on-GPU round trip, though it isn't directly relevant to your problem.

Disadvantages are that drawing will cost you an extra texture unit and textures use integer components.

EDIT: for the purposes of keeping the example simple, suppose you were packing all of your depth information into the red channel of a texture. That'd give you a really low precision depth buffer, but just to keep things clear, you could write a quick fragment shader like:

void main()
{
// write a value to the depth map
gl_FragColor = vec4(gl_FragCoord.w, 0.0, 0.0, 1.0);
}

To store depth in the red channel. So you've partially recreated the old depth texture extension — you'll have an image that has a brighter red in pixels that are closer, a darker red in pixels that are further away. I think that in your question, you'd actually load this image from disk.

To then use the texture in a future fragment shader, you'd do something like:

uniform sampler2D depthMap;

void main()
{
// read a value from the depth map
lowp vec3 colourFromDepthMap = texture2D(depthMap, gl_FragCoord.xy);

// discard the current fragment if it is less close than the stored value
if(colourFromDepthMap.r > gl_FragCoord.w) discard;

... set gl_FragColor appropriately otherwise ...
}

EDIT2: you can see a much smarter mapping from depth to an RGBA value here. To tie in directly to that document, OES_depth_texture definitely isn't supported on the iPad or on the third generation iPhone. I've not run a complete test elsewhere.

How do I change the texture of a GLTF model dynamically?

Once you’ve loaded a model in A-Frame or three.js, it doesn’t matter much what format it was before1. For A-Frame, you can use JS to modify the model after it loads.

var tex = new THREE.TextureLoader().load('diffuse.png');
tex.flipY = false; // for glTF models.

el.addEventListener('model-loaded', function (e {
e.detail.model.traverse(function(node) {
if (node.isMesh) node.material.map = tex;
});
});

See docs on THREE.MeshStandardMaterial to learn what properties there are to edit, although this could vary depending on the model you’re loading.

1 One exception is the tex.flipY=false setting above — you'll (probably) only need that for glTF, where the UVs have a different orientation than the three.js default.

Modify part of a Texture Map that is in use in OpenGL ES 2.0

the thread is not the same

OpenGL-ES API is absolutely not multi-threaded. Update your texture from main thread.
Because your texture must be uploaded on gpu, glTextSubImage2D is the fastest and simplest path. Keep this direction :)

Render on a Frame Buffer (attached on your texture) is very fast for rendering data which are already on gpu. (not your case). And yes you can draw on a frame buffer bound to a texture (= a frame buffer which use the texture as color attachment).

Just one contrain: You can't read and write the same texture in one draw call (The texture attached to the current frame buffer can't be bound to a texture unit)



Related Topics



Leave a reply



Submit