• Create Account

FREE SOFTWARE GIVEAWAY

We have 4 x Pro Licences (valued at \$59 each) for 2d modular animation software Spriter to give away in this Thursday's GDNet Direct email newsletter.

Read more in this forum topic or make sure you're signed up (from the right-hand sidebar on the homepage) and read Thursday's newsletter to get in the running!

Set some specific vertex position, interpolating it for the others

Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

No replies to this topic

#1Makers_F  Members   -  Reputation: 820

Like
0Likes
Like

Posted 20 September 2012 - 06:26 AM

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

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


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

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

/* 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;
}


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
v_pointPosition.y = interpolatedValue(a_position.x) * (a_position.y) / (a_position.y + 0.0001);


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


The function
float offsetValue(float Xposition)

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
vec2 interpolationVertices(float vertexX)

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
left_filter = step(positionX + ERROR_LIMIT, u_specialCoordinatesPosition[0]);

will set each component to 0 for each vertex on the left of the passed X position, and to 1.0 otherwise, while
u_specialCoordinatesPosition[0] - positionX + left_filter * MIN_VALUE

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
float interpolatedValue(float vertexX)

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, 20 September 2012 - 06:31 AM.