Skip to content

Instantly share code, notes, and snippets.

@EternalTamago
Last active October 16, 2024 16:02
Show Gist options
  • Select an option

  • Save EternalTamago/fca72c36caf198a88de6bbda16649b7c to your computer and use it in GitHub Desktop.

Select an option

Save EternalTamago/fca72c36caf198a88de6bbda16649b7c to your computer and use it in GitHub Desktop.
PhysicsComponent.ColliderShapesの扱いについてのメモ
public class AddingColliderShapesScript : AsyncScript
{
[DataMember(10)]
public CameraComponent Camera = null;
[DataMember(20)]
public Model SphereModel { get; set; }
[DataMember(30)]
public Model BoxModel { get; set; }
[DataMember(40)]
public Material BallMaterial = null;
private List<Material> materialList = new List<Material>();
private Mesh sphereMesh = null;
public override async Task Execute()
{
var random = new Random(Environment.TickCount);
// Camera
if (Camera is null)
{
Camera = SceneSystem.SceneInstance.RootScene.Entities.First(e => e.Components.Any(c => c is CameraComponent)).Get<CameraComponent>();
}
// Materials
materialList.Add(CreateMaterialWithTexture(CreateCheckeredPatternTexture(512, 512, Color.White, Color.Red)));
materialList.Add(CreateMaterialWithTexture(CreateCheckeredPatternTexture(512, 512, Color.White, Color.Yellow)));
materialList.Add(CreateMaterialWithTexture(CreateCheckeredPatternTexture(512, 512, Color.White, Color.Green)));
materialList.Add(CreateMaterialWithTexture(CreateCheckeredPatternTexture(512, 512, Color.White, Color.Cyan)));
materialList.Add(CreateMaterialWithTexture(CreateCheckeredPatternTexture(512, 512, Color.White, Color.Blue)));
materialList.Add(CreateMaterialWithTexture(CreateCheckeredPatternTexture(512, 512, Color.White, Color.Purple)));
// Mesh for ball
sphereMesh = new Mesh { Draw = GeometricPrimitive.Sphere.New(GraphicsDevice).ToMeshDraw() };
// Model for sphere collider shape
if (SphereModel == null)
{
SphereModel = new Model
{
new Mesh { Draw = GeometricPrimitive.Sphere.New(GraphicsDevice).ToMeshDraw() },
materialList[random.Next(0, materialList.Count)],
};
}
// Model for box collider shape
if (BoxModel == null)
{
BoxModel = new Model
{
new Mesh { Draw = GeometricPrimitive.Cube.New(GraphicsDevice).ToMeshDraw() },
materialList[random.Next(0, materialList.Count)],
};
}
while (Game.IsRunning)
{
await Script.NextFrame();
if (Input.IsKeyPressed(Keys.Z))
{
// [A] For an entity that is not in the scene
// Sceneに追加されていないEntityに対して追加
var entity = new Entity(new Vector3(0, 0.5f, 0));
entity.Add(new ModelComponent(SphereModel));
var component = entity.GetOrCreate<StaticColliderComponent>();
component.ColliderShapes.Add(new SphereColliderShapeDesc());
SceneSystem.SceneInstance.RootScene.Entities.Add(entity);
}
else if (Input.IsKeyPressed(Keys.X))
{
var entity = new Entity(new Vector3(1, 0.5f, 0));
entity.Add(new ModelComponent(SphereModel));
SceneSystem.SceneInstance.RootScene.Entities.Add(entity);
// [B] For an entity that is in the scene
// Set up ColliderShapes before adding the component to the entity.
// In this case, you shouldn't use "Entity.GetOrCreate".
// シーンにあるEntityに追加する場合
// EntityにPhysicsComponentを追加する前にColliderShapesを設定しておく.
// GetOrCreateで取得すると[Cb]の状態になる
var component = new StaticColliderComponent();
component.ColliderShapes.Add(new SphereColliderShapeDesc());
entity.Add(component);
}
else if (Input.IsKeyPressed(Keys.C))
{
var entity = new Entity(new Vector3(0, 0.5f, 1));
entity.Add(new ModelComponent(BoxModel));
var temp = entity.GetOrCreate<StaticColliderComponent>();
temp.ColliderShapes.Add(new BoxColliderShapeDesc());
SceneSystem.SceneInstance.RootScene.Entities.Add(entity);
// Model
entity.AddChild(new Entity(new Vector3(0, 1f, 0)));
entity.Transform.Children[0].Entity.Add(new ModelComponent(SphereModel));
// [Ca] For adding new collider shape to PhysicsComponent(ColliderShapes.Count > 0) that is in the Simulation
// This doesn't work when you remove an item from the ColliderShapes. "Cb" is only way in that case.
// Simulationに関連付けられたPhysicsComponent(ColliderShapes.Count > 0)に新しいコライダーを追加する場合
// ColliderShapesからアイテムを削除する場合はこれでは動かない。その場合は"Cb"の方法しかない。
var component = entity.Get<StaticColliderComponent>();
component.ColliderShapes.Add(new SphereColliderShapeDesc { LocalOffset = new Vector3(0, 1f, 0), });
component.ComposeShape();
component.UpdatePhysicsTransformation();
// In this case, if you are rendering debug physics shapes by DebugPhysicsShapes.cs, disable and re-enable it to show new collider shape.
// この場合、もしDebugPhysicsShapesでコライダーシェイプのデバッグレンダリングを有効にしていたら一度無効にして再度有効にしないと追加した形状は表示されない.
}
else if (Input.IsKeyPressed(Keys.V))
{
var entity = new Entity(new Vector3(0, 0.5f, 2));
entity.Add(new StaticColliderComponent());
SceneSystem.SceneInstance.RootScene.Entities.Add(entity);
// NOTE: At this point, error message that tells PhysicsComponent has no collider shape is outputed.
// 注意: この時点でPhysicsComponentにコライダーシェイプがないとエラーメッセージが出る
// Model
entity.Add(new ModelComponent(SphereModel));
// [Cb] For adding new collider shape to PhysicsComponent(ColliderShapes.Count == 0) that is in the Simulation
// "Ca" doesn't work in this case.
// Simulationに関連付けられたPhysicsComponent(ColliderShapes.Count == 0)に新しいコライダーを追加する場合
// この場合は"Ca"の方法では動作しない.
var component = entity.Get<StaticColliderComponent>();
entity.Remove(component);
var physicsProcessor = SceneSystem.SceneInstance.Processors.Get<PhysicsProcessor>();
physicsProcessor.UpdateRemovals();
component.ColliderShapes.Add(new SphereColliderShapeDesc());
entity.Add(component);
}
// スペースキーでボールを射出
else if (Input.IsKeyPressed(Keys.Space))
{
if (BallMaterial is null)
{
EmitBall(Camera, materialList[random.Next(0, materialList.Count)]);
}
else
{
EmitBall(Camera, BallMaterial);
}
}
}
}
private void EmitBall(CameraComponent camera, Material material)
{
var direction = Vector3.Transform(-Vector3.UnitZ, camera.Entity.Transform.Rotation);
var entity = new Entity(camera.Entity.Transform.Position);
//entity.GetOrCreate<ModelComponent>().Model = new Model
//{
// new Mesh { Draw = GeometricPrimitive.Sphere.New(GraphicsDevice).ToMeshDraw() },
// material,
//};
entity.GetOrCreate<ModelComponent>().Model = new Model
{
sphereMesh,
material,
};
var rigidbody = entity.GetOrCreate<RigidbodyComponent>();
rigidbody.ColliderShapes.Add(new SphereColliderShapeDesc { Is2D = false, LocalOffset = Vector3.Zero, Radius = 0.5f });
entity.Add(new LifeTimeOfBall());
Entity.Scene.Entities.Add(entity);
rigidbody.ApplyImpulse(direction * 10f);
}
private Texture CreateCheckeredPatternTexture(int width, int height, Color first, Color second, int squareWidth = 0, int squareHeight = 0)
{
squareWidth = squareWidth <= 0 ? width / 2 : squareWidth;
squareHeight = squareHeight <= 0 ? height / 2 : squareHeight;
Color[] pixels = new Color[width * height];
void SetPixel(int x, int y, Color value) => pixels[y * width + x] = value;
for (int y = 0; y < height; ++y)
{
for (int x = 0; x < width; ++x)
{
if ((((x / squareWidth) & 1) + (y / squareHeight & 1)) == 1)
{
SetPixel(x, y, second);
}
else
{
SetPixel(x, y, first);
}
}
}
return Texture.New2D(GraphicsDevice, width, height, PixelFormat.R8G8B8A8_UNorm, pixels);
}
private Material CreateMaterialWithTexture(Texture texture)
{
var descriptor = new MaterialDescriptor
{
Attributes = new MaterialAttributes
{
MicroSurface = new MaterialGlossinessMapFeature(new ComputeFloat(0.1f))
{
Invert = false,
},
Diffuse = new MaterialDiffuseMapFeature
{
DiffuseMap = new ComputeTextureColor
{
Texture = texture,
FallbackValue = new ComputeColor(Color4.White),
TexcoordIndex = TextureCoordinate.Texcoord0,
AddressModeU = TextureAddressMode.Clamp,
AddressModeV = TextureAddressMode.Clamp,
Filtering = TextureFilter.Point,
Offset = Vector2.Zero,
Scale = Vector2.One,
}
},
DiffuseModel = new MaterialDiffuseLambertModelFeature(),
CullMode = CullMode.Back,
Specular = new MaterialMetalnessMapFeature(new ComputeFloat(0f)),
SpecularModel = new MaterialSpecularMicrofacetModelFeature
{
Fresnel = new MaterialSpecularMicrofacetFresnelSchlick(),
Visibility = new MaterialSpecularMicrofacetVisibilitySmithSchlickGGX(),
NormalDistribution = new MaterialSpecularMicrofacetNormalDistributionGGX(),
},
},
};
return Material.New(GraphicsDevice, descriptor);
}
public class LifeTimeOfBall : SyncScript
{
public override void Update()
{
if (Entity.Transform.Position.Y < -50f)
{
Entity.Scene.Entities.Remove(Entity);
Entity.Dispose();
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment