-
Notifications
You must be signed in to change notification settings - Fork 104
Description
Hi, just followed the discussion in sourceforge forum, see here:
I did some test, and what I need to find a way to tweak the transformation of each Geometry class instances.
You can see the animation when I press the "Arrow up" and "Arrow down" key, so that the objects in the scene get shifted.
Here is the code/patch I used to modify the gs file, I'm not sure it is correct, so I hope the devs can help.
--- F:/code/asymptote/webgl/gl.js Fri Mar 14 19:30:07 2025
+++ F:/code/asy-test/asygl.js Sat Mar 15 19:47:39 2025
@@ -92,14 +92,16 @@
let projViewMat=mat4.create(); // projection view matrix
let normMat=mat3.create();
let viewMat3=mat3.create(); // 3x3 view matrix
let cjMatInv=mat4.create();
let Temp=mat4.create();
+let gMotionMatrix = mat4.create(); // identity matrix
+
let zmin,zmax;
let center={x:0,y:0,z:0};
let size2;
let ArcballFactor;
let shift={
x:0,y:0
};
@@ -450,14 +452,15 @@
data.indicesBuffer,copy,
gl.ELEMENT_ARRAY_BUFFER);
data.rendered=true;
gl.drawElements(normal ? (wireframe ? gl.LINES : data.type) : gl.POINTS,
indices.length,
indexExt ? gl.UNSIGNED_INT : gl.UNSIGNED_SHORT,0);
+ console.log("drawElements() function call: normal], wireframe], data.type], indices.length]", normal, wireframe, data.type, indices.length);
}
let TRIANGLES;
class vertexBuffer {
constructor(type) {
this.type=type ? type : TRIANGLES;
@@ -579,14 +582,16 @@
}
class Geometry {
constructor() {
this.data=new vertexBuffer();
this.Onscreen=false;
this.m=[];
+ // Local transformation matrix (4x4) - initialized as identity matrix
+ this.localTransform = mat4.create();
}
// Is 2D bounding box formed by projecting 3d points in vector v offscreen?
offscreen(v) {
let m=projViewMat;
let v0=v[0];
let x=v0[0], y=v0[1], z=v0[2];
@@ -611,23 +616,35 @@
this.Onscreen=false;
return true;
}
return false;
}
T(v) {
- let c0=this.c[0];
- let c1=this.c[1];
- let c2=this.c[2];
- let x=v[0]-c0;
- let y=v[1]-c1;
- let z=v[2]-c2;
- return [x*normMat[0]+y*normMat[3]+z*normMat[6]+c0,
- x*normMat[1]+y*normMat[4]+z*normMat[7]+c1,
- x*normMat[2]+y*normMat[5]+z*normMat[8]+c2];
+ let c0 = this.c[0];
+ let c1 = this.c[1];
+ let c2 = this.c[2];
+
+ // Translate vertex relative to the object center
+ let x = v[0] - c0;
+ let y = v[1] - c1;
+ let z = v[2] - c2;
+ let w = 1.0; // Homogeneous coordinate
+
+ // Apply localTransform (4×4 matrix)
+ let lx = this.localTransform[0] * x + this.localTransform[4] * y + this.localTransform[8] * z + this.localTransform[12] * w;
+ let ly = this.localTransform[1] * x + this.localTransform[5] * y + this.localTransform[9] * z + this.localTransform[13] * w;
+ let lz = this.localTransform[2] * x + this.localTransform[6] * y + this.localTransform[10] * z + this.localTransform[14] * w;
+
+ // Apply normal transformation matrix
+ return [
+ lx * normMat[0] + ly * normMat[3] + lz * normMat[6] + c0,
+ lx * normMat[1] + ly * normMat[4] + lz * normMat[7] + c1,
+ lx * normMat[2] + ly * normMat[5] + lz * normMat[8] + c2
+ ];
}
Tcorners(m,M) {
return [this.T(m),this.T([m[0],m[1],M[2]]),this.T([m[0],M[1],m[2]]),
this.T([m[0],M[1],M[2]]),this.T([M[0],m[1],m[2]]),
this.T([M[0],m[1],M[2]]),this.T([M[0],M[1],m[2]]),this.T(M)];
}
@@ -663,18 +680,23 @@
}
let p=this.controlpoints;
let P;
if(this.CenterIndex == 0) {
if(!remesh && this.Onscreen) { // Fully onscreen; no need to re-render
+ console.log("render(): calling this.append, remesh, this.Onscreen, but return early", remesh, this.Onscreen);
this.append();
return;
}
- P=p;
+ // modify every point's coordinates by local transform matrix
+ let n=p.length;
+ P=Array(n);
+ for(let i=0; i < n; ++i)
+ P[i]=this.localT(p[i]);
} else { // Transform billboard labels
let n=p.length;
P=Array(n);
for(let i=0; i < n; ++i)
P[i]=this.T(p[i]);
}
@@ -684,16 +706,34 @@
s*(viewParam.ymax-viewParam.ymin))/size2;
this.res2=res*res;
this.Epsilon=FillFactor*res;
this.data.clear();
this.notRendered();
this.Onscreen=true;
+ console.log("render(): calling this.process(P), which copies data", P);
this.process(P);
}
+ // Function to modify local transformation matrix
+ setLocalTransform(matrix) {
+ this.localTransform = matrix;
+ // this.data.clear(); // Clear old data
+ }
+
+ localT(v) {
+ if (!this.localTransform) return v; // If no transformation, return original vertex
+
+ let x = v[0], y = v[1], z = v[2], w = 1.0;
+ // Apply the local transformation matrix (this.localTransform)
+ return [
+ this.localTransform[0] * x + this.localTransform[4] * y + this.localTransform[8] * z + this.localTransform[12] * w,
+ this.localTransform[1] * x + this.localTransform[5] * y + this.localTransform[9] * z + this.localTransform[13] * w,
+ this.localTransform[2] * x + this.localTransform[6] * y + this.localTransform[10] * z + this.localTransform[14] * w
+ ];
+ }
}
function boundPoints(p,m)
{
let b=p[0];
let n=p.length;
for(let i=1; i < n; ++i)
@@ -2830,14 +2870,16 @@
if(W.embedded && zoomEnabled && event.keyCode == ESC) {
disableZoom();
return;
}
let keycode=event.key;
let axis=[];
+ let translation = [0, 0, 0]; // Translation vector
+ let translMatrix = mat4.create(); // Create an empty 4x4 matrix
switch(keycode) {
case 'x':
axis=[1,0,0];
break;
case 'y':
axis=[0,1,0];
@@ -2868,14 +2910,34 @@
case '_':
case '<':
shrink();
break;
case 'c':
showCamera();
break;
+ case 'ArrowUp':
+ translation = [0, 0, 5];
+ mat4.fromTranslation(translMatrix, translation); // Fill translMatrix with the translation matrix
+ gMotionMatrix = translMatrix // Move up
+ console.log("up key arrow up, gMotionMatrix = ", gMotionMatrix);
+ remesh=true;
+ drawScene();
+ break;
+ case 'ArrowDown':
+ translation = [0, 0, -5];
+ mat4.fromTranslation(translMatrix, translation); // Fill translMatrix with the translation matrix
+ gMotionMatrix = translMatrix // Move up
+ console.log("up key arrow down, gMotionMatrix = ", gMotionMatrix);
+ remesh=true;
+ drawScene();
+ break;
+ case 'ArrowLeft':
+ break;
+ case 'ArrowRight':
+ break;
default:
break;
}
if(axis.length > 0) {
mat4.rotate(rotMat,rotMat,0.1,axis);
updateViewMatrix();
@@ -3086,18 +3148,21 @@
offscreen.width=W.canvasWidth;
offscreen.height=W.canvasHeight;
setViewport();
}
gl.clearColor(W.background[0],W.background[1],W.background[2],W.background[3]);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+ console.log("loop on all geometry P list");
+ for (let i = 0; i < P.length; i++) {
+ P[i].setLocalTransform(gMotionMatrix);
+ P[i].render();
+ }
- for(const p of P)
- p.render();
-
+ console.log("drawBuffers()");
drawBuffers();
if(W.embedded) {
context.clearRect(0,0,W.canvasWidth,W.canvasHeight);
context.drawImage(offscreen,0,0);
}
The main change here is:
In the class Geometry, I added a new field named this.localTransform
So, the constructor becomes like below:
class Geometry {
constructor() {
this.data=new vertexBuffer();
this.Onscreen=false;
this.m=[];
// Local transformation matrix (4x4) - initialized as identity matrix
this.localTransform = mat4.create();
}
In the event handler for the keyboard, I try to modify a global matrix variable:
case 'ArrowUp':
translation = [0, 0, 5];
mat4.fromTranslation(translMatrix, translation); // Fill translMatrix with the translation matrix
gMotionMatrix = translMatrix // Move up
console.log("up key arrow up, gMotionMatrix = ", gMotionMatrix);
remesh=true;
drawScene();
break;
case 'ArrowDown':
translation = [0, 0, -5];
mat4.fromTranslation(translMatrix, translation); // Fill translMatrix with the translation matrix
gMotionMatrix = translMatrix // Move up
console.log("up key arrow down, gMotionMatrix = ", gMotionMatrix);
remesh=true;
drawScene();
break;
case 'ArrowLeft':
break;
case 'ArrowRight':
break;
And when drawScene() get called inside the keyboard event handler, I try to update every object's localTransform matrix
function drawScene()
{
if(W.embedded) {
offscreen.width=W.canvasWidth;
offscreen.height=W.canvasHeight;
setViewport();
}
gl.clearColor(W.background[0],W.background[1],W.background[2],W.background[3]);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
console.log("loop on all geometry P list");
for (let i = 0; i < P.length; i++) {
P[i].setLocalTransform(gMotionMatrix);
P[i].render();
}
...
Now, you can see: P[i].setLocalTransform(gMotionMatrix); will copy the global matrix to the P[i], and later, inside the render() function call, I just re-calculate the position, like below:
render() {
this.setMaterialIndex();
// First check if re-rendering is required
let v;
if(this.CenterIndex == 0)
v=corners(this.Min,this.Max);
else {
this.c=W.Centers[this.CenterIndex-1];
v=this.Tcorners(this.Min,this.Max);
}
if(this.offscreen(v)) { // Fully offscreen
this.data.clear();
this.notRendered();
return;
}
let p=this.controlpoints;
let P;
if(this.CenterIndex == 0) {
if(!remesh && this.Onscreen) { // Fully onscreen; no need to re-render
console.log("render(): calling this.append, remesh, this.Onscreen, but return early", remesh, this.Onscreen);
this.append();
return;
}
// modify every point's coordinates by local transform matrix
let n=p.length;
P=Array(n);
for(let i=0; i < n; ++i)
P[i]=this.localT(p[i]);
} else { // Transform billboard labels
let n=p.length;
P=Array(n);
for(let i=0; i < n; ++i)
P[i]=this.T(p[i]);
}
...
So, here is the test asymptote code:
import three; // Import 3D drawing module
size(300);
//currentprojection = perspective(10, 10, 10);
currentprojection=
perspective(camera=(0.26829265777219125,16.279223021307676,6.398560022438133),
up=(0.00008257171178993584,-0.0013914064579275548,0.003844414421333313),
target=(0.5042383,-0.004253902,0.5000156),
zoom=0.5846792890864372,
angle=6.953767995927329,
autoadjust=false);
// Define triangle vertices
triple A = (0, 0, 0);
triple B = (0, 0, 1);
triple C = (1, 0, 0);
triple D = (1, 0, 1);
// Draw two triangles
draw(A--B, red);
draw(C--D, blue);
The issue here is:
In the event handler, I try to move the objects up and down, but it looks like for some unknown reasons I don't know, the objects dose not shifted as expected on the Z axis, not sure why.
In the future, I need to find a way to choose which geometry instances should move/rotate when I press the mouse. For example, if I have a robot arm to move, I need to know which pieces of the patches/triangles belongs to which robot links. so that I can assign a single/same mat4 matrix for those components, so that I can move the robot arms.
What do you think about the idea? Thanks.
