# Set some specific vertex position, interpolating it for the others

This topic is 1948 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

I have a mesh composed by numerous vertices (600 ± 300 ).

The vertices are simply disposed on 2 parallel line, so that every vertices on a line have the y component equal to the other(they practically are along the sides of a rectangle orthogonal to the screen).
I'm working in a 2D world.

I'm trying to position some vertices in specific points i pass to the shader, and make the other vertices interpolate their position from them.
I generate in my code this matrix

[CODE]
u_specialCoordinatesLocation = {
x1, x2, x3, x4,
y1, y2, y3, y4,
x5, x6, x7, x8,
y5, y6, y7, y8 };
[/CODE]

and pass it to the shader as an uniform (transposing it).

This is the code of the shader. Below i explain it.

[CODE]
/* externally defined:
* QUALITY_CODE
* SCREEN_WIDTH
* SCREEN_HEIGHT
*/

uniform mat4 u_modelViewProjectionMatrix;
uniform vec2 u_playerPosition;
uniform float u_elapsedSeconds;
/*
* mat4 = {
* {x1, x2, x3, x4},
* {y1, y2, y3, y4},
* {x5, ...},
* {}}
*/

uniform mat4 u_specialCoordinatesPosition;

attribute vec4 a_position;
attribute vec2 a_textureCoordinates;

varying vec2 v_textureCoordinates;
varying vec2 v_playerPosition;
varying vec2 v_pointPosition;

const float ERROR_LIMIT = 0.01;
const float MIN_VALUE = -2e6;
const float MAX_VALUE = 2e6;

float linearInterp(float n0, float n1, float a) {
return ((1.0 - a) * n0) + (a * n1);
}

float scurve5(float a) {
float a3 = a*a*a;
float a4 = a3 * a;
float a5 = a4 * a;
return (6.0 * a5) - (15.0 * a4) + (10.0 * a3);
}

float min4fv(vec4 vector) {
return min(min(vector.x, vector.y),min(vector.z, vector.w));
}

float max4fv(vec4 vector) {
return max(max(vector.x, vector.y),max(vector.z, vector.w));
}

/* only return the correct value to offset the vertex if the vertex is one of the ones in the uniform, 0.f otherwise*/
float offsetValue(float Xposition) {
float offSet = 0.0;
vec4 tmp_vector4;
vec4 positionX = vec4(Xposition);

// first row
// 1.0 if positionX is almost equal to the one specified in the uniform
tmp_vector4 = 1.0 - step(ERROR_LIMIT, abs(u_specialCoordinatesPosition[0] - positionX));
tmp_vector4 = tmp_vector4 * u_specialCoordinatesPosition[1];
offSet += tmp_vector4.x + tmp_vector4.y + tmp_vector4.z + tmp_vector4.w;

// second row
tmp_vector4 = 1.0 - step(ERROR_LIMIT, abs(u_specialCoordinatesPosition[2] - positionX));
tmp_vector4 = tmp_vector4 * u_specialCoordinatesPosition[3];
offSet += tmp_vector4.x + tmp_vector4.y + tmp_vector4.z + tmp_vector4.w;

return offSet;
}

vec2 interpolationVertices(float vertexX) {
/* .x = left distance
* .y = right distance
*/
vec2 distances;

/* 0 if at the left of the vertex, else 1*/
vec4 left_filter;
/* 1 if at the left of the vertex, else 0*/
vec4 right_filter;

vec4 positionX = vec4(vertexX);
/* First row*/
left_filter = step(positionX + ERROR_LIMIT, u_specialCoordinatesPosition[0]);
// grants that the vertices at the right of the point will not count, by adding only to them a very negative number
distances.x = max4fv(u_specialCoordinatesPosition[0] - positionX + left_filter * MIN_VALUE);

right_filter = 1.0 - step(positionX - ERROR_LIMIT, u_specialCoordinatesPosition[0]);
// grants that the vertices at the left of the point will not count, by adding only to them a very positive number
distances.y = min4fv(u_specialCoordinatesPosition[0] - positionX + left_filter * MAX_VALUE);

/* Second row*/
left_filter = step(positionX + ERROR_LIMIT, u_specialCoordinatesPosition[2]);
// grants that the vertices at the right of the point will not count, by adding only to them a very negative number
distances.x = max(distances.x, max4fv(u_specialCoordinatesPosition[2] - positionX + left_filter * MIN_VALUE));

right_filter = 1.0 - step(positionX - ERROR_LIMIT, u_specialCoordinatesPosition[2]);
// grants that the vertices at the left of the point will not count, by adding only to them a very positive number
distances.y = min(distances.y , min4fv(u_specialCoordinatesPosition[2] - positionX + left_filter * MAX_VALUE));

return distances;
}

