mirror of
https://github.com/alicevision/Meshroom.git
synced 2025-07-19 17:47:25 +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.Render 2.9
|
||||
import Qt3D.Input 2.0
|
||||
import Qt3D.Extras 2.9
|
||||
import Qt3D.Extras 2.10
|
||||
import QtQuick 2.0
|
||||
import "Materials"
|
||||
|
||||
/**
|
||||
* MaterialSwitcher is an Entity that can change its parent's material
|
||||
* according to a set of property it exposes.
|
||||
* It can be used to toggle between a Phong and a DiffuseMapColor
|
||||
* depending on 'showTextures' value.
|
||||
* by setting the 'mode' property.
|
||||
*/
|
||||
Entity {
|
||||
id: root
|
||||
objectName: "MaterialSwitcher"
|
||||
|
||||
property bool showTextures: true
|
||||
property int mode: 2
|
||||
readonly property var modes: ["Solid", "Wireframe", "Textured"]
|
||||
property string diffuseMap: ""
|
||||
property color ambient: "#AAA"
|
||||
property real shininess
|
||||
property color specular
|
||||
property color diffuseColor: "#AAA"
|
||||
property alias object: instantiator.object
|
||||
|
||||
NodeInstantiator {
|
||||
id: instantiator
|
||||
readonly property alias activeMaterial: m.material
|
||||
|
||||
delegate: root.showTextures ? textured : colored
|
||||
|
||||
// add the created Node delegate to the root's parent components
|
||||
onObjectAdded: {
|
||||
if(!root.parent)
|
||||
return
|
||||
var comps = [];
|
||||
for(var i=0; i < root.parent.components.length; ++i)
|
||||
{
|
||||
comps.push(root.parent.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;
|
||||
QtObject {
|
||||
id: m
|
||||
property Material material
|
||||
onMaterialChanged: {
|
||||
// remove previous material(s)
|
||||
removeComponentsByType(parent, "Material")
|
||||
addComponent(root.parent, material)
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: colored
|
||||
PhongMaterial {
|
||||
parent: root.parent
|
||||
objectName: "DiffuseColorMaterial"
|
||||
ambient: root.ambient
|
||||
diffuse: root.diffuseColor
|
||||
shininess: root.shininess
|
||||
specular: root.specular
|
||||
function printComponents(entity)
|
||||
{
|
||||
console.log("Components of Entity '" + entity + "'")
|
||||
for(var i=0; i < entity.components.length; ++i)
|
||||
{
|
||||
console.log(" -- [" + i + "]: " + entity.components[i])
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
function addComponent(entity, component)
|
||||
{
|
||||
if(!entity)
|
||||
return
|
||||
var comps = [];
|
||||
comps.push(component);
|
||||
|
||||
for(var i=0; i < entity.components.length; ++i)
|
||||
{
|
||||
comps.push(entity.components[i]);
|
||||
}
|
||||
entity.components = comps;
|
||||
}
|
||||
|
||||
function removeComponentsByType(entity, type)
|
||||
{
|
||||
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
|
||||
objectName: "SolidMaterial"
|
||||
ambient: root.ambient
|
||||
shininess: root.shininess
|
||||
specular: root.specular
|
||||
diffuse: root.diffuseColor
|
||||
}
|
||||
|
||||
DiffuseSpecularMaterial {
|
||||
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
|
||||
}
|
||||
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
|
||||
diffuse: root.diffuseColor
|
||||
shininess: 0
|
||||
specular: root.specular
|
||||
}
|
||||
|
||||
}
|
||||
|
|
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 depthMapSource: modelLoader.depthMapSource
|
||||
|
||||
property int renderMode: 2
|
||||
readonly property alias loading: modelLoader.loading
|
||||
|
||||
// Alembic optional support => won't be available if AlembicEntity plugin is not available
|
||||
|
@ -62,8 +63,11 @@ FocusScope {
|
|||
})
|
||||
|
||||
entities.forEach(function(entity) {
|
||||
var comps = [];
|
||||
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)
|
||||
{
|
||||
var comp = entity.components[i]
|
||||
|
@ -76,32 +80,23 @@ FocusScope {
|
|||
"shininess": comp.shininess,
|
||||
"specular": comp.specular,
|
||||
"ambient": comp.ambient,
|
||||
"showTextures": texturesCheckBox.checked
|
||||
"mode": root.renderMode
|
||||
}
|
||||
mats.push(m)
|
||||
// unparent previous material
|
||||
// and exclude it from the entity components
|
||||
comp.parent = null
|
||||
continue; // skip original component and continue
|
||||
hasTextures = true
|
||||
}
|
||||
|
||||
// make default material brighter
|
||||
if(comp.toString().indexOf("QPhongMaterial") > -1) {
|
||||
comp.diffuse = "#AAA"
|
||||
comp.ambient = "#AAA"
|
||||
// create MaterialSwitcher with default colors
|
||||
mats.push({})
|
||||
}
|
||||
comps.push(comp)
|
||||
}
|
||||
entity.components = comps
|
||||
|
||||
modelLoader.meshHasTexture = mats.length > 0
|
||||
mats.forEach(function(m){
|
||||
// create a material switcher for each material definition
|
||||
var matSwitcher = materialSwitcherComponent.createObject(entity, m)
|
||||
// trigger showTextures update by inverting it
|
||||
// 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 })
|
||||
matSwitcher.mode = Qt.binding(function(){ return root.renderMode })
|
||||
})
|
||||
})
|
||||
}
|
||||
|
@ -395,9 +390,11 @@ FocusScope {
|
|||
}
|
||||
}
|
||||
|
||||
// Outliner
|
||||
Pane {
|
||||
background: Rectangle { color: palette.base; opacity: 0.5; radius: 2 }
|
||||
anchors.right: parent.right
|
||||
background: Rectangle { color: palette.base; opacity: 0.5; radius: 2 }
|
||||
|
||||
Column {
|
||||
Row {
|
||||
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
|
||||
}
|
||||
}
|
||||
CheckBox { id: texturesCheckBox; text: "Textures"; checked: true; opacity: modelLoader.meshHasTexture ? 1.0 : 0.6 }
|
||||
CheckBox { id: gridCheckBox; text: "Grid"; 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 {
|
||||
id: contextMenu
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue