Does the order of indices matter? - javascript

this._vertices = new Float32Array([
-0.5, 0, 0, // left
0, 0.5, 0, // top
0.5, 0, 0 // right
]);
this._indicies = new Uint16Array([0, 1, 2]);
As you can see I have 3 points for a triangle. The problem with this is that my triangle doesn't end up getting rendered unless I change the indices to
this._indicies = new Uint16Array([0, 2, 1]);
do you know why that is? Why does the order of the indices matter? And how do I know the correct order to put the indices in?
Ps. It works when setting the draw type to LINE_LOOP but it doesn't work on triangles.

If culling is on gl.enable(gl.CULL_FACE) then triangles are culled if their vertex are counter clockwise in clip space (ie, after the vertex shader). You can choose which triangles, clockwise or counter-clockwise get culled with gl.cullFace(...)
0 0
/ \ / \
/ \ / \
2-----1 1-----2
clockwise counter-clockwise

Order of vertices does indeed matter if face culling is enabled. What's the front and what's the back of a triangle depends on the set winding order. If counterclock winding is enabled (the default) then faces which vertices appear in counterclock wise order on the screen are considered "front" side.
If culling is enabled then only triangle upon which you look from a selected side are drawn.

Related

WebGL Cannot Draw More Than 44 Points Even If Enough Buffer Space

As the title says I have a WebGL application. I am making use of drawArrays in such a fashion
gl.drawArrays(gl.LINES, 0, 44);
But I seem to be running into a problem where if I try to draw more than 44 points than I get the following error
[.WebGL-0x7000c6e700] GL_INVALID_OPERATION: Vertex buffer is not big enough for the draw call
And I have checked to make sure I have enough buffer space even hardcoding the values, it happens on whatever browser I am on.
I think the problem is my laptop (M1 MacBook Pro) as when I move the code to my windows desktop it runs fine.
// edit
As for a code example
// points is an array of 46 points i.e. [[0,0,1,1],....]
let wBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, wBuffer);
gl.bufferData(gl.ARRAY_BUFFER, flatten(points), gl.STATIC_DRAW);
let vPosition = gl.getAttribLocation(program, "vPosition");
gl.vertexAttribPointer(vPosition, 4, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(vPosition);
gl.drawArrays(gl.LINES, 0, 46);
I am unsure on the specific details on why this works but turning hardware acceleration off on my browser fixed it for me.
I was having this issue myself, and I realised it was because the count (drawArrays third argument) was wrong.
The problem for me was, that the array had single co-ordinates, so every two elements === one vec2 for the vertex shader.
That means that the count is not the length of the buffer array, but the length / 2.
You should match the count to how many shapes you will draw - if you're drawing points, then it's buffer.length / 2. If you're drawing triangles, it will be buffer.length / 6.

Placing a Polygon using a given set of 3D coordinates in ThreeJS

I'm trying to draw a polygon (wall) in 3D space with Three.JS but it's proving hard to do.
I want to use ExtrudeGeometry as my wall needs thickness. Also, assume there might be anywhere from three to an infinite amount of points so, a simple BoxGeometry is not suitable.
Consider this:
Starting from the bottom left and moving clockwise, say these are the coordinates of the green points. Assume given points are always on the same plane.
[
[1, 0, -1],
[1, 3, -1],
[5, 3, -4],
[5, 0, -4],
]
It works fine on a 2D plane because Shape takes 2D points. Something like this:
const shape = new THREE.Shape();
shape.lineTo(0, 0);
shape.lineTo(0, 5);
shape.lineTo(5, 5);
shape.lineTo(5, 0);
const geometry = new THREE.ExtrudeGeometry(shape, { steps: 1, depth: 1 });
const material = new THREE.MeshStandardMaterial();
const mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
The only way I can think of doing this is by rotating my points to a 2D plane to find what the 2D equivalent coordinates would be, then to create the shape then rotate the geometry back to where I want. This seems excessively complicated though and, if my coordinates were rotated about two axes, then that would open another can of worms.
So how can I place a polygon in 3D space given a set of three or more points?

WebGL, gl-matrix. How to get frustrum vertices from camera view and projection matrices?

I am using the gl-matrix library. For linear algebra calculations
I have a view and projection matrix that I used for my camera in a 3d engine. The view is a lookat matrix.
const view = mat4.lookAt(
[],
camera.eye,
camera.target,
camera.up
);
const projection = mat4.perspective(
[],
Math.PI / 4,
viewport.width / viewport.height,
0.1,
1000.0
);
I want to get the 8 camera frustum vertices from this camera setup to use in a bounding box for a shadow map.
At perspective projection the projection matrix describes the mapping from 3D points in the world as they are seen from of a pinhole camera, to 2D points of the viewport.
The eye space coordinates in the camera frustum (a truncated pyramid) are mapped to a cube (the normalized device coordinates).
In normalized device space the corner points of the view volume are the corners of a cube with the left, bottom, near of (-1, -1, -1) and the right, top, far of (1, 1, 1).
To get the points in view space, the points in normalized device space have to be transformed by the inverse projection matrix, followed by a Perspective divide.
A point in view space can be transformed to a point in world space, by the inverse view matrix.
The inverse matrix can be computed by mat4.invert. The code to transform a point from normalized device space to world space may be as follows:
inv_view = mat4.invert([], view);
inv_proj = mat4.invert([], projection);
ndc_corner = vec4.set([], -1, -1, -1, 1); // (-1, -1, -1) left, bottom, near
view_corner_h = vec4.transformMat4([], ndc_corner, inv_proj);
view_corner = vec4.scale([], view_corner_h, 1/view_corner_h[3]);
world_corner = vec4.transformMat4([], view_corner, inv_view);

Threejs Transform Matrix ordering

I would like to know how threejs ordering multiple matrix?
For instance ,
......
var mesh = new THREE.Mesh( geometry, material );
mesh.position.set( 0, 20, 0 ); // T , transform matrix
mesh.rotation.set( 0, Math.PI, 0 );//R , rotation matrix
mesh.scale.set( 1, 1, 10 );//S , scale matrix
So , how threejs to combine three matrix? It will according my set value order(In my example , it is TRS , so final matrix should T*R*S ) or fixed order (For instance, it is always using SRT ordering , the finally matrix is S*R*T)?
You can specify the parameters as you have done so long as the mesh property 'matrixAutoUpdate' is true and you only want it in order by scale, rotation then translation (typical).
If you need something more complicated, such as a specific series of translations and rotations, then you should set matrixAutoUpdate to false and calculate the matrix yourself.
Important note: when using the matrix multiply function, you must do it in 'reverse' order. For example if you want to position a limb then logically you would:
1) do local rotation (such as arm up/down)
2) move limb with respect to its offset (put it at its joint)
3) rotate according to body rotation
4) move to body offset
The actual operations would be done in reverse:
arm_mesh.matrixAutoUpdate = false;
var mat4: THREE.Matrix4 = new THREE.Matrix4();
var arm_matrix = arm_mesh.matrix;
arm_matrix.identity(); // reset
arm_matrix.multiply(mat4.makeTranslation(body_pos.x, body_pos.y, body_pos.z));
arm_matrix.multiply(mat4.makeRotationFromQuaternion(body_rotation));
arm_matrix.multiply(mat4.makeTranslation(arm_offset.x, arm_offset.y, arm_offset.z));
arm_matrix.multiply(mat4.makeRotationFromEuler(new THREE.Euler(arm_angle, 0, 0)));
Of course this does not utilize or account for parent/child relationships.

CSS3 Matrix rotation

I have a CSS 3D cube that I'm trying to rotate left/right/up/down straight as it appears to user. If I use css rotation functions, then I rotate the axis, not the cube.
There are lots of articles on the web about X,Y,Z matrix rotation calculation, but I've spend days now trying to set this thing and none of this information really helps me.
The work around to my problem would be a WebKitCSSMatrix object, which has its own rotation functions that work as magic. An example on Fiddle: http://jsfiddle.net/joecritch/tZBDW/. But again, that relies only uppon Webkit, but I need to be crossbrowsy here.
Now, there are 3 steps on the way of success:
1) I need to get current matrix, set directional vector (1,0,0 for up/down and 0,1,0 for left/right rotations) and set the angle. DONE.
2) I need to calculate new rotation vector based on current matrix. DONE.
3) I need to actually rotate my current matrix by new vector and angle. PROBLEM.
var newMArray = deMatrix(".cube");//getting current matrix from CSS
var v = [vecX, vecY, vecZ, 0];//current vector (1,0,0) or (0,1,0)
var newV = newMVector(newMArray, v);//calculating new vector for current matrix
//getting the angle for each axis based on new vector
angleX = newV[0]*angle;
angleY = newV[1]*angle;
angleZ = newV[2]*angle;
this.rotateX -= angleX;
this.rotateY -= angleY;
this.rotateZ -= angleZ;
//calculating the rotation matrix
var rotationXMatrix, rotationYMatrix, rotationZMatrix, s, transformationMatrix;
rotationXMatrix = $M([[1, 0, 0, 0], [0, Math.cos(this.rotateX * deg2rad), Math.sin(-this.rotateX * deg2rad), 0], [0, Math.sin(this.rotateX * deg2rad), Math.cos(this.rotateX * deg2rad), 0], [0, 0, 0, 1]]);
rotationYMatrix = $M([[Math.cos(this.rotateY * deg2rad), 0, Math.sin(this.rotateY * deg2rad), 0], [0, 1, 0, 0], [Math.sin(-this.rotateY * deg2rad), 0, Math.cos(this.rotateY * deg2rad), 0], [0, 0, 0, 1]]);
rotationZMatrix = $M([[Math.cos(this.rotateZ * deg2rad), Math.sin(-this.rotateZ * deg2rad), 0, 0], [Math.sin(this.rotateZ * deg2rad), Math.cos(this.rotateZ * deg2rad), 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]);
transformationMatrix = rotationXMatrix.x(rotationYMatrix).x(rotationZMatrix);//getting all axis rotation into one matrix
Than I'm setting new transformation matrix to my CSS Cube. The problem is - it doesn't rotate as it should. Now I'm using Sylvester plugin to do all matrix calculation.
So, please help me on how to use my new vector for proper matrix rotation.
I am having a very hard time following your code. But if I understand it correctly you are going around a basic problem really backwards.
Your starting point is an object that has a matrix transform. You want to change that transform. At this point it is very tempting to just try things and see what sticks. No offense, but that is what your code looks like it is doing. What you really need is to understand how matrices work. There are lots of good tutorials. (first google hit: http://chortle.ccsu.edu/vectorlessons/vectorindex.html) It will take some time but help a lot in the long run.
The basic issue you are facing is that matrix multiplication is no commutative. A * B != B * A for matrices. Depending on what matrix you are setting it includes a lot of transformations where order matter: (A) Move the object to it's origin (B) Rotate the object around it's origin (C) Move the object to a position in the world (D) Move the object to where the camera is at the origin (E) Rotate around the camera. The matrix you see is just A * B * C * D * E. Now depending on what you want to do you better have a good plan. In most cases you either want to rotate the object or the camera and you can just multiply either on the left or right side. Your code looks a little bit like you are multiplying on the wrong side and trying to jump through hoops to compensate for that which somewhat works because a lot of the matrices are identity.
So even more practical: Get your cube matrix, make a rotation matrix independent of it (no -angle!), and set back rotation*cubematrix as your new transform.
Sylvester can generate rotation matrixes as well. Looking at the fiddle example - the webkit function that seems to do the rotation:
// Rotate the Matrix around the transformed vector
var newMatrix = m.rotateAxisAngle(vector.x, vector.y, vector.z, angle);
Looks like it's more along the lines of the Matrix.Rotation(angle [, axis]) function, I think you'd provide axis as a Sylvester Vector object, rather than the webkit x,y,z arguments - http://sylvester.jcoglan.com/api/matrix.html#rotation
Multiplying the x,y,z matrices doesn't work too well because the additional transforms will be applied on the new context. I've just fallen into this trap with this js/canvas page: http://benjaminbenben.com/projects/twittny_test/

Categories