Ray-tracing quartic surfaces - opengl
I have implemented ray-tracing of quartic surfaces in GLSL
#version 400 core
in vec2 q; // Screen coordinates. Entire screen is covered by 2 triangles, in which the ray-tracing is done.
uniform vec3 X; // Position of the screen centre in world coordinates.
uniform vec3 R; // View direction in euler angles.
uniform vec2 B; // Screen width and height.
uniform vec3 P; // Position of the eyes in the coordinates given by R.
out vec4 color;
const float pi = 2 * asin (1.0);
// Creating an unit vector from sferical coordinates.
vec3 sfe (const float fi, const float te)
{
return vec3 (cos (fi) * cos (te), sin (fi) * cos (te), sin (te));
}
// Get the vector basis for view space.
mat3 getb (const vec3 r)
{
mat3 M;
M [0] = sfe (r [0], r [1]);
vec3 a = sfe (r [0] + 0.5 * pi, 0);
vec3 b = sfe (r [0], r [1] + 0.5 * pi);
M [1] = a * cos (r [2]) + b * sin (r [2]);
M [2] = - a * sin (r [2]) + b * cos (r [2]);
return M;
}
// Get the pixel position in world coordinates.
vec3 getx (const vec3 e, const vec3 f, const vec2 b, const vec2 q)
{
return b [0] * q [0] * e + b [1] * q [1] * f;
}
// Complex numbers.
// Complex multiplication.
vec2 nb (const vec2 a, const vec2 b)
{
return vec2 (a [0] * b [0] - a [1] * b [1], a [0] * b [1] + a [1] * b
[0]);
}
// Complex conjugate.
vec2 ks (const vec2 z)
{
return vec2 (z [0], - z [1]);
}
// Complex division.
vec2 lm (const vec2 a, const vec2 b)
{
return nb (a, ks (b)) / dot (b, b);
}
// Complex exponential.
vec2 ena (const vec2 z)
{
return exp (z [0]) * vec2 (cos (z [1]), sin (z [1]));
}
// Complex logarithm.
vec2 ln (const vec2 z)
{
float f;
if (z [0] > 0)
f = 0;
else
f = pi;
return vec2 (0.5 * log (dot (z, z)), atan (z [1] / z [0]) + f);
}
// Complex power.
vec2 om (const float n, const vec2 z)
{
if (z == vec2 (0, 0))
return vec2 (0, 0);
else
return ena (n * ln (z));
}
// Ferrari's solution to quartic equation
// Solution to degree 2 equation.
vec2 [2] rov2 (const float a [3])
{
vec2 w [2];
float D = a [1] * a [1] - 4 * a [0] * a [2];
w [0] = (- vec2 (a [1], 0) - om (0.5, vec2 (D, 0))) / (2 * a [0]);
w [1] = (- vec2 (a [1], 0) + om (0.5, vec2 (D, 0))) / (2 * a [0]);
return w;
}
// Solution to degree 3 equation.
vec2 [3] rov3 (const float a [4])
{
vec2 w [3];
float p, q;
p = (3 * a [0] * a [2] - a [1] * a [1]) / (3 * a [0] * a [0]);
q = (2 * a [1] * a [1] * a [1] - 9 * a [0] * a [1] * a [2] + 27 * a [0] * a [0] * a [3]) / (27 * a [0] * a [0] * a [0]);
float A [3] = float [3] (1, q, - p * p * p / 27);
vec2 k [2] = rov2 (A);
vec2 u = om (1.0 / 3, k [0]);
vec2 U;
for (int i = 0; i < 3; i = i + 1)
{
U = nb (u, ena (vec2 (0, i * 2 * pi / 3)));
w [i] = U - p / 3 * lm (vec2 (1, 0), U) - vec2 (a [1], 0) / (3 * a [0]);;
}
return w;
}
// Solution to degree 4 equation.
vec2 [4] rov4 (const float a [5])
{
vec2 w [4];
float p, q, r;
p = (8 * a [2] * a [0] - 3 * a [1] * a [1]) / (8 * a [0] * a [0]);
q = (a [1] * a [1] * a [1] - 4 * a [2] * a [1] * a [0] + 8 * a [3] * a [0] * a [0]) / (8 * a [0] * a [0] * a [0]);
r = (- 3 * a [1] * a [1] * a [1] * a [1] + 256 * a [4] * a [0] * a [0] * a [0] - 64 * a [3] * a [1] * a [0] * a [0] + 16 * a [2] * a [1] * a [1] * a [0]) / (256 * a [0] * a [0] * a [0] * a [0]);
if (q == 0)
{
float A [3] = float [3] (1, p, r);
vec2 k [2] = rov2 (A);
w [0] = om (0.5, k [0]);
w [1] = - om (0.5, k [0]);
w [2] = om (0.5, k [1]);
w [3] = - om (0.5, k [1]);
}
else
{
float B [4] = float [4] (8, 8 * p, 2 * p * p - 8 * r, - q * q);
vec2 m [3] = rov3 (B);
float o2 = sqrt (2.0f);
vec2 omm = om (0.5, m [0]);
vec2 om1 = om (0.5, - (2.0f * vec2 (p, 0) + 2.0f * m [0] - o2 * q * lm (vec2 (1, 0), omm)));
vec2 om2 = om (0.5, - (2.0f * vec2 (p, 0) + 2.0f * m [0] + o2 * q * lm (vec2 (1, 0), omm)));
w [0] = 0.5f * (- o2 * omm - om1) - vec2 (a [1], 0) / (4 * a [0]);
w [1] = 0.5f * (- o2 * omm + om1) - vec2 (a [1], 0) / (4 * a [0]);
w [2] = 0.5f * (+ o2 * omm - om2) - vec2 (a [1], 0) / (4 * a [0]);
w [3] = 0.5f * (+ o2 * omm + om2) - vec2 (a [1], 0) / (4 * a [0]);
}
return w;
}
// Evaluation and derivation of quartic.
struct quartic
{
bool lv [4];
float v4 [15];
float v3 [10];
float v2 [6];
float v1 [3];
float v0;
};
float eval (const quartic q, vec3 v)
{
float x = v [0];
float y = v [1];
float z = v [2];
float S = 0;
if (q.lv [0])
{
S = S + x * x * (x * (q.v4 [0] * x + q.v4 [3] * y + q.v4 [4] * z) + y * (q.v4 [5] * z + q.v4 [12] * y)) +
y * y * (y * (q.v4 [1] * y + q.v4 [6] * z + q.v4 [7] * x) + z * (q.v4 [8] * x + q.v4 [13] * z)) +
z * z * (z * (q.v4 [2] * z + q.v4 [9] * x + q.v4 [10] * y) + x * (q.v4 [11] * y + q.v4 [14] * x));
}
if (q.lv [1])
{
S = S + x * (x * (q.v3 [0] * x + q.v3 [3] * y + q.v3 [4] * z) - q.v3 [9] * y * z) +
y * y * (q.v3 [1] * y + q.v3 [5] * z + q.v3 [6] * x) +
z * z * (q.v3 [2] * z + q.v3 [7] * x + q.v3 [8] * y);
}
if (q.lv [2])
{
S = S + x * (q.v2 [0] * x + q.v2 [3] * y) +
y * (q.v2 [1] * y + q.v2 [4] * z) +
z * (q.v2 [2] * z + q.v2 [5] * x);
}
if (q.lv [3])
S = S + q.v1 [0] * x + q.v1 [1] * y + q.v1 [2] * z;
return S + q.v0;
}
quartic D (const quartic q0, const vec3 v)
{
quartic q;
q.lv = bool [4] (false, false, false, false);
if (q0.lv [0])
{
q.lv [1] = true;
q.v3 = float [10] (4 * q0.v4 [0] * v [0] + q0.v4 [3] * v [1] + q0.v4 [4] * v [2],
q0.v4 [7] * v [0] + 4 * q0.v4 [1] * v [1] + q0.v4 [6] * v [2],
q0.v4 [9] * v [0] + q0.v4 [10] * v [1] + 4 * q0.v4 [2] * v [2],
3 * q0.v4 [3] * v [0] + 2 * q0.v4 [12] * v [1] + q0.v4 [5] * v [2],
3 * q0.v4 [4] * v [0] + q0.v4 [5] * v [1] + 2 * q0.v4 [14] * v [2],
q0.v4 [8] * v [0] + 3 * q0.v4 [6] * v [1] + 2 * q0.v4 [13] * v [2],
2 * q0.v4 [12] * v [0] + 3 * q0.v4 [7] * v [1] + q0.v4 [8] * v [2],
2 * q0.v4 [14] * v [0] + q0.v4 [11] * v [1] + 3 * q0.v4 [9] * v [2],
q0.v4 [11] * v [0] + 2 * q0.v4 [13] * v [1] + 3 * q0.v4 [10] * v [2],
2 * q0.v4 [5] * v [0] + 2 * q0.v4 [8] * v [1] + 2 * q0.v4 [11] * v [2]);
}
if (q0.lv [1])
{
q.lv [2] = true;
q.v2 = float [6] (3 * q0.v3 [0] * v [0] + q0.v3 [3] * v [1] + q0.v3 [4] * v [2],
q0.v3 [6] * v [0] + 3 * q0.v3 [1] * v [1] + q0.v3 [5] * v [2],
q0.v3 [7] * v [0] + q0.v3 [8] * v [1] + 3 * q0.v3 [2] * v [2],
2 * q0.v3 [3] * v [0] + 2 * q0.v3 [6] * v [1] + q0.v3 [9] * v [2],
q0.v3 [9] * v [0] + 2 * q0.v3 [5] * v [1] + 2 * q0.v3 [8] * v [2],
2 * q0.v3 [4] * v [0] + q0.v3 [9] * v [1] + 2 * q0.v3 [7] * v[2]);
}
if (q0.lv [2])
{
q.lv [3] = true;
q.v1 = float [3] (2 * q0.v2 [0] * v [0] + q0.v2 [3] * v [1] + q0.v2 [5] * v [2],
q0.v2 [3] * v [0] + 2 * q0.v2 [1] * v [1] + q0.v2 [4] * v [2],
q0.v2 [5] * v [0] + q0.v2 [4] * v [1] + 2 * q0.v2 [2] * v [2]);
}
if (q0.lv [3])
q.v0 = q0.v1 [0] * v [0] + q0.v1 [1] * v [1] + q0.v1 [2] * v [2];
else
q.v0 = 0;
return q;
}
// Intersection with a ray.
struct ptn
{
vec3 x;
int l;
};
ptn pt (const vec3 x, const int l)
{
ptn p;
p.x = x;
p.l = l;
return p;
}
// Using Taylor series at screen point x0, we are trying to find intersection point in the form x0 + t * v.
ptn nika (const quartic q0, const vec3 x0, const vec3 v)
{
float k0 = eval (q0, x0);
quartic q = D (q0, v);
float k1 = eval (q, x0);
q = D (q, v);
float k2 = eval (q, x0);
q = D (q, v);
float k3 = eval (q, x0);
q = D (q, v);
float k4 = eval (q, x0);
vec2 k [4] = rov4 (float [5] (k4 / 24, k3 / 6, 0.5 * k2, k1, k0));
float t = 0;
int l = 0;
for (int i = 0; i < 4; i = i + 1)
{
if (abs (k [i] [1]) < 0.001 && k [i] [0] >= 0)
if (k [i] [0] < t || l == 0)
{
t = k [i] [0];
l = 1;
}
}
return pt (x0 + t * v, l);
}
// Main loop.
void main()
{
mat3 b = getb (R);
vec3 x_ = transpose (b) * vec3 (0, B * q);
vec3 x = X + x_;
vec3 v = x_ - transpose (b) * P;
quartic q;
q.lv = bool [4] (true, false, true, false);
float r = 0.2;
float R = 1.25;
// A torus.
q.v4 = float [15] (1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2);
q.v3 = float [10] (0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
q.v2 = float [6] (- 2 * (R * R + r * r), - 2 * (R * R + r * r), 2 * (R * R - r * r), 0, 0, 0);
q.v1 = float [3] (0, 0, 0);
q.v0 = (R * R - r * r) * (R * R - r * r);
ptn p = nika (q, x, v);
vec3 svetlo = vec3 (1, 1, 1);
vec3 barva = vec3 (1, 0.5, 0.4);
color = vec4 (p.l * barva * svetlo, 1.0);
}
The algorithm provides mostly accurate results, hovewer, in some areas a visible noise appears.
As the quartic (a torus) moves farther away from the screen, noise increases to the point that the torus becomes entirely obscured.
I would like to know the cause of this noise and, if possible, how to eliminate it.
[Edit by Spektre] dictionary
barva means color
svetlo means light
I have rewritten the code to use double presission.
The scale-related noise was completely removed:
However, scale-independent noise still persists:
so it probably has different causes.
2-order surfaces are rendered without a single problem, while a similar noise curve appears when rendering 3-order surfaces, so it most likely has something to do with my solutions of 3- and 4-order equations.
Related
Plasma Shader is not rendering as expected
I am trying to hack this Plasma shader from ShaderToy so it works with Spark AR ... I'm very close but there is a weird issue with the shader being compressed into the corner. Are there any shader guru's who can give me some pointers? Here's what it looks like now in Spark: The inputs are the screen size, a screen touch coordinate, the time, and a direction vec2 that could be the culprit. I'm not entirely sure what this input is doing. Here's my converted shader code: precision highp float; vec4 main( in vec2 direction, in float time, in vec2 touch, in vec2 screen ) { vec2 uv = fragment(std::getVertexTexCoord()); float t = time/.1 + touch.x; vec2 R = uv.xy, S = screen * 0.01, p = ( direction+direction - R ) / R * S, q = vec2(cos(-t / 165.), cos( t / 45.)) * S - p; t = 1. + cos( length( vec2(cos( t / 98.), sin( t / 178.)) * S - p ) / 30.) + cos( length( vec2(sin(-t / 124.), cos( t / 104.)) * S - p ) / 20.) + sin( length(q) / 25. ) * sin(q.x / 20.) * sin(q.y / 15.); return .5 + .5* cos( (time+touch.y) / vec4(63,78,45,1) + ( t + vec4(0,1,-.5,0) ) *3.14 ); } This is a sca file which is the Spark AR format for shaders. It is a conversion of this code from ShaderToy: void mainImage( out vec4 O, vec2 U ) { float t = iTime/.1 + iMouse.x; vec2 R = iResolution.xy, S = vec2(160,100), p = ( U+U - R ) / R * S, q = vec2(cos(-t / 165.), cos( t / 45.)) * S - p; t = 1. + cos( length( vec2(cos( t / 98.), sin( t / 178.)) * S - p ) / 30.) + cos( length( vec2(sin(-t / 124.), cos( t / 104.)) * S - p ) / 20.) + sin( length(q) / 25. ) * sin(q.x / 20.) * sin(q.y / 15.); O = .5 + .5* cos( (iTime+iMouse.y) / vec4(63,78,45,1) + ( t + vec4(0,1,-.5,0) ) *3.14 ); } Hope someone can help.
The problem comes from the fact that you misinterpreted the iResolution variable in the shadertoy code as the uv coordinates of the fragment. iResolution is just a variable that stores the dimensions in pixels of the image on the screen. It is the same for each pixel. U on the other side, stores the coordinates of the fragment measured in pixels ( so that uv = U / iResolution ). It is called fragCoord in the default shadertoy shader. In your case, as you already have uv going from 0 to 1, you don't need R to define p : p = ( U + U - R ) / R * S can become p = ( U/R + U/R - R/R ) * S and then p = (uv + uv - vec2(1)) * S. I hope this fixes your problem, tell me if it doesn't. EDIT: I just realized that you can simplify the definition of p even further as the - vec2(1) is a translation that doesn't really affect the result and the uv + uv can be replaced by uv by compensating with S. So it can become p = uv * S.
OpenGL Triangle pipe around line segment
I would like to ask how can I render in geometry shader a triangle pipe from a line segment? I first compute perpendicular vector "perp" to the line vector "axis". Then I rotate the "perp" vector few times by "rotate" function. Since mesh is composed from 8 vertices I am trying to use "triangle_strip". My current code : #version 330 core layout (lines) in; layout(triangle_strip, max_vertices = 8) out;//triangle_strip uniform float u_thickness ; uniform vec2 u_viewportSize ; uniform bool u_scale_width_by_zoom ; in gl_PerVertex { vec4 gl_Position; //float gl_PointSize; //float gl_ClipDistance[]; } gl_in[]; vec4 rotate(vec4 p, float x, float y, float z,float angle ) { vec3 q; q[0] = p[0] * (x*x * (1.0 - cos(angle)) + cos(angle)) + p[1] * (x*y * (1.0 - cos(angle)) + z * sin(angle)) + p[2] * (x*z * (1.0 - cos(angle)) - y * sin(angle)); q[1] = p[0] * (y*x * (1.0 - cos(angle)) - z * sin(angle)) + p[1]* (y*y * (1.0 - cos(angle)) + cos(angle)) + p[2] * (y*z * (1.0 - cos(angle)) + x * sin(angle)); q[2] = p[0] * (z*x * (1.0 - cos(angle)) + y * sin(angle)) + p[1] * (z*y * (1.0 - cos(angle)) - x * sin(angle)) + p[2] * (z*z * (1.0 - cos(angle)) + cos(angle)); return vec4(q, 0.0); } void main() { //https://stackoverflow.com/questions/54686818/glsl-geometry-shader-to-replace-gllinewidth vec4 p1 = gl_in[0].gl_Position; vec4 p2 = gl_in[1].gl_Position; //tube // Specify the axis to rotate about: vec4 axis = p2-p1; float x = axis[0]; float y = axis[1]; float z = axis[2]; axis = normalize(axis); //float length = hypotf(axis[0], hypotf(axis[1], axis[2])); float length = sqrt((axis[0]*axis[0]) + sqrt(axis[1]*axis[1]+ axis[2]*axis[2])); float dir_scalar = (axis[0] > 0.0) ? length : -length; float xt = axis[0] + dir_scalar; float dot = -axis[1] / (dir_scalar * xt); vec3 perp_0 = vec3(dot * xt, 1.0f + dot * axis.y, dot * axis.z); perp_0 = normalize(perp_0); vec4 perp = vec4(perp_0,0)*u_thickness*0.001; //side0 vec4 p1_1 = p1+perp; vec4 p1_2 = p2+perp; vec4 perp_rot_2=rotate(perp,x,y,z,60.0 * 3.14 / 180.0); vec4 p2_1 = p1+perp_rot_2; vec4 p2_2 = p2+perp_rot_2; vec4 perp_rot_3=rotate(perp,x,y,z, 120.0 * 3.14 / 180.0); vec4 p3_1 = p1+perp_rot_3; vec4 p3_2 = p2+perp_rot_3; gl_Position = p1_1; EmitVertex(); gl_Position = p1_2; EmitVertex(); gl_Position = p2_1; EmitVertex(); gl_Position = p2_2; EmitVertex(); gl_Position = p3_1; EmitVertex(); gl_Position = p3_2; EmitVertex(); gl_Position = p1_1; EmitVertex(); gl_Position = p1_2; EmitVertex(); EndPrimitive(); } It produces wrong results:
Issue with 3d rotation along the X axis
I'm working on a project that required a 3d cube to be rotated along 3 axes. The cube is made up of 12 triangles, each with an instance of the Triangle class. Each triangle has a p0, p1, and p2 with the type sf::Vector3f. The triangles also have a float* position and a float* rotation. The position and rotation of a triangle is updated using this method. void Triangle::update() { position; p0 = originalP0; p1 = originalP1; p2 = originalP2; sf::Vector3f rotatedP0; sf::Vector3f rotatedP1; sf::Vector3f rotatedP2; // along z rotatedP0.x = p0.x * cos((*rotation).z * 0.0174533) - p0.y * sin((*rotation).z * 0.0174533); rotatedP0.y = p0.x * sin((*rotation).z * 0.0174533) + p0.y * cos((*rotation).z * 0.0174533); rotatedP0.z = p0.z; rotatedP1.x = p1.x * cos((*rotation).z * 0.0174533) - p1.y * sin((*rotation).z * 0.0174533); rotatedP1.y = p1.x * sin((*rotation).z * 0.0174533) + p1.y * cos((*rotation).z * 0.0174533); rotatedP1.z = p1.z; rotatedP2.x = p2.x * cos((*rotation).z * 0.0174533) - p2.y * sin((*rotation).z * 0.0174533); rotatedP2.y = p2.x * sin((*rotation).z * 0.0174533) + p2.y * cos((*rotation).z * 0.0174533); rotatedP2.z = p2.z; p0 = rotatedP0; p1 = rotatedP1; p2 = rotatedP2; // along y rotatedP0.x = p0.x * cos((*rotation).y * 0.0174533) + originalP0.z * sin((*rotation).y * 0.0174533); rotatedP0.y = p0.y; rotatedP0.z = p0.x * -sin((*rotation).y * 0.0174533) + originalP0.z * cos((*rotation).y * 0.0174533); rotatedP1.x = p1.x * cos((*rotation).y * 0.0174533) + originalP1.z * sin((*rotation).y * 0.0174533); rotatedP1.y = p1.y; rotatedP1.z = p1.x * -sin((*rotation).y * 0.0174533) + originalP1.z * cos((*rotation).y * 0.0174533); rotatedP2.x = p2.x * cos((*rotation).y * 0.0174533) + originalP2.z * sin((*rotation).y * 0.0174533); rotatedP2.y = p2.y; rotatedP2.z = p2.x * -sin((*rotation).y * 0.0174533) + originalP2.z * cos((*rotation).y * 0.0174533); p0 = rotatedP0; p1 = rotatedP1; p2 = rotatedP2; // along x rotatedP0.x = p0.x; rotatedP0.y = p0.y * cos((*rotation).x * 0.0174533) - p0.z * sin((*rotation).x * 0.0174533); rotatedP0.z = p0.y * sin((*rotation).x * 0.0174533) + p0.z * cos((*rotation).x * 0.0174533); rotatedP1.x = p1.x; rotatedP1.y = p1.y * cos((*rotation).x * 0.0174533) - p1.z * sin((*rotation).x * 0.0174533); rotatedP1.z = p1.y * sin((*rotation).x * 0.0174533) + p1.z * cos((*rotation).x * 0.0174533); rotatedP2.x = p2.x; rotatedP2.y = p2.y * cos((*rotation).x * 0.0174533) - p2.z * sin((*rotation).x * 0.0174533); rotatedP2.z = p2.y * sin((*rotation).x * 0.0174533) + p2.z * cos((*rotation).x * 0.0174533); p0 = rotatedP0 + *position; p1 = rotatedP1 + *position; p2 = rotatedP2 + *position; } This method works well for all axes except the X axis. The cube has two red faces intersecting the Z axis, two green faces intersecting the Y axis, and two blue faces intersecting the X axis. Rotating the cube along the Z and Y axes works fine. The cube is rotating around the red and green faces. When rotating along the X axis, the cube is not rotated around the blue faces, but rather the global X axis. Am I doing something wrong? Is it supposed to be this way? Is there any way to fix it? I searched all over and couldn't find anything helpful.
bro you did it all wrong. use this 3D point rotation algorithm. i know it is javascript but the math still the same
OpenGL Matrix Multiplication C++
So I am trying to multiply rotation and translation matrices together and I can't quite figure out what is going wrong. If, in the program I multiply a translation matrix by a rotation matrix then send that matrix as a uniform to my shader program I end up with the object becoming 2D then 3D again as it spins [ https://a.pomf.se/xvvrsg.mp4 ] (object on the right). shader.setUniformMat4("model_matrix", Matrix4::translation(Vector3(10.0f, 0.0f, 0.0f)) * Matrix4::rotation(rotation, Vector3(0.0f, 1.0f, 0.0f))); (vertex shader) #version 330 core layout (location = 0) in vec4 in_position; layout (location = 1) in vec4 in_normal; uniform mat4 pr_matrix; uniform mat4 vw_matrix = mat4(1.0); uniform mat4 model_matrix = mat4(1.0); out vec4 pos; out vec4 normal; void main() { pos = pr_matrix * vw_matrix * model_matrix * in_position; normal = in_normal; gl_Position = pos; } However if I send my individual translation and rotation matrices as separate uniforms and then multiply them in the shader to create my model matrix it works as intended [ https://a.pomf.se/jyxpnb.mp4 ] (object on the right). shader.setUniformMat4("translation_matrix", Matrix4::translation(Vector3(10.0f, 0.0f, 0.0f))); shader.setUniformMat4("rotation_matrix", Matrix4::rotation(rotation, Vector3(0.0f, 1.0f, 0.0f))); shader.setUniformMat4("scale_matrix", Matrix4::identity()); (vertex shader) #version 330 core layout (location = 0) in vec4 in_position; layout (location = 1) in vec4 in_normal; uniform mat4 pr_matrix; uniform mat4 vw_matrix = mat4(1.0); uniform mat4 translation_matrix = mat4(1.0); uniform mat4 rotation_matrix = mat4(1.0); uniform mat4 scale_matrix = mat4(1.0); out vec4 pos; out vec4 normal; void main() { mat4 model_matrix = translation_matrix * rotation_matrix * scale_matrix; pos = pr_matrix * vw_matrix * model_matrix * in_position; normal = in_normal; gl_Position = pos; } This leads me to believe that there must be an error in my multiplication of matrices, this is how I am currently doing it: Matrix4 &Matrix4::multiply(const Matrix4 &other) { elements[0] = elements[0] * other.elements[0] + elements[4] * other.elements[1] + elements[8] * other.elements[2] + elements[12] * other.elements[3]; elements[1] = elements[1] * other.elements[0] + elements[5] * other.elements[1] + elements[9] * other.elements[2] + elements[13] * other.elements[3]; elements[2] = elements[2] * other.elements[0] + elements[6] * other.elements[1] + elements[10] * other.elements[2] + elements[14] * other.elements[3]; elements[3] = elements[3] * other.elements[0] + elements[7] * other.elements[1] + elements[11] * other.elements[2] + elements[15] * other.elements[3]; elements[4] = elements[0] * other.elements[4] + elements[4] * other.elements[5] + elements[8] * other.elements[6] + elements[12] * other.elements[7]; elements[5] = elements[1] * other.elements[4] + elements[5] * other.elements[5] + elements[9] * other.elements[6] + elements[13] * other.elements[7]; elements[6] = elements[2] * other.elements[4] + elements[6] * other.elements[5] + elements[10] * other.elements[6] + elements[14] * other.elements[7]; elements[7] = elements[3] * other.elements[4] + elements[7] * other.elements[5] + elements[11] * other.elements[6] + elements[15] * other.elements[7]; elements[8] = elements[0] * other.elements[8] + elements[4] * other.elements[9] + elements[8] * other.elements[10] + elements[12] * other.elements[11]; elements[9] = elements[1] * other.elements[8] + elements[5] * other.elements[9] + elements[9] * other.elements[10] + elements[13] * other.elements[11]; elements[10] = elements[2] * other.elements[8] + elements[6] * other.elements[9] + elements[10] * other.elements[10] + elements[14] * other.elements[11]; elements[11] = elements[3] * other.elements[8] + elements[7] * other.elements[9] + elements[11] * other.elements[10] + elements[15] * other.elements[11]; elements[12] = elements[0] * other.elements[12] + elements[4] * other.elements[13] + elements[8] * other.elements[14] + elements[12] * other.elements[15]; elements[13] = elements[1] * other.elements[12] + elements[5] * other.elements[13] + elements[9] * other.elements[14] + elements[13] * other.elements[15]; elements[14] = elements[2] * other.elements[12] + elements[6] * other.elements[13] + elements[10] * other.elements[14] + elements[14] * other.elements[15]; elements[15] = elements[3] * other.elements[12] + elements[7] * other.elements[13] + elements[11] * other.elements[14] + elements[15] * other.elements[15]; return *this; } I did have a nested loop to do this but I ended up writing it all out while trying to find out an answer to this problem. Bear in mind the matrices are in column major and do not get transposed by OpenGL The rotation and translation matrices are as follows but I don't believe there is any problem with them: Matrix4 Matrix4::translation(const Vector3 &translation) { Matrix4 result(1.0f); result.elements[0 + 3 * 4] = translation.x; result.elements[1 + 3 * 4] = translation.y; result.elements[2 + 3 * 4] = translation.z; return result; } Matrix4 Matrix4::rotation(float angle, const Vector3 &axis) { Matrix4 result(1.0f); float r = toRadians(angle); float c = (float)cos(r); float s = (float)sin(r); float cFlip = 1.0f - c; result.elements[0 + 0 * 4] = axis.x * cFlip + c; result.elements[1 + 0 * 4] = axis.y * axis.x * cFlip + axis.z * s; result.elements[2 + 0 * 4] = axis.x * axis.z * cFlip - axis.y * s; result.elements[0 + 1 * 4] = axis.x * axis.y * cFlip - axis.z * s; result.elements[1 + 1 * 4] = axis.y * cFlip + c; result.elements[2 + 1 * 4] = axis.y * axis.z * cFlip + axis.x * s; result.elements[0 + 2 * 4] = axis.x * axis.y * cFlip + axis.y * s; result.elements[1 + 2 * 4] = axis.y * axis.z * cFlip - axis.x * s; result.elements[2 + 2 * 4] = axis.z * cFlip + c; return result; } Any ideas on what the problem here could be or how to fix it would be greatly appreciated :^)
At your multiply function, you wrote: elements[0] = elements[0] * other.elements[0] ... ... Notice that element[0] got its contents actualized now and then you do: elements[8] = elements[0] * other.elements[8] ... which use the new value and not the original one. I guess, you want to make a copy of your original matrix before doing this multiplication
opssss !! i just saw !!! in your multiply, your output matrice is the first input matrix, so the latest operations are calculated with coefficient of the multiplied matrix !! : elements[0] = elements[0] * ..... .... elements[4] = elements[0] * ..... /* here element[ 0 ] is the top left element of the multiplied matix */ moreover, operator* shouldn't modfify (nor return) one of his operand, operator*= is here for that
Rotate quad made in geometry shader
I'm drawing a quad using Geometry Shader, but can't figure out how to rotate it with angle. void main(void) { float scaleX = 2.0f / u_resolution.x; float scaleY = 2.0f / u_resolution.y; float nx = (u_position.x * scaleX) - 1.0f; float ny = -(u_position.y * scaleY) + 1.0f; float nw = u_size.x * scaleX; float nh = u_size.y * scaleY; gl_Position = vec4( nx+nw, ny, 0.0, 1.0 ); texcoord = vec2( 1.0, 0.0 ); EmitVertex(); gl_Position = vec4(nx, ny, 0.0, 1.0 ); texcoord = vec2( 0.0, 0.0 ); EmitVertex(); gl_Position = vec4( nx+nw, ny-nh, 0.0, 1.0 ); texcoord = vec2( 1.0, 1.0 ); EmitVertex(); gl_Position = vec4(nx, ny-nh, 0.0, 1.0 ); texcoord = vec2( 0.0, 1.0 ); EmitVertex(); EndPrimitive(); } Should I use a rotation matrix or sin and cos? I'm not too great at math.
You don't have to use matrices, but you need to use those sine functions. Here is a way to rotate a 3D position about some arbitrary axis by some angle specified in degrees: // This is the 3D position that we want to rotate: vec3 p = position.xyz; // Specify the axis to rotate about: float x = 0.0; float y = 0.0; float z = 1.0; // Specify the angle in radians: float angle = 90.0 * 3.14 / 180.0; // 90 degrees, CCW vec3 q; q.x = p.x * (x*x * (1.0 - cos(angle)) + cos(angle)) + p.y * (x*y * (1.0 - cos(angle)) + z * sin(angle)) + p.z * (x*z * (1.0 - cos(angle)) - y * sin(angle)); q.y = p.x * (y*x * (1.0 - cos(angle)) - z * sin(angle)) + p.y * (y*y * (1.0 - cos(angle)) + cos(angle)) + p.z * (y*z * (1.0 - cos(angle)) + x * sin(angle)); q.z = p.x * (z*x * (1.0 - cos(angle)) + y * sin(angle)) + p.y * (z*y * (1.0 - cos(angle)) - x * sin(angle)) + p.z * (z*z * (1.0 - cos(angle)) + cos(angle)); gl_Position = vec4(q, 1.0); If you know that you are rotating about some standard x-, y-, or z-axis, you can simplify the "algorithm" a lot by defining it explicitly for that standard axis. Notice how we rotate about the z-axis in the above code. For example, rotation about the x-axis would be (x,y,z) = (1,0,0). You could set the variables to anything, but the values should result in the axis being a unit vector (if that even matters.) Then again, you might as well use matrices: vec3 n = vec3(0.0, 0.0, 1.0); // the axis to rotate about // Specify the rotation transformation matrix: mat3 m = mat3( n.x*n.x * (1.0f - cos(angle)) + cos(angle), // column 1 of row 1 n.x*n.y * (1.0f - cos(angle)) + n.z * sin(angle), // column 2 of row 1 n.x*n.z * (1.0f - cos(angle)) - n.y * sin(angle), // column 3 of row 1 n.y*n.x * (1.0f - cos(angle)) - n.z * sin(angle), // column 1 of row 2 n.y*n.y * (1.0f - cos(angle)) + cos(angle), // ... n.y*n.z * (1.0f - cos(angle)) + n.x * sin(angle), // ... n.z*n.x * (1.0f - cos(angle)) + n.y * sin(angle), // column 1 of row 3 n.z*n.y * (1.0f - cos(angle)) - n.x * sin(angle), // ... n.z*n.z * (1.0f - cos(angle)) + cos(angle) // ... ); // Apply the rotation to our 3D position: vec3 q = m * p; gl_Position = vec4(q, 1.0); Notice how the elements of the matrix are laid out such that we first complete the first column, and then the second, and so on; the matrix is in column-major order. This matters when you try to transfer a matrix written in mathematical notation into a data type in your code. You basically need to transpose it (to flip the elements diagonally) in order to use it in your code. Also, we are essentially multiplying a matrix on left with a column vector on right. If you need a 4-by-4 homogeneous matrix, then you would simply add an extra column and a row into the above matrix, such that both the new rightmost column and bottommost row would consist of [0 0 0 1]: vec4 p = position.xyzw; // new dimension vec3 n = ...; // same mat4 m = mat4( // new dimension ... 0.0, ... 0.0, ... 0.0, 0.0, 0.0, 0.0, 1.0 ); vec4 q = m * p; gl_Position = q; Again, notice the order of the multiplication when applying the rotation, it is important because it affects the end result. What happens in the multiplication is basically that a new vector is formed by calculating the dot-product of the position vector and each column in the matrix; each coordinate in the resulting vector is the dot-product of the original vector and a single column in the matrix (see the first code example.) The q.x = p.x * (x*x * (1.0 - cos(angle)) + cos(angle)) + p.y * (x*y * (1.0 - cos(angle)) + z * sin(angle)) + p.z * (x*z * (1.0 - cos(angle)) - y * sin(angle)); Is same as: q.x = dot(p, m[0]); One could even compose the matrix with itself: m = m*m; which would result in a 180-degree counterclockwise rotation matrix, depending on the angle used.