VisuTwin Canvas
C++ 3D Engine — Metal Backend
Loading...
Searching...
No Matches
material.h
Go to the documentation of this file.
1// SPDX-License-Identifier: Apache-2.0
2// Copyright 2025-2026 Arnis Lektauers
3//
4// Created by Arnis Lektauers on 11.10.2025.
5//
6#pragma once
7
8#include <cmath>
9#include <cstdint>
10#include <unordered_map>
11#include <string>
12#include <variant>
13#include <vector>
14
15#include "core/math/color.h"
16#include "core/math/matrix4.h"
17#include "core/math/vector2.h"
18#include "core/math/vector3.h"
19#include "core/math/vector4.h"
24#include "scene/constants.h"
25
26namespace visutwin::canvas
27{
28 class Texture;
29
37 {
38 Vector2 tiling{1.0f, 1.0f};
39 Vector2 offset{0.0f, 0.0f};
40 float rotation = 0.0f; // degrees
41
42 bool isIdentity() const
43 {
44 return tiling.x == 1.0f && tiling.y == 1.0f &&
45 offset.x == 0.0f && offset.y == 0.0f &&
46 rotation == 0.0f;
47 }
48 };
49
50 enum class AlphaMode
51 {
52 OPAQUE = 0,
53 MASK = 1,
55 };
56
62 {
63 float baseColor[4] = {1.0f, 1.0f, 1.0f, 1.0f};
64 float emissiveColor[4] = {0.0f, 0.0f, 0.0f, 1.0f};
65 uint32_t flags = 0u;
67 float alphaCutoff = 0.5f;
68 float metallicFactor = 0.0f;
69 float roughnessFactor = 1.0f;
70 float normalScale = 1.0f;
71 float occlusionStrength = 1.0f;
73
74 // per-texture UV transforms as pre-computed 3×2 affine matrices.
75 // Each pair of float[4] encodes one row of the matrix:
76 // row0 = {cos(θ)*sx, -sin(θ)*sy, ox, 0}
77 // row1 = {sin(θ)*sx, cos(θ)*sy, 1-sy-oy, 0}
78 // Identity: row0={1,0,0,0}, row1={0,1,0,0}
79 // GPU applies: uv' = float2(dot(float3(uv,1), row0.xyz), dot(float3(uv,1), row1.xyz))
80 float baseColorTransform0[4] = {1, 0, 0, 0};
81 float baseColorTransform1[4] = {0, 1, 0, 0};
82 float normalTransform0[4] = {1, 0, 0, 0};
83 float normalTransform1[4] = {0, 1, 0, 0};
84 float metalRoughTransform0[4] = {1, 0, 0, 0};
85 float metalRoughTransform1[4] = {0, 1, 0, 0};
86 float occlusionTransform0[4] = {1, 0, 0, 0};
87 float occlusionTransform1[4] = {0, 1, 0, 0};
88 float emissiveTransform0[4] = {1, 0, 0, 0};
89 float emissiveTransform1[4] = {0, 1, 0, 0};
90
91 // clearcoat dual-layer material properties.
92 // Ported from StandardMaterial clearCoat/clearCoatGloss/clearCoatBumpiness.
93 float clearCoatFactor = 0.0f; // 0 = disabled, 1 = full clearcoat
94 float clearCoatRoughness = 0.0f; // 0 = mirror, 1 = rough (computed from gloss)
95 float clearCoatBumpiness = 1.0f; // clearcoat normal map intensity
96 float heightMapFactor = 0.0f; // parallax height scale (0 = no parallax)
97
98 float anisotropy = 0.0f; // anisotropic specular: -1..1 (0 = isotropic)
99 float transmissionFactor = 0.0f; // 0 = opaque, 1 = fully transmissive
100 float refractionIndex = 1.5f; // IOR (1.0 = air, 1.5 = glass, 1.33 = water)
101 float thickness = 0.0f; // volume thickness for absorption scaling
102
103 // --- Sheen (KHR_materials_sheen) ---
104 // fabric/velvet sheen layer.
105 float sheenColor[4] = {0, 0, 0, 0}; // rgb=sheen color, w=sheen roughness
106
107 // --- Iridescence (KHR_materials_iridescence) ---
108 // thin-film interference layer.
109 float iridescenceParams[4] = {0, 1.3f, 100.0f, 400.0f}; // intensity, IOR, thicknessMin(nm), thicknessMax(nm)
110
111 // --- Spec-Gloss (KHR_materials_pbrSpecularGlossiness) ---
112 // alternative PBR parameterization.
113 float specGlossParams[4] = {1, 1, 1, 1}; // rgb=specular color, w=glossiness
114
115 // --- Detail Normals + Displacement ---
116 // detail normal overlay and vertex displacement.
117 float detailDisplacementParams[4] = {1, 0, 0.5f, 0}; // detailNormalScale, displacementScale, displacementBias, pad
118
119 // --- Detail Normal UV Transform ---
120 float detailNormalTransform0[4] = {1, 0, 0, 0};
121 float detailNormalTransform1[4] = {0, 1, 0, 0};
122 };
123
128 {
129 int slot = -1;
130 Texture* texture = nullptr;
131 };
132
143 {
144 public:
145 using ParameterValue = std::variant<float, int32_t, uint32_t, bool, Color, Vector2, Vector3, Vector4, Matrix4, Texture*>;
146
147 Material();
148
149 virtual ~Material() = default;
150
151 const std::string& name() const { return _name; }
152 void setName(const std::string& name) { _name = name; }
153
154 bool transparent() const { return _transparent; }
155 void setTransparent(const bool value) { _transparent = value; }
156
157 uint64_t shaderVariantKey() const { return _shaderVariantKey; }
158 void setShaderVariantKey(const uint64_t value) { _shaderVariantKey = value; }
159
160 const std::shared_ptr<Shader>& shaderOverride() const { return _shaderOverride; }
161 void setShaderOverride(const std::shared_ptr<Shader>& shader) { _shaderOverride = shader; }
162
163 const std::shared_ptr<BlendState>& blendState() const { return _blendState; }
164 void setBlendState(const std::shared_ptr<BlendState>& blendState) { _blendState = blendState; }
165
166 const std::shared_ptr<DepthState>& depthState() const { return _depthState; }
167 void setDepthState(const std::shared_ptr<DepthState>& depthState) { _depthState = depthState; }
168
169 CullMode cullMode() const { return _cullMode; }
170 void setCullMode(const CullMode mode) { _cullMode = mode; }
171
172 const Color& baseColorFactor() const { return _baseColorFactor; }
173 void setBaseColorFactor(const Color& value) { _baseColorFactor = value; }
174
175 Texture* baseColorTexture() const { return _baseColorTexture; }
176 void setBaseColorTexture(Texture* texture) { _baseColorTexture = texture; }
177
178 bool hasBaseColorTexture() const { return _hasBaseColorTexture; }
179 void setHasBaseColorTexture(const bool value) { _hasBaseColorTexture = value; }
180 int baseColorUvSet() const { return _baseColorUvSet; }
181 void setBaseColorUvSet(const int uvSet) { _baseColorUvSet = uvSet; }
182
183 Texture* normalTexture() const { return _normalTexture; }
184 void setNormalTexture(Texture* texture) { _normalTexture = texture; }
185 float normalScale() const { return _normalScale; }
186 void setNormalScale(const float value) { _normalScale = value; }
187
188 bool hasNormalTexture() const { return _hasNormalTexture; }
189 void setHasNormalTexture(const bool value) { _hasNormalTexture = value; }
190 int normalUvSet() const { return _normalUvSet; }
191 void setNormalUvSet(const int uvSet) { _normalUvSet = uvSet; }
192
193 float metallicFactor() const { return _metallicFactor; }
194 void setMetallicFactor(const float value) { _metallicFactor = value; }
195
196 float roughnessFactor() const { return _roughnessFactor; }
197 void setRoughnessFactor(const float value) { _roughnessFactor = value; }
198
199 Texture* metallicRoughnessTexture() const { return _metallicRoughnessTexture; }
200 void setMetallicRoughnessTexture(Texture* texture) { _metallicRoughnessTexture = texture; }
201 bool hasMetallicRoughnessTexture() const { return _hasMetallicRoughnessTexture; }
202 void setHasMetallicRoughnessTexture(const bool value) { _hasMetallicRoughnessTexture = value; }
203 int metallicRoughnessUvSet() const { return _metallicRoughnessUvSet; }
204 void setMetallicRoughnessUvSet(const int uvSet) { _metallicRoughnessUvSet = uvSet; }
205
206 Texture* occlusionTexture() const { return _occlusionTexture; }
207 void setOcclusionTexture(Texture* texture) { _occlusionTexture = texture; }
208 bool hasOcclusionTexture() const { return _hasOcclusionTexture; }
209 void setHasOcclusionTexture(const bool value) { _hasOcclusionTexture = value; }
210 int occlusionUvSet() const { return _occlusionUvSet; }
211 void setOcclusionUvSet(const int uvSet) { _occlusionUvSet = uvSet; }
212 float occlusionStrength() const { return _occlusionStrength; }
213 void setOcclusionStrength(const float value) { _occlusionStrength = value; }
214 bool occludeDirect() const { return _occludeDirect; }
215 void setOccludeDirect(const bool value) { _occludeDirect = value; }
216 uint32_t occludeSpecular() const { return _occludeSpecular; }
217 void setOccludeSpecular(const uint32_t value) { _occludeSpecular = value; }
218 float occludeSpecularIntensity() const { return _occludeSpecularIntensity; }
219 void setOccludeSpecularIntensity(const float value) { _occludeSpecularIntensity = value; }
220
221 const Color& emissiveFactor() const { return _emissiveFactor; }
222 void setEmissiveFactor(const Color& value) { _emissiveFactor = value; }
223 Texture* emissiveTexture() const { return _emissiveTexture; }
224 void setEmissiveTexture(Texture* texture) { _emissiveTexture = texture; }
225 bool hasEmissiveTexture() const { return _hasEmissiveTexture; }
226 void setHasEmissiveTexture(const bool value) { _hasEmissiveTexture = value; }
227 int emissiveUvSet() const { return _emissiveUvSet; }
228 void setEmissiveUvSet(const int uvSet) { _emissiveUvSet = uvSet; }
229
230 // per-texture UV transforms (tiling, offset, rotation).
231 const TextureTransform& baseColorTransform() const { return _baseColorTransform; }
232 void setBaseColorTransform(const TextureTransform& t) { _baseColorTransform = t; }
233 const TextureTransform& normalTransform() const { return _normalTransform; }
234 void setNormalTransform(const TextureTransform& t) { _normalTransform = t; }
235 const TextureTransform& metalRoughTransform() const { return _metalRoughTransform; }
236 void setMetalRoughTransform(const TextureTransform& t) { _metalRoughTransform = t; }
237 const TextureTransform& occlusionTransform() const { return _occlusionTransform; }
238 void setOcclusionTransform(const TextureTransform& t) { _occlusionTransform = t; }
239 const TextureTransform& emissiveTransform() const { return _emissiveTransform; }
240 void setEmissiveTransform(const TextureTransform& t) { _emissiveTransform = t; }
241
242 AlphaMode alphaMode() const { return _alphaMode; }
243 void setAlphaMode(const AlphaMode mode) { _alphaMode = mode; }
244
245 float alphaCutoff() const { return _alphaCutoff; }
246 void setAlphaCutoff(const float value) { _alphaCutoff = value; }
247
248 bool isSkybox() const { return _isSkybox; }
249 void setIsSkybox(const bool value) { _isSkybox = value; }
250
251 void setParameter(const std::string& name, const ParameterValue& value);
252 bool removeParameter(const std::string& name);
253 void clearParameters();
254 const std::unordered_map<std::string, ParameterValue>& parameters() const { return _parameters; }
255 const ParameterValue* parameter(const std::string& name) const;
256
261 virtual void updateUniforms(MaterialUniforms& uniforms) const;
262
276 virtual const void* customUniformData(size_t& outSize) const { return nullptr; }
277
284 virtual void getTextureSlots(std::vector<TextureSlot>& slots) const;
285
286 uint64_t sortKey() const;
287
288 private:
289 std::string _name;
290
291 bool _transparent = false;
292 uint64_t _shaderVariantKey = 0;
293
294 // Optional user-provided shader override.
295 std::shared_ptr<Shader> _shaderOverride;
296
297 // Material render states used by the renderer when binding draw calls.
298 std::shared_ptr<BlendState> _blendState;
299 std::shared_ptr<DepthState> _depthState;
301
302 // glTF PBR base color subset used by current forward pass.
303 Color _baseColorFactor = Color(1.0f, 1.0f, 1.0f, 1.0f);
304 Texture* _baseColorTexture = nullptr;
305 bool _hasBaseColorTexture = false;
306 int _baseColorUvSet = 0;
307 Texture* _normalTexture = nullptr;
308 bool _hasNormalTexture = false;
309 int _normalUvSet = 0;
310 float _normalScale = 1.0f;
311 float _metallicFactor = 0.0f;
312 float _roughnessFactor = 1.0f;
313 Texture* _metallicRoughnessTexture = nullptr;
314 bool _hasMetallicRoughnessTexture = false;
315 int _metallicRoughnessUvSet = 0;
316 Texture* _occlusionTexture = nullptr;
317 bool _hasOcclusionTexture = false;
318 int _occlusionUvSet = 0;
319 float _occlusionStrength = 1.0f;
320 bool _occludeDirect = false;
321 uint32_t _occludeSpecular = SPECOCC_AO;
322 float _occludeSpecularIntensity = 1.0f;
323 Color _emissiveFactor = Color(0.0f, 0.0f, 0.0f, 1.0f);
324 Texture* _emissiveTexture = nullptr;
325 bool _hasEmissiveTexture = false;
326 int _emissiveUvSet = 0;
327 AlphaMode _alphaMode = AlphaMode::OPAQUE;
328 float _alphaCutoff = 0.5f;
329 bool _isSkybox = false;
330
331 // per-texture UV transforms.
332 TextureTransform _baseColorTransform;
333 TextureTransform _normalTransform;
334 TextureTransform _metalRoughTransform;
335 TextureTransform _occlusionTransform;
336 TextureTransform _emissiveTransform;
337
338 std::unordered_map<std::string, ParameterValue> _parameters;
339 };
340
341 // Assigns the default material to device cache
342 void setDefaultMaterial(const std::shared_ptr<GraphicsDevice>& device, const std::shared_ptr<Material>& material);
343 std::shared_ptr<Material> getDefaultMaterial(const std::shared_ptr<GraphicsDevice>& device);
344}
void setShaderOverride(const std::shared_ptr< Shader > &shader)
Definition material.h:161
void setNormalScale(const float value)
Definition material.h:186
CullMode cullMode() const
Definition material.h:169
const TextureTransform & emissiveTransform() const
Definition material.h:239
void setIsSkybox(const bool value)
Definition material.h:249
void setOcclusionTransform(const TextureTransform &t)
Definition material.h:238
void setHasEmissiveTexture(const bool value)
Definition material.h:226
void setNormalUvSet(const int uvSet)
Definition material.h:191
void setMetallicRoughnessTexture(Texture *texture)
Definition material.h:200
float normalScale() const
Definition material.h:185
const std::shared_ptr< Shader > & shaderOverride() const
Definition material.h:160
void setBaseColorFactor(const Color &value)
Definition material.h:173
void setMetallicRoughnessUvSet(const int uvSet)
Definition material.h:204
virtual void getTextureSlots(std::vector< TextureSlot > &slots) const
Definition material.cpp:330
std::variant< float, int32_t, uint32_t, bool, Color, Vector2, Vector3, Vector4, Matrix4, Texture * > ParameterValue
Definition material.h:145
float metallicFactor() const
Definition material.h:193
float roughnessFactor() const
Definition material.h:196
uint64_t shaderVariantKey() const
Definition material.h:157
virtual ~Material()=default
void setRoughnessFactor(const float value)
Definition material.h:197
void setHasNormalTexture(const bool value)
Definition material.h:189
Texture * emissiveTexture() const
Definition material.h:223
void setBaseColorTexture(Texture *texture)
Definition material.h:176
void setDepthState(const std::shared_ptr< DepthState > &depthState)
Definition material.h:167
Texture * baseColorTexture() const
Definition material.h:175
void setOccludeDirect(const bool value)
Definition material.h:215
void setAlphaCutoff(const float value)
Definition material.h:246
int metallicRoughnessUvSet() const
Definition material.h:203
const std::shared_ptr< DepthState > & depthState() const
Definition material.h:166
const Color & baseColorFactor() const
Definition material.h:172
virtual void updateUniforms(MaterialUniforms &uniforms) const
Definition material.cpp:182
float alphaCutoff() const
Definition material.h:245
void setEmissiveTexture(Texture *texture)
Definition material.h:224
const std::shared_ptr< BlendState > & blendState() const
Definition material.h:163
Texture * normalTexture() const
Definition material.h:183
const std::unordered_map< std::string, ParameterValue > & parameters() const
Definition material.h:254
const TextureTransform & baseColorTransform() const
Definition material.h:231
void setEmissiveTransform(const TextureTransform &t)
Definition material.h:240
float occlusionStrength() const
Definition material.h:212
void setOcclusionTexture(Texture *texture)
Definition material.h:207
void setHasOcclusionTexture(const bool value)
Definition material.h:209
bool hasOcclusionTexture() const
Definition material.h:208
const Color & emissiveFactor() const
Definition material.h:221
void setOccludeSpecular(const uint32_t value)
Definition material.h:217
void setHasBaseColorTexture(const bool value)
Definition material.h:179
void setBaseColorTransform(const TextureTransform &t)
Definition material.h:232
void setCullMode(const CullMode mode)
Definition material.h:170
void setMetallicFactor(const float value)
Definition material.h:194
void setEmissiveUvSet(const int uvSet)
Definition material.h:228
void setBlendState(const std::shared_ptr< BlendState > &blendState)
Definition material.h:164
void setName(const std::string &name)
Definition material.h:152
virtual const void * customUniformData(size_t &outSize) const
Definition material.h:276
bool hasNormalTexture() const
Definition material.h:188
uint64_t sortKey() const
Definition material.cpp:356
void setOccludeSpecularIntensity(const float value)
Definition material.h:219
const TextureTransform & occlusionTransform() const
Definition material.h:237
Texture * occlusionTexture() const
Definition material.h:206
const TextureTransform & metalRoughTransform() const
Definition material.h:235
const TextureTransform & normalTransform() const
Definition material.h:233
void setTransparent(const bool value)
Definition material.h:155
bool hasMetallicRoughnessTexture() const
Definition material.h:201
void setNormalTransform(const TextureTransform &t)
Definition material.h:234
void setNormalTexture(Texture *texture)
Definition material.h:184
void setOcclusionUvSet(const int uvSet)
Definition material.h:211
void setBaseColorUvSet(const int uvSet)
Definition material.h:181
float occludeSpecularIntensity() const
Definition material.h:218
bool removeParameter(const std::string &name)
Definition material.cpp:163
void setAlphaMode(const AlphaMode mode)
Definition material.h:243
const std::string & name() const
Definition material.h:151
uint32_t occludeSpecular() const
Definition material.h:216
void setParameter(const std::string &name, const ParameterValue &value)
Definition material.cpp:155
void setHasMetallicRoughnessTexture(const bool value)
Definition material.h:202
bool occludeDirect() const
Definition material.h:214
void setOcclusionStrength(const float value)
Definition material.h:213
bool hasBaseColorTexture() const
Definition material.h:178
AlphaMode alphaMode() const
Definition material.h:242
void setEmissiveFactor(const Color &value)
Definition material.h:222
void setMetalRoughTransform(const TextureTransform &t)
Definition material.h:236
const ParameterValue * parameter(const std::string &name) const
Definition material.cpp:176
void setShaderVariantKey(const uint64_t value)
Definition material.h:158
bool hasEmissiveTexture() const
Definition material.h:225
Texture * metallicRoughnessTexture() const
Definition material.h:199
GPU texture resource supporting 2D, cubemap, volume, and array formats with mipmap management.
Definition texture.h:57
std::shared_ptr< Material > getDefaultMaterial(const std::shared_ptr< GraphicsDevice > &device)
Definition material.cpp:382
constexpr uint32_t SPECOCC_AO
Definition constants.h:37
void setDefaultMaterial(const std::shared_ptr< GraphicsDevice > &device, const std::shared_ptr< Material > &material)
Definition material.cpp:372
RGBA color with floating-point components in [0, 1].
Definition color.h:18
2D vector for UV coordinates, screen positions, and 2D math.
Definition vector2.h:18