イメージエレメント
イメージエレメントは矩形を描画します。描画するのは、単色、テクスチャ、またはスプライトのフレームです。パネル、背景、アイコン、ボタン、マスクは、いずれもイメージエレメントです。
色と不透明度
colorはイメージにティントを適用します。テクスチャの色にはこの色が乗算されるため、白やグレースケールのテクスチャを任意の色で描画でき、テクスチャのないイメージはその色の矩形になります。opacityは、イメージの透明度を0から1の範囲で設定します。colorのアルファは無視されるため、代わりにopacityを使ってください。
コードから変更するには、新しいpc.Colorを代入します。
panel.element.color = new pc.Color(0.23, 0.55, 1);
panel.element.opacity = 0.8;
エレメントの色と不透明度は、その子には影響しません。グループエレメントを参照してください。
テクスチャ
画像を描画するには、イメージエレメントにテクスチャアセットを指定します。
- Engine
- Editor
- React
- Web Components
const icon = new pc.Entity('icon');
icon.addComponent('element', {
type: pc.ELEMENTTYPE_IMAGE,
anchor: [0.5, 0.5, 0.5, 0.5],
pivot: [0.5, 0.5],
width: 128,
height: 128,
textureAsset: iconTexture.id
});
screen.addChild(icon);
iconTextureは、app.assetsに追加して読み込んだテクスチャアセットです。代わりにpc.Textureオブジェクトを使うには、textureを設定します。
テクスチャアセットを、イメージエレメントのTextureフィールドにドラッグします。
import { Entity } from '@playcanvas/react';
import { Element } from '@playcanvas/react/components';
import { useTexture } from '@playcanvas/react/hooks';
export function Icon() {
const { asset: texture } = useTexture('textures/icon.png');
if (!texture) return null;
return (
<Entity name="icon">
<Element type="image" anchor={[0.5, 0.5, 0.5, 0.5]} pivot={[0.5, 0.5]}
width={128} height={128} textureAsset={texture} />
</Entity>
);
}
<pc-asset id="icon" src="textures/icon.png"></pc-asset>
<pc-entity name="icon">
<pc-element type="image" anchor="0.5 0.5 0.5 0.5" pivot="0.5 0.5"
width="128" height="128" texture-asset="icon"></pc-element>
</pc-entity>
<pc-asset>は<pc-app>の中に、<pc-entity>はスクリーンの下に宣言します。
イメージが表示するのは、テクスチャかスプライトのどちらか一方です。テクスチャアセットを割り当てるとスプライトアセットがクリアされ、スプライトを割り当てるとテクスチャアセットがクリアされます。
テクスチャのフィッティング
テクスチャは、エレメントの形状に合わせて引き伸ばされ、エレメント全体を埋めます。Fit Modeを使うと、代わりにテクスチャのアスペクト比が保たれます。

| フィットモード | テクスチャの表示 |
|---|---|
| Stretch | エレメントを埋めるように引き伸ばされます。これがデフォルトです |
| Contain | エレメントの内側に収まるようにスケーリングされ、左右または上下に余白が残ります |
| Cover | エレメントを覆うようにスケーリングされ、左右または上下がはみ出します。はみ出した部分はマスクで切り取ります |
ContainやCoverで表示したテクスチャは、エレメントのピボットの位置に配置されます。ピボットが中央にあれば中央に配置され、角にあればその角に揃えられます。エンジンではfitModeをpc.FITMODE_STRETCH、pc.FITMODE_CONTAIN、pc.FITMODE_COVERのいずれかに設定し、ReactではfitModeプロパティ、Web Componentsではfit-mode属性を使います。
テクスチャの一部
rectはテクスチャの一部を描画します。その部分は、テクスチャの左下隅を0, 0として、テクスチャに対する割合で表したu、v、幅、高さで指定します。デフォルトの0, 0, 1, 1では、テクスチャ全体が描画されます。
// テクスチャの左上の4分の1
icon.element.rect = new pc.Vec4(0, 0.5, 0.5, 0.5);
多くの画像を1つのテクスチャにまとめる場合は、テクスチャアトラスとスプライトを使うほうが管理しやすくなります。
スプライト
スプライトは、テクスチャアトラス(名前付きの矩形を定義したテクスチャ)のフレームの集まりです。イメージエレメントにスプライトアセットを割り当てると最初のフレームが描画され、spriteFrameを設定すると別のフレームを選べます。さらにスプライトには、どのサイズでもフレームのボーダーをくっきりと保つレンダーモードがあります。
9スライスとタイルのスプライト
レンダーモードがSlicedのスプライトは、フレームのボーダーを一定のサイズに保ったまま、残りの部分をエレメントのサイズまで引き伸ばします。Tiledでは、残りの部分を引き伸ばす代わりに繰り返します。これにより、1枚の小さな画像から任意のサイズのパネル、ボタン、枠を作れます。フレームのボーダーの定義方法については、9スライスを参照してください。

