Skip to content

Commit 50062e5

Browse files
authored
Add fileTextureVerticalFlip option for MDL generation (#1418)
When investigating the differences in the MaterialXTest I implemented the fileTextureVerticalFlip in the MDL shader gen. In theory this option is not needed because the MaterialX and MDL define the image coordinate both in the lower left. But it might be useful to align with existing but non standard conform renderers. It could for instance be used in the MaterialXTest to align with the flipped GLSL and OSL results.
1 parent 6a5a1ad commit 50062e5

6 files changed

Lines changed: 164 additions & 13 deletions

File tree

libraries/stdlib/genmdl/stdlib_genmdl_impl.mtlx

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,22 +22,22 @@
2222
<!-- ======================================================================== -->
2323

2424
<!-- <image> -->
25-
<implementation name="IM_image_float_genmdl" nodedef="ND_image_float" sourcecode="mx::stdlib::mx_image_float({{file}}, {{layer}}, {{default}}, {{texcoord}}, {{uaddressmode}}, {{vaddressmode}}, {{filtertype}}, {{framerange}}, {{frameoffset}}, {{frameendaction}})" target="genmdl">
25+
<implementation name="IM_image_float_genmdl" nodedef="ND_image_float" sourcecode="mx::stdlib::mx_image_float({{file}}, {{layer}}, {{default}}, {{texcoord}}, {{uaddressmode}}, {{vaddressmode}}, {{filtertype}}, {{framerange}}, {{frameoffset}}, {{frameendaction}}, mxp_flip_v:{{flip_v}})" target="genmdl">
2626
<input name="default" type="float" implname="default_value" />
2727
</implementation>
28-
<implementation name="IM_image_color3_genmdl" nodedef="ND_image_color3" sourcecode="mx::stdlib::mx_image_color3({{file}}, {{layer}}, {{default}}, {{texcoord}}, {{uaddressmode}}, {{vaddressmode}}, {{filtertype}}, {{framerange}}, {{frameoffset}}, {{frameendaction}})" target="genmdl">
28+
<implementation name="IM_image_color3_genmdl" nodedef="ND_image_color3" sourcecode="mx::stdlib::mx_image_color3({{file}}, {{layer}}, {{default}}, {{texcoord}}, {{uaddressmode}}, {{vaddressmode}}, {{filtertype}}, {{framerange}}, {{frameoffset}}, {{frameendaction}}, mxp_flip_v:{{flip_v}})" target="genmdl">
2929
<input name="default" type="color3" implname="default_value" />
3030
</implementation>
31-
<implementation name="IM_image_color4_genmdl" nodedef="ND_image_color4" sourcecode="mx::stdlib::mx_image_color4({{file}}, {{layer}}, {{default}}, {{texcoord}}, {{uaddressmode}}, {{vaddressmode}}, {{filtertype}}, {{framerange}}, {{frameoffset}}, {{frameendaction}})" target="genmdl">
31+
<implementation name="IM_image_color4_genmdl" nodedef="ND_image_color4" sourcecode="mx::stdlib::mx_image_color4({{file}}, {{layer}}, {{default}}, {{texcoord}}, {{uaddressmode}}, {{vaddressmode}}, {{filtertype}}, {{framerange}}, {{frameoffset}}, {{frameendaction}}, mxp_flip_v:{{flip_v}})" target="genmdl">
3232
<input name="default" type="color4" implname="default_value" />
3333
</implementation>
34-
<implementation name="IM_image_vector2_genmdl" nodedef="ND_image_vector2" sourcecode="mx::stdlib::mx_image_vector2({{file}}, {{layer}}, {{default}}, {{texcoord}}, {{uaddressmode}}, {{vaddressmode}}, {{filtertype}}, {{framerange}}, {{frameoffset}}, {{frameendaction}})" target="genmdl">
34+
<implementation name="IM_image_vector2_genmdl" nodedef="ND_image_vector2" sourcecode="mx::stdlib::mx_image_vector2({{file}}, {{layer}}, {{default}}, {{texcoord}}, {{uaddressmode}}, {{vaddressmode}}, {{filtertype}}, {{framerange}}, {{frameoffset}}, {{frameendaction}}, mxp_flip_v:{{flip_v}})" target="genmdl">
3535
<input name="default" type="vector2" implname="default_value" />
3636
</implementation>
37-
<implementation name="IM_image_vector3_genmdl" nodedef="ND_image_vector3" sourcecode="mx::stdlib::mx_image_vector3({{file}}, {{layer}}, {{default}}, {{texcoord}}, {{uaddressmode}}, {{vaddressmode}}, {{filtertype}}, {{framerange}}, {{frameoffset}}, {{frameendaction}})" target="genmdl">
37+
<implementation name="IM_image_vector3_genmdl" nodedef="ND_image_vector3" sourcecode="mx::stdlib::mx_image_vector3({{file}}, {{layer}}, {{default}}, {{texcoord}}, {{uaddressmode}}, {{vaddressmode}}, {{filtertype}}, {{framerange}}, {{frameoffset}}, {{frameendaction}}, mxp_flip_v:{{flip_v}})" target="genmdl">
3838
<input name="default" type="vector3" implname="default_value" />
3939
</implementation>
40-
<implementation name="IM_image_vector4_genmdl" nodedef="ND_image_vector4" sourcecode="mx::stdlib::mx_image_vector4({{file}}, {{layer}}, {{default}}, {{texcoord}}, {{uaddressmode}}, {{vaddressmode}}, {{filtertype}}, {{framerange}}, {{frameoffset}}, {{frameendaction}})" target="genmdl">
40+
<implementation name="IM_image_vector4_genmdl" nodedef="ND_image_vector4" sourcecode="mx::stdlib::mx_image_vector4({{file}}, {{layer}}, {{default}}, {{texcoord}}, {{uaddressmode}}, {{vaddressmode}}, {{filtertype}}, {{framerange}}, {{frameoffset}}, {{frameendaction}}, mxp_flip_v:{{flip_v}})" target="genmdl">
4141
<input name="default" type="vector4" implname="default_value" />
4242
</implementation>
4343

source/MaterialXGenMdl/MdlShaderGenerator.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include <MaterialXGenMdl/Nodes/ClosureCompoundNodeMdl.h>
1818
#include <MaterialXGenMdl/Nodes/ClosureSourceCodeNodeMdl.h>
1919
#include <MaterialXGenMdl/Nodes/SwizzleNodeMdl.h>
20+
#include <MaterialXGenMdl/Nodes/ImageNodeMdl.h>
2021

2122
#include <MaterialXGenShader/GenContext.h>
2223
#include <MaterialXGenShader/Shader.h>
@@ -187,6 +188,14 @@ MdlShaderGenerator::MdlShaderGenerator() :
187188

188189
// <!-- <sheen_bsdf> -->
189190
registerImplementation("IM_sheen_bsdf_" + MdlShaderGenerator::TARGET, LayerableNodeMdl::create);
191+
192+
// <!-- <image> -->
193+
registerImplementation("IM_image_float_" + MdlShaderGenerator::TARGET, ImageNodeMdl::create);
194+
registerImplementation("IM_image_color3_" + MdlShaderGenerator::TARGET, ImageNodeMdl::create);
195+
registerImplementation("IM_image_color4_" + MdlShaderGenerator::TARGET, ImageNodeMdl::create);
196+
registerImplementation("IM_image_vector2_" + MdlShaderGenerator::TARGET, ImageNodeMdl::create);
197+
registerImplementation("IM_image_vector3_" + MdlShaderGenerator::TARGET, ImageNodeMdl::create);
198+
registerImplementation("IM_image_vector4_" + MdlShaderGenerator::TARGET, ImageNodeMdl::create);
190199
}
191200

