Ambiera Forum

Discussions, Help and Support.

Ambiera Forum > CopperLicht
How to Linepick Clones and animated Meshes??

csp-games
Guest
Quote
2022-01-14 02:12:30

Title says it all. I got the collision example running, Linepicks work on the loaded static meshes, but when I try it on a clone or an animated mesh, it fails.

I did tho manage to add collision response to the clones by code. How do I add pickability??

Also: how do I determine the node that was linepicked?

Understandably, when I have a shooter game, I need to know what dude was shot, and to be able to pick the target at all.

If I can't figure this out, then that's literally a game stopper for me, so - please!!


just_in_case
Moderator
Quote
2022-01-15 13:16:39

It should work on clones too, I am not sure about the animated mesh, but you can have a dummy cube as children for the animated mesh to check linepick for the animated mesh. Will try to check if it works with clones or not. By the way I will do it in CC, so am not sure if it will work for copperlicht or not. But I think that if it will work for CC then it should work for Copperlicht also.


csp-games
Guest
Quote
2022-01-15 13:37:04

Thanks a lot! So good to see somebody is actually trying to help and solve this problem. Yeah I was thinking too, use a lowpoly static hull, set invisible, parented to the NPC. But that will be a clone too, so I need it at least on the clones. Well, I could just save the scene in CC with a supply of cubes or so, but that would be kind of silly, wouldn't it?

It was already a little challenge to make camera vs clone collision work (code was posted in "createClone() prob..." thread), so I'd expect this one may be tricky too.


just_in_case
Moderator
Quote
2022-01-15 14:50:29

So, I just created a sample scene that creates a clone of a cubemesh and checks the linepick with the cloned mesh that uses the example code from the documentation that draws red rectangle over the colliding node, and I checked it with the cloned node and it did worked correctly, just to confirm that It should work in Copperlicht, I tried this for webGL platform as well and it did worked in the webGL as coppercube webGL uses copperlicht so I am damn sure it will work with copperlicht too. You might be doing something wrong with your code of linepicking or something else.

just to make sure that everything is working I added code to check the Collistion Point of world with the line code too, that will print the collision cordinates if mouse is over a 3D node, wether its the original one or cloned one it doesn't matter if there is collision it will return the cordinates, otherwise return null or 0, I checked that too in WebGL and that was working too.

here is the link to the sample ccb file, that creates a clone and check the linepick with the cloned mesh.It uses the "F" key to clone the "cubeMesh" and rename the clonedMesh with an incremented value so the Cloned mesh name will be "cubeMesh1" and there is an on frame event that check the linepick with mouse position and the cloned Cubemesh.

https://drive.google.com/file/d/...

hope this will help you.


csp-games
Guest
Quote
2022-01-15 23:21:46

Thanks, I highly appreciate you spending precious time to help here. I have to ask, or find out, whether when I clone a mesh in CC that has collision activated, the clone will also have collision? If it does, then that means CC adds some code to the file that is not part of CC, because the CL command createClone does not automatically clone the collision features.

When I use CC to clone the things that need to be cloned already in the ccbz file, I won't have the flexibility to use CLs full potential, for example to write a modeler. Right now I am capable of constructing a mesh from scratch using vertex and triangle data, eg. from a file (a mesh importer), add textures and add collision.

The ccbz file, encrypted as it seems, or just not human readable , also doesn't reveal how CC uses CL, and what is added.

Well I just keep on hacking.

Interestingly, after many hours trying to solve this, I had to make a break and code something completely different, which went from scratch to a full procedural terrain generator in less time than I spent already, trying to crack CLs Linepick enigma ^^

Not trying to show off (well maybe a bit), but here's a screenie:
🔎︎

Now back to hacking CL.


csp-games
Guest
Quote
2022-01-16 11:09:45

Not so much progress, but one thing I want to mention:

So I'm using Example 3 of the CL tutorials, the collision example that allows one to "shoot cubes at a wall". Ok, there's the Linepick code that works with the loaded mesh node, and not with the clones. But it gives only the 3D coordinate of the ray impact, not the node ID of the node that was hit.

The original line was:

var collisionPoint = scene.getCollisionGeometry().getCollisionPointWithLine(startLine, endLine, true, null);

"Null" allows to provide a triangle structure to receive the vertex coords of the triangle that was hit by the line, so I say:


var mytriangle=new CL3D.Triangle3d(true); // note its 3d, not 3D ! unlike in Vertex3D(
var collisionPoint = scene.getCollisionGeometry().getCollisionPointWithLine(startLine, endLine, false, mytriangle,false);
if (collisionPoint)
{
//alert(scene.getCollisionGeometry().getRelatedSceneNode());
alert(mytriangle.pointA);
...


mytriangle should consist of 3 vect3D structures named pointA, pointB and pointC, so I could say:
x=mytriangle.PointB.X;

Now the thing is, this works perfectly for pointB and C, but pointA will return not a Vect3D, but just a boolean "true" - that's weird, a bug?

Because, at least this triangle structure would have allowed me to simply go trough some stored mesh buffer data and compare triangles, and given there is only 1 triangle at that very position, I could at least identify the involved mesh (yet, still not working on clones, however). But as pointA doesn't seem to work, I can't see how to use this.


csp-games
Guest
Quote
2022-01-16 11:57:51

Ok, I may have found a way to work around this problem:

I don't use Linepick at all, but create a bullet mesh. To this mesh I add the collision response animater, just like I did with the fps camera. Then I shoot the bullet in the wanted direction, move it to a certain point, weapon max range away. Then, AFTER the next collision response took place (I yet have to figure out how to determine that), I compare the actual position of the bullet to the wanted position. If they are not the same, the bullet hit a wall. As I was able to add collision to clones and custom made meshes, this should work.
It still doesn't tell me what node was hit, but I could then eg. see what node is closest to that point (seems unreliable), or go trough the triangle data and find a triangle that represents a plane on which the new position of the bullet is co-planar, maybe by using

var myplane= new CL3D.Plane3d().setPlaneFrom3Points(point1, point2, point3)

That said, I have no idea how those planes should be used, see:
https://www.ambiera.com/copperlicht/documentation/symbols/CL3D.Plane3d.html

After all this being said, I am seriously thinking about to implement my own mesh loader code that keeps all triangle data in quickly accessible arrays, so I could just do a plain 3D math ray-intersects-triangle check. It may seem complicated, but in fact it boils down to a simple port of the RIT function from Blitz3D (where I got the Moller algorithm working) to javascript. Alternatively I could try to obtain the triangle data from ccbz-loaded meshes using CL functions, and then do that homegrown ray intersection test.

At least these are now 3 potential solutions to the problem. If I can make one of them do the job, I'll post it here.


csp-games
Guest
Quote
2022-01-16 12:35:56

For the records, here's the RIT function in Blitz3D, resembling easy to port pseudo code:


Function rit(px,py,pz, dx,dy,dz, V0x,V0y,V0z, V1x,V1y,V1z, V2x,V2y,V2z, Extend_To_Infinity=0, Cull_Backfaces=0)
; ray intersect triangle: px...= start point, dx...=offset to start point (start+offset=end point)
;-

E1x = V2x - V0x
E1y = V2y - V0y
E1z = V2z - V0z

;-
E2x = V1x - V0x
E2y = V1y - V0y
E2z = V1z - V0z

; Hxyz = Crossproduct(Dxyz, E2xyz)
Hx = (Dy * E2z) - (E2y * Dz)
Hy = (Dz * E2x) - (E2z * Dx)
Hz = (Dx * E2y) - (E2x * Dy)

; Calculate the dot product of the above vector and the vector between point 0 and point 2.
A = (E1x * Hx) + (E1y * Hy) + (E1z * Hz)

;cull
If (Cull_Backfaces = 1) And (A >= 0) Then Return 0

;parallel?
If (A > -0.00001) And (A < 0.00001) Then Return 0


;Inverse Determinant
F = 1.0 / A

;-
Sx = Px - V0x
Sy = Py - V0y
Sz = Pz - V0z

; U = F * (DotProduct(Sxyz, Hxyz))
U = F * ((Sx * Hx) + (Sy * Hy) + (Sz * Hz))

;check u
If (U < 0.0) Or (U > 1.0) Return 0

; Qxyz = CrossProduct(Sxyz, E1xyz)
Qx = (Sy * E1z) - (E1y * Sz)
Qy = (Sz * E1x) - (E1z * Sx)
Qz = (Sx * E1y) - (E1x * Sy)


; V = F * DotProduct(Dxyz, Qxyz)
V = F * ((Dx * Qx) + (Dy * Qy) + (Dz * Qz))

;check v
If (V < 0.0) Or ((U + V) > 1.0) Return 0

T = F*((E2x*Qx)+(E2y*Qy)+(E2z*Qz))

If T<0 Return 0; orig
;If T<=0 Return 0


If (Extend_To_Infinity=0) And (T>1) Return 0

;intersects
Return 1

End Function





csp-games
Guest
Quote
2022-01-16 14:11:12

Here's some further info, for those interested in the subject matter:

This is how to parse all meshes and their mesh buffers and their vertices, for instance:


// this reads the first vertexX of the first meshbuffer of the first scene node (given that is a mesh - see the weird string getType returns...)
var kids=scene.getRootSceneNode().getChildren(); // get all children of root scene node in array

alert(kids[0].getType);
alert(kids[0].Name);
if(kids[0].getType == 'function(){return"mesh"}' ){alert("very weird...");} // very weird, but works

var mybuf=kids[0].getMesh().GetMeshBuffers(); // get all meshbuffers of first mesh in an array, this will crash if getType is not 'function(){return"mesh"}'

//finally access the meshbuffer data
alert(mybuf[0].Vertices[0].Pos.X); // Pos XYZ, Normal XYZ, Color int argb, TCoords XY, TCoords2, see CL3D.Vertex3D

// this shows how to determine the number of child nodes, meshbuffers per meshnode, vertices per meshbuffer:
alert("kids:"+mymesh7.length+" surfs:"+mybuf.length+" vertices: "+mybuf[0].Vertices.length);
// (note, a node can be a mesh, but doesn't have to. It can contain multiple meshbuffer, which means basically parts of the mesh, using individual textures)


So this allows to parse all meshes and store their vertex coords in a directly accessible array that can then be used by the beforementioned RIT function.


csp-games
Guest
Quote
2022-01-16 14:15:30

oops, second last line should be

alert("kids:"+kids.length+" surfs:"+mybuf.length+" vertices: "+mybuf[0].Vertices.length);

using a name like mymesh7 is confusing, I was just hacking around. kids is more descriptive for the children of the root scene node.


csp-games
Guest
Quote
2022-01-17 02:02:48

Ok, I got it working, my way.

It works with static meshes, also when positioned and scaled, however rotation is not taken into account. It works for walls etc, but for animated meshes one should tweak the code so it does also index a collision mesh that was parented to the animated mesh node, a low poly cylinder I'd suggest. Currently it parses only the direct children of the root scene. It could be made recursive, so it would call itself on any child, but a global recursion-depth limit should be used to prevent stack overflows and stuff.

These are the main functions used:

[code]

// Reading all triangles and write them to one long list, containing vertex coords and the node id a triangle belongs to
var Tri_l=0; // global counter for pickable triangles in the scene
TriArr=new Array(); // array holding all triangle data
//TriArr[0]=[0,0,0, 0,0,0, 0,0,0, 0,0,0]; // 3x vertex coords, node id, some reserved for: meshbuffer id, pickability
// note: for now, nodes are ignored when their name contains: "_nopick"
// note: this should be called at the end of the ingcomplete event handler,
// Or called to refresh the data, but then Tri_l must be set to 0 first.

function ReadAllTriangles(){
var mytype="";
var scene = engine.getScene();
var kids=scene.getRootSceneNode().getChildren();
var kids_length=kids.length;
for(i=0;i<kids_length;i++){ // parse all children
mytype=kids[i].getType;
//return lin.indexOf(search,ii-1)+1;
if((mytype == 'function(){return"mesh"}') && (kids[i].Name.indexOf("_nopick",0)<0)){ // if they are a mesh and name does not contain "_nopick"
var mybuf=kids[i].getMesh().GetMeshBuffers();
var mybuf_length=mybuf.length;
for(j=0;j<mybuf_length;j++){ // parse all their mesh buffers
indices_length=mybuf[j].Indices.length;
for(k=0;k<indices_length;k+=3){ // parse all triangles of a meshbuffer
vx0=mybuf[j].Vertices[ mybuf[j].Indices[ k+0 ] ].Pos.X;
vy0=mybuf[j].Vertices[ mybuf[j].Indices[ k+0 ] ].Pos.Y;
vz0=mybuf[j].Vertices[ mybuf[j].Indices[ k+0 ] ].Pos.Z;

vx1=mybuf[j].Vertices[ mybuf[j].Indices[ k+1 ] ].Pos.X;
vy1=mybuf[j].Vertices[ mybuf[j].Indices[ k+1 ] ].Pos.Y;
vz1=mybuf[j].Vertices[ mybuf[j].Indices[ k+1 ] ].Pos.Z;

vx2=mybuf[j].Vertices[ mybuf[j].Indices[ k+2 ] ].Pos.X;
vy2=mybuf[j].Vertices[ mybuf[j].Indices[ k+2 ] ].Pos.Y;
vz2=mybuf[j].Vertices[ mybuf[j].Indices[ k+2 ] ].Pos.Z;

TriArr[Tri_l]=new Array();
TriArr[Tri_l][0] = vx0;
TriArr[Tri_l][1] = vy0;
TriArr[Tri_l][2] = vz0;

TriArr[Tri_l][3] = vx1;
TriArr[Tri_l][4] = vy1;
TriArr[Tri_l][5] = vz1;

TriArr[Tri_l][6] = vx2;
TriArr[Tri_l][7] = vy2;
TriArr[Tri_l][8] = vz2;

TriArr[Tri_l][9] = kids[i]; // store node id this triangle belongs to

Tri_l++;
} // k
} // j
} // if is mesh
} // i
} // eo function


// globals to deliver last linepick coords
var PickedX=0;
var PickedY=0;
var PickedZ=0;

function LinePick(x0,y0,z0,x1,y1,z1){ // start point, end point. will return picked node or 0.
var dist=100000000;
var victim=0; // potentially hit node
var currnod=0; // currently tested node
// hitlist=new Array();
for(i=0;i<Tri_l;i++){
var nod=TriArr[i][9];
if(nod != currnod){
currnod=nod;
var currpos=nod.getAbsolutePosition(); // take into account dynamic position+scale, but not rotation
var ox=currpos.X;
var oy=currpos.Y;
var oz=currpos.Z;
var currscale=nod.getAbsoluteTransformation().getScale()
var scax=currscale.X;
var scay=currscale.Y;
var scaz=currscale.Z;
} // if
var vx0=TriArr[i][0]*scax+ox;
var vy0=TriArr[i][1]*scay+oy;
var vz0=TriArr[i][2]*scaz+oz;

var vx1=TriArr[i][3]*scax+ox;
var vy1=TriArr[i][4]*scay+oy;
var vz1=TriArr[i][5]*scaz+oz;

var vx2=TriArr[i][6]*scax+ox;
var vy2=TriArr[i][7]*scay+oy;
var vz2=TriArr[i][8]*scaz+oz;

var intersect = rit(x0,y0,z0, x1-x0,y1-y0,


csp-games
Guest
Quote
2022-01-17 04:13:48

The forum just cut off half of my code, but it was less than 8k...

I will upload this on itch.io, I'll put a link in here:

https://jfkeo1010etc.itch.io/alternative-linepick-for-copperlichtjs

But I gotta say, these things become increasingly unbearable.


just_in_case
Moderator
Quote
2022-01-18 19:33:55

Awesome, Glad that it worked out for you, just wanted to know can't you make a mesh loader for CopperCube, instead of CL.
Coppercube does provide mesh creation and modification API and it works during runtime of windows and mac client apps.
So it can be possible to create a custom mesh loader script for Coppercube as well, Right?

I will check out the itch.io page soon, when I reach to my desktop.
Thanks for all your contribution to the community.


csp-games
Guest
Quote
2022-01-18 21:13:26

Thanks. As far as I see, that should be possible, most if not all commands that are required are there. (makes you wonder why these commands were not implemented for the WebGL target so far) Tho, in CL materials are bound to meshbuffers, but in CC you can access the materials only by the node handle and a material index (whether that is the same as the meshbuffer index IDK), but certainly, loading a mesh from a file at runtime is possible. Tho, you have to create a mesh node first, for instance a cube, then remove all meshbuffers (I guess 1 for a cube), then you can start adding your own meshbuffers and add vertices and vertex indices (which define the triangles) to it.

However, writing a good importer for a certain 3D file format is a job that should not be taken lightly. Personally I'd rather dump the mesh data to a file (eg. by using Blitz3D) that I have made the format for myself, so I won't lose time in studying fbx, collada, b3d or whatever file format. - Those file format tutorials that have you always more confused after reading than before :)


csp-games
Guest
Quote
2022-01-18 21:42:40

Additional note:
by using ccbGetPlatform() it may be possible to use a plugin in CC that will execute a different mesh loader, depending on whether webGL is running or not. But whether Niko's js script executor that's part of the EXE etc., will then just accept full javascript code, as long as it's not executed, IDK. But I guess there's a good chance for this to work.


Create reply:


Posted by: (you are not logged in)


Enter the missing letter in: "Inte?national" (you are not logged in)


Text:

 

  

Possible Codes


Feature Code
Link [url] www.example.com [/url]
Bold [b]bold text[/b]
Image [img]http://www.example.com/image.jpg[/img]
Quote [quote]quoted text[/quote]
Code [code]source code[/code]

Emoticons


   






Copyright© Ambiera e.U. all rights reserved.
Privacy Policy | Terms and Conditions | Imprint | Contact