three#Group TypeScript Examples
The following examples show how to use
three#Group.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: FacePlayer.tsx From spacesvr with MIT License | 6 votes |
export function FacePlayer(props: FacePlayerProps) {
const { children, lockX = false, lockY = false, lockZ = false } = props;
const group = useRef<Group>();
const limiter = useLimiter(45);
useFrame(({ clock, camera }) => {
if (!limiter.isReady(clock)) return;
if (group.current) {
const prev = {
x: group.current.rotation.x,
y: group.current.rotation.y,
z: group.current.rotation.z,
};
group.current.lookAt(camera.position);
if (lockX) group.current.rotation.x = prev.x;
if (lockY) group.current.rotation.y = prev.y;
if (lockZ) group.current.rotation.z = prev.z;
}
});
return (
<group name="spacesvr-faceplayer" ref={group}>
{children}
</group>
);
}
Example #2
Source File: Floating.tsx From spacesvr with MIT License | 6 votes |
export function Floating(props: FloatingProps) {
const { children, height = 0.2, speed = 1 } = props;
const group = useRef<Group>();
const seed = useRef(Math.random());
const limiter = useLimiter(75);
useFrame(({ clock }) => {
if (!group.current || !limiter.isReady(clock)) return;
group.current.position.y =
height *
Math.sin(clock.getElapsedTime() * speed * 0.4 + seed.current * 10000);
});
return (
<group name="spacesvr-floating" ref={group}>
{children}
</group>
);
}
Example #3
Source File: Spinning.tsx From spacesvr with MIT License | 6 votes |
export function Spinning(props: Props) {
const { children, xSpeed = 0, ySpeed = 1, zSpeed = 0 } = props;
const group = useRef<Group>();
const [seed] = useState(Math.random());
const limiter = useLimiter(75);
useFrame(({ clock }) => {
if (!group.current || !limiter.isReady(clock)) return;
group.current.rotation.x =
clock.getElapsedTime() * xSpeed * 0.25 + xSpeed * seed * 100;
group.current.rotation.y =
clock.getElapsedTime() * ySpeed * (0.25 + seed / 10) +
ySpeed * seed * 1000;
group.current.rotation.z =
clock.getElapsedTime() * zSpeed * 0.25 + zSpeed * seed * 40;
});
return (
<group name="spacesvr-spinning" ref={group}>
{children}
</group>
);
}
Example #4
Source File: MapView.ts From geo-three with MIT License | 6 votes |
/**
* Ajust node configuration depending on the camera distance.
*
* Called everytime before render.
*/
public onBeforeRender: (renderer: WebGLRenderer, scene: Scene, camera: Camera, geometry: BufferGeometry, material: Material, group: Group)=> void = (renderer, scene, camera, geometry, material, group) =>
{
this.lod.updateLOD(this, camera, renderer, scene);
};
Example #5
Source File: Tool.tsx From spacesvr with MIT License | 5 votes |
/**
* Tool modifier will place its children in constant view of the camera
*
* pos will determine relative placement on [x, y] axis
* face will make item face the player (defaults to true)
*
* @param props
* @constructor
*/
export function Tool(props: Props) {
const { children, pos, face = true, pinY = false, distance = 1 } = props;
const DISTANCE = distance * 0.05;
const { size, camera } = useThree();
const group = useRef<Group>();
const groupPos = useRef(new Vector3());
const { current: dummyVector } = useRef(new Vector3());
useFrame(() => {
if (!group.current) return;
if (pos !== undefined) {
const xPos = (pos[0] * 0.00008 * size.width) / 2;
const yPos = 0.04 * pos[1];
dummyVector.set(xPos * distance, yPos * distance, -DISTANCE);
const moveQuaternion = camera.quaternion.clone();
if (!pinY) {
moveQuaternion.x = 0;
moveQuaternion.z = 0;
}
dummyVector.applyQuaternion(moveQuaternion);
group.current.getWorldPosition(groupPos.current);
const deltaPos = groupPos.current.sub(camera.position);
group.current.position.sub(deltaPos);
group.current.position.add(dummyVector);
}
if (face) {
group.current.quaternion.copy(camera.quaternion);
}
});
return (
<group name="spacesvr-tool">
<group ref={group}>
<group scale={SCALE * distance}>{children}</group>
</group>
</group>
);
}
Example #6
Source File: MapView.d.ts From geo-three with MIT License | 5 votes |
onBeforeRender: (renderer: WebGLRenderer, scene: Scene, camera: Camera, geometry: BufferGeometry, material: Material, group: Group) => void;
Example #7
Source File: TextMeshObject.ts From movy with MIT License | 4 votes |
export default class TextMeshObject extends Group {
initParams: TextMeshObjectParams;
shouldUpdate = true;
fonts: Font[];
text: string;
material: Material;
constructor(params: TextMeshObjectParams = {}) {
super();
this.initParams = {
centerTextVertically: false,
color: new Color(0xffffff),
font: 'en,zh',
fontSize: 1.0,
letterSpacing: 0,
stroke: false,
strokeWidth: 0.02,
text3D: false,
...params,
};
if (this.initParams.material) {
this.material = this.initParams.material.clone();
} else {
this.material = new MeshBasicMaterial({
color: this.initParams.color,
side: DoubleSide,
});
}
}
async init() {
this.fonts = await Promise.all(
this.initParams.font.split(',').map((fontName) => preloadFont(fontName))
);
}
setText(text: string, forceUpdate = false) {
this.text = text;
this.shouldUpdate = true;
if (forceUpdate) {
this.updateText();
}
}
updateText() {
if (this.shouldUpdate) {
// TODO: optimize: text update is slow.
this.children.length = 0;
let totalWidth = 0;
const letterPosX: number[] = [];
let minY = Number.MAX_VALUE;
let maxY = Number.MIN_VALUE;
const geometries: ShapeBufferGeometry[] = [];
for (const [i, char] of [...this.text].entries()) {
if (char === ' ') {
totalWidth += this.initParams.fontSize * 0.5;
} else {
let font: Font;
let glyph: any;
for (let j = 0; j < this.fonts.length; j++) {
font = this.fonts[j];
glyph = (font.data as any).glyphs[char];
if (glyph) {
break;
} else if (j == this.fonts.length - 1) {
glyph = (font.data as any).glyphs['?'];
}
}
const fontData = font.data as any;
const resolution = fontData.resolution;
const ha = (glyph.ha / resolution) * this.initParams.fontSize;
const shapes = font.generateShapes(char, this.initParams.fontSize);
let geometry;
if (this.initParams.text3D) {
const extrudeSettings = {
depth: this.initParams.fontSize * 0.2,
bevelEnabled: false,
};
geometry = new ExtrudeGeometry(shapes, extrudeSettings);
} else if (this.initParams.stroke) {
const style = SVGLoader.getStrokeStyle(
this.initParams.strokeWidth,
this.initParams.color.getStyle() // color in CSS context style
);
// Add shape.holes to shapes
const holeShapes = [];
for (let i = 0; i < shapes.length; i++) {
const shape = shapes[i];
if (shape.holes && shape.holes.length > 0) {
for (let j = 0; j < shape.holes.length; j++) {
const hole = shape.holes[j];
holeShapes.push(hole);
}
}
}
shapes.push.apply(shapes, holeShapes);
const geoms: BufferGeometry[] = [];
for (const shape of shapes) {
const points = shape.getPoints();
const geom = SVGLoader.pointsToStroke(
points.map((v) => new Vector3(v.x, v.y)),
style
);
geoms.push(geom);
}
geometry = geoms.length > 1 ? mergeBufferGeometries(geoms) : geoms[0];
} else {
geometry = new ShapeBufferGeometry(shapes);
}
geometry.computeBoundingBox();
geometries.push(geometry);
// Always create a separate material for each letter
const mesh = new Mesh(geometry, this.material.clone());
mesh.name = char;
const letterWidth = ha;
const xMid = 0.5 * letterWidth;
geometry.translate(
-0.5 * (geometry.boundingBox.min.x + geometry.boundingBox.max.x),
-0.5 * this.initParams.fontSize,
0
);
letterPosX.push(totalWidth + xMid);
totalWidth +=
letterWidth +
(i < this.text.length - 1
? this.initParams.letterSpacing * this.initParams.fontSize
: 0);
minY = Math.min(minY, geometry.boundingBox.min.y);
maxY = Math.max(maxY, geometry.boundingBox.max.y);
this.add(mesh);
}
}
// Center text geometry vertically
const deltaY = (maxY + minY) * 0.5;
if (this.initParams.centerTextVertically) {
for (const geometry of geometries) {
geometry.translate(0, -deltaY, 0);
}
}
this.children.forEach((letter, i) => {
letter.position.set(-0.5 * totalWidth + letterPosX[i], 0, 0);
});
this.shouldUpdate = false;
}
}
}
Example #8
Source File: Interactable.tsx From spacesvr with MIT License | 4 votes |
/**
*
* Interactable adds on click and hover methods to any group of Object3D's.
*
* This is a bit convoluted for the sake of working with the ClickDragControls
* (i.e. the test for a double click)
*
* @param props
* @constructor
*/
export function Interactable(props: Props) {
const { onClick, onHover, onUnHover, children } = props;
const gl = useThree((state) => state.gl);
const { domElement } = gl;
const { raycaster } = usePlayer();
const group = useRef<Group>();
const [hovered, setHovered] = useState(false);
const { current: downPos } = useRef(new Vector2());
const limiter = useLimiter(30);
// continuously update the hover state
useFrame(({ clock }) => {
if (!group.current || !limiter.isReady(clock) || !raycaster) return;
const intersections = raycaster.intersectObject(group.current, true);
if (intersections && intersections.length > 0) {
if (!hovered) {
setHovered(true);
if (onHover) {
onHover();
}
}
} else if (hovered) {
setHovered(false);
if (onUnHover) {
onUnHover();
}
}
});
// start touch
const onTouchStart = (e: TouchEvent) => {
downPos.set(e.touches[0].clientX, e.touches[0].clientY);
};
// if little to no movement on touch end, call click event
const onTouchEnd = (e: TouchEvent) => {
const dist = downPos.distanceTo(
new Vector2(e.changedTouches[0].clientX, e.changedTouches[0].clientY)
);
if (onClick && dist < 5 && hovered) {
onClick();
}
};
// set mouse down position
const onMouseDown = (e: MouseEvent) => {
downPos.set(e.clientX, e.clientY);
};
// if little to no movement on mouse up, queue a click event
const onMouseUp = useCallback(
(e: MouseEvent) => {
const dist = downPos.distanceTo(new Vector2(e.clientX, e.clientY));
if (onClick && dist < 5 && hovered) {
onClick();
}
},
[downPos, hovered]
);
useEffect(() => {
if (isMobile) {
domElement.addEventListener("touchstart", onTouchStart);
domElement.addEventListener("touchend", onTouchEnd);
} else {
domElement.addEventListener("mousedown", onMouseDown);
domElement.addEventListener("mouseup", onMouseUp);
}
return () => {
if (isMobile) {
domElement.removeEventListener("touchstart", onTouchStart);
domElement.removeEventListener("touchend", onTouchEnd);
} else {
domElement.removeEventListener("mousedown", onMouseDown);
domElement.removeEventListener("mouseup", onMouseUp);
}
};
}, [onMouseUp, onTouchEnd, onClick]);
return (
<group name="spacesvr-interactable" ref={group}>
{children}
</group>
);
}