mirror of
https://github.com/alicevision/Meshroom.git
synced 2025-07-21 10:37:18 +02:00
[ui][3d] introduce Wireframe render mode
* add WireframeMaterial from Qt 3D example * MaterialSwitcher now has 3 render modes: Solid, Wireframe, Textured * Remove NodeInstantiator; always create the material and modify entity's components (avoid rendering issues when switching between materials) * use DiffuseSpecularMaterial for Solid and Textured mode * create a MaterialSwitcher for all types of meshes (with/without textures) * add a render settings panel as part of 3D viewport overlay and remove "Textures" entry from outliner
This commit is contained in:
parent
f1d4291219
commit
74e80e70b5
7 changed files with 497 additions and 74 deletions
|
@ -1,85 +1,149 @@
|
||||||
import Qt3D.Core 2.0
|
import Qt3D.Core 2.0
|
||||||
import Qt3D.Render 2.9
|
import Qt3D.Render 2.9
|
||||||
import Qt3D.Input 2.0
|
import Qt3D.Input 2.0
|
||||||
import Qt3D.Extras 2.9
|
import Qt3D.Extras 2.10
|
||||||
import QtQuick 2.0
|
import QtQuick 2.0
|
||||||
|
import "Materials"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* MaterialSwitcher is an Entity that can change its parent's material
|
* MaterialSwitcher is an Entity that can change its parent's material
|
||||||
* according to a set of property it exposes.
|
* by setting the 'mode' property.
|
||||||
* It can be used to toggle between a Phong and a DiffuseMapColor
|
|
||||||
* depending on 'showTextures' value.
|
|
||||||
*/
|
*/
|
||||||
Entity {
|
Entity {
|
||||||
id: root
|
id: root
|
||||||
objectName: "MaterialSwitcher"
|
objectName: "MaterialSwitcher"
|
||||||
|
|
||||||
property bool showTextures: true
|
property int mode: 2
|
||||||
|
readonly property var modes: ["Solid", "Wireframe", "Textured"]
|
||||||
property string diffuseMap: ""
|
property string diffuseMap: ""
|
||||||
property color ambient: "#AAA"
|
property color ambient: "#AAA"
|
||||||
property real shininess
|
property real shininess
|
||||||
property color specular
|
property color specular
|
||||||
property color diffuseColor: "#AAA"
|
property color diffuseColor: "#AAA"
|
||||||
property alias object: instantiator.object
|
|
||||||
|
|
||||||
NodeInstantiator {
|
readonly property alias activeMaterial: m.material
|
||||||
id: instantiator
|
|
||||||
|
|
||||||
delegate: root.showTextures ? textured : colored
|
QtObject {
|
||||||
|
id: m
|
||||||
|
property Material material
|
||||||
|
onMaterialChanged: {
|
||||||
|
// remove previous material(s)
|
||||||
|
removeComponentsByType(parent, "Material")
|
||||||
|
addComponent(root.parent, material)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// add the created Node delegate to the root's parent components
|
function printComponents(entity)
|
||||||
onObjectAdded: {
|
{
|
||||||
if(!root.parent)
|
console.log("Components of Entity '" + entity + "'")
|
||||||
|
for(var i=0; i < entity.components.length; ++i)
|
||||||
|
{
|
||||||
|
console.log(" -- [" + i + "]: " + entity.components[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function addComponent(entity, component)
|
||||||
|
{
|
||||||
|
if(!entity)
|
||||||
return
|
return
|
||||||
var comps = [];
|
var comps = [];
|
||||||
for(var i=0; i < root.parent.components.length; ++i)
|
comps.push(component);
|
||||||
|
|
||||||
|
for(var i=0; i < entity.components.length; ++i)
|
||||||
{
|
{
|
||||||
comps.push(root.parent.components[i]);
|
comps.push(entity.components[i]);
|
||||||
}
|
|
||||||
comps.push(object);
|
|
||||||
root.parent.components = comps;
|
|
||||||
}
|
|
||||||
// remove the created Node delegate from the root's parent components
|
|
||||||
onObjectRemoved: {
|
|
||||||
if(!root.parent)
|
|
||||||
return
|
|
||||||
var comps = [];
|
|
||||||
for(var i=0; i < root.parent.components.length; ++i)
|
|
||||||
{
|
|
||||||
if(object != root.parent.components[i])
|
|
||||||
comps.push(root.parent.components[i]);
|
|
||||||
}
|
|
||||||
root.parent.components = comps;
|
|
||||||
}
|
}
|
||||||
|
entity.components = comps;
|
||||||
}
|
}
|
||||||
|
|
||||||
Component {
|
function removeComponentsByType(entity, type)
|
||||||
id: colored
|
{
|
||||||
PhongMaterial {
|
if(!entity)
|
||||||
|
return
|
||||||
|
var comps = [];
|
||||||
|
for(var i=0; i < entity.components.length; ++i)
|
||||||
|
{
|
||||||
|
if(entity.components[i].toString().indexOf(type) == -1)
|
||||||
|
{
|
||||||
|
comps.push(entity.components[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
entity.components = comps;
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeComponent(entity, component)
|
||||||
|
{
|
||||||
|
if(!entity)
|
||||||
|
return
|
||||||
|
var comps = [];
|
||||||
|
|
||||||
|
for(var i=0; i < entity.components.length; ++i)
|
||||||
|
{
|
||||||
|
if(entity.components[i] == component)
|
||||||
|
{
|
||||||
|
comps.push(entity.components[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
entity.components = comps;
|
||||||
|
}
|
||||||
|
|
||||||
|
StateGroup {
|
||||||
|
id: modeState
|
||||||
|
state: modes[mode]
|
||||||
|
|
||||||
|
states: [
|
||||||
|
State {
|
||||||
|
name: "Solid"
|
||||||
|
PropertyChanges { target: m; material: solid }
|
||||||
|
},
|
||||||
|
State {
|
||||||
|
name: "Wireframe"
|
||||||
|
PropertyChanges { target: m; material: wireframe }
|
||||||
|
},
|
||||||
|
State {
|
||||||
|
name: "Textured"
|
||||||
|
PropertyChanges { target: m; material: diffuseMap ? textured : solid }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Solid and Textured modes could and should be using the same material
|
||||||
|
// but get random shader errors (No shader program found for DNA)
|
||||||
|
// when toggling between a color and a texture for the diffuse property
|
||||||
|
|
||||||
|
DiffuseSpecularMaterial {
|
||||||
|
id: solid
|
||||||
parent: root.parent
|
parent: root.parent
|
||||||
objectName: "DiffuseColorMaterial"
|
objectName: "SolidMaterial"
|
||||||
|
ambient: root.ambient
|
||||||
|
shininess: root.shininess
|
||||||
|
specular: root.specular
|
||||||
|
diffuse: root.diffuseColor
|
||||||
|
}
|
||||||
|
|
||||||
|
DiffuseSpecularMaterial {
|
||||||
|
id: textured
|
||||||
|
parent: root.parent
|
||||||
|
objectName: "SolidMaterial"
|
||||||
|
ambient: root.ambient
|
||||||
|
shininess: root.shininess
|
||||||
|
specular: root.specular
|
||||||
|
diffuse: TextureLoader {
|
||||||
|
magnificationFilter: Texture.Linear
|
||||||
|
mirrored: false
|
||||||
|
source: diffuseMap
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
WireframeMaterial {
|
||||||
|
id: wireframe
|
||||||
|
parent: root.parent
|
||||||
|
objectName: "WireframeMaterial"
|
||||||
|
effect: WireframeEffect {}
|
||||||
ambient: root.ambient
|
ambient: root.ambient
|
||||||
diffuse: root.diffuseColor
|
diffuse: root.diffuseColor
|
||||||
shininess: root.shininess
|
shininess: 0
|
||||||
specular: root.specular
|
specular: root.specular
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
Component {
|
|
||||||
id: textured
|
|
||||||
DiffuseMapMaterial {
|
|
||||||
parent: root.parent
|
|
||||||
objectName: "DiffuseMapMaterial"
|
|
||||||
ambient: root.ambient
|
|
||||||
shininess: root.shininess
|
|
||||||
specular: root.specular
|
|
||||||
|
|
||||||
diffuse: TextureLoader {
|
|
||||||
id: baseColorLoader
|
|
||||||
mirrored: false
|
|
||||||
source: root.diffuseMap
|
|
||||||
magnificationFilter: Texture.Linear
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
43
meshroom/ui/qml/Viewer/Materials/WireframeEffect.qml
Normal file
43
meshroom/ui/qml/Viewer/Materials/WireframeEffect.qml
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
import Qt3D.Core 2.0
|
||||||
|
import Qt3D.Render 2.0
|
||||||
|
|
||||||
|
Effect {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
parameters: [
|
||||||
|
Parameter { name: "ka"; value: Qt.vector3d( 0.1, 0.1, 0.1 ) },
|
||||||
|
Parameter { name: "kd"; value: Qt.vector3d( 0.7, 0.7, 0.7 ) },
|
||||||
|
Parameter { name: "ks"; value: Qt.vector3d( 0.95, 0.95, 0.95 ) },
|
||||||
|
Parameter { name: "shininess"; value: 150.0 }
|
||||||
|
]
|
||||||
|
|
||||||
|
techniques: [
|
||||||
|
Technique {
|
||||||
|
graphicsApiFilter {
|
||||||
|
api: GraphicsApiFilter.OpenGL
|
||||||
|
profile: GraphicsApiFilter.CoreProfile
|
||||||
|
majorVersion: 3
|
||||||
|
minorVersion: 1
|
||||||
|
}
|
||||||
|
|
||||||
|
filterKeys: [ FilterKey { name: "renderingStyle"; value: "forward" } ]
|
||||||
|
|
||||||
|
parameters: [
|
||||||
|
Parameter { name: "light.position"; value: Qt.vector4d( 0.0, 0.0, 0.0, 1.0 ) },
|
||||||
|
Parameter { name: "light.intensity"; value: Qt.vector3d( 1.0, 1.0, 1.0 ) },
|
||||||
|
Parameter { name: "line.width"; value: 1.0 },
|
||||||
|
Parameter { name: "line.color"; value: Qt.vector4d( 1.0, 1.0, 1.0, 1.0 ) }
|
||||||
|
]
|
||||||
|
|
||||||
|
renderPasses: [
|
||||||
|
RenderPass {
|
||||||
|
shaderProgram: ShaderProgram {
|
||||||
|
vertexShaderCode: loadSource(Qt.resolvedUrl("shaders/robustwireframe.vert"))
|
||||||
|
geometryShaderCode: loadSource(Qt.resolvedUrl("shaders/robustwireframe.geom"))
|
||||||
|
fragmentShaderCode: loadSource(Qt.resolvedUrl("shaders/robustwireframe.frag"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
28
meshroom/ui/qml/Viewer/Materials/WireframeMaterial.qml
Normal file
28
meshroom/ui/qml/Viewer/Materials/WireframeMaterial.qml
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
import Qt3D.Core 2.0
|
||||||
|
import Qt3D.Render 2.0
|
||||||
|
|
||||||
|
Material {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property color ambient: Qt.rgba( 0.05, 0.05, 0.05, 1.0 )
|
||||||
|
property color diffuse: Qt.rgba( 0.7, 0.7, 0.7, 1.0 )
|
||||||
|
property color specular: Qt.rgba( 0.95, 0.95, 0.95, 1.0 )
|
||||||
|
property real shininess: 1.0
|
||||||
|
property real lineWidth: 0.8
|
||||||
|
property color lineColor: Qt.rgba( 0.2, 0.2, 0.2, 1.0 )
|
||||||
|
property vector3d lightIntensity: Qt.vector3d(0.7, 0.7, 0.7)
|
||||||
|
property vector4d lightPosition: Qt.vector4d(0.0, 0.0, 0.0, 1.0)
|
||||||
|
|
||||||
|
effect: WireframeEffect {}
|
||||||
|
|
||||||
|
parameters: [
|
||||||
|
Parameter { name: "ka"; value: Qt.vector3d(root.ambient.r, root.ambient.g, root.ambient.b) },
|
||||||
|
Parameter { name: "kd"; value: Qt.vector3d(root.diffuse.r, root.diffuse.g, root.diffuse.b) },
|
||||||
|
Parameter { name: "ksp"; value: Qt.vector3d(root.specular.r, root.specular.g, root.specular.b) },
|
||||||
|
Parameter { name: "shininess"; value: root.shininess },
|
||||||
|
Parameter { name: "line.width"; value: root.lineWidth },
|
||||||
|
Parameter { name: "line.color"; value: root.lineColor },
|
||||||
|
Parameter { name: "light.intensity"; value: root.lightIntensity },
|
||||||
|
Parameter { name: "light.position"; value: root.lightPosition }
|
||||||
|
]
|
||||||
|
}
|
112
meshroom/ui/qml/Viewer/Materials/shaders/robustwireframe.frag
Normal file
112
meshroom/ui/qml/Viewer/Materials/shaders/robustwireframe.frag
Normal file
|
@ -0,0 +1,112 @@
|
||||||
|
#version 330 core
|
||||||
|
|
||||||
|
uniform struct LightInfo {
|
||||||
|
vec4 position;
|
||||||
|
vec3 intensity;
|
||||||
|
} light;
|
||||||
|
|
||||||
|
uniform struct LineInfo {
|
||||||
|
float width;
|
||||||
|
vec4 color;
|
||||||
|
} line;
|
||||||
|
|
||||||
|
uniform vec3 ka; // Ambient reflectivity
|
||||||
|
uniform vec3 kd; // Diffuse reflectivity
|
||||||
|
uniform vec3 ks; // Specular reflectivity
|
||||||
|
uniform float shininess; // Specular shininess factor
|
||||||
|
|
||||||
|
in WireframeVertex {
|
||||||
|
vec3 position;
|
||||||
|
vec3 normal;
|
||||||
|
noperspective vec4 edgeA;
|
||||||
|
noperspective vec4 edgeB;
|
||||||
|
flat int configuration;
|
||||||
|
} fs_in;
|
||||||
|
|
||||||
|
out vec4 fragColor;
|
||||||
|
|
||||||
|
vec3 adsModel( const in vec3 pos, const in vec3 n )
|
||||||
|
{
|
||||||
|
// Calculate the vector from the light to the fragment
|
||||||
|
vec3 s = normalize( vec3( light.position ) - pos );
|
||||||
|
|
||||||
|
// Calculate the vector from the fragment to the eye position (the
|
||||||
|
// origin since this is in "eye" or "camera" space
|
||||||
|
vec3 v = normalize( -pos );
|
||||||
|
|
||||||
|
// Calculate the diffus component
|
||||||
|
vec3 diffuse = vec3( max( dot( s, n ), 0.0 ) );
|
||||||
|
|
||||||
|
// Calculate the specular component
|
||||||
|
vec3 specular = vec3(0.0, 0.0, 0.0);
|
||||||
|
if(shininess > 0)
|
||||||
|
{
|
||||||
|
// Refleft the light beam using the normal at this fragment
|
||||||
|
vec3 r = reflect( -s, n );
|
||||||
|
vec3( pow( max( dot( r, v ), 0.0 ), shininess ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Combine the ambient, diffuse and specular contributions
|
||||||
|
return light.intensity * ( ka + kd * diffuse + ks * specular );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
vec4 shadeLine( const in vec4 color )
|
||||||
|
{
|
||||||
|
// Find the smallest distance between the fragment and a triangle edge
|
||||||
|
float d;
|
||||||
|
if ( fs_in.configuration == 0 )
|
||||||
|
{
|
||||||
|
// Common configuration
|
||||||
|
d = min( fs_in.edgeA.x, fs_in.edgeA.y );
|
||||||
|
d = min( d, fs_in.edgeA.z );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Handle configuration where screen space projection breaks down
|
||||||
|
// Compute and compare the squared distances
|
||||||
|
vec2 AF = gl_FragCoord.xy - fs_in.edgeA.xy;
|
||||||
|
float sqAF = dot( AF, AF );
|
||||||
|
float AFcosA = dot( AF, fs_in.edgeA.zw );
|
||||||
|
d = abs( sqAF - AFcosA * AFcosA );
|
||||||
|
|
||||||
|
vec2 BF = gl_FragCoord.xy - fs_in.edgeB.xy;
|
||||||
|
float sqBF = dot( BF, BF );
|
||||||
|
float BFcosB = dot( BF, fs_in.edgeB.zw );
|
||||||
|
d = min( d, abs( sqBF - BFcosB * BFcosB ) );
|
||||||
|
|
||||||
|
// Only need to care about the 3rd edge for some configurations.
|
||||||
|
if ( fs_in.configuration == 1 || fs_in.configuration == 2 || fs_in.configuration == 4 )
|
||||||
|
{
|
||||||
|
float AFcosA0 = dot( AF, normalize( fs_in.edgeB.xy - fs_in.edgeA.xy ) );
|
||||||
|
d = min( d, abs( sqAF - AFcosA0 * AFcosA0 ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
d = sqrt( d );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Blend between line color and phong color
|
||||||
|
float mixVal;
|
||||||
|
if ( d < line.width - 1.0 )
|
||||||
|
{
|
||||||
|
mixVal = 1.0;
|
||||||
|
}
|
||||||
|
else if ( d > line.width + 1.0 )
|
||||||
|
{
|
||||||
|
mixVal = 0.0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
float x = d - ( line.width - 1.0 );
|
||||||
|
mixVal = exp2( -2.0 * ( x * x ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
return mix( color, line.color, mixVal );
|
||||||
|
}
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
// Calculate the color from the phong model
|
||||||
|
vec4 color = vec4( adsModel( fs_in.position, normalize( fs_in.normal ) ), 1.0 );
|
||||||
|
fragColor = shadeLine( color );
|
||||||
|
}
|
131
meshroom/ui/qml/Viewer/Materials/shaders/robustwireframe.geom
Normal file
131
meshroom/ui/qml/Viewer/Materials/shaders/robustwireframe.geom
Normal file
|
@ -0,0 +1,131 @@
|
||||||
|
#version 330 core
|
||||||
|
|
||||||
|
layout( triangles ) in;
|
||||||
|
layout( triangle_strip, max_vertices = 3 ) out;
|
||||||
|
|
||||||
|
in EyeSpaceVertex {
|
||||||
|
vec3 position;
|
||||||
|
vec3 normal;
|
||||||
|
} gs_in[];
|
||||||
|
|
||||||
|
out WireframeVertex {
|
||||||
|
vec3 position;
|
||||||
|
vec3 normal;
|
||||||
|
noperspective vec4 edgeA;
|
||||||
|
noperspective vec4 edgeB;
|
||||||
|
flat int configuration;
|
||||||
|
} gs_out;
|
||||||
|
|
||||||
|
uniform mat4 viewportMatrix;
|
||||||
|
|
||||||
|
const int infoA[] = int[]( 0, 0, 0, 0, 1, 1, 2 );
|
||||||
|
const int infoB[] = int[]( 1, 1, 2, 0, 2, 1, 2 );
|
||||||
|
const int infoAd[] = int[]( 2, 2, 1, 1, 0, 0, 0 );
|
||||||
|
const int infoBd[] = int[]( 2, 2, 1, 2, 0, 2, 1 );
|
||||||
|
|
||||||
|
vec2 transformToViewport( const in vec4 p )
|
||||||
|
{
|
||||||
|
return vec2( viewportMatrix * ( p / p.w ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
gs_out.configuration = int(gl_in[0].gl_Position.z < 0) * int(4)
|
||||||
|
+ int(gl_in[1].gl_Position.z < 0) * int(2)
|
||||||
|
+ int(gl_in[2].gl_Position.z < 0);
|
||||||
|
|
||||||
|
// If all vertices are behind us, cull the primitive
|
||||||
|
if (gs_out.configuration == 7)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Transform each vertex into viewport space
|
||||||
|
vec2 p[3];
|
||||||
|
p[0] = transformToViewport( gl_in[0].gl_Position );
|
||||||
|
p[1] = transformToViewport( gl_in[1].gl_Position );
|
||||||
|
p[2] = transformToViewport( gl_in[2].gl_Position );
|
||||||
|
|
||||||
|
if (gs_out.configuration == 0)
|
||||||
|
{
|
||||||
|
// Common configuration where all vertices are within the viewport
|
||||||
|
gs_out.edgeA = vec4(0.0);
|
||||||
|
gs_out.edgeB = vec4(0.0);
|
||||||
|
|
||||||
|
// Calculate lengths of 3 edges of triangle
|
||||||
|
float a = length( p[1] - p[2] );
|
||||||
|
float b = length( p[2] - p[0] );
|
||||||
|
float c = length( p[1] - p[0] );
|
||||||
|
|
||||||
|
// Calculate internal angles using the cosine rule
|
||||||
|
float alpha = acos( ( b * b + c * c - a * a ) / ( 2.0 * b * c ) );
|
||||||
|
float beta = acos( ( a * a + c * c - b * b ) / ( 2.0 * a * c ) );
|
||||||
|
|
||||||
|
// Calculate the perpendicular distance of each vertex from the opposing edge
|
||||||
|
float ha = abs( c * sin( beta ) );
|
||||||
|
float hb = abs( c * sin( alpha ) );
|
||||||
|
float hc = abs( b * sin( alpha ) );
|
||||||
|
|
||||||
|
// Now add this perpendicular distance as a per-vertex property in addition to
|
||||||
|
// the position and normal calculated in the vertex shader.
|
||||||
|
|
||||||
|
// Vertex 0 (a)
|
||||||
|
gs_out.edgeA = vec4( ha, 0.0, 0.0, 0.0 );
|
||||||
|
gs_out.normal = gs_in[0].normal;
|
||||||
|
gs_out.position = gs_in[0].position;
|
||||||
|
gl_Position = gl_in[0].gl_Position;
|
||||||
|
EmitVertex();
|
||||||
|
|
||||||
|
// Vertex 1 (b)
|
||||||
|
gs_out.edgeA = vec4( 0.0, hb, 0.0, 0.0 );
|
||||||
|
gs_out.normal = gs_in[1].normal;
|
||||||
|
gs_out.position = gs_in[1].position;
|
||||||
|
gl_Position = gl_in[1].gl_Position;
|
||||||
|
EmitVertex();
|
||||||
|
|
||||||
|
// Vertex 2 (c)
|
||||||
|
gs_out.edgeA = vec4( 0.0, 0.0, hc, 0.0 );
|
||||||
|
gs_out.normal = gs_in[2].normal;
|
||||||
|
gs_out.position = gs_in[2].position;
|
||||||
|
gl_Position = gl_in[2].gl_Position;
|
||||||
|
EmitVertex();
|
||||||
|
|
||||||
|
// Finish the primitive off
|
||||||
|
EndPrimitive();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Viewport projection breaks down for one or two vertices.
|
||||||
|
// Caclulate what we can here and defer rest to fragment shader.
|
||||||
|
// Since this is coherent for the entire primitive the conditional
|
||||||
|
// in the fragment shader is still cheap as all concurrent
|
||||||
|
// fragment shader invocations will take the same code path.
|
||||||
|
|
||||||
|
// Copy across the viewport-space points for the (up to) two vertices
|
||||||
|
// in the viewport
|
||||||
|
gs_out.edgeA.xy = p[infoA[gs_out.configuration]];
|
||||||
|
gs_out.edgeB.xy = p[infoB[gs_out.configuration]];
|
||||||
|
|
||||||
|
// Copy across the viewport-space edge vectors for the (up to) two vertices
|
||||||
|
// in the viewport
|
||||||
|
gs_out.edgeA.zw = normalize( gs_out.edgeA.xy - p[ infoAd[gs_out.configuration] ] );
|
||||||
|
gs_out.edgeB.zw = normalize( gs_out.edgeB.xy - p[ infoBd[gs_out.configuration] ] );
|
||||||
|
|
||||||
|
// Pass through the other vertex attributes
|
||||||
|
gs_out.normal = gs_in[0].normal;
|
||||||
|
gs_out.position = gs_in[0].position;
|
||||||
|
gl_Position = gl_in[0].gl_Position;
|
||||||
|
EmitVertex();
|
||||||
|
|
||||||
|
gs_out.normal = gs_in[1].normal;
|
||||||
|
gs_out.position = gs_in[1].position;
|
||||||
|
gl_Position = gl_in[1].gl_Position;
|
||||||
|
EmitVertex();
|
||||||
|
|
||||||
|
gs_out.normal = gs_in[2].normal;
|
||||||
|
gs_out.position = gs_in[2].position;
|
||||||
|
gl_Position = gl_in[2].gl_Position;
|
||||||
|
EmitVertex();
|
||||||
|
|
||||||
|
// Finish the primitive off
|
||||||
|
EndPrimitive();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
#version 330 core
|
||||||
|
|
||||||
|
in vec3 vertexPosition;
|
||||||
|
in vec3 vertexNormal;
|
||||||
|
|
||||||
|
out EyeSpaceVertex {
|
||||||
|
vec3 position;
|
||||||
|
vec3 normal;
|
||||||
|
} vs_out;
|
||||||
|
|
||||||
|
uniform mat4 modelView;
|
||||||
|
uniform mat3 modelViewNormal;
|
||||||
|
uniform mat4 mvp;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
vs_out.normal = normalize( modelViewNormal * vertexNormal );
|
||||||
|
vs_out.position = vec3( modelView * vec4( vertexPosition, 1.0 ) );
|
||||||
|
|
||||||
|
gl_Position = mvp * vec4( vertexPosition, 1.0 );
|
||||||
|
}
|
|
@ -14,6 +14,7 @@ FocusScope {
|
||||||
property alias abcSource: modelLoader.abcSource
|
property alias abcSource: modelLoader.abcSource
|
||||||
property alias depthMapSource: modelLoader.depthMapSource
|
property alias depthMapSource: modelLoader.depthMapSource
|
||||||
|
|
||||||
|
property int renderMode: 2
|
||||||
readonly property alias loading: modelLoader.loading
|
readonly property alias loading: modelLoader.loading
|
||||||
|
|
||||||
// Alembic optional support => won't be available if AlembicEntity plugin is not available
|
// Alembic optional support => won't be available if AlembicEntity plugin is not available
|
||||||
|
@ -62,8 +63,11 @@ FocusScope {
|
||||||
})
|
})
|
||||||
|
|
||||||
entities.forEach(function(entity) {
|
entities.forEach(function(entity) {
|
||||||
var comps = [];
|
|
||||||
var mats = []
|
var mats = []
|
||||||
|
var hasTextures = false
|
||||||
|
// Create as many MaterialSwitcher as individual materials for this entity
|
||||||
|
// NOTE: we let each MaterialSwitcher modify the components of the entity
|
||||||
|
// and therefore remove the default material spawned by the sceneLoader
|
||||||
for(var i=0; i < entity.components.length; ++i)
|
for(var i=0; i < entity.components.length; ++i)
|
||||||
{
|
{
|
||||||
var comp = entity.components[i]
|
var comp = entity.components[i]
|
||||||
|
@ -76,32 +80,23 @@ FocusScope {
|
||||||
"shininess": comp.shininess,
|
"shininess": comp.shininess,
|
||||||
"specular": comp.specular,
|
"specular": comp.specular,
|
||||||
"ambient": comp.ambient,
|
"ambient": comp.ambient,
|
||||||
"showTextures": texturesCheckBox.checked
|
"mode": root.renderMode
|
||||||
}
|
}
|
||||||
mats.push(m)
|
mats.push(m)
|
||||||
// unparent previous material
|
hasTextures = true
|
||||||
// and exclude it from the entity components
|
|
||||||
comp.parent = null
|
|
||||||
continue; // skip original component and continue
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// make default material brighter
|
|
||||||
if(comp.toString().indexOf("QPhongMaterial") > -1) {
|
if(comp.toString().indexOf("QPhongMaterial") > -1) {
|
||||||
comp.diffuse = "#AAA"
|
// create MaterialSwitcher with default colors
|
||||||
comp.ambient = "#AAA"
|
mats.push({})
|
||||||
}
|
}
|
||||||
comps.push(comp)
|
|
||||||
}
|
}
|
||||||
entity.components = comps
|
|
||||||
modelLoader.meshHasTexture = mats.length > 0
|
modelLoader.meshHasTexture = mats.length > 0
|
||||||
mats.forEach(function(m){
|
mats.forEach(function(m){
|
||||||
// create a material switcher for each material definition
|
// create a material switcher for each material definition
|
||||||
var matSwitcher = materialSwitcherComponent.createObject(entity, m)
|
var matSwitcher = materialSwitcherComponent.createObject(entity, m)
|
||||||
// trigger showTextures update by inverting it
|
matSwitcher.mode = Qt.binding(function(){ return root.renderMode })
|
||||||
// and re-bind textures checkbox to texture switch property
|
|
||||||
// (this double update ensure the texture display is correct)
|
|
||||||
matSwitcher.showTextures = !matSwitcher.showTextures
|
|
||||||
matSwitcher.showTextures = Qt.binding(function(){ return texturesCheckBox.checked })
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -395,9 +390,11 @@ FocusScope {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Outliner
|
||||||
Pane {
|
Pane {
|
||||||
background: Rectangle { color: palette.base; opacity: 0.5; radius: 2 }
|
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
|
background: Rectangle { color: palette.base; opacity: 0.5; radius: 2 }
|
||||||
|
|
||||||
Column {
|
Column {
|
||||||
Row {
|
Row {
|
||||||
CheckBox { id: showSfMCheckBox; text: "SfM"; checked: true; visible: root.supportAlembic; opacity: root.abcSource ? 1.0 : 0.6 }
|
CheckBox { id: showSfMCheckBox; text: "SfM"; checked: true; visible: root.supportAlembic; opacity: root.abcSource ? 1.0 : 0.6 }
|
||||||
|
@ -427,12 +424,39 @@ FocusScope {
|
||||||
ToolTip.visible: hovered
|
ToolTip.visible: hovered
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
CheckBox { id: texturesCheckBox; text: "Textures"; checked: true; opacity: modelLoader.meshHasTexture ? 1.0 : 0.6 }
|
|
||||||
CheckBox { id: gridCheckBox; text: "Grid"; checked: true }
|
CheckBox { id: gridCheckBox; text: "Grid"; checked: true }
|
||||||
CheckBox { id: locatorCheckBox; text: "Locator"; checked: true }
|
CheckBox { id: locatorCheckBox; text: "Locator"; checked: true }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Render Mode
|
||||||
|
Pane {
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
background: Rectangle { color: palette.base; opacity: 0.5; radius: 2 }
|
||||||
|
|
||||||
|
Row {
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
Repeater {
|
||||||
|
model: [ // Can't use ListModel because of MaterialIcons expressions
|
||||||
|
{"name": "Solid", "icon": MaterialIcons.crop_din},
|
||||||
|
{"name": "Wireframe", "icon": MaterialIcons.grid_on},
|
||||||
|
{"name": "Textured", "icon": MaterialIcons.texture },
|
||||||
|
]
|
||||||
|
delegate: ToolButton {
|
||||||
|
text: modelData["icon"]
|
||||||
|
ToolTip.text: modelData["name"]
|
||||||
|
ToolTip.visible: hovered
|
||||||
|
font.family: MaterialIcons.fontFamily
|
||||||
|
font.pointSize: 11
|
||||||
|
padding: 4
|
||||||
|
onClicked: root.renderMode = index
|
||||||
|
checkable: !checked // hack to disable check toggle on click
|
||||||
|
checked: renderMode === index
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Menu
|
// Menu
|
||||||
Menu {
|
Menu {
|
||||||
id: contextMenu
|
id: contextMenu
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue