diff options
author | Jere Tuliniemi <jere.tuliniemi@qt.io> | 2018-10-22 14:18:24 +0300 |
---|---|---|
committer | Jere Tuliniemi <jere.tuliniemi@qt.io> | 2019-01-15 12:14:07 +0000 |
commit | 0cf63f1de93635c85fc3120cdfce3410a59edc9b (patch) | |
tree | 30ea4185da967d19e2c33298698fb6deadfec1d4 | |
parent | 7c203cb04362c246c709285d583052ec1358e7de (diff) |
Enable vertex shaders in custom materials
If <VertexShader> tags in custom material contain a main function, use
the shaders provided as is. The shader generator adds } to the end of
the fully custom fragment shaders so I left that also to the vertex
shader generation.
Custom attributes can be provided with a user-generated .mesh file. The
test scene has a sphere with the normal attr_pos and a sphere with an
attr_pos2 instead. "simple-pos.material" expects an attr_pos vertex
attribute and "simple-pos2.material" an attr_pos2.
Task-number: QT3DS-2026
Change-Id: I2c0cd1c079f9c741900f119aefd2e3515d42f36d
Reviewed-by: Miikka Heikkinen <miikka.heikkinen@qt.io>
Reviewed-by: Antti Määttä <antti.maatta@qt.io>
Reviewed-by: Tomi Korpipää <tomi.korpipaa@qt.io>
-rw-r--r-- | src/runtime/q3dsmaterial.cpp | 2 | ||||
-rw-r--r-- | src/runtime/q3dsmaterial_p.h | 1 | ||||
-rw-r--r-- | src/runtime/shadergenerator/q3dscustommaterialvertexpipeline.cpp | 152 | ||||
-rw-r--r-- | tests/scenes/customvertex/customvertex.uia | 15 | ||||
-rw-r--r-- | tests/scenes/customvertex/materials/simple-pos.material | 25 | ||||
-rw-r--r-- | tests/scenes/customvertex/materials/simple-pos2.material | 25 | ||||
-rw-r--r-- | tests/scenes/customvertex/models/Sphere-pos.mesh | bin | 0 -> 4356 bytes | |||
-rw-r--r-- | tests/scenes/customvertex/models/Sphere-pos2.mesh | bin | 0 -> 8372 bytes | |||
-rw-r--r-- | tests/scenes/customvertex/presentations/customvertex.uip | 39 |
9 files changed, 210 insertions, 49 deletions
diff --git a/src/runtime/q3dsmaterial.cpp b/src/runtime/q3dsmaterial.cpp index 6255248..468d448 100644 --- a/src/runtime/q3dsmaterial.cpp +++ b/src/runtime/q3dsmaterial.cpp @@ -311,6 +311,8 @@ PropertyElement parsePropertyElement(QXmlStreamReader *r) Q3DSMaterial::ClampType type; if (Q3DSMaterial::convertToClampType(attribute.value(), &type, "clamp type", r)) property.clampType = type; + } else if (attribute.name() == QStringLiteral("stage")) { + property.stage = attribute.value().toString(); } else if (attribute.name() == QStringLiteral("format")) { property.format = attribute.value().toString(); } else if (attribute.name() == QStringLiteral("binding")) { diff --git a/src/runtime/q3dsmaterial_p.h b/src/runtime/q3dsmaterial_p.h index 13b2a7e..45fd7b2 100644 --- a/src/runtime/q3dsmaterial_p.h +++ b/src/runtime/q3dsmaterial_p.h @@ -154,6 +154,7 @@ struct Q3DSV_PRIVATE_EXPORT PropertyElement FilterType magFilterType; FilterType minFilterType; ClampType clampType; + QString stage; // Buffers QString format; diff --git a/src/runtime/shadergenerator/q3dscustommaterialvertexpipeline.cpp b/src/runtime/shadergenerator/q3dscustommaterialvertexpipeline.cpp index e95aa33..0cc993c 100644 --- a/src/runtime/shadergenerator/q3dscustommaterialvertexpipeline.cpp +++ b/src/runtime/shadergenerator/q3dscustommaterialvertexpipeline.cpp @@ -203,54 +203,104 @@ struct ShaderGenerator : public Q3DSCustomMaterialShaderGenerator } } - void generateVertexShader(const QString &shaderName) + bool generateVertexShader(const QString &shaderName) { - Q_UNUSED(shaderName); - // XXX TODO include vertex data (I dont think 3DS even supports this) + QString vertSource; + for (const auto &shader : m_currentMaterial->shaders()) { + if (shader.name == shaderName) + vertSource = shader.shared + shader.vertexShader; + } + if (vertSource.isEmpty() + && shaderName.isEmpty() + && m_currentMaterial->shaders().count() == 1) { + // fallback to first shader + auto shader = m_currentMaterial->shaders().first(); + vertSource = shader.vertexShader; + } - // the pipeline opens/closes up the shaders stages - // XXX add displacement map - vertexGenerator().beginVertexGeneration(nullptr); + if (vertSource.isEmpty() || !vertSource.contains(QStringLiteral("void main()"))) { + vertexGenerator().beginVertexGeneration(nullptr); + return false; + } + Q3DSShaderGeneratorStageFlags theStages(Q3DSAbstractShaderProgramGenerator::defaultFlags()); + programGenerator()->beginProgram(theStages); + vertexGenerator() << "#define VERTEX_SHADER"; + vertexGenerator() << vertSource.toUtf8().constData(); + return true; } - void addProperties(Q3DSAbstractShaderStageGenerator &fragmentShader) + void addProperties(Q3DSDefaultVertexPipeline &vertexShader, + Q3DSAbstractShaderStageGenerator &fragmentShader) { // Add Uniforms from material properties for (auto property : m_currentMaterial->properties()) { - switch (property.type) { - case Q3DS::Boolean: - fragmentShader.addUniform(property.name.toLocal8Bit(), "bool"); - break; - case Q3DS::Long: - fragmentShader.addUniform(property.name.toLocal8Bit(), "int"); - break; - case Q3DS::FloatRange: - case Q3DS::Float: - case Q3DS::FontSize: - fragmentShader.addUniform(property.name.toLocal8Bit(), "float"); - break; - case Q3DS::Float2: - fragmentShader.addUniform(property.name.toLocal8Bit(), "vec2"); - break; - case Q3DS::Vector: - case Q3DS::Scale: - case Q3DS::Rotation: - case Q3DS::Color: - fragmentShader.addUniform(property.name.toLocal8Bit(), "vec3"); - break; - case Q3DS::Texture: - fragmentShader.addUniform(property.name.toLocal8Bit(), "sampler2D"); - break; - case Q3DS::StringList: - fragmentShader.addUniform(property.name.toLocal8Bit(), "int"); - break; - default: - break; + if (property.stage == QStringLiteral("vertex")) { + switch (property.type) { + case Q3DS::Boolean: + vertexShader.addUniform(property.name.toLocal8Bit(), "bool"); + break; + case Q3DS::Long: + vertexShader.addUniform(property.name.toLocal8Bit(), "int"); + break; + case Q3DS::FloatRange: + case Q3DS::Float: + case Q3DS::FontSize: + vertexShader.addUniform(property.name.toLocal8Bit(), "float"); + break; + case Q3DS::Float2: + vertexShader.addUniform(property.name.toLocal8Bit(), "vec2"); + break; + case Q3DS::Vector: + case Q3DS::Scale: + case Q3DS::Rotation: + case Q3DS::Color: + vertexShader.addUniform(property.name.toLocal8Bit(), "vec3"); + break; + case Q3DS::Texture: + vertexShader.addUniform(property.name.toLocal8Bit(), "sampler2D"); + break; + case Q3DS::StringList: + vertexShader.addUniform(property.name.toLocal8Bit(), "int"); + break; + default: + break; + } + } else { + switch (property.type) { + case Q3DS::Boolean: + fragmentShader.addUniform(property.name.toLocal8Bit(), "bool"); + break; + case Q3DS::Long: + fragmentShader.addUniform(property.name.toLocal8Bit(), "int"); + break; + case Q3DS::FloatRange: + case Q3DS::Float: + case Q3DS::FontSize: + fragmentShader.addUniform(property.name.toLocal8Bit(), "float"); + break; + case Q3DS::Float2: + fragmentShader.addUniform(property.name.toLocal8Bit(), "vec2"); + break; + case Q3DS::Vector: + case Q3DS::Scale: + case Q3DS::Rotation: + case Q3DS::Color: + fragmentShader.addUniform(property.name.toLocal8Bit(), "vec3"); + break; + case Q3DS::Texture: + fragmentShader.addUniform(property.name.toLocal8Bit(), "sampler2D"); + break; + case Q3DS::StringList: + fragmentShader.addUniform(property.name.toLocal8Bit(), "int"); + break; + default: + break; + } } } } - void generateFragmentShader(const QString &shaderName) + void generateFragmentShader(const QString &shaderName, bool hasCustomVertexShader) { // Get the shader source from the Q3DSCustomMaterial based // on the name provided. If there is only 1 shader then @@ -291,9 +341,11 @@ struct ShaderGenerator : public Q3DSCustomMaterialShaderGenerator lightmapShadowImage = m_materialInstance->lightmapShadowMap(); hasLightmaps = lightmapIndirectImage || lightmapRadiosityImage || lightmapShadowImage; - vertexGenerator().generateUVCoords(0); - if (hasLightmaps) - vertexGenerator().generateUVCoords(1); + if (!hasCustomVertexShader) { + vertexGenerator().generateUVCoords(0); + if (hasLightmaps) + vertexGenerator().generateUVCoords(1); + } Q3DSDefaultVertexPipeline &vertexShader(vertexGenerator()); Q3DSAbstractShaderStageGenerator &fragmentShader(fragmentGenerator()); @@ -321,13 +373,15 @@ struct ShaderGenerator : public Q3DSCustomMaterialShaderGenerator // and we don't need to add anything. if (srcString.contains(QStringLiteral("void main()"))) { - // Nothing beyond the basics, anyway - vertexShader.generateWorldNormal(); - vertexShader.generateVarTangentAndBinormal(); - vertexShader.generateWorldPosition(); + if (!hasCustomVertexShader) { + // Nothing beyond the basics, anyway + vertexShader.generateWorldNormal(); + vertexShader.generateVarTangentAndBinormal(); + vertexShader.generateWorldPosition(); - vertexShader.generateViewVector(); - addProperties(fragmentShader); + vertexShader.generateViewVector(); + } + addProperties(vertexShader, fragmentShader); return; } @@ -369,7 +423,7 @@ struct ShaderGenerator : public Q3DSCustomMaterialShaderGenerator fragmentShader << "}\n\n"; } - addProperties(fragmentShader); + addProperties(vertexShader, fragmentShader); // setup main vertexGenerator().beginFragmentGeneration(); @@ -429,8 +483,8 @@ struct ShaderGenerator : public Q3DSCustomMaterialShaderGenerator Qt3DRender::QShaderProgram *generateCustomMaterialShader(const QString &shaderName) { - generateVertexShader(shaderName); - generateFragmentShader(shaderName); + bool hasCustomVertexShader = generateVertexShader(shaderName); + generateFragmentShader(shaderName, hasCustomVertexShader); vertexGenerator().endVertexGeneration(); vertexGenerator().endFragmentGeneration(); diff --git a/tests/scenes/customvertex/customvertex.uia b/tests/scenes/customvertex/customvertex.uia new file mode 100644 index 0000000..06c0c6a --- /dev/null +++ b/tests/scenes/customvertex/customvertex.uia @@ -0,0 +1,15 @@ +<?xml version='1.0' encoding='utf-8'?> +<application xmlns="http://qt.io/qt3dstudio/uia"> + <assets initial="customvertex"> + <presentation src="presentations/customvertex.uip" id="customvertex"/> + </assets> + <statemachine ref="#logic"> + <visual-states> + <state ref="Initial"> + <enter> + <goto-slide element="main:Scene" rel="next"/> + </enter> + </state> + </visual-states> + </statemachine> +</application> diff --git a/tests/scenes/customvertex/materials/simple-pos.material b/tests/scenes/customvertex/materials/simple-pos.material new file mode 100644 index 0000000..6a76694 --- /dev/null +++ b/tests/scenes/customvertex/materials/simple-pos.material @@ -0,0 +1,25 @@ +<Material name="simple" version="1.0"> + <MetaData> + <Property formalName="Test Vertex" name="test_vertex" type="Float" default="1.000000" stage="vertex" category="Material" /> + <Property formalName="Test Fragment" name="test_fragment" type="Float" default="1.000000" stage="fragment" category="Material" /> + </MetaData> + <Shaders type="GLSL" version="330"> + <Shader> + <VertexShader> + attribute vec3 attr_pos; + uniform mat4 modelViewProjection; + + void main() { + gl_Position = modelViewProjection * vec4(attr_pos, test_vertex); + </VertexShader> + <FragmentShader> + void main() { + fragOutput = vec4(1.0, test_fragment, 0.0, 1.0); + </FragmentShader> + </Shader> + </Shaders> +<Passes> + <Pass> + </Pass> +</Passes> +</Material> diff --git a/tests/scenes/customvertex/materials/simple-pos2.material b/tests/scenes/customvertex/materials/simple-pos2.material new file mode 100644 index 0000000..8d14185 --- /dev/null +++ b/tests/scenes/customvertex/materials/simple-pos2.material @@ -0,0 +1,25 @@ +<Material name="simple" version="1.0"> + <MetaData> + <Property formalName="Test Vertex" name="test_vertex" type="Float" default="1.000000" stage="vertex" category="Material" /> + <Property formalName="Test Fragment" name="test_fragment" type="Float" default="1.000000" stage="fragment" category="Material" /> + </MetaData> + <Shaders type="GLSL" version="330"> + <Shader> + <VertexShader> + attribute vec3 attr_pos2; + uniform mat4 modelViewProjection; + + void main() { + gl_Position = modelViewProjection * vec4(attr_pos2, test_vertex); + </VertexShader> + <FragmentShader> + void main() { + fragOutput = vec4(1.0, test_fragment, 0.0, 1.0); + </FragmentShader> + </Shader> + </Shaders> +<Passes> + <Pass> + </Pass> +</Passes> +</Material> diff --git a/tests/scenes/customvertex/models/Sphere-pos.mesh b/tests/scenes/customvertex/models/Sphere-pos.mesh Binary files differnew file mode 100644 index 0000000..5eace9d --- /dev/null +++ b/tests/scenes/customvertex/models/Sphere-pos.mesh diff --git a/tests/scenes/customvertex/models/Sphere-pos2.mesh b/tests/scenes/customvertex/models/Sphere-pos2.mesh Binary files differnew file mode 100644 index 0000000..c54f34f --- /dev/null +++ b/tests/scenes/customvertex/models/Sphere-pos2.mesh diff --git a/tests/scenes/customvertex/presentations/customvertex.uip b/tests/scenes/customvertex/presentations/customvertex.uip new file mode 100644 index 0000000..076b1c6 --- /dev/null +++ b/tests/scenes/customvertex/presentations/customvertex.uip @@ -0,0 +1,39 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<UIP version="5" > + <Project > + <ProjectSettings author="" company="" presentationWidth="1280" presentationHeight="720" maintainAspect="False" preferKtx="False" > + <CustomColors count="16" >#7391ff #ffffff #ffffff #ffffff #ffffff #ffffff #ffffff #ffffff #ffffff #ffffff #ffffff #ffffff #ffffff #ffffff #ffffff #ffffff</CustomColors> + </ProjectSettings> + <Classes > + <CustomMaterial id="simple-pos" name="simple-pos" sourcepath="../materials/simple-pos.material" /> + <CustomMaterial id="simple-pos2" name="simple-pos2" sourcepath="../materials/simple-pos2.material" /> + </Classes> + <Graph > + <Scene id="Scene" > + <Layer id="Layer" > + <Camera id="Camera" /> + <Light id="Light" /> + <Model id="Sphere-pos" > + <CustomMaterial id="simple-pos_001" class="#simple-pos" /> + </Model> + <Model id="Sphere-pos2" > + <CustomMaterial id="simple-pos2_001" class="#simple-pos2" /> + </Model> + </Layer> + </Scene> + </Graph> + <Logic > + <State name="Master Slide" component="#Scene" > + <Add ref="#Layer" /> + <Add ref="#Camera" /> + <Add ref="#Light" /> + <State id="Scene-Slide1" name="Slide1" > + <Add ref="#Sphere-pos" name="Sphere-pos" position="200 0 0" scale="2 2 2" sourcepath="../models/Sphere-pos.mesh" /> + <Add ref="#simple-pos_001" name="simple-pos" test_fragment="0.5" test_vertex="0.7" /> + <Add ref="#Sphere-pos2" name="Sphere-pos2" position="-200 0 0" scale="2 2 2" sourcepath="../models/Sphere-pos2.mesh" /> + <Add ref="#simple-pos2_001" name="simple-pos2" test_vertex="2" /> + </State> + </State> + </Logic> + </Project> +</UIP> |