mirror of
https://github.com/galacean/engine.git
synced 2026-05-07 15:27:19 +08:00
194 lines
6.3 KiB
TypeScript
194 lines
6.3 KiB
TypeScript
/**
|
|
* @title input-pointerRaycast
|
|
* @category input
|
|
* @thumbnail https://mdn.alipayobjects.com/merchant_appfe/afts/img/A*unTBRblIIkUAAAAAAAAAAAAADiR2AQ/original
|
|
*/
|
|
import {
|
|
BlinnPhongMaterial,
|
|
BoxColliderShape,
|
|
Camera,
|
|
Color,
|
|
DirectLight,
|
|
Entity,
|
|
HitResult,
|
|
Layer,
|
|
MeshRenderer,
|
|
PrimitiveMesh,
|
|
Ray,
|
|
Script,
|
|
StaticCollider,
|
|
UnlitMaterial,
|
|
Vector3,
|
|
WebGLEngine,
|
|
} from "@galacean/engine";
|
|
import { LitePhysics } from "@galacean/engine-physics-lite";
|
|
import { WireframeManager } from "@galacean/engine-toolkit";
|
|
|
|
// Create engine
|
|
WebGLEngine.create({ canvas: "canvas", physics: new LitePhysics() }).then(
|
|
(engine) => {
|
|
engine.canvas.resizeByClientSize();
|
|
engine.canvas._webCanvas.style.touchAction = "none";
|
|
const scene = engine.sceneManager.activeScene;
|
|
const rootEntity = scene.createRootEntity("root");
|
|
|
|
// add light
|
|
const lightEntity = rootEntity.createChild("light");
|
|
lightEntity.addComponent(DirectLight);
|
|
lightEntity.transform.setRotation(-45, 0, 0);
|
|
|
|
// init main camera
|
|
const mainCameraEntity = rootEntity.createChild("camera");
|
|
const mainCamera = mainCameraEntity.addComponent(Camera);
|
|
mainCameraEntity.transform.setPosition(0, 0, 20);
|
|
mainCameraEntity.transform.lookAt(new Vector3(0, 0, 0));
|
|
mainCamera.cullingMask = Layer.Layer0 | Layer.Layer1;
|
|
mainCamera.fieldOfView = 35;
|
|
mainCamera.nearClipPlane = 1;
|
|
mainCamera.farClipPlane = 30;
|
|
// add wire frame
|
|
rootEntity.addComponent(MeshRenderer);
|
|
rootEntity.addComponent(WireframeManager).addCameraWireframe(mainCamera);
|
|
|
|
// init side camera
|
|
const sideCameraEntity = rootEntity.createChild("sideCamera");
|
|
const sideCamera = sideCameraEntity.addComponent(Camera);
|
|
sideCamera.priority = 1;
|
|
sideCamera.viewport.set(0, 0.6, 0.4, 0.4);
|
|
sideCameraEntity.transform.setPosition(-45, 0, 0);
|
|
sideCameraEntity.transform.rotation.set(0, -90, 0);
|
|
sideCamera.cullingMask = Layer.Layer0 | Layer.Layer2;
|
|
sideCameraEntity.addComponent(
|
|
class extends Script {
|
|
onBeginRender(camera: Camera): void {
|
|
scene.background.solidColor.set(0, 0, 0, 1);
|
|
}
|
|
onEndRender(camera: Camera): void {
|
|
scene.background.solidColor.set(0.25, 0.25, 0.25, 1.0);
|
|
}
|
|
}
|
|
);
|
|
|
|
for (let i = 0; i < 30; i++) {
|
|
createRandomBox(rootEntity);
|
|
}
|
|
|
|
rootEntity.addComponent(
|
|
class extends Script {
|
|
private _entities: Entity[] = [];
|
|
private _tempRay: Ray = new Ray();
|
|
private _tempVec3: Vector3 = new Vector3();
|
|
private _hitResult: HitResult = new HitResult();
|
|
|
|
onUpdate(deltaTime: number): void {
|
|
const { pointers } = engine.inputManager;
|
|
const {
|
|
_tempRay: tempRay,
|
|
_entities: entities,
|
|
_hitResult: hitResult,
|
|
} = this;
|
|
for (let i = 0, n = entities.length; i < n; i++) {
|
|
entities[i].isActive = false;
|
|
}
|
|
for (let i = 0, n = pointers.length; i < n; i++) {
|
|
mainCamera.screenPointToRay(pointers[i].position, tempRay);
|
|
if (scene.physics.raycast(tempRay, 100, hitResult)) {
|
|
(
|
|
hitResult.entity.getComponent(BoxScript) as BoxScript
|
|
).hitFrameCount = engine.time.frameCount;
|
|
}
|
|
this._adjustByRay(this._getOrCreateRayEntity(i), tempRay);
|
|
}
|
|
}
|
|
|
|
private _getOrCreateRayEntity(index: number) {
|
|
const { _entities: entities } = this;
|
|
let entity = entities[index];
|
|
if (!entity) {
|
|
entity = entities[index] = this.entity.createChild(`ray${index}`);
|
|
const ray = entity.createChild();
|
|
ray.layer = Layer.Layer2;
|
|
const rayRenderer = ray.addComponent(MeshRenderer);
|
|
rayRenderer.mesh = PrimitiveMesh.createCylinder(
|
|
engine,
|
|
0.05,
|
|
0.05,
|
|
40
|
|
);
|
|
ray.transform.position = new Vector3(0, 0, -20);
|
|
ray.transform.rotation = new Vector3(-90, 0, 0);
|
|
const material = new UnlitMaterial(engine);
|
|
material.baseColor = new Color(0, 1, 0);
|
|
rayRenderer.setMaterial(material);
|
|
const ball = entity.createChild();
|
|
ball.layer = Layer.Layer1;
|
|
const ballRenderer = ball.addComponent(MeshRenderer);
|
|
ballRenderer.mesh = PrimitiveMesh.createSphere(engine, 0.008);
|
|
ballRenderer.setMaterial(material);
|
|
} else {
|
|
entity.isActive = true;
|
|
}
|
|
return entities[index];
|
|
}
|
|
|
|
private _adjustByRay(rayEntity: Entity, ray: Ray) {
|
|
const { _tempVec3: tempVec3 } = this;
|
|
const { origin, direction } = ray;
|
|
Vector3.scale(direction, 0.5, tempVec3);
|
|
Vector3.add(origin, tempVec3, rayEntity.transform.position);
|
|
Vector3.add(origin, direction, tempVec3);
|
|
rayEntity.transform.lookAt(tempVec3);
|
|
}
|
|
}
|
|
);
|
|
|
|
// Run engine
|
|
engine.run();
|
|
}
|
|
);
|
|
|
|
function createRandomBox(root: Entity) {
|
|
const { engine } = root;
|
|
const boxEntity = root.createChild("box");
|
|
boxEntity.transform.setPosition(
|
|
5 - Math.random() * 10,
|
|
5 - Math.random() * 10,
|
|
8 - Math.random() * 16
|
|
);
|
|
|
|
const renderer = boxEntity.addComponent(MeshRenderer);
|
|
const width = Math.random() * 1.5 + 0.5;
|
|
const height = Math.random() * 1.5 + 0.5;
|
|
const depth = Math.random() * 1.5 + 0.5;
|
|
renderer.mesh = PrimitiveMesh.createCuboid(engine, width, height, depth);
|
|
const material = new BlinnPhongMaterial(engine);
|
|
material.baseColor = new Color(1, 1, 1);
|
|
renderer.setMaterial(material);
|
|
|
|
const collider = boxEntity.addComponent(StaticCollider);
|
|
const shape = new BoxColliderShape();
|
|
shape.size.set(width, height, depth);
|
|
collider.addShape(shape);
|
|
|
|
boxEntity.addComponent(BoxScript);
|
|
}
|
|
|
|
class BoxScript extends Script {
|
|
hitFrameCount: number = 0;
|
|
private _material: BlinnPhongMaterial;
|
|
|
|
onStart(): void {
|
|
this._material = (
|
|
this.entity.getComponent(MeshRenderer) as MeshRenderer
|
|
).getMaterial() as BlinnPhongMaterial;
|
|
}
|
|
|
|
onLateUpdate(deltaTime: number): void {
|
|
if (this.engine.time.frameCount === this.hitFrameCount) {
|
|
this._material.baseColor = new Color(1, 0, 0);
|
|
} else {
|
|
this._material.baseColor = new Color(1, 1, 1);
|
|
}
|
|
}
|
|
}
|