bピクセルのボーダーの幅は、スクリーンの単位でb / pixelsPerUnitになります。Pixels Per Unitには、イメージエレメントが独自の値を設定していない限りスプライトの値が使われるため、1単位あたり1ピクセルのスプライトでは、16ピクセルのボーダーが16単位の幅で描画されます。エレメントが小さすぎて両側のボーダーが収まらない場合は、収まるようにボーダーが縮小されます。
- Engine
- Editor
- React
- Web Components
// 64 x 64のフレームを1つ持つテクスチャアトラス。フレームの16ピクセルのボーダーはサイズが保たれる
const atlas = new pc.TextureAtlas();
atlas.texture = panelTexture.resource;
atlas.frames = {
panel: {
rect: new pc.Vec4(0, 0, 64, 64),
pivot: new pc.Vec2(0.5, 0.5),
border: new pc.Vec4(16, 16, 16, 16)
}
};
const sprite = new pc.Sprite(app.graphicsDevice, {
atlas,
frameKeys: ['panel'],
pixelsPerUnit: 1,
renderMode: pc.SPRITE_RENDERMODE_SLICED
});
const dialog = new pc.Entity('dialog');
dialog.addComponent('element', {
type: pc.ELEMENTTYPE_IMAGE,
anchor: [0.5, 0.5, 0.5, 0.5],
pivot: [0.5, 0.5],
width: 400,
height: 240,
sprite
});
screen.addChild(dialog);
フレームのrectは、テクスチャの左下隅から測ったピクセル単位のx、y、幅、高さで、borderは左、下、右、上の順です。スプライトアセットを使う場合は、spriteの代わりにspriteAssetを設定します。
スプライトエディターでフレームのボーダーを設定し、New Sliced Sprite From Selectionをクリックします。次に、新しいスプライトアセットをイメージエレメントのSpriteフィールドにドラッグします。
useAssetはテクスチャアトラスやスプライトを読み込まないため、テクスチャから作成します。
import { useEffect, useState } from 'react';
import { SPRITE_RENDERMODE_SLICED, Sprite, TextureAtlas, Vec2, Vec4 } from 'playcanvas';
import { Entity } from '@playcanvas/react';
import { Element } from '@playcanvas/react/components';
import { useApp, useTexture } from '@playcanvas/react/hooks';
export function Dialog() {
const app = useApp();
const { asset: texture } = useTexture('textures/panel.png');
const [sprite, setSprite] = useState(null);
// 64 x 64のフレームを1つ持つテクスチャアトラス。フレームの16ピクセルのボーダーはサイズが保たれる。
// スプライトはGPU上のメッシュを持つため、エフェクトの中で作成し、ダイアログと一緒に破棄する
useEffect(() => {
if (!texture) return;
const atlas = new TextureAtlas();
atlas.texture = texture.resource;
atlas.frames = {
panel: { rect: new Vec4(0, 0, 64, 64), pivot: new Vec2(0.5, 0.5), border: new Vec4(16, 16, 16, 16) }
};
const panelSprite = new Sprite(app.graphicsDevice, {
atlas, frameKeys: ['panel'], pixelsPerUnit: 1, renderMode: SPRITE_RENDERMODE_SLICED
});
setSprite(panelSprite);
return () => {
setSprite(null);
panelSprite.destroy();
};
}, [app, texture]);
if (!sprite) return null;
return (
<Entity name="dialog">
<Element type="image" anchor={[0.5, 0.5, 0.5, 0.5]} pivot={[0.5, 0.5]}
width={400} height={240} sprite={sprite} />
</Entity>
);
}
<pc-asset id="panel-sheet" type="textureatlas" src="textures/panel.png"
data='{"frames":{"panel":{"rect":[0,0,64,64],"pivot":[0.5,0.5],"border":[16,16,16,16]}}}'></pc-asset>
<pc-asset id="panel" type="sprite" atlas="panel-sheet" frame-keys="panel" render-mode="sliced"></pc-asset>
<pc-entity name="dialog">
<pc-element type="image" anchor="0.5 0.5 0.5 0.5" pivot="0.5 0.5"
width="400" height="240" sprite-asset="panel"></pc-element>
</pc-entity>
テクスチャアトラスは、それを使うスプライトより前に宣言します。<pc-asset>を参照してください。
3Dをイメージにレンダリングする
カメラは、イメージエレメントが表示するテクスチャにレンダリングできます。キャラクターのポートレート、アイテムのプレビュー、ミニマップなどに使えます。そのカメラには、映すべきものだけを入れた専用のレイヤーを与え、メインカメラより先にレンダリングします。
// レンダリング先のテクスチャ
const previewTexture = new pc.Texture(app.graphicsDevice, {
width: 512,
height: 512,
format: pc.PIXELFORMAT_SRGBA8,
mipmaps: false
});
const renderTarget = new pc.RenderTarget({
colorBuffer: previewTexture,
depth: true,
origin: pc.RENDERTARGET_ORIGIN_TOP
});
// プレビューカメラが映すもののためのレイヤー。メインカメラはこのレイヤーをレンダリングしない
const previewLayer = new pc.Layer({ name: 'Preview' });
app.scene.layers.push(previewLayer);
const previewCamera = new pc.Entity('preview camera');
previewCamera.addComponent('camera', {
layers: [previewLayer.id],
renderTarget,
priority: -1,
clearColor: new pc.Color(0, 0, 0, 0)
});
previewCamera.setPosition(0, 0.5, 3);
previewCamera.lookAt(model.getPosition());
app.root.addChild(previewCamera);
// モデルをプレビューレイヤーに置き、テクスチャをインターフェースに表示する
model.render.layers = [previewLayer.id];
portrait.element.texture = previewTexture;
カメラのpriorityを-1にすると、優先度が0のメインカメラより先にレンダリングされるため、インターフェースを描画する時点でテクスチャの準備ができています。クリアカラーが透明なので、イメージの背景は透明のままです。テクスチャはsRGB形式のpc.PIXELFORMAT_SRGBA8のままにしてください。pc.PIXELFORMAT_RGBA8にすると、イメージが明るくなりすぎます。originをpc.RENDERTARGET_ORIGIN_TOPにすると、画像テクスチャと同じく一番上の行から順に格納されるので、WebGL2でもWebGPUでも正しい向きになります。指定しないと、WebGL2では上下が逆になります。originオプションはエンジン2.22から使えます。
カスタムマテリアル
イメージエレメントは、自身の色、不透明度、テクスチャを使うデフォルトのマテリアルで描画されます。グラデーションやシェーダーエフェクトのために独自のマテリアルで描画するには、そのマテリアルをmaterialに割り当てるか、エディターではMaterialフィールドに割り当てます。このマテリアルは、エレメントの色、不透明度、テクスチャの処理も含めて、デフォルトのマテリアルを置き換えます。
UIレイヤーは透明なマテリアルしか描画しないため、そこに表示するにはマテリアルがブレンドを使う必要があります。
const material = new pc.StandardMaterial();
material.useLighting = false;
material.emissive = new pc.Color(1, 0.55, 0.2);
material.blendType = pc.BLEND_NORMAL;
material.depthWrite = false;
material.update();
panel.element.material = material;
ブレンドしないマテリアル(新しいマテリアルのデフォルト)は、UIレイヤーでは一切描画されません。スクリーン空間のスクリーン上のマテリアルは、シーンのライトによって意味のある形で照らされることがないため、ライティングをオフにしてください。
暗い縁を防ぐ
丸いアイコンのように透明な領域を持つテクスチャでは、縁の周りに暗い、または明るい細い縁取りが出ることがあります。透明な領域のピクセルも、目には見えなくても色(通常は黒か白)を持っています。テクスチャが別のサイズで描画されると、フィルタリングによってその色が縁の見えているピクセルに混ざります。
これはエンジンではなく画像の側で修正します。透明なピクセルのアルファはそのままにして、その色を最も近い見えているピクセルの色で埋めてください。多くの画像エディターやテクスチャツールでこの処理ができ、alpha bleeding、texture padding、dilationといった名前で用意されていることがよくあります。
関連情報
- マスク - エレメントの矩形や形状による子の切り抜き
- ボタン - ホバー時や押下時のイメージのティントやスプライトの変更
- 9スライスとスプライトエディター - エディターでのスプライトとそのボーダーの作成
- Elementコンポーネント、
<pc-element>、ElementComponent - イメージのすべてのプロパティのリファレンス