Skip to content

Commit

Permalink
WIP offset and tiling (#459)
Browse files Browse the repository at this point in the history
* fist draft

* more info on textures & screenshots

* texture tween

* Update materials.md

Signed-off-by: Nicolas Earnshaw <[email protected]>

* retouches

---------

Signed-off-by: Nicolas Earnshaw <[email protected]>
  • Loading branch information
nearnshaw authored Jan 16, 2025
1 parent c657396 commit 3c5cda5
Show file tree
Hide file tree
Showing 5 changed files with 223 additions and 33 deletions.
256 changes: 223 additions & 33 deletions content/creator/sdk7/3d-essentials/materials.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,15 +115,15 @@ MeshRenderer.setBox(meshEntity)
//Create material and configure its fields
Material.setPbrMaterial(meshEntity, {
texture: Material.Texture.Common({
src: 'materials/wood.png',
src: 'assets/materials/wood.png',
}),
})
```

In the example above, the image for the material is located in a `materials` folder, which is located at root level of the scene project folder.
In the example above, the image for the material is located in a `assets/materials` folder, which is located at root level of the scene project folder.

{{< hint info >}}
**💡 Tip**: We recommend keeping your texture image files separate in a `/materials` folder inside your scene.
**💡 Tip**: We recommend keeping your texture image files somewhere in the `/assets` folder inside your scene.
{{< /hint >}}

While creating a texture, you can also pass additional parameters:
Expand All @@ -134,7 +134,7 @@ While creating a texture, you can also pass additional parameters:
```ts
Material.setPbrMaterial(myEntity, {
texture: Material.Texture.Common({
src: 'materials/wood.png',
src: 'assets/materials/wood.png',
filterMode: TextureFilterMode.TFM_BILINEAR,
wrapMode: TextureWrapMode.TWM_CLAMP,
}),
Expand All @@ -146,7 +146,7 @@ To create a texture that is not affected by light and shadows in the environment
```ts
Material.setBasicMaterial(myEntity, {
texture: Material.Texture.Common({
src: 'materials/wood.png',
src: 'assets/materials/wood.png',
}),
})
```
Expand All @@ -165,6 +165,184 @@ Material.setBasicMaterial(myEntity, {

The URL must start with `https`, `http` URLs aren't supported. The site where the image is hosted should also have [CORS policies (Cross Origin Resource Sharing)](https://en.wikipedia.org/wiki/Cross-origin_resource_sharing) that permit externally accessing it.

### Texture wrapping

You can set how a texture aligns with a surface. By default, the texture is stretched to occupy the surface once, but you can scale it, and offset it.

The following fields are available on all textures:

- `offset`: Shifts the texture to change its alignment. The value is a Vector2, where both axis go from 0 to 1, where 1 is the full width or height of the texture.
- `tiling`: Scales the texture. The default value is the Vector 2 `[1, 1]`, which makes the image repeat once covering all of the surface.
- `TextureWrapMode`: Determines what happens if the image tiling doesn't cover all of the surface. This property takes its values from the `TextureWrapMode` enum, which allows for the following values:

- `TextureWrapMode.TWM_CLAMP`: The texture is only displayed once in the specified size. The rest of the surface of the mesh is left transparent. The value of `tiling` is ignored.
- `TextureWrapMode.TWM_REPEAT`: The texture is repeated as many times as it fits in the mesh, using the specified size.
- `TextureWrapMode.TWM_MIRROR`: As in wrap, the texture is repeated as many times as it fits, but the orientation of these repetitions is mirrored.

```ts
Material.setPbrMaterial(myEntity, {
texture: Material.Texture.Common({
src: 'assets/materials/wood.png',
wrapMode: TextureWrapMode.TWM_REPEAT,
offset: Vector2.create(0, 0.2),
tiling: Vector2.create(1, 1),
}),
})
```

{{< hint warning >}}
**📔 Note**: The `offset` and `tiling` properties are only supported in the DCL 2.0 desktop client.
{{< /hint >}}

Use this feature to cover a large surface with a tiled pattern. For example, repeat the following image:

<img src="/images/editor/tiles.png" width="200" />

```ts
Material.setPbrMaterial(myEntity, {
texture: Material.Texture.Common({
src: 'assets/materials/wood.png',
wrapMode: TextureWrapMode.TWM_REPEAT,
tiling: Vector2.create(8, 8),
}),
})
```

<img src="/images/editor/tiles-in-scene.png" width="500" />

In the example below, the texture uses a _mirror_ wrap mode, and each repetition of the texture takes only 1/4 of the surface. This means that we'll see 4 copies of the image, mirrored against each other on both axis.

```ts
Material.setPbrMaterial(myEntity, {
texture: Material.Texture.Common({
src: 'materials/atlas.png',
wrapMode: TextureWrapMode.TWM_MIRROR,
tiling: Vector2.create(0.25, 0.25),
}),
})
```

### Texture tweens

Make a texture slide smoothly by using a `Tween` component, set up with the `TextureMove` mode. The tween gradually changes the value of the `offset` or the `tiling` properties of a texture over a period of time, in a smooth and optimized way.

{{< hint warning >}}
**📔 Note**: Texture Tweens are a feature that's only supported in the DCL 2.0 desktop client.
{{< /hint >}}

The new `TextureMove` option on the `Tween` component has the following fields:

- `TextureMovementType`: _(optional)_, defines if the movement will be on the `offset` or the `tiling` field. By default it uses `offset`.
- `start`: _Vector2_ the initial value of the offset or tiling
- `end`: _Vector2_ the final value of the offset or tiling
- `duration`: _number_ how long the transition takes, in milliseconds
- `easingFunction`: The curve for the rate of change over time, the default value is `EasingFunction.EF_LINEAR`. Other values make the change accelerate and/or decelerate at different rates.

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

MeshRenderer.setPlane(myEntity)

Transform.create(myEntity, {
position: Vector3.create(4, 1, 4),
})

Material.setPbrMaterial(myEntity, {
texture: Material.Texture.Common({
src: 'materials/water.png',
wrapMode: TextureWrapMode.TWM_REPEAT,
}),
})

Tween.create(myEntity, {
mode: Tween.Mode.TextureMove({
start: Vector2.create(0, 0),
end: Vector2.create(0, 1),
}),
duration: 1000,
easingFunction: EasingFunction.EF_LINEAR,
})
```

The above example runs a tween that lasts 1 second, and moves the texture only once. To achieve a continuous movement, for example to simulate the falling of a cascade, you need to use a `TweenSequence` component.

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

MeshRenderer.setPlane(myEntity)

Transform.create(myEntity, {
position: Vector3.create(4, 1, 4),
})

Material.setPbrMaterial(myEntity, {
texture: Material.Texture.Common({
src: 'materials/water.png',
wrapMode: TextureWrapMode.TWM_REPEAT,
}),
})

Tween.create(myEntity, {
mode: Tween.Mode.TextureMove({
start: Vector2.create(0, 0),
end: Vector2.create(0, 1),
}),
duration: 1000,
easingFunction: EasingFunction.EF_LINEAR,
})

TweenSequence.create(myEntity, { sequence: [], loop: TweenLoop.TL_RESTART })
```

The example above sets the `loop` mode to `TweenLoop.TL_RESTART`, which makes the same transition repeat continuously. You can also set the `loop`mode to `TweenLoop.TL_YOYO` to alternate back and forth in the opposite direction.

#### Complex tween sequences

You can also make the texture movements follow a complex sequence with as many steps as you want. Use the `sequence` field to list as many tweens as you want, they will be executed sequentially after the first tween described on the `Tween` component.

```ts
//(...)

Tween.create(myEntity, {
mode: Tween.Mode.TextureMove({
start: Vector2.create(0, 0),
end: Vector2.create(0, 1),
}),
duration: 1000,
easingFunction: EasingFunction.EF_LINEAR,
})

TweenSequence.create(myEntity, {
sequence: [
{
mode: Tween.Mode.TextureMove({
start: Vector2.create(0, 1),
end: Vector2.create(1, 1),
}),
duration: 1000,
easingFunction: EasingFunction.EF_LINEAR,
},
{
mode: Tween.Mode.TextureMove({
start: Vector2.create(1, 1),
end: Vector2.create(1, 0),
}),
duration: 1000,
easingFunction: EasingFunction.EF_LINEAR,
},
{
mode: Tween.Mode.TextureMove({
start: Vector2.create(1, 0),
end: Vector2.create(0, 0),
}),
duration: 1000,
easingFunction: EasingFunction.EF_LINEAR,
},
],
loop: TweenLoop.TL_RESTART,
})
```

### Multi-layered textures

You can use several image files as layers to compose more realistic textures, for example including a `bumpTexture` and a `emissiveTexture`.
Expand All @@ -177,12 +355,21 @@ Material.setPbrMaterial(myEntity, {
bumpTexture: Material.Texture.Common({
src: 'materials/woodBump.png',
}),
emissiveTexture: Material.Texture.Common({
src: 'materials/glow.png',
}),
})
```

### Texture wrapping
The `bumpTexture` can simulate bumps and wrinkles on a surface, by modifying how the normals of the surface behave on each pixel.

<img src="/images/editor/wood-bump.png" width="500" />

If you want the texture to be mapped to specific scale or alignment on your entities, then you need to configure _uv_ properties on the [MeshRenderer component]({{< ref "/content/creator/sdk7/3d-essentials/shape-components.md" >}}).
The `emissiveTexture` can accentuate glow on certain parts of a material, to achieve very interesting effects.

#### Set UVs

Another alternative for changing a texture's scale or alignment is to configure _uv_ properties on the [MeshRenderer component]({{< ref "/content/creator/sdk7/3d-essentials/shape-components.md" >}}).

You set _u_ and _v_ coordinates on the 2D image of the texture to correspond to the vertices of the shape. The more vertices the entity has, the more _uv_ coordinates need to be defined on the texture, a plane for example needs to have 8 _uv_ points defined, 4 for each of its two faces.

Expand Down Expand Up @@ -269,25 +456,8 @@ function setUVs(rows: number, cols: number) {

For setting the UVs for a `box` mesh shape, the same structure applies. Each of the 6 faces of the cube takes 4 pairs of coordinates, one for each corner. All of these 48 values are listed as a single array.

You can also define how the texture is tiled if the mapping spans more than the dimensions of the texture image. The `texture` object lets you configure the wrapping mode by setting the `wrapMode` field. This property takes its values from the `TextureWrapMode` enum, which allows for the following values:

- `TextureWrapMode.TWM_CLAMP`: The texture is only displayed once in the specified size. The rest of the surface of the mesh is left transparent.
- `TextureWrapMode.TWM_REPEAT`: The texture is repeated as many times as it fits in the mesh, using the specified size.
- `TextureWrapMode.TWM_MIRROR`: As in wrap, the texture is repeated as many times as it fits, but the orientation of these repetitions is mirrored.

```ts
Material.setPbrMaterial(myEntity, {
texture: Material.Texture.Common({
src: 'materials/atlas.png',
wrapMode: TextureWrapMode.TWM_MIRROR,
}),
})
```

The example above sets the wrapping mode to `TWM_MIRROR`.

{{< hint warning >}}
**📔 Note**: Uv properties are currently only available on `plane` and on `box` shapes.
**📔 Note**: Uv properties are currently only available on `plane` and on `box` shapes. Also, _uv_ values affect all the texture layers equally, since they are set on the _shape_.
{{< /hint >}}

### Texture scaling
Expand Down Expand Up @@ -361,15 +531,20 @@ Material.setPbrMaterial(meshEntity, {
})
```

To make a material with a texture only transparent in regions of the texture:

- Set an image in `alphaTexture`.
If a material uses a .png texture that includes transparency, it will be opaque by default, but you can activate its transparency by setting the `transparencyMode` to `MaterialTransparencyMode.MTM_ALPHA_BLEND`.

> Note: This must be a single-channel image. In this image use the color red to determine what parts of the real texture should be transparent.
<img src="/images/editor/transparent-image.png" width="500" />

- Optionally set the texture normally, and set the `transparencyMode` to field.
```typescript
Material.setPbrMaterial(floor, {
texture: Material.Texture.Common({
src: 'assets/scene/transparent-image.png',
}),
transparencyMode: MaterialTransparencyMode.MTM_ALPHA_BLEND,
})
```

The `transparencyMode` takes its value from the `MaterialTransparencyMode` enum, that can have the following values:
The `transparencyMode` can have the following values:

- `MaterialTransparencyMode.MTM_OPAQUE`: No transparency at all
- `MaterialTransparencyMode.MTM_ALPHA_TEST`: Each pixel is either completely opaque or completely transparent, based on a threshold.
Expand All @@ -390,16 +565,31 @@ Material.setPbrMaterial(meshEntity1, {
transparencyMode: MaterialTransparencyMode.MTM_ALPHA_TEST,
alphaTest: 1,
})
```

When using an [unlit material](#unlit-materials), you can add an `alphaTexture` to make only certain regions of the material transparent, based on a texture.

{{< hint warning >}}
**📔 Note**: This must be a single-channel image. In this image use the color red or black to determine what parts of the real texture should be transparent.
{{< /hint >}}

<img src="/images/circular-video-screen.png" width="500" />

// Using a alpha blend
```ts
// Using alpha test
Material.setPbrMaterial(meshEntity1, {
texture: Material.Texture.Common({
src: 'images/myTexture.png',
}),
transparencyMode: MaterialTransparencyMode.MTM_ALPHA_BLEND,
alphaTexture: Material.Texture.Common({
src: 'assets/scene/circle_mask.png',
wrapMode: TextureWrapMode.TWM_MIRROR,
}),
})
```

This can be used in very interesting ways together with videos. See [video playing]({{< ref "/content/creator/sdk7/media/video-playing.md" >}}).

<!--
## Casting no shadows
Expand Down
Binary file added static/images/editor/tiles-in-scene.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added static/images/editor/tiles.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added static/images/editor/transparent-image.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added static/images/editor/wood-bump.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 3c5cda5

Please sign in to comment.