float interpolatedValue(float vertexX) {
vec2 interpVertices = interpolationVertices(vertexX);
vec2 interpValue = vec2(offsetValue(vertexX + interpVertices.x), offsetValue(vertexX + interpVertices.y));
float int_value = scurve5(abs((vertexX - interpVertices.x) / (interpVertices.y - interpVertices.x)));
return linearInterp(interpValue.x, interpValue.y, int_value);
}

void main(void)
{
v_textureCoordinates = a_textureCoordinates;
v_playerPosition = u_playerPosition;
v_pointPosition = a_position.xy;
v_pointPosition.y += interpolatedValue(a_position.x) * (a_position.y) / (a_position.y + 0.0001);
vec4 temp_position = u_modelViewProjectionMatrix * vec4(v_pointPosition, a_position.z, a_position.w);
gl_Position = temp_position;
}
[/CODE]

The vertices y position in the VBO have only 2 different values: 0, or another fixed value (SCREEN_HEIGHT/3).
The vertices that have position.y = 0 shouldn't be moved, so
[CODE]
v_pointPosition.y = interpolatedValue(a_position.x) * (a_position.y) / (a_position.y + 0.0001);
[/CODE]

is equal 0 if a_position.y is 0, else is almost equal
[CODE]
v_pointPosition.y = interpolatedValue(a_position.x);
[/CODE]

The function
[CODE]float offsetValue(float Xposition)[/CODE]

should find the value of the Ya in the u_specialCoordinateLocation when passed Xa, 0 otherwise.
The 1.0 - step function is used in order to only account for the correct value each time (since only if the passed vertices distance from the Xa is less than ERROR_LIMIT it will be set to 1.0 and then multiplied by the Ya value)

The function
[CODE]vec2 interpolationVertices(float vertexX)[/CODE]

should find the Xa and Xb value of the 2 vertices inside the u_specialCoordinateLocation matrix that are nearest to the passed x coordinate.
This is achived by calculating the max of the distance from the left (that should be negative) without taking into account the values bigger than 0
In fact
[CODE]
left_filter = step(positionX + ERROR_LIMIT, u_specialCoordinatesPosition[0]);
[/CODE]
will set each component to 0 for each vertex on the left of the passed X position, and to 1.0 otherwise, while
[CODE]
u_specialCoordinatesPosition[0] - positionX + left_filter * MIN_VALUE
[/CODE]
will subtract a big value if the filter component is set to 1, thus making impossible to vertices at the right of the position X to contribute once this value is passed to max4fv()

The same is done for the right distance, and then the 2 X coordinates of the 2 vertices are returned.

Finally
[CODE]
float interpolatedValue(float vertexX)
[/CODE]
find the 2 vertices "bounding" the passed vertex, retrieve their values, interpolate between them, and return the new position.

I think everything should work, but when i test it on my phone the mesh doesn't show up.
What i'm doing wrong?
Is there a better way of doing it, i must admit that my code isn't really stright forward, and i wish there is a more elegant way?
What do you suggest? (rebuilding the VBO on the cpu and streaming is not a viable option since i would need to do it every frame for 2 meshes of this kind)

Thanks for the help and the patience Edited by Makers_F