# Components de forma

Cenas tridimensionais em Decentraland são baseadas no [Entity-Component](https://en.wikipedia.org/wiki/Entity%E2%80%93component%E2%80%93system) model, em que tudo numa cena é uma *entity*, e cada entity pode incluir *components* que moldam as suas características e funcionalidade.

A forma renderizada de uma entity é determinada pelo component que ela usa.

![](/files/bd50850b6fd34216f615151ed3a8b05c68ecec0f)

## Use o Scene Editor no Creator Hub

A maneira mais fácil de dar forma a uma entity é usar o Scene Editor. Podes adicionar um **Mesh Renderer** component para fornecer uma forma primitiva, ou um **GLTF** component para referenciar um modelo 3D a partir de um ficheiro. Vê [Add Components](/creator/content-creator-pt/scene-editor/construir/components.md#add-components).

## Formas primitivas

Várias formas básicas, frequentemente chamadas *primitives*, podem ser adicionadas a uma entity dando à entity um `MeshRenderer` componente.

As seguintes formas estão disponíveis. Várias formas incluem campos adicionais opcionais, específicos para essa forma.

* **caixa**:

  Use `MeshRenderer.setBox()`, passando a entidade. Passe `uvs` como um campo adicional opcional, para mapear o alinhamento da texture. Vê [materials](/creator/content-creator-pt/scenes-sdk7/essenciais-de-conteudo-3d/materials.md) para mais detalhes.
* **plano**:

  Use `MeshRenderer.setPlane()`, passando a entidade. Passe `uvs` como um campo adicional opcional, para mapear o alinhamento da texture. Vê [materials](/creator/content-creator-pt/scenes-sdk7/essenciais-de-conteudo-3d/materials.md) para mais detalhes.
* **esfera**:

  Use `MeshRenderer.setSphere()`, passando a entidade.
* **cilindro**:

  Use `MeshRenderer.setCylinder()`, passando a entidade. Passe `radiusTop` e `radiusBottom` como campos opcionais adicionais, para modificar o cilindro.

  DICA: Define qualquer um `radiusTop` ou `radiusBottom` como 0 para criar um cone.

O seguinte exemplo cria um cubo:

```ts
const myCube = engine.addEntity()

Transform.create(myCube, {
	position: Vector3.create(8, 1, 8),
})

MeshRenderer.setBox(myCube)
```

O seguinte exemplo cria um cilindro com um `radiusTop` de 0, o que produz um cone:

```ts
const myCone = engine.addEntity()

Transform.create(myCone, {
	position: Vector3.create(8, 1, 8),
})

MeshRenderer.setCylinder(myCone, 0, 1)
```

As primitive shapes não incluem materials. Para lhes dar uma cor ou uma texture, tens de atribuir um [material component](/creator/content-creator-pt/scenes-sdk7/essenciais-de-conteudo-3d/materials.md) à mesma entity.

Para tornar uma primitive clicável, ou para impedir que os jogadores andem através dela, tens de dar à entity um *collider* através de um [MeshCollider](/creator/content-creator-pt/scenes-sdk7/essenciais-de-conteudo-3d/colliders.md) componente.

Para alterar a forma de uma entity que já tem um `MeshRenderer` component, execute `MeshRenderer.setBox()` ou qualquer uma das outras helper functions, isso irá substituir a forma original. Não é necessário remover o original `MeshRenderer` nem usar a sintaxe avançada.

```ts
const myCube = engine.addEntity()

Transform.create(myCube, {
	position: Vector3.create(8, 1, 8),
})

MeshRenderer.setBox(myCube)

// substituir forma
MeshRenderer.setSphere(myCube)
```

{% hint style="warning" %}
**📔 Nota**: O `MeshRenderer` component deve ser importado através de

> `import { MeshRenderer } from "@dcl/sdk/ecs"`

Veja [Imports](/creator/content-creator-pt/scenes-sdk7/comecar/coding-scenes.md#imports) para saber como lidar facilmente com estes casos.
{% endhint %}

## modelos 3D

Para formas mais complexas, podes criar um modelo 3D numa ferramenta externa como o Blender e depois importá-lo em *.glTF* ou *.glb* (binário *.glTF*). [glTF](https://www.khronos.org/gltf) (GL Transmission Format) é um projeto aberto da Khronos que fornece um formato comum e extensível para 3D assets, eficiente e altamente interoperável com tecnologias web modernas.

Para adicionar um modelo externo a uma cena, adiciona um `GltfContainer` component a uma entity e define o seu `src` para o caminho do ficheiro glTF que contém o modelo.

```ts
const houseEntity = engine.addEntity()

GltfContainer.create(houseEntity, {
	src: 'models/House.gltf',
})
```

O `src` é obrigatório, tens de lhe dar um valor ao construir o component. No exemplo acima, o modelo está localizado numa `models` pasta ao nível raiz da pasta do projeto da scene.

{% hint style="info" %}
**💡 Dica**: Recomendamos manter os teus modelos separados na `assets/scene/models` dentro da tua scene.
{% endhint %}

Os modelos glTF podem incluir as suas próprias textures, materials, colliders e animations incorporadas. Vê [modelos 3D](https://github.com/decentraland/docs-creator/blob/main/creator/3d-modeling/3d-models/README.md) para mais informações sobre isto. Para substituir os materials de um modelo, usa o [GltfNodeModifiers](/creator/content-creator-pt/scenes-sdk7/essenciais-de-conteudo-3d/materials.md#modify-gltf-materials) component. Veja [Modificar materiais glTF](/creator/content-creator-pt/scenes-sdk7/essenciais-de-conteudo-3d/materials.md#modify-gltf-materials) para mais detalhes.

Para impedir que os jogadores andem através de um modelo 3D, ou para tornar um modelo clicável, tens de ter um [collider](/creator/content-creator-pt/scenes-sdk7/essenciais-de-conteudo-3d/colliders.md), que pode estar incorporado no modelo ou ser fornecido através de um `MeshCollider` componente.

Tem em atenção que todos os modelos, os seus shaders e as suas textures têm de estar dentro dos parâmetros do [limitações da scene](/creator/content-creator-pt/scenes-sdk7/otimizacao/scene-limitations.md).

{% hint style="warning" %}
**📔 Nota**: O `GltfContainer` component deve ser importado através de

`import { GltfContainer } from "@dcl/sdk/ecs"`

Veja [Imports](/creator/content-creator-pt/scenes-sdk7/comecar/coding-scenes.md#imports) para saber como lidar facilmente com estes casos.
{% endhint %}

### Pré-carregar um modelo 3D

Em alguns casos, um modelo 3D personalizado é adicionado à scene mas não é usado imediatamente. Por exemplo, um modelo de cadeira personalizado pode apenas ser carregado quando o player interage com outro objeto. Neste cenário, a primeira interação pode demorar algum tempo até terminar de descarregar e carregar o modelo.

Para evitar isso, usa o `AssetLoad.create` method para garantir que o asset é descarregado antes de ser necessário.

```ts
import { AssetLoad } from "@dcl/sdk/ecs"

AssetLoad.create(engine.RootEntity, {
  assets: [
    "assets/scene/bundle1/explosion.glb",
  ],
})
```

Para mais informações, consulta a documentação de [Pre Load Resources](/creator/content-creator-pt/scenes-sdk7/otimizacao/pre-load-resources.md) .

### Bibliotecas gratuitas de modelos 3D

Em vez de criar os seus próprios modelos 3D, você também pode transferi-los de várias bibliotecas gratuitas ou pagas.

Para o ajudar a começar, abaixo está uma lista de bibliotecas que têm conteúdo gratuito ou relativamente barato:

* [IWB Catalog](https://dcl-iwb.co/)
* [Asset Ovi](https://assetovi.com/)
* [Assets do Builder](https://github.com/decentraland/builder-assets/tree/master/assets)
* [SketchFab](https://sketchfab.com/)
* [Clara.io](https://clara.io/)
* [Archive3D](https://archive3d.net/)
* [SketchUp 3D Warehouse](https://3dwarehouse.sketchup.com/)
* [Thingiverse](https://www.thingiverse.com/) (modelos 3D feitos principalmente para impressão 3D, mas adaptáveis a Virtual Worlds)
* [ShareCG](https://www.sharecg.com/)
* [CGTrader](https://www.cgtrader.com/)

{% hint style="warning" %}
**📔 Nota**: Preste atenção às restrições de licença que o conteúdo que você descarrega tem.
{% endhint %}

Note que em vários destes sites, você pode escolher o formato em que deseja descarregar o modelo. Escolha sempre *.glTF* formato, se disponível. Se não estiver disponível, você deve convertê-los para *glTF* antes de os poderes usar numa scene. Para isso, recomendamos importá-los para o Blender e exportar como *.glTF* a partir daí.

### Otimizar modelos 3D

Para garantir que os modelos 3D na tua scene carregam mais depressa e ocupam menos memória, segue estas melhores práticas:

* Guarda os teus modelos em *.glb* format, que é uma versão mais leve de *.gltf*.
* Se tiveres vários modelos que partilham as mesmas textures, exporta os teus modelos com textures num ficheiro separado. Dessa forma, vários modelos podem referir-se a um único ficheiro de texture que só precisa de ser carregado uma vez.
* Se a tua scene tiver entities que aparecem e desaparecem, pode ser boa ideia agrupar essas entities e mantê-las subterrâneas, ou numa escala de 0. Isto vai ajudá-las a aparecer mais depressa; a desvantagem é que vão ocupar memória quando não estiverem em uso. Vê [entities e components](/creator/content-creator-pt/scenes-sdk7/arquitetura/entities-components.md#pooling-entities-and-components)

## Esticar uma forma

As primitive shapes e os modelos 3D têm dimensões predefinidas que podes alterar mudando a escala no `Transform` componente.

```ts
const primitiveEntity = engine.addEntity()

MeshRenderer.setBox(primitiveEntity)

Transform.create(primitiveEntity, {
	position: { x: 8, y: 1, z: 8 },
	scale: { x: 4, y: 0.5, z: 4 },
})
```

## Tornar invisível

Podes tornar uma entity invisível dando a uma entity um `VisibilityComponent`, com a sua `visible` propriedade definida como *false*.

```ts
const myEntity = engine.addEntity()
Transform.create(myEntity, {
	position: Vector3.create(4, 0, 4),
})
MeshRenderer.setBox(myEntity)

VisibilityComponent.create(myEntity, { visible: false })
```

O `VisibilityComponent` funciona da mesma forma para entities com primitive shapes e com `GLTFContainer` components.

Se uma entity for invisível, o seu collider pode bloquear o caminho de um player e/ou impedir o clique em entities que estejam atrás dela, dependendo das collision layers atribuídas ao collider.

### Propagar visibilidade

Você pode usar o `propagateToChildren` campo no `VisibilityComponent` para aplicar uma configuração a cada child na árvore de children da entity. Se `propagateToChildren` estiver definido como *true*, estas definições afetam todos os children em todos os níveis descendentes. Isto pode poupar-te muito trabalho tedioso ao marcar cada child entity como invisível ou visível também.

```ts
// Entity pai (explicitamente invisível)
const parentEntity = engine.addEntity()
Transform.create(parentEntity, {
	position: Vector3.create(4, 0, 4),
})
MeshRenderer.setBox(parentEntity)
VisibilityComponent.create(parentEntity, { visible: false, propagateToChildren: true })

// Child entity (implicitamente invisível por causa do pai)
const child = engine.addEntity()
Transform.create(child, {
	position: Vector3.create(0, 1, 0),
	parent: parentEntity
})
MeshRenderer.setBox(child)
```

{% hint style="warning" %}
**📔 Nota**: Se uma entity tiver o seu próprio `VisibilityComponent`, isso substitui qualquer configuração dos pais.

Se uma entity não tiver o seu próprio `VisibilityComponent`, então a sua visibilidade é determinada pelo seu pai mais próximo com um `VisibilityComponent` e `propagateToChildren` definido como *true*.
{% endhint %}

## Estado de carregamento

Se um modelo 3D for bastante grande, pode demorar algum tempo visível a ser renderizado; esse tempo pode variar consoante o hardware do player e muitos outros fatores. Às vezes precisas de garantir que um modelo terminou de carregar antes de executares outra ação. Por exemplo, se quiseres teleportar o player para uma plataforma no céu, primeiro tens de garantir que a plataforma está totalmente renderizada antes de mover o player para lá, caso contrário o player pode cair diretamente através da plataforma.

Para verificar se um modelo 3D terminou de ser renderizado, verifica o `GltfContainerLoadingState` component da entity. Este component destina-se a ser apenas de leitura e existe em qualquer entity que também tenha um `GltfContainer`componente.

Este component tem uma única propriedade chamada `currentState`, contendo um valor do `LoadingState` enum.

O seguinte exemplo usa um system para verificar periodicamente o estado de carregamento do modelo 3D de uma entity. Se o estado for `LoadingState.FINISHED`, podes querer executar lógica personalizada aí e terminar a execução do system.

```ts
export function main() {
	const meshEntity = engine.addEntity()
	GltfContainer.create(meshEntity, { src: 'models/Monster.glb' })
	engine.addSystem((deltaTime) => {
		const loadingState = GltfContainerLoadingState.getOrNull(meshEntity)
		if (!loadingState) return
		switch (loadingState.currentState) {
			case LoadingState.LOADING:
				console.log('mesh is LOADING')
				break
			case LoadingState.FINISHED:
				console.log('mesh is FINISHED')
				// Executar lógica personalizada
				break
			case LoadingState.FINISHED_WITH_ERROR:
				console.log('mesh is FINISHED BUT MAY HAVE PROBLEMS')
				break
			case LoadingState.UNKNOWN:
				console.log('mesh is in an UNKNOWN STATE')
				break
		}
	})
}
```

## Sintaxe avançada

A sintaxe completa para criar um `MeshRenderer` component, sem quaisquer auxiliares para o simplificar, é a seguinte:

```ts
MeshRenderer.setBox(myBox, {
	mesh: {
		$case: 'box',
		box: { uvs: [] },
	},
})

MeshRenderer.create(myPlane, {
	mesh: {
		$case: 'plane',
		plane: { uvs: [] },
	},
})

MeshRenderer.create(myShpere, {
	mesh: {
		$case: 'sphere',
		sphere: {},
	},
})

MeshRenderer.create(myCylinder, {
	mesh: {
		$case: 'cylinder',
		cylinder: {},
	},
})
```

É assim que o protocolo base interpreta components MeshRenderer. As helper functions abstraem isto e expõem uma sintaxe mais amigável, mas por trás dos bastidores produzem esta sintaxe.

O `$case` campo permite-lhe especificar um dos tipos permitidos. Cada tipo suporta um conjunto diferente de parâmetros. No exemplo acima, o `caixa` tipo suporta um `uvs` field.

Os valores suportados para `$case` são os seguintes:

* `caixa`
* `plano`
* `esfera`
* `cilindro`

Dependendo do valor de `$case`, é válido definir o objeto para a forma correspondente, passando quaisquer propriedades relevantes.

Para adicionar um `MeshRenderer` component a uma entity que potencialmente já tem uma instância deste component, use `MeshRenderer.createOrReplace()`. As funções auxiliares como `MeshRenderer.setBox()` tratam de substituir instâncias existentes do component, mas executar `MeshRenderer.create()` numa entity que já tem este component devolve um erro.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.decentraland.org/creator/content-creator-pt/scenes-sdk7/essenciais-de-conteudo-3d/shape-components.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
