Custom matrices & OpenGL shaders. - c++

I am trying to make a simple 4x4 matrix class.
The data (float) is a single dimension array, and I use this code to store numbers as if it were a grid.
const inline int ind1(short x, short y) { // Convert coords to spot on linear array, uses SIZE
return x * (SIZE >> 2) + y;
}
This part is in the .h file
float *data;
These are in the .cpp
Mat::Mat() {
define();
diagDefine(1.0f);
}
void Mat::define() {
data = new float[SIZE];
for (int x = 0; x < SIZE >> 2; x++) {
for (int y = 0; y < SIZE >> 2; y++) {
data[ind1(x, y)] = 0;
}
}
}
void Mat::diagDefine(float nval) {
data[ind1(0, 0)] = nval;
data[ind1(1, 1)] = nval;
data[ind1(2, 2)] = nval;
data[ind1(3, 3)] = nval;
}
The problem is that when I try to multiply the matrix to my position in the vertex shader, the triangle or whatever I am drawing disappears.
My class has orthographic, perspective, translation, rotation, and scaling.
Mat Mat::getOrthographic(float left, float right, float top, float bottom, float near, float far) {
Mat newmat;
newmat.data[ind1(0, 0)] = 2.0f / (right - left);
newmat.data[ind1(1, 1)] = 2.0f / (top - bottom);
newmat.data[ind1(2, 2)] = 2.0f / (near - far);
newmat.data[ind1(0, 3)] = (left + right) / (left - right);
newmat.data[ind1(1, 3)] = (bottom + top) / (bottom - top);
newmat.data[ind1(2, 3)] = (far + near) / (far - near);
return newmat;
}
Mat Mat::getPerspective(float fov, float aspectratio, float near, float far) {
Mat newmat;
newmat.data[ind1(0, 0)] = (1.0f / tan((0.5f * fov) * (3.141519 / 180.0f))) / aspectratio;
newmat.data[ind1(1, 1)] = 1.0f / tan((0.5f * fov) * (3.141519 / 180.0f));
newmat.data[ind1(2, 2)] = (near + far) / (near - far);
newmat.data[ind1(3, 2)] = -1.0f;
newmat.data[ind1(2, 3)] = (2.0f * near * far) / (near - far);
return newmat;
}
Mat Mat::getTranslation(Vec3f &vec) {
Mat newmat;
newmat.data[ind1(0, 3)] = vec.x;
newmat.data[ind1(1, 3)] = vec.y;
newmat.data[ind1(2, 3)] = vec.z;
return newmat;
}
Mat Mat::getRotation(double angle, Vec3f &vec) {
Mat newmat;
float s = sin(angle);
float c = cos(angle);
newmat.data[ind1(0, 0)] = vec.x * (1.0f - c) + c;
newmat.data[ind1(1, 0)] = vec.y * vec.x * (1.0f - c) + vec.z * s;
newmat.data[ind1(2, 0)] = vec.x * vec.z * (1.0f - c) - vec.y * s;
newmat.data[ind1(0, 1)] = vec.x * vec.y * (1.0f - c) - vec.z * s;
newmat.data[ind1(1, 1)] = vec.y * (1.0f - c) + c;
newmat.data[ind1(2, 1)] = vec.y * vec.z * (1.0f - c) + vec.x * s;
newmat.data[ind1(0, 2)] = vec.x * vec.z * (1.0f - c) + vec.y * s;
newmat.data[ind1(1, 2)] = vec.y * vec.z * (1.0f - c) - vec.x * s;
newmat.data[ind1(2, 2)] = vec.z * (1.0f - c) + c;
return newmat;
}
Mat Mat::getScale(Vec3f &vec) {
Mat newmat;
newmat.data[ind1(0, 0)] = vec.x;
newmat.data[ind1(1, 1)] = vec.y;
newmat.data[ind1(2, 2)] = vec.z;
return newmat;
}
Vertex code
#version 330
layout(location = 0) in vec3 pos;
uniform mat4 view_mat;
void main() {
gl_Position = view_mat * vec4(pos, 1.0);
}
Finally, here is how I send the data to the shader.
// In the matrix file
float *getRawDataAsArray() { return data; }
// In the shader.h file
void Shader::GL_SET_UNIFORM_MATRIX(const char *name, Mat matrix) {
GLint location = glGetUniformLocation(program, name);
if(location != -1) {
glUniformMatrix4x2fv(location, 1, GL_FALSE, matrix.getRawDataAsArray());
}
}
// In the main.cpp (sh is shader object that contained the GET_UNIFORM_MATRIX
sh.GL_SET_UNIFORM_MATRIX("view_mat", sod2::Mat::getRotation(3.141519 / 2, 0, 0, 1));
sh.GL_SET_UNIFORM_4f("color", 0.0, 1.0, 0.0, 1.0);
Final note: My shaders do compile perfectly. When I run it without anything to do with matrices it works perfectly. (Dealing with color or modifying position).
Thanks

