OpenGL ES 2.0纹理拉扯偏移效果实现故障排查与方案求助
Let's break down what's going wrong with your current code and how to adjust it to get the desired pulling/stretching effect:
Key Issues in Your Current Implementation
- Mesh Isn't Actually Deforming: Your vertex shader sets
gl_Position = opos;(the original MVP result), which means the mesh stays in its original position—you're just shifting the texture over a static mesh, which causes the double-texture overlap you're seeing. - Incorrect Shifting Space: The
v_ShiftingFactoris calculated using clip-space coordinates (from MVP matrices), which range from -1 to 1. Adding these values directly to texture coordinates (0-1) results in extreme, incorrect offsets. - Fragment Shader Logic Causes Overlap: The
else ifbranch displays the original texture wherever the shifted texture is transparent, leading to two overlapping textures instead of a smooth pulled effect.
Step-by-Step Fixes
1. Update the Vertex Shader to Render the Deformed Mesh
First, make sure the mesh is drawn in its deformed position by setting gl_Position to the result of your translated MVP matrix. We'll also calculate the texture offset in a space that maps correctly to your texture coordinates.
Instead of using clip-space differences, let's use a translation uniform (simpler for pulling effects) and scale it to match your texture's mapping:
uniform mat4 u_MVPMatrix; // Deformed MVP matrix (with translation/stretch) uniform vec3 u_Translation; // The amount your mesh is being pulled/moved uniform vec2 u_TexScale; // Scales world-space translation to texture space (adjust based on your mesh/texture size) attribute vec4 a_Position; attribute vec2 a_TexCoordinate; varying vec2 v_TexCoordinate; varying vec2 v_TexOffset; void main() { // Render the mesh in its deformed position gl_Position = u_MVPMatrix * a_Position; v_TexCoordinate = a_TexCoordinate; // Convert world-space translation to texture-space offset v_TexOffset = u_Translation.xy * u_TexScale; }
Note: Adjust u_TexScale based on your mesh and texture size. For example, if your mesh is 2 units wide and your texture covers the entire mesh (UVs 0-1), set u_TexScale to vec2(0.5, 0.5) so 1 unit of world movement equals 0.5 units of texture movement.
2. Simplify the Fragment Shader for Smooth Pulling
Remove the logic that displays the original texture—instead, sample the shifted texture directly and discard transparent fragments to avoid overlap:
precision highp float; uniform sampler2D u_Texture; varying vec2 v_TexCoordinate; varying vec2 v_TexOffset; void main() { // Calculate the shifted texture coordinate vec2 shiftedTexCoord = v_TexCoordinate + v_TexOffset; vec4 texColor = texture2D(u_Texture, shiftedTexCoord); // Discard transparent fragments to avoid rendering empty areas if (texColor.a <= 0.0) { discard; } gl_FragColor = texColor; }
3. Adjust Texture Wrap Settings
To ensure new parts of your ocean texture are revealed when the rock mask is pulled, set your texture's wrap mode to:
GL_REPEATif your ocean texture is tiled (repeats seamlessly)GL_CLAMP_TO_EDGEif it's a single large texture (clamps to the edge instead of repeating)
Additional Tips for More Dynamic Pulling
If you want a more natural stretch (where vertices further from the pull point shift more), replace the u_Translation uniform with a calculation based on the vertex's position relative to the pull origin. For example:
uniform vec3 u_PullOrigin; // World-space origin of the pull uniform float u_PullStrength; // How strong the pull is uniform mat4 u_ModelMatrix; // Model matrix for converting vertex to world space // In vertex shader: vec3 worldPos = (u_ModelMatrix * a_Position).xyz; float distanceToPull = distance(worldPos, u_PullOrigin); vec3 pullDirection = normalize(worldPos - u_PullOrigin); v_TexOffset = (pullDirection * distanceToPull * u_PullStrength).xy * u_TexScale;
This will create a radial stretch effect, pulling texture coordinates more strongly for vertices farther from the pull point.
内容的提问来源于stack exchange,提问作者Syed Usama Ahmad

