Comments (21)
Hey, sorry, I really need to document this stuff.
Babylon.js has a lot of game-engine features that this library doesn't use, and collision checking is one of them. Setting mesh.checkCollisions
tells Babylon to do something about mesh-vs-mesh checking (I haven't looked at the details), but it's completely orthogonal to this engine, voxels, and so on.
Here's the high-level view of what this engine supports related to what you're looking at:
- Any entity with the
physics
component will collide with solid terrain blocks (that is, block IDs that were registered withsolid
set to true - Any entity with the
collidesTerrain
component will emit an event (to the component callback) when it collides with voxel terrain (i.e. solid blocks) - Entities with the
collidesEntities
component will emit an event when they collide (i.e. overlap) with each other. But there's no physics for this - they just emit events. - Custom meshes only exist for rendering purposes. The physics and collision tracking systems only know about voxels and entities.
So, if you assign a custom mesh to a particular voxel ID, noa
will make an instance of that mesh every time the block shows up, but the physics engine only knows about the voxel and its solidity. If you want a non-solid voxel that does something when the player overlaps it, what I do is have a voxel that creates an entity in its onSet / onLoad handlers, and that entity does something on collisions with the player entity. But in that case the voxel won't collide (in the physics sense).
So, a little limited, but that's how things stand as of now. Let me know if that's clear!
from noa.
Incidentally now that I type all that, the collidesTerrain
component doesn't really make sense. I should remove it and make onCollide events happen equivalently for any entity with the physics component.
from noa.
Follow-up: I now remember why collidesTerrain is a separate component - because I had a to-do item someday to make it possible to have physics-driven entities that don't collide with terrain (ghosts, etc). Not sure that's worth spending time on, but anyway.
from noa.
So, you mean I should be registering the custom mesh as a solid block even though it is not necessarily a block? That might work if I want to add some items but I am not sure for other things.
I am asking because I want to import some mobs and I want them to have collisions and I don't want to handle them as other blocks.
from noa.
Right now the physics in this library only knows how to collide entity AABBs and solid voxels. It has no idea whether the entities or voxels have meshes associated with them or not.
If you want voxels that are partly-solid - where the collision volume is still an AABB, just not the full voxel, you could try hacking voxel-physics-engine to support that. It wouldn't be super trivial, but certainly possible. (It's on my to-do list, just not very high 😁)
But if you want something that resembles "real physics" - where objects aren't just AABBs, and entities collide with each other - then that probably isn't feasible with the current physics engine. It's relatively easy to replace the default physics engine with a real one (like cannon.js), but this would only make sense if the engine supported voxel terrain as a collision object type. I've played with extending cannon.js to do that -
see here - but haven't gone far enough to see if it's really doable.
from noa.
Oh I see. I took a look at the projectile code you had, since it seemed to be a nice and simple way to add collision between entities. Here is my current code:
this.blankmesh = this.make_test_mesh();
this.blankmesh.position = new BABYLON.Vector3(x, y, z);
let blank_mat = new BABYLON.StandardMaterial('blank-mat', this.scene);
// Id 254, so it won't bother any of the other blocks
this.noa.registry.registerBlock(254, {
blockMesh: this.blankmesh,
opaque: true,
solid: true,
});
// Make an instance
let new_sprite_mesh = this.noa.rendering.makeMeshInstance(this.blankmesh, false);
let vectorsWorld = this.blankmesh.getBoundingInfo().boundingBox.vectorsWorld;
let width = Number(vectorsWorld[1].x-(vectorsWorld[0].x));
let height = Number(vectorsWorld[1].y-(vectorsWorld[0].y));
// usage: entities.add( pos, w, h, mesh, meshOffset, doPhysics, shadow
var eid = this.noa.entities.add(new BABYLON.Vector3(x, y, z), width, height, new_sprite_mesh, [0,0,0], true, true);
// make it collide with player
this.noa.entities.addComponent(eid, this.noa.entities.names.player);
But the problem now is that it doesn't seem to show anywhere, can you spot any problem?
EDIT: I looked into makeMeshInstance and it seems that it handles already whether it should be added as a DynamicMesh or not, so that shouldn't be the problem, right?
from noa.
Hi! This is just a guess, but I think that the problem is probably that you've passed a Babylon Vector3 into a method that expects regular [x, y, z]
array (for the position argument of entites.add
).
As a general rule, noa
uses arrays (technically Float32 arrays) for vectors, because I do all my vector twiddling with the gl-vec3
library. Babylon uses its own vector objects (that look like {x:x, y:y, z:z}
), but in general noa
doesn't use them except internally. I'm pretty sure there are a few exceptions to that - I haven't been completely rigorous about it. But in general, most noa APIs that take a vector are expecting an array.
So, since the code above passes in a Babylon vector, I'm guessing the entity adder probably winds up setting the mesh's position to [NaN, NaN, NaN]
and that's why it's not appearing.
from noa.
Yeah, that was it!
Now it appears but the shadow is quite off and the mesh doesn't collide with the player.
Should I have used this.noa.entities.names.player
or something like this.noa.entities.names.collideEntities
(similar to collideTerrain
)?
from noa.
Okay, looking back a few posts I think there are a few issues confounding each other that I need to explain.
Fundamentally, noa understands two kinds of things - blocks (i.e. voxels) and entities. When you register a block type with a custom mesh, that's meant for things that are part of the voxel terrain, but you don't want them to get meshed like a voxel. So - a flower, a mailbox, etc. Then, when noa is building a "chunk" of terrain, and it encounters a block ID with a custom mesh, instead of making that block part of the terrain, now will create an instance of the custom mesh and put it at the given voxel.
But defining a block ID with a custom mesh doesn't do anything to the world unless you also set some voxels with that ID.
Entities, meanwhile, are completely separate - they represent anything that can move around, etc. The only thing noa really does with entities is, if they have the physics
component, it will handle their velocity and whatnot, and keep them from moving through solid voxels.
In general, it's probably necessary to look inside components you want to use, to get some idea what they do. E.g. the player component has no functionality at all, it just tags which entity is the player. (Also, I think it's not currently used - I think I need to remove it!)
Anyway, if I understand your question correctly then the collideEntities component may be what you need. Note, when I said earlier that the physics system doesn't collide entities, I meant it doesn't make the bounce off each other, etc. The collideEntities component does detect entity collisions, and send an event, which is likely what you need for projectiles, etc.
from noa.
Oh, and for your current bug, you might try not using the entities.add()
helper, and instead try adding the various components (position, shadow, physics) one-by-one. This might show where the issue is. Note that some components depend on each other (e.g. the physics component assumes its entity has a position.)
from noa.
Ok, just to clarify my goal: I want to create a second player (some sort of NPC or mob with AI) which just needs to be able to acts like any other solid object. If it can have some physics concerning gravity and whatnot: awesome, but I would like to start off by not being able to go through it with my player.
What would be the simplest thing to do?
Imagine having a mesh which acts like your mobs in the testbed demo but which cannot be walked through.
from noa.
Okay, if I understand you correctly then it's back to my first answer - this engine only models terrain and entities, where terrain is solid but doesn't move, and entities can move but are not solid. The collideEntities component will report entities that are overlapping, and you could catch that event and apply a force or impulse to push one entity away from the other, but the engine can't currently model having entities physically collide with each other the way they do with terrain.
from noa.
Oh I see!
How do I catch that event? Something like noa.on('onCollision', function(eventData) { ... });
?
from noa.
Every component works the same way - you add a component to an entity, and set any parameters in the state object for that entity-component pair. In this case it would look like:
var id = // my entity ID
var state = {
callback: function(other) console.log('Entity', id, 'collided with', other)
}
noa.entities.addComponent( id, noa.entities.names.collideEntities, state )
Or something like that!
from noa.
That worked nicely, I will try to move the player to its previous position anytime there is a collision, let's see :D
from noa.
Hey @andyhall,
as an extension of this question: I am currently having a hard time properly offsetting my custom mesh.
Here is my code:
this.new_sprite_mesh = this.noa.rendering.makeMeshInstance(this.blankmesh, false);
// Flip X axis
this.new_sprite_mesh.scaling.x = -scale;
this.new_sprite_mesh.scaling.y = scale;
this.new_sprite_mesh.scaling.z = scale;
let width = Math.abs(this.new_sprite_mesh.getBoundingInfo().boundingBox.extendSize.x * this.new_sprite_mesh.scaling.x);
let height = Math.abs(this.new_sprite_mesh.getBoundingInfo().boundingBox.extendSize.y * this.new_sprite_mesh.scaling.y);
// usage: entities.add( pos, w, h, mesh, meshOffset, doPhysics, shadow
let eid = this.noa.entities.add([position.x, position.y, position.z], width, height , this.new_sprite_mesh, false, true, false);
this.noa.entities.addComponent(eid, this.noa.entities.names.shadow, { size: width * 2});
let state = {
callback: function(other) {
if(other === this.noa.playerEntity) {
this.move_player_to(this.previous_player_position);
}
}.bind(this),
};
// // make it collide with player
this.noa.entities.addComponent(eid, this.noa.entities.names.collideEntities, state);
The mesh is correctly shown but the problem is the offset (relative to the shadow and its collision). I tried every sort of combination that I could think of but still nothing.
I checked in the debug layer and the bounding box of my meshes is tightly fitting around their geometry, so that's not the problem.
I simply want to have the lowest part of the bounding box of my mesh touching the floor and centered within their shadow. How can I do that?
from noa.
Hey, sorry for the late reply. From reading the code above, I think the answer here is to change the mesh offset vector, but let me just try to explain what assumptions the library is making.
Effectively, an entity with a mesh has two positions. There's the "noa position", which is an [x, y, z] array and is stored in the entity's position
component. This position is what noa uses to handle the physics, and entity collisions, etc. This noa position refers to the feet position of the entity - i.e. the bottom-center of its bounding box.
On the other hand there's the "Babylon position", that Babylon knows about, and uses to render meshes. Note that babylon positions have arbitrary centering - the babylon position could be the mesh's center, or one of its corners, or whatever, depending on how the mesh was made.
So with all that said, all noa
does each frame is, it calculates an entity's "noa position" (from physics etc), then it overwrites the entities "Babylon position" to be equal to the noa position plus the mesh offset.
So, if physics and collisions are working right but the mesh is rendering in the wrong spot, the probelm should be with the mesh offset property of the mesh component. If that's not working, then I suspect something else might be going on (like some property getting set to NaN
or whatever), but that's just guessing.
from noa.
Ohhh, I see! But shouldn't the mesh have just an incorrect Y position? My meshes seems to be completely off on all axis.
from noa.
Well, if I understand your issue correctly then my best guess would be that the problem is with the Babylon mesh's registration point, which in principle can be anywhere. When you make meshes with its built in methods (Babylon.Mesh.CreateBox or whatever) I think the registration points are always in the center, but if the mesh was imported from somewhere then there's no way of knowing.
But I could just be misunderstanding what's going on.
from noa.
Yeah, I think that's it. Do you know of any way to reset those points to the center?
I am using this: https://github.com/Nesh108/babylon-voxel-critter , to import a mesh from the VoxelBuilder. Is there anything you can see that might misbehave when added to your engine?
from noa.
Well, the key should be changing the [0,0,0]
offset when you add the entity, but the correct values depend totally on how the mesh was made.
That is, a mesh's "center" is baked into its vertex data, right? Like, if a mesh has vertices whose x
coordinates are all between -1 and 1, then that mesh is more or less centered on the x axis. But if you went through and added 5 to every x vertex, you'd have the exact same mesh, but centered around x=5, so then you'd want a mesh offset of [-5,0,0]
when adding it to an entity.
But the vertex values in your mesh are down to whatever tool created them. Probably the tool has some idea of where the "origin" is, and it generates vertex data that are relative to that origin.
I expect you could investigate this by importing the mesh into the scene, and then looking at mesh.getBoundingInfo().boundingBox
- e.g. the maximum
and minimum
properties, which I think should be the extents of the mesh's data in local coordinates.
Hope this helps!
from noa.
Related Issues (20)
- Using a texture atlas for block materials HOT 12
- Is there any way to use this as an es6 module? HOT 10
- Support gamepad input
- Outdated comment + note on blockMesh registration HOT 2
- Alpha blended mesh ordering issue HOT 2
- Terrain remeshing bug when block is neither solid nor opaque HOT 3
- Custom voxel occasionally leaves one side after removal. HOT 4
- UV offsets wrapping at edges of blocks HOT 2
- object meshing bug HOT 6
- Meshing with non-opaque blocks is incredibly slow + block textures with alpha dont work HOT 4
- custom renderMaterial performance (for animated textures) HOT 2
- Supporting noa HOT 2
- Does NOA support child meshes? HOT 3
- webgpu? HOT 2
- How to define new objects in NOA engine. HOT 5
- Optimal octreeBlockSize
- What is the best way to manually build worlds? HOT 2
- render all blocks even if covered HOT 1
- How to import an obj model?
- refresh the registry on the go HOT 2
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from noa.