summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJere Tuliniemi <jere.tuliniemi@qt.io>2018-10-22 14:18:24 +0300
committerJere Tuliniemi <jere.tuliniemi@qt.io>2019-01-15 12:14:07 +0000
commit0cf63f1de93635c85fc3120cdfce3410a59edc9b (patch)
tree30ea4185da967d19e2c33298698fb6deadfec1d4
parent7c203cb04362c246c709285d583052ec1358e7de (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.cpp2
-rw-r--r--src/runtime/q3dsmaterial_p.h1
-rw-r--r--src/runtime/shadergenerator/q3dscustommaterialvertexpipeline.cpp152
-rw-r--r--tests/scenes/customvertex/customvertex.uia15
-rw-r--r--tests/scenes/customvertex/materials/simple-pos.material25
-rw-r--r--tests/scenes/customvertex/materials/simple-pos2.material25
-rw-r--r--tests/scenes/customvertex/models/Sphere-pos.meshbin0 -> 4356 bytes
-rw-r--r--tests/scenes/customvertex/models/Sphere-pos2.meshbin0 -> 8372 bytes
-rw-r--r--tests/scenes/customvertex/presentations/customvertex.uip39
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
new file mode 100644
index 0000000..5eace9d
--- /dev/null
+++ b/tests/scenes/customvertex/models/Sphere-pos.mesh
Binary files differ
diff --git a/tests/scenes/customvertex/models/Sphere-pos2.mesh b/tests/scenes/customvertex/models/Sphere-pos2.mesh
new file mode 100644
index 0000000..c54f34f
--- /dev/null
+++ b/tests/scenes/customvertex/models/Sphere-pos2.mesh
Binary files differ
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>