its all part of a larger project sure once it all comes together nicely it should be possible
@JohnK this is awesome John, I have some doubts posted them in the arrow thread
@JohnK
“The normal, N, the gradient vector G = (p, p2 + q2, q ) and (N cross G) form 3 orthogonal vectors. To get these to match you may have to play around with using (G cross N) rather than (N cross G) direction of one in in opposite to the other and setting y = N then play with x = G or z = G”
I will try this, so do you mean that the final 3 axis for Vector3.RotationFromAxis would be:
(N, G, NxG) ?
or
(G, N, N x G)? or (NxG, N, G)? or (G,N,GxN) or (GxN, N, G)?
now I wonder if its better to try this, or to try the new arrow you posted that seems that could go from any point in 3d space directly into the direction of gradient in 3dspace
One of these.
My choice would be to go with using the extrusion with start and direction for the arrow.
@JohnK thank you John, so yes Im going to try your new arrow,
so I just tried and yes I can create and position the arrow in space, but now I need to constantly update it every few milliseconds to change its starting point and of course its direction (towards the gradient vector), so mmm, in order to do that, what do you recommend, would I have to reconstruct that entire arrow every time I do that? in terms of performance that would not be ideal, what would be the way to just update start and direction of the arrow every few milliseconds without reconstructing the entire arrow?
Did not realise you needed to do that. In that case doing the rotation on your original arrow will probably be faster.
@JohnK I’m actually creating the code now to do that, i already have the beginning of arrow , and now to do the end of it I guess i have to add to the beginning the gradient vector, im going to try it now
@JohnK mm, so if i have
const dir = new Vector3(-gp,-(gp x gp+gq x gq), -gq);
const arrowStart = pickInfo.pickedPoint;
let arrowDirection = dir;
const arrowBodyEnd = arrowStart.add(arrowDirection.scale(arrowBodyLength));
const arrowHeadEnd = arrowBodyEnd.add(arrowDirection.scale(arrowHeadLength))
This is not working, the start of arrow yes appears perfect, but the end of arrow continues fixed in a point in space moving just a tiny bit, how do I apply the gradient direction vector to the end of this arrow? Im really curious to try it
@JohnK wow it works now, and I think even better than the rotation, im testing, will share code in a bit to see what u think
wow this really works much better than the other arrow, wow
in performance i guess it may be worse, but it just behaves much better
@JohnK rotating the other arrow wasnt working well, this really points in the right direction, this works much better, now I just need to do the scaling because i need the scaling, im gonna try to do the scaling then will show the code here to see what u think, but this is definitely the way
You could speed up the arrow rendering by using n = 3 to construct myShape, this reduces the vertex count
@JohnK wonderful John, thank you so much again, so it works really good, and the direction of the arrow is really good, this is the code:
I separately declare myShape and scaling variables as you did in your code
Then create the arrow with:
const createArrow2=(scene)=>{
const arrowHeadLength = 1.5;
const arrowHeadMaxSize = 1.5;
const arrowLength = 10;
const arrowBodyLength = arrowLength - arrowHeadLength;
const arrowStart = new Vector3(1, 2, 1);
let arrowDirection = new Vector3(2, 1, 10);
arrowDirection.normalize();
const arrowBodyEnd = arrowStart.add(arrowDirection.scale(arrowBodyLength));
const arrowHeadEnd = arrowBodyEnd.add(arrowDirection.scale(arrowHeadLength))
const myPath = ;
myPath.push(arrowStart);
myPath.push(arrowBodyEnd);
myPath.push(arrowBodyEnd)
myPath.push(arrowHeadEnd);
let arrow = MeshBuilder.ExtrudeShapeCustom(“arrow”, {shape: myShape, path: myPath, updatable: true, scaleFunction: scaling, sideOrientation: Mesh.DOUBLESIDE});
const arrowMat = new StandardMaterial(‘arrowMat’, scene);
arrowMat.emissiveColor = Color3.Yellow();
arrow.material = arrowMat;
return arrow;
};
And then when user moves around every x milliseconds I update arrow with this:
const setArrow2 = (pickInfo) =>{
//// … here go all the previous calculations to calculate gradient info…
const arrowHeadLength = 1.5;
const arrowHeadMaxSize = 1.5;
// here I decide the new length for the arrow
let gradFact=arrowScale[mcur]*gradmag/20;
if (gradFact<10) {gradFact=10;} //prevent it from going to small
let arrowLength = gradFact;
const arrowBodyLength = arrowLength - arrowHeadLength;
const arrowStart = pickInfo.pickedPoint;
let arrowDirection = dir;
arrowDirection.normalize();
const arrowBodyEnd = arrowStart.add(arrowDirection.scale(arrowBodyLength));
const arrowHeadEnd = arrowBodyEnd.add(arrowDirection.scale(arrowHeadLength))
const myPath = [];
myPath.push(pickInfo.pickedPoint);
myPath.push(arrowBodyEnd);
myPath.push(arrowBodyEnd)
myPath.push(arrowHeadEnd);
MeshBuilder.ExtrudeShapeCustom("arrow", {shape: myShape, path: myPath, scaleFunction: scaling, instance: myArrow2} );
return gradmag;
};
So all that works really well, much better than before,
my only doubt now is about displaying the strength of the gradient, at the moment Im using
const Grad = new Vector2(gp,gq);
const gradmag=Grad.length();
and I display that, and it makes sense, its larger in more steep parts and smaller in less steep parts, however sometimes I see some inconsistencies, like sometimes in 2 areas of model with steepness quite similar the value of Grad.length may be clearly different which confuses me a bit, maybe this gradient strength value still needs some tweaking
Update: the gradient strength (length) is good I think, did some more tests, I think its all good with it yeah
@JohnK I changed from 30 to 3 as you suggested in shape, to improve performance, any other tweaks that can help in performance let me know, this is definitely the way
about gradient strength:
Update: the gradient strength (length) is good I think, did some more tests, I think its all good with it yeah
@JohnK what controls the thickness of arrow? I am changing well the length of both parts of arrow like this:
let gradFact=arrowScale[mcur]*gradmag/20;
if (gradFact<2) {gradFact=2;}
let arrowLength = gradFact;
arrowHeadLength = gradFact/3;
and that works very well, but what about the thickness of the arrow
yes i can see that thickness is controlled by
const arrowRadius = 0.5;
const arrowHeadMaxSize = 1.5;
which are used when creating the shape
so if i want to adapt those dynamically, I think i have an idea for doing it just adapting to each case, and not in every iteration,
update: yes I just did it, works well yeah
@JohnK John quick one, sometimes the arrow seems to appear on the model on the outside rather than the inside of the model (or just get kind of within the model to some degree other times), I was thinking in pushing the points a bit in the directions of the normal doing something like:
arrowComp[mcur]: this is a variable that specifies the strength of the push in the direction of the normal
multiplied by: because I cannot write the multiply symbol in here
const p1= new Vector3(pickInfo.pickedPoint._x+normal._x multiplied by arrowComp[mcur],pickInfo.pickedPoint._y+normal._y multiplied by arrowComp[mcur], pickInfo.pickedPoint._z+normal._z multiplied by arrowComp[mcur] );
const p2= new Vector3(arrowBodyEnd._x+normal._x multiplied by arrowComp[mcur],arrowBodyEnd._y+normal._y multiplied by arrowComp[mcur], arrowBodyEnd._z+normal._z multiplied by arrowComp[mcur] );
const p3= new Vector3(arrowHeadEnd._x+normal._x multiplied by
arrowComp[mcur],arrowHeadEnd._y+normal._y multiplied by arrowComp[mcur], arrowHeadEnd._z+normal._z multiplied by arrowComp[mcur] );
myPath.push(p1);
myPath.push(p2);myPath.push(p2);myPath.push(p3);
is that the best way to do that?
update: I did that and yes now the arrow stays always on top of the model, so this seems to solve the issue, in any case let me know if the calculations make sense because I just hope that im not pushing the arrow in an incorrect direction. If I set arrowComp[mcur]=4.0 for example then the deviation will be too large, but if i set arrowComp[mcur]=1.0 for example, then the deviation is small and seems enough to ensure the arrow stays almost always on top of the model
thank you
A couple of points.
A
Generally do not use underscore variables, eg use
arrowHeadEnd.y
not
arrowHeadEnd._y
Why not?
Many modern languages, including Typescript, allow objects to have private and public properties. In any application users are not allowed direct access to private properties only public ones. When the app coder wants to give the user access to private properties the add a getter and/or setter as accessors to the property.
babylon.js is written in Typescript and compiled to JavaScript. JavaScript does not care about private or public properties so that when you do a console.log(babylon.js object) it will list private and public properties of that object. For a vector3, console.log(vec3) will display the private properties vec3._x, vec3._y, vec3._z. However to access x, y, z of vec3 you use vec3.x, vec3.y, vec3.z as x, y, z are provided as accessors. Just use what is in API Vector3 | Babylon.js Documentation
Don’t ask me to explain further the reasons for this I have set out the extent of my understanding. Just know that unless there are very good reasons to do so never use underscore properties or methods as they are not guaranteed to remain the same.
B
Whenever possible use an existing variable rather than a new one this produces less garbage collection time.
Maybe something more along these lines
//outside of loop
let offset = BABYLON.Vector3.Zero() //create variable once
const myPath = [];
const offsetScale = 1.1;
//inside loop
//normal normalized to unit vector
//arrowDirection calculated and normalized
offset = normal.scale(offsetScale); //reuse offset
const arrowStart = position.add(offset); //needs to be new for each triangle
const arrowBodyEnd = arrowStart.add(arrowDirection.scale(arrowBodyLength));
const arrowHeadEnd = arrowBodyEnd.add(arrowDirection.scale(arrowHeadLength))
myPath.push(arrowStart);
myPath.push(arrowBodyEnd);
myPath.push(arrowBodyEnd)
myPath.push(arrowHeadEnd);
@JohnK great tips as usual thank you John,
I was using _x, _y etc because in the javascript console I could see them inside the objects but now I get totally what you mean, I will switch them all therefore to the x, y, z, etc versions yes
regarding the other code, I get it, using ‘scale’ is similar to multiplying I see, and yes to the reuse of variables to avoid garbage collection saturation yes
by the way, if inside the same function that gets repeated often I use const and let declarations are those always creating a new variable in memory I wonder? or reusing the previous space created by the previous declaration mmm
thank you