192201
ShaderPtr MdlShaderGenerator::generate(const string& name, ElementPtr element, GenContext& context) const
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
//
2+
// Copyright Contributors to the MaterialX Project
3+
// SPDX-License-Identifier: Apache-2.0
4+
//
5+
6+
#include <MaterialXGenMdl/Nodes/ImageNodeMdl.h>
7+
#include <MaterialXGenShader/ShaderGenerator.h>
8+
#include <MaterialXGenShader/Shader.h>
9+
#include <MaterialXGenShader/GenContext.h>
10+
11+
MATERIALX_NAMESPACE_BEGIN
12+
13+
const string ImageNodeMdl::FLIP_V = "flip_v";
14+
15+
ShaderNodeImplPtr ImageNodeMdl::create()
16+
{
17+
return std::make_shared<ImageNodeMdl>();
18+
}
19+
20+
void ImageNodeMdl::addInputs(ShaderNode& node, GenContext& context) const
21+
{
22+
BASE::addInputs(node, context);
23+
node.addInput(ImageNodeMdl::FLIP_V, Type::BOOLEAN)->setUniform();
24+
}
25+
26+
bool ImageNodeMdl::isEditable(const ShaderInput& input) const
27+
{
28+
if (input.getName() == ImageNodeMdl::FLIP_V)
29+
{
30+
return false;
31+
}
32+
return BASE::isEditable(input);
33+
}
34+
35+
void ImageNodeMdl::emitFunctionCall(const ShaderNode& _node, GenContext& context, ShaderStage& stage) const
36+
{
37+
DEFINE_SHADER_STAGE(stage, Stage::PIXEL)
38+
{
39+
ShaderNode& node = const_cast<ShaderNode&>(_node);
40+
ShaderInput* flipUInput = node.getInput(ImageNodeMdl::FLIP_V);
41+
ValuePtr value = TypedValue<bool>::createValue(context.getOptions().fileTextureVerticalFlip);
42+
if (flipUInput)
43+
{
44+
flipUInput->setValue(value);
45+
}
46+
BASE::emitFunctionCall(_node, context, stage);
47+
}
48+
}
49+
50+
MATERIALX_NAMESPACE_END
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
//
2+
// Copyright Contributors to the MaterialX Project
3+
// SPDX-License-Identifier: Apache-2.0
4+
//
5+
6+
#ifndef MATERIALX_IMAGENODEMDL_H
7+
#define MATERIALX_IMAGENODEMDL_H
8+
9+
#include <MaterialXGenMdl/Export.h>
10+
11+
#include "SourceCodeNodeMdl.h"
12+
13+
MATERIALX_NAMESPACE_BEGIN
14+
15+
/// Image node implementation for MDL
16+
class MX_GENMDL_API ImageNodeMdl : public SourceCodeNodeMdl
17+
{
18+
using BASE = SourceCodeNodeMdl;
19+
20+
public:
21+
static const string FLIP_V; ///< the empty string ""
22+
23+
static ShaderNodeImplPtr create();
24+
25+
void addInputs(ShaderNode& node, GenContext& context) const override;
26+
27+
bool isEditable(const ShaderInput& input) const override;
28+
29+
void emitFunctionCall(const ShaderNode& node, GenContext& context, ShaderStage& stage) const override;
30+
};
31+
32+
MATERIALX_NAMESPACE_END
33+
34+
#endif

source/MaterialXGenMdl/mdl/materialx/stdlib.mdl

Lines changed: 48 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,11 @@ export float mx_image_float(
139139
anno::description("Enumeration {constant,clamp,periodic,mirror}."),
140140
anno::display_name("Frame End Action"),
141141
anno::unused()
142+
]],
143+
uniform bool mxp_flip_v = false
144+
[[
145+
anno::usage("for applying the 'fileTextureVerticalFlip' shader generator option."),
146+
anno::hidden()
142147
]]
143148
)
144149
[[
@@ -153,7 +158,9 @@ export float mx_image_float(
153158
return mxp_default;
154159

155160
float returnValue = ::tex::lookup_float(tex: mxp_file,
156-
coord: mxp_texcoord,
161+
coord: mxp_flip_v
162+
? float2(mxp_texcoord.x, 1.0f - mxp_texcoord.y)
163+
: mxp_texcoord,
157164
wrap_u: map_addressmode(mxp_uaddressmode),
158165
wrap_v: map_addressmode(mxp_vaddressmode));
159166
return returnValue;
@@ -207,6 +214,11 @@ export color mx_image_color3(
207214
anno::description("Enumeration {constant,clamp,periodic,mirror}."),
208215
anno::display_name("Frame End Action"),
209216
anno::unused()
217+
]],
218+
uniform bool mxp_flip_v = false
219+
[[
220+
anno::usage("for applying the 'fileTextureVerticalFlip' shader generator option."),
221+
anno::hidden()
210222
]]
211223
)
212224
[[
@@ -221,7 +233,9 @@ export color mx_image_color3(
221233
return mxp_default;
222234

223235
color returnValue = ::tex::lookup_color(tex: mxp_file,
224-
coord: mxp_texcoord,
236+
coord: mxp_flip_v
237+
? float2(mxp_texcoord.x, 1.0f - mxp_texcoord.y)
238+
: mxp_texcoord,
225239
wrap_u: map_addressmode(mxp_uaddressmode),
226240
wrap_v: map_addressmode(mxp_vaddressmode));
227241
return returnValue;
@@ -275,6 +289,11 @@ export color4 mx_image_color4(
275289
anno::description("Enumeration {constant,clamp,periodic,mirror}."),
276290
anno::display_name("Frame End Action"),
277291
anno::unused()
292+
]],
293+
uniform bool mxp_flip_v = false
294+
[[
295+
anno::usage("for applying the 'fileTextureVerticalFlip' shader generator option."),
296+
anno::hidden()
278297
]]
279298
)
280299
[[
@@ -289,7 +308,9 @@ export color4 mx_image_color4(
289308
return mxp_default;
290309

291310
color4 returnValue = mk_color4( ::tex::lookup_float4(tex: mxp_file,
292-
coord: mxp_texcoord,
311+
coord: mxp_flip_v
312+
? float2(mxp_texcoord.x, 1.0f - mxp_texcoord.y)
313+
: mxp_texcoord,
293314
wrap_u: map_addressmode(mxp_uaddressmode),
294315
wrap_v: map_addressmode(mxp_vaddressmode)));
295316
return returnValue;
@@ -343,6 +364,11 @@ export float2 mx_image_vector2(
343364
anno::description("Enumeration {constant,clamp,periodic,mirror}."),
344365
anno::display_name("Frame End Action"),
345366
anno::unused()
367+
]],
368+
uniform bool mxp_flip_v = false
369+
[[
370+
anno::usage("for applying the 'fileTextureVerticalFlip' shader generator option."),
371+
anno::hidden()
346372
]]
347373
)
348374
[[
@@ -357,7 +383,9 @@ export float2 mx_image_vector2(
357383
return mxp_default;
358384

359385
float2 returnValue = ::tex::lookup_float2(tex: mxp_file,
360-
coord: mxp_texcoord,
386+
coord: mxp_flip_v
387+
? float2(mxp_texcoord.x, 1.0f - mxp_texcoord.y)
388+
: mxp_texcoord,
361389
wrap_u: map_addressmode(mxp_uaddressmode),
362390
wrap_v: map_addressmode(mxp_vaddressmode));
363391
return returnValue;
@@ -411,6 +439,11 @@ export float3 mx_image_vector3(
411439
anno::description("Enumeration {constant,clamp,periodic,mirror}."),
412440
anno::display_name("Frame End Action"),
413441
anno::unused()
442+
]],
443+
uniform bool mxp_flip_v = false
444+
[[
445+
anno::usage("for applying the 'fileTextureVerticalFlip' shader generator option."),
446+
anno::hidden()
414447
]]
415448
)
416449
[[
@@ -425,7 +458,9 @@ export float3 mx_image_vector3(
425458
return mxp_default;
426459

427460
float3 returnValue = ::tex::lookup_float3(tex: mxp_file,
428-
coord: mxp_texcoord,
461+
coord: mxp_flip_v
462+
? float2(mxp_texcoord.x, 1.0f - mxp_texcoord.y)
463+
: mxp_texcoord,
429464
wrap_u: map_addressmode(mxp_uaddressmode),
430465
wrap_v: map_addressmode(mxp_vaddressmode));
431466
return returnValue;
@@ -479,6 +514,11 @@ export float4 mx_image_vector4(
479514
anno::description("Enumeration {constant,clamp,periodic,mirror}."),
480515
anno::display_name("Frame End Action"),
481516
anno::unused()
517+
]],
518+
uniform bool mxp_flip_v = false
519+
[[
520+
anno::usage("for applying the 'fileTextureVerticalFlip' shader generator option."),
521+
anno::hidden()
482522
]]
483523
)
484524
[[
@@ -493,7 +533,9 @@ export float4 mx_image_vector4(
493533
return mxp_default;
494534

495535
float4 returnValue = ::tex::lookup_float4(tex: mxp_file,
496-
coord: mxp_texcoord,
536+
coord: mxp_flip_v
537+
? float2(mxp_texcoord.x, 1.0f - mxp_texcoord.y)
538+
: mxp_texcoord,
497539
wrap_u: map_addressmode(mxp_uaddressmode),
498540
wrap_v: map_addressmode(mxp_vaddressmode));
499541
return returnValue;

source/MaterialXTest/MaterialXGenMdl/GenMdl.cpp

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -288,7 +288,10 @@ void MdlShaderGeneratorTester::compileSource(const std::vector<mx::FilePath>& so
288288
std::string iblFile = (rootPath / "resources/lights/san_giuseppe_bridge.hdr").asString();
289289
renderCommand += " --hdr \"" + iblFile + "\" --hdr_rotate 90";
290290
// set scene
291-
renderCommand += " --uv_scale 0.5 1.0 --uv_offset 0.0 0.0 --uv_repeat --uv_flip";
291+
renderCommand += " --uv_scale 0.5 1.0 --uv_offset 0.0 0.0 --uv_repeat";
292+
renderCommand += " --uv_flip"; // this will flip the v coordinate of the vertices, which flips all the
293+
// UV operations. In contrast, the fileTextureVerticalFlip option will
294+
// only flip the image access nodes.
292295
renderCommand += " --camera 0 0 3 0 0 0 --fov 45";
293296

294297
// set the material
@@ -365,6 +368,19 @@ TEST_CASE("GenShader: MDL Shader Generation", "[genmdl]")
365368

366369
mx::GenOptions genOptions;
367370
genOptions.targetColorSpaceOverride = "lin_rec709";
371+
372+
// Flipping the texture lookups for the test renderer only.
373+
// This is because OSL testrender does not allow to change the UV layout of their sphere (yet) and the MaterialX test suite
374+
// adopts the OSL behavior in order to produce comparable results. This means that raw texture coordinates, or procedurals
375+
// that use the texture coordinates, do not match what might be expected when reading the MaterialX spec:
376+
// "[...] the image is mapped onto the geometry based on geometry UV coordinates, with the lower-left corner of an image
377+
// mapping to the (0,0) UV coordinate [...]"
378+
// This means for MDL: here, and only here in the test suite, we flip the UV coordinates of mesh using the `--uv_flip` option
379+
// of the renderer, and to correct the image orientation, we apply `fileTextureVerticalFlip`.
380+
// In regular MDL integrations this is not needed because MDL and MaterialX define the texture space equally with the origin
381+
// at the bottom left.
382+
genOptions.fileTextureVerticalFlip = true;
383+
368384
mx::FilePath optionsFilePath = searchPath.find("resources/Materials/TestSuite/_options.mtlx");
369385
tester.validate(genOptions, optionsFilePath);
370386
}

0 commit comments

Comments
 (0)