diff --git a/content/creator/sdk7/3d-essentials/materials.md b/content/creator/sdk7/3d-essentials/materials.md index e3a8b774..3d9efcea 100644 --- a/content/creator/sdk7/3d-essentials/materials.md +++ b/content/creator/sdk7/3d-essentials/materials.md @@ -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: @@ -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, }), @@ -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', }), }) ``` @@ -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: + + + +```ts +Material.setPbrMaterial(myEntity, { + texture: Material.Texture.Common({ + src: 'assets/materials/wood.png', + wrapMode: TextureWrapMode.TWM_REPEAT, + tiling: Vector2.create(8, 8), + }), +}) +``` + + + +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`. @@ -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. + + -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. @@ -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 @@ -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. + -- 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. @@ -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 >}} + + -// 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" >}}). +