Sign in to follow this  
Makers_F

Set some specific vertex position, interpolating it for the others

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]
/* upperVertexShader*/
/* 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

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this