There are 2 issues in your code:
You use the wrong glUniform* function to set the view_mat uniform in your function Shader::GL_SET_UNIFORM_MATRIX. While glUniformMatrix4fv commits 16 floats for a 4*4* matrix, glUniformMatrix4x2fv commits 8 floats for a 4*2 matrix. See glUniform.
Further See The OpenGL Shading Language 4.6, 5.4.2 Vector and Matrix Constructors, page 101:
To initialize a matrix by specifying vectors or scalars, the components are assigned to the matrix elements in column-major order.
mat4(float, float, float, float, // first column
float, float, float, float, // second column
float, float, float, float, // third column
float, float, float, float); // fourth column
But your matrix is set up in row-major order:
const inline int ind1(short x, short y) {
return x * (SIZE >> 2) + y;
}
Either the ind1 function has to be changed to fix this issue:
const inline int ind1(short x, short y) {
return y * (SIZE >> 2) + x;
}
Or the matrix has to be transposed, when it is set to the uniform variable:
glUniformMatrix4fv(
location,
1,
GL_TRUE, // <----------------- transpose
matrix.getRawDataAsArray());
Or the vector has to be multiplied to the matrix from the left:
gl_Position = vec4(pos, 1.0) * view_mat;

Related

rotating bone with quaternion issue

I need to rotate bones of skeleton, i have already the quaterinion corresponding for each joints; and i am confused when it comes on rotating.
Skeleton to move is my opengl scene i need to move.
My problem is that i can't rotate the joint; Can anyone Help
Bellow is my code
//i evaluate each joint to get the translation and rotation.
void Node::EvaluatePoi(std::vector<POI> pois, const Vector &par_pos,
const Quaternion &par_rot, Vector Node::*world_pos,std::vector<Arti> joints)
{ Vector poi=this->PoiVec ;
Quaternion rot;
if (pois.empty()){
this->*world_pos= this->rest_position ;//OFFSET
rot= this-> rest_rotation ;//identity
}else{
if(this->name=="Hips")
{
this->*world_pos = eval_instant_positionPOI(poi);
rot= this-> rest_rotation ;// do not rotate
}else if(this->name=="LeftUpLeg")
{
this->*world_pos = this->rest_position;// set to OFFSET
rot= this-> rest_rotation ;// do not rotate
}else if(this->name=="RightUpLeg")
{
this->*world_pos = this->rest_position;
rot= this-> rest_rotation ;
}
else
{
this->*world_pos= this->rest_position;
rot= eval_instant_rotationPOI(joints);
}
}
//Applying transformation on the global position with rot =qparent * qchild
(this->*world_pos).rotate(par_rot);
this->*world_pos += par_pos;
rot = par_rot * rot;
// draw joint's subhierarchy
for (int i = 0; i < n_children; i++)
child[i]->EvaluatePoi(pois, this->*world_pos, rot, world_pos,joints);
}
EDIT:
//here i get the local rotation of each joint, after that create quaternions equivalent to individual Euler rotations and then compose to one rotation
Vector x_vector(1.0, 0.0, 0.0),
y_vector(0.0, 1.0, 0.0),
z_vector(0.0, 0.0, 1.0);
Quaternion Node::eval_instant_rotationPOI( std::vector<Arti> joints)
{
Quaternion roto;//= new Quaternion();
Quaternion sample;
double t= 0.02;
Vector v;
Vector Euler(0,0,0);;
string x =this->name;
if(x== "Head"){
Euler=GetEulers(joints,JOINT_HEAD);
}else if(x== "Neck"){
Euler=GetEulers(joints,JOINT_NECK);
}
else if(x== "LeftUpArm"){
Euler=GetEulers(joints,JOINT_LEFT_SHOULDER);
}
else if(x== "RightUpArm"){
Euler=GetEulers(joints,JOINT_RIGHT_SHOULDER);
}
else if(x== "LeftLowArm"){
Euler=GetEulers(joints,JOINT_LEFT_ELBOW);
}
else if(x== "LeftHand"){
Euler=GetEulers(joints,JOINT_LEFT_HAND);
}
else if(x== "RightLowArm"){
Euler=GetEulers(joints,JOINT_RIGHT_ELBOW);
}
else if(x== "RightHand"){
Euler=GetEulers(joints,JOINT_RIGHT_HAND);
}
else if(x== "Hips"){
Euler=GetEulers(joints,JOINT_TORSO);
}
else if(x== "LeftUpLeg"){
Euler=GetEulers(joints,JOINT_LEFT_HIP);
}
else if(x== "RightUpLeg"){
Euler=GetEulers(joints,JOINT_RIGHT_HIP);
}
else if(x== "LeftLowLeg"){
Euler=GetEulers(joints,JOINT_LEFT_KNEE);
}
else if(x== "LeftFoot"){
Euler=GetEulers(joints,JOINT_LEFT_FOOT);
}
else if(x== "RightLowLeg"){
Euler=GetEulers(joints,JOINT_RIGHT_KNEE);
}
else if(x== "RightFoot"){
Euler=GetEulers(joints,JOINT_RIGHT_FOOT);
}
Quaternion qx(x_vector, (Euler.x ));
Quaternion qy(y_vector, (Euler.y ));
Quaternion qz(z_vector, (Euler.z ));
sample = qz * qy * qx;
roto= slerp(qTemp, sample, t);
qTemp=roto;
return roto ;
}
/*here i multiply the joint and its parent to get the Euler Angle ; is it necessary to convert to
Euler Angle?/
Vector Node::GetEulers(std::vector<Arti> joints, const int idx) {
// Get the quaternion of its parent.
Quaternion q_parent;
Quaternion q_current;
if (idx == JOINT_TORSO) {
q_parent.identity();
}
/////
{
q_parent = Quaternion(joints[parent_joint_map[idx]].quat.x,
joints[parent_joint_map[idx]].quat.y,
joints[parent_joint_map[idx]].quat.z,
joints[parent_joint_map[idx]].quat.w);
}
// Get the quaternion of the joint.
q_current = Quaternion(joints[idx].quat.x, joints[idx].quat.y,
joints[idx].quat.z, joints[idx].quat.w);
// Calculate the relative quaternion.
Quaternion q_delta = quat_left_multiply(q_current , quat_inverse(q_parent));
Vector angle = euler_from_quat(q_delta);
// cout<<this->name<<" "<<angle<<" ";
return angle;
}
Quaternion quat_left_multiply(Quaternion l, Quaternion r) {
Quaternion q = {r.w * l.x + r.x * l.w + r.y * l.z - r.z * l.y,
r.w * l.y + r.y * l.w + r.z * l.x - r.x * l.z,
r.w * l.z + r.z * l.w + r.x * l.y - r.y * l.x,
r.w * l.w - r.x * l.x - r.y * l.y - r.z * l.z};
return q;
}
Vector& Vector::rotate(const Quaternion& q)
{
Quaternion p(x, y, z, 0.0f);
Quaternion qc(q);
qc.conjugate();
Quaternion pp(q * p * qc);
x = pp.x;
y = pp.y;
z = pp.z;
return *this;
}
Rotating a quaternion is actually multiplying a quaternion by another. Given the quaternion qA representing the current rotation of an object and qB the quaternion representing the amount of rotation to apply (to add) to this object, the resulting new rotation of this object is computed as follow (pseudocode):
qA = qA * qB;
Alternatively, you can apply (add) this rotation in what is called "object" or "local" transformation space by swapping operands:
qA = qB * qA
Each joint should hold (usualy as class member) a quaternion representing its current rotation in local space. This is probably what you already done. If you want to apply a rotation to that joint, then you simply need multiply the joint quaternion, by another quaternion representing the amount of rotation to apply. A quaterion rotation method can be like this (pseudocode):
Joint::Rotate(const quaterion& amount, bool local)
{
if(local) {
this->rotation = amount * this->rotation;
} else {
this->rotation = this->rotation * amount;
}
this->rotation.normalize();
}
That is all you need for the rotation part, nothing else. After that, you will need to convert the joint quaternion to a rotation matrix, so to be combined with the other joint transformations (translation, scale, whatever). Here is one implementation of the quaternion to rotation matrix conversion (pseudocode):
Matrix3 QuaternionToMatrix(const quaternion& q)
{
float x2 = q.x + q.x;
float y2 = q.y + q.y;
float z2 = q.z + q.z;
float xx = q.x * x2;
float xy = q.x * y2;
float xz = q.x * z2;
float yy = q.y * y2;
float yz = q.y * z2;
float zz = q.z * z2;
float wx = q.w * x2;
float wy = q.w * y2;
float wz = q.w * z2;
Matrix3 m; //< 3x3 matrix
m[0] = (1.0f - (yy + zz));
m[1] = (xy - wz);
m[2] = (xz + wy);
m[3] = (xy + wz);
m[4] = (1.0f - (xx + zz));
m[5] = (yz - wx);
m[6] = (xz - wy);
m[7] = (yz + wx);
m[8] = (1.0f - (xx + yy));
return m;
}
What you may finally need is to input rotation using Euler angles instead of quaternion values. Indeed, Euler angles are easier to handle and understand when it come to apply a rotation in a human point of view. In this case, you'll need to convert the input Euler angles to a quaternion. Here is one possible implementation of Euler angle to quaternion conversion:
Quaternion EulerToQuaternion(float x, float y, float z)
{
float sx = sinf(x * -0.5f);
float cx = cosf(x * -0.5f);
float sy = sinf(y * -0.5f);
float cy = cosf(y * -0.5f);
float sz = sinf(z * -0.5f);
float cz = cosf(z * -0.5f);
Quaternion q;
q.x = sx * cy * cz + cx * sy * sz;
q.y = cx * sy * cz - sx * cy * sz;
q.z = cx * cy * sz + sx * sy * cz;
q.w = cx * cy * cz - sx * sy * sz;
return q;
}

OpenGL Object rotation using your own Matrix class in C++

I am playing around with OpenGL and one thing I decided to do is create my own Matrix class, instead of using glm's matrices.
The Matrix class has methods for translating, rotating and scaling the object, which are written below:
Matrix4 Matrix4::translate(Matrix4& matrix, Vector3& translation)
{
Vector4 result(translation, 1.0f);
result.multiply(matrix);
matrix.mElements[3 * 4 + 0] = result.x;
matrix.mElements[3 * 4 + 1] = result.y;
matrix.mElements[3 * 4 + 2] = result.z;
return matrix;
}
Matrix4 Matrix4::rotate(Matrix4& matrix, float angle, Vector3& axis)
{
if (axis.x == 0 && axis.y == 0 && axis.z == 0)
return matrix;
float r = angle;
float s = sin(r);
float c = cos(r);
float omc = 1.0f - cos(r);
float x = axis.x;
float y = axis.y;
float z = axis.z;
matrix.mElements[0 + 0 * 4] = c + x * x * omc;
matrix.mElements[1 + 0 * 4] = x * y * omc - z * s;
matrix.mElements[2 + 0 * 4] = z * x * omc + y * s;
matrix.mElements[0 + 1 * 4] = x * y * omc + z * s;
matrix.mElements[1 + 1 * 4] = c + y * y * omc;
matrix.mElements[2 + 1 * 4] = z * y * omc - x * s;
matrix.mElements[0 + 2 * 4] = x * z * omc - y * s;
matrix.mElements[1 + 2 * 4] = y * z * omc + x * s;
matrix.mElements[2 + 2 * 4] = c + z * z * omc;
return matrix;
}
Matrix4 Matrix4::scale(Matrix4& matrix, Vector3& scaler)
{
matrix.mElements[0 + 0 * 4] *= scaler.x;
matrix.mElements[1 + 0 * 4] *= scaler.x;
matrix.mElements[2 + 0 * 4] *= scaler.x;
matrix.mElements[0 + 1 * 4] *= scaler.y;
matrix.mElements[1 + 1 * 4] *= scaler.y;
matrix.mElements[2 + 1 * 4] *= scaler.y;
matrix.mElements[0 + 2 * 4] *= scaler.z;
matrix.mElements[1 + 2 * 4] *= scaler.z;
matrix.mElements[2 + 2 * 4] *= scaler.z;
matrix.mElements[3 + 3 * 4] = 1;
return matrix;
}
When I call the translate, rotate and scale methods in while loop (in this particular order), it does what I want, which is translate the object, then rotate it around its local origin and scale it. However, when I want to switch order so I call rotation first and then translation, I want it to do this:
But my code dosen't do that. Instead, its doing this:
What can I do so that my object only rotates around the center of the screen and not around it's local origin aswell?
My only guess is that I am doing something wrong with adding the rotation calculation on transformed matrix, but I still can't tell what it is.
EDIT: One thing i need to point out is if i left out the rotation method and i only tackle with translation and scaling, they do what i expect them to do in translation first, rotation second and in rotation first, translation second order.
EDIT 2: Here is how i call these functions in while loop.
Matrix4 trans = Matrix4(1.0f);
trans = Matrix4::rotate(trans, (float)glfwGetTime(), Vector3(0.0f, 0.0f, 1.0f));
trans = Matrix4::translate(trans, Vector3(0.5f, -0.5f, 0.0f));
trans = Matrix4::scale(trans, Vector3(0.5f, 0.5f, 1.0f));
shader.setUniformMatrix4f("uTransform", trans);
You have to concatenate the matrices by a matrix multiplication.
A matrix multiplication C = A * B works like this:
Matrix4x4 A, B, C;
// C = A * B
for ( int k = 0; k < 4; ++ k )
for ( int j = 0; j < 4; ++ j )
C[k][j] = A[0][j] * B[k][0] + A[1][j] * B[k][1] + A[2][j] * B[k][2] + A[3][j] * B[k][3];
I recommend to create specify the matrix class somehow like this:
#include <array>
class Matrix4
{
public:
std::array<float, 16> mElements{
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1 };
const float * dataPtr( void ) const { return mElements.data(); }
Matrix4 & multiply( const Matrix4 &mat );
Matrix4 & translate( const Vector3 &translation );
Matrix4 & scale( const Vector3 &scaler );
Matrix4 & rotate( float angle, const Vector3 &axis );
};
Implement the matrix multiplication. Note, you have to store the result in a buffer.
If you would write the result back to the matrix member directly, then you would change elements, which will read again later in the nested loop and the result wouldn't be correct:
Matrix4& Matrix4::multiply( const Matrix4 &mat )
{
// multiply the existing matrix by the new and store the result in a buffer
const float *A = dataPtr();
const float *B = mat.dataPtr();
std::array<float, 16> C;
for ( int k = 0; k < 4; ++ k ) {
for ( int j = 0; j < 4; ++ j ) {
C[k*4+j] =
A[0*4+j] * B[k*4+0] +
A[1*4+j] * B[k*4+1] +
A[2*4+j] * B[k*4+2] +
A[3*4+j] * B[k*4+3];
}
}
// copy the buffer to the attribute
mElements = C;
return *this;
}
Adapt the methods for translation, rotation and scaling like this:
Matrix4 & Matrix4::translate( const Vector3 &translation )
{
float x = translation.x;
float y = translation.y;
float z = translation.z;
Matrix4 transMat;
transMat.mElements = {
1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
x, y, z, 1.0f };
return multiply(transMat);
}
Matrix4 & Matrix4::rotate( float angle, const Vector3 &axis )
{
float x = axis.x;
float y = axis.y;
float z = axis.z;
float c = cos(angle);
float s = sin(angle);
Matrix4 rotationMat;
rotationMat.mElements = {
x*x*(1.0f-c)+c, x*y*(1.0f-c)-z*s, x*z*(1.0f-c)+y*s, 0.0f,
y*x*(1.0f-c)+z*s, y*y*(1.0f-c)+c, y*z*(1.0f-c)-x*s, 0.0f,
z*x*(1.0f-c)-y*s, z*y*(1.0f-c)+x*s, z*z*(1.0f-c)+c, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f };
return multiply(rotationMat);
}
Matrix4 & Matrix4::scale( const Vector3 &scaler )
{
float x = scaler.x;
float y = scaler.y;
float z = scaler.z;
Matrix4 scaleMat;
scaleMat.mElements = {
x, 0.0f, 0.0f, 0.0f,
0.0f, y, 0.0f, 0.0f,
0.0f, 0.0f, z, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f };
return multiply(scaleMat);
}
If you use the matrix class like this,
float angle_radians = ....;
Vector3 scaleVec{ 0.2f, 0.2f, 0.2f };
Vector3 transVec{ 0.3f, 0.3f, 0.0f };
Vector3 rotateVec{ 0.0f, 0.0f, 1.0f };
Matrix4 model;
model.rotate( angle_rad, rotateVec );
model.translate( transVec );
model.scale( scaleVec );
then the result would look like this:
The function rotate() isn't performing an actual rotation. Only generating a partial rotation matrix, and overwriting it over the original matrix.
You need to construct a complete one and multiply it to the original matrix.
Matrix4 Matrix4::rotate(const Matrix4& matrix, float angle, const Vector3& axis)
{
if (axis.x == 0 && axis.y == 0 && axis.z == 0)
return matrix;
float r = angle;
float s = sin(r);
float c = cos(r);
float omc = 1.0f - cos(r);
float x = axis.x;
float y = axis.y;
float z = axis.z;
Matrix4 r;
r.mElements[0 + 0 * 4] = c + x * x * omc;
r.mElements[1 + 0 * 4] = x * y * omc - z * s;
r.mElements[2 + 0 * 4] = z * x * omc + y * s;
r.mElements[3 + 0 * 4] = 0;
r.mElements[0 + 1 * 4] = x * y * omc + z * s;
r.mElements[1 + 1 * 4] = c + y * y * omc;
r.mElements[2 + 1 * 4] = z * y * omc - x * s;
r.mElements[3 + 1 * 4] = 0;
r.mElements[0 + 2 * 4] = x * z * omc - y * s;
r.mElements[1 + 2 * 4] = y * z * omc + x * s;
r.mElements[2 + 2 * 4] = c + z * z * omc;
r.mElements[3 + 2 * 4] = 0;
r.mElements[0 + 3 * 4] = 0;
r.mElements[1 + 3 * 4] = 0;
r.mElements[2 + 3 * 4] = 0;
r.mElements[3 + 3 * 4] = 1;
return r * matrix;
}

Cocos2d-x 3.8 - RenderTexture ,OpenGL not rendering

i'm trying to draw a bezier line on texture created with RenderTexture, but the line is not showing, only the texture
this is the tutorial i followed
Bezier.h:
class Bezier : public Node
{
private:
Color4F genRandomBrightColor();
public:
Sprite* create(float width, float height);
};
Bezier.cpp:
Sprite* Bezier::create(float width, float height){
auto rt = RenderTexture::create(width, height);
auto randomColor = genRandomBrightColor();
//rt->begin();
rt->beginWithClear(randomColor.r, randomColor.g, randomColor.b, randomColor.a);
//draw bezier line
int segments = 50;
//tried with Vec2 too
Vertex2F vertices[51];
Color4F colors[51];
float t = 0;
Point startPoint = Point(0, CCRANDOM_0_1()*height);
Point anchor1 = Point(CCRANDOM_0_1()*width / 2, CCRANDOM_0_1()*height);
Point anchor2 = Point((CCRANDOM_0_1()*width / 2) + (width / 2), CCRANDOM_0_1()*height);
Point endPoint = Point(width, CCRANDOM_0_1()*height);
//this i copied from DrawNode so it should be good
for (int i = 0; i < segments; i++){
colors[i] = Color4F::WHITE;
vertices[i] = Vertex2F(powf(1 - t, 3) * startPoint.x + 3.0f * powf(1 - t, 2) * t * anchor1.x + 3.0f * (1 - t) * t * t * anchor2.x + t * t * t * endPoint.x,
powf(1 - t, 3) * startPoint.y + 3.0f * powf(1 - t, 2) * t * anchor1.y + 3.0f * (1 - t) * t * t * anchor2.y + t * t * t * endPoint.y);
t += 1.0f / segments;
}
vertices[segments] = Vertex2F(endPoint.x, endPoint.y);
//////////////////////////////////////////////////////////////////////////
auto shaderProgram = ShaderCache::getInstance()->getProgram(GLProgram::SHADER_NAME_POSITION_COLOR);
setShaderProgram(shaderProgram);
CC_NODE_DRAW_SETUP();
GL::enableVertexAttribs(GL::VERTEX_ATTRIB_FLAG_POSITION | GL::VERTEX_ATTRIB_FLAG_COLOR);
glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_POSITION, 2, GL_FLOAT, GL_FALSE, 0, vertices);
glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_COLOR, 4, GL_FLOAT, GL_FALSE, 0, colors);
glDrawArrays(GL_TRIANGLE_STRIP, 0, segments);
rt->end();
auto sprite = Sprite::createWithTexture(rt->getSprite()->getTexture());
return sprite;
}
Color4F Bezier::genRandomBrightColor(){
while (true){
float r = CCRANDOM_0_1();
float g = CCRANDOM_0_1();
float b = CCRANDOM_0_1();
if ((r < 0.25) && (g > 0.5) && (b > 0.75) || (r > 0.75) && (g > 0.5) && (b<0.25)){
return Color4F(r,g,b,1);
}
}
}
GameScene.cpp:
#include <Bezier.h>
....
auto dl = new Bezier();
auto sprite = dl->create(visibleSize.width, visibleSize.height/2);
sprite->setPosition(Point(visibleSize.width / 2 + origin.x, visibleSize.height / 4 + origin.y));
this->addChild(sprite);
here's the screenshot: http://postimg.org/image/cvy46wtwv/
any help would be appreciated!
PS: i'm not using DrawNode's function because i want to know more about this
EDIT: GOT IT! I NEEDED TO USE CUSTOM COMMAND
OpenGl code is not working for cocos2dx- 3.0 with VS2013 CPP
in function create at the end ,put addchild(sprite) like this:
auto sprite = Sprite::createWithTexture(rt->getSprite()->getTexture());
addChild(sprite);
return sprite;

Rotate point sprite

I can already rotate point sprite on 0, 90, 180, 270 degrees
Fragment shader
precision lowp float;
uniform sampler2D us_tex;
uniform mat3 um_tex;
void main ()
{
vec2 tex_coords = (um_tex * vec3(gl_PointCoord, 1.0)).xy;
gl_FragColor = texture2D(us_tex, tex_coords);
}
2*2 Matrix operations (i know about GLM - it's great, academic purpose to handle matrix on your own)
typedef GLfloat m3[9]//3*3 matrix
#define DEG_TO_RAD(x) (x * M_PI/180.0f)
void ident_m3(m3 res)
{
memset(res, 0, sizeof(m3));
res[0] = res[4] = res[8] = 1.0f;
}
void trans_m3(m3 res, const p2* pos)
{
ident_m3(res);
res[7] = pos->x;
res[8] = pos->y;
}
void mult_m3(m3 res, const m3 m1, const m3 m2)
{
res[0] = m1[0] * m2[0] + m1[3] * m2[1] + m1[6] * m2[2];
res[1] = m1[1] * m2[0] + m1[4] * m2[1] + m1[7] * m2[2];
res[2] = m1[2] * m2[0] + m1[5] * m2[1] + m1[8] * m2[2];
res[3] = m1[0] * m2[3] + m1[3] * m2[4] + m1[6] * m2[5];
res[4] = m1[1] * m2[3] + m1[4] * m2[4] + m1[7] * m2[5];
res[5] = m1[2] * m2[3] + m1[5] * m2[4] + m1[8] * m2[5];
res[6] = m1[0] * m2[6] + m1[3] * m2[7] + m1[6] * m2[8];
res[7] = m1[1] * m2[6] + m1[4] * m2[7] + m1[7] * m2[8];
res[8] = m1[2] * m2[6] + m1[5] * m2[7] + m1[8] * m2[8];
}
in ParticlesDraw()
m3 r;
rot_m3(r, 90.0f);
...
glUniformMatrix3fv(/*um_tex uniform*/, 1, GL_FALSE, res);
glDrawArrays(GL_POINTS, 0, /*particles count*/);
...
Also i know how rotate ordinary sprite around pos(x,y,z)
Translate to pos(-x,-y,-z)
Rotate
Translate to pos(x,y,z)
Result Matrix = (Rot Matrix * Translate Matrix) * Anti-Traslate Matrix.
I want to rotate point sprite to 45, 32,64,72 e.g any degree (now it rotates not right, last frame 45 deg)
But in this case, i can translate to center of tex (0.5, 0.5), but what will be anti translate - (0.0, 0.0)?
I try something like this, but it does not work for example for 30, 45 rotation, also if my texture is 64*64, do i need to set gl_PointSize to 64.0 for rotation?
This:
Translate to pos(-x,-y,-z)
Rotate
Translate to pos(x,y,z)
Is not the same thing as this:
Result Matrix = (Rot Matrix * Translate Matrix) * Anti-Traslate Matrix.
If you wish to rotate around the point (x,y,z), then you need to do this:
Matrix T1 = Translate(x, y, z);
Matrix R1 = Rotate();
Matrix T2 = Translate(-x, -y, -z);
Which is the same thing as:
Result Matrix = T1 * R1 * T2

glm::perspective explanation

I am trying to understand what the following code does:
glm::mat4 Projection = glm::perspective(35.0f, 1.0f, 0.1f, 100.0f);
Does it create a projection matrix? Clips off anything that is not in the user's view?
I wasn't able to find anything on the API page, and the only thing I could find in the pdf on their website was this:
gluPerspective:
glm::mat4 perspective(float fovy, float aspect, float zNear,
float zFar);
glm::dmat4 perspective(
double fovy, double aspect, double zNear,
double zFar);
From GLM_GTC_matrix_transform extension: <glm/gtc/matrix_transform.hpp>
But it doesn't explain the parameters. Maybe I missed something.
It creates a projection matrix, i.e. the matrix that describes the set of linear equations that transforms vectors from eye space into clip space. Matrices really are not black magic. In the case of OpenGL they happen to be a 4-by-4 arrangement of numbers:
X_x Y_x Z_x T_x
X_y Y_y Z_y T_y
X_z Y_z Z_z T_z
X_w Y_w Z_w W_w
You can multply a 4-vector by a 4×4 matrix:
v' = M * v
v'_x = M_xx * v_x + M_yx * v_y + M_zx * v_z + M_tx * v_w
v'_y = M_xy * v_x + M_yy * v_y + M_zy * v_z + M_ty * v_w
v'_z = M_xz * v_x + M_yz * v_y + M_zz * v_z + M_tz * v_w
v'_w = M_xw * v_x + M_yw * v_y + M_zw * v_z + M_tw * v_w
After reaching clip space (i.e. after the projection step), the primitives are clipped. The vertices resulting from the clipping are then undergoing the perspective divide, i.e.
v'_x = v_x / v_w
v'_y = v_y / v_w
v'_z = v_z / v_w
( v_w = 1 = v_w / v_w )
And that's it. There's really nothing more going on in all those transformation steps than ordinary matrix-vector multiplication.
Now the cool thing about this is, that matrices can be used to describe the relative alignment of a coordinate system within another coordinate system. What the perspective transform does is, that it let's the vertices z-values "slip" into their projected w-values as well. And by the perspective divide a non-unity w will cause "distortion" of the vertex coordinates. Vertices with small z will be divided by a small w, thus their coordinates "blow" up, whereas vertices with large z will be "squeezed", which is what's causing the perspective effect.
This is a c standalone version of the same function. This is roughly a copy paste version of the original.
# include <math.h>
# include <stdlib.h>
# include <string.h>
typedef struct s_mat {
float *array;
int width;
int height;
} t_mat;
t_mat *mat_new(int width, int height)
{
t_mat *to_return;
to_return = (t_mat*)malloc(sizeof(t_mat));
to_return->array = malloc(width * height * sizeof(float));
to_return->width = width;
to_return->height = height;
return (to_return);
}
void mat_zero(t_mat *dest)
{
bzero(dest->array, dest->width * dest->height * sizeof(float));
}
void mat_set(t_mat *m, int x, int y, float val)
{
if (m == NULL || x > m->width || y > m->height)
return ;
m->array[m->width * (y - 1) + (x - 1)] = val;
}
t_mat *mat_perspective(float angle, float ratio,
float near, float far)
{
t_mat *to_return;
float tan_half_angle;
to_return = mat_new(4, 4);
mat_zero(to_return);
tan_half_angle = tan(angle / 2);
mat_set(to_return, 1, 1, 1 / (ratio * tan_half_angle));
mat_set(to_return, 2, 2, 1 / (tan_half_angle));
mat_set(to_return, 3, 3, -(far + near) / (far - near));
mat_set(to_return, 4, 3, -1);
mat_set(to_return, 3, 4, -(2 * far * near) / (far - near));
return (to_return);
}