Skip to content

Commit

Permalink
Flat shaders for 2d models
Browse files Browse the repository at this point in the history
  • Loading branch information
sjackso committed Apr 15, 2019
1 parent 8062b58 commit 9880e95
Show file tree
Hide file tree
Showing 5 changed files with 139 additions and 37 deletions.
90 changes: 53 additions & 37 deletions src/athena/viewer.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,60 +135,76 @@ def resize(self, new_width, new_height):


class AthenaViewer(Qt3DExtras.Qt3DWindow):


def _athenaMaterial( self, flavor ):
engine = QQmlEngine()
main_qml = Path(ATHENA_SRC_DIR) / 'qml' / 'main.qml'
component = QQmlComponent(engine, main_qml.as_uri() )
if ( component.status() != QQmlComponent.Ready ):
print ("Error loading QML:")
print(component.errorString())
material = component.create()

# Need to hold a reference in python to the QQmlComponent, or else
# PySide2 will helpfully delete the material object along with it
# after this function ends.
self._qtrefs.append(component)

shader_path = Path(ATHENA_SRC_DIR) / 'shaders'
vert_shader = shader_path / 'wireframe.vert'
geom_shader = shader_path / 'wireframe.geom'
frag_shader = shader_path / (flavor+'_wireframe.frag')
def loadShader( s ):
return Qt3DRender.QShaderProgram.loadSource( s.as_uri() )
shader = Qt3DRender.QShaderProgram(material)
shader.setVertexShaderCode( loadShader( vert_shader ) )
shader.setGeometryShaderCode( loadShader( geom_shader ) )
shader.setFragmentShaderCode( loadShader( frag_shader ) )
for rpass in material.effect().techniques()[0].renderPasses():
rpass.setShaderProgram( shader )

return material



def __init__(self):
super(AthenaViewer, self).__init__()
self._qtrefs = []

self.defaultFrameGraph().setClearColor( QColor(63, 63, 63) )
self.renderSettings().setRenderPolicy(self.renderSettings().OnDemand)

self.rootEntity = Qt3DCore.QEntity()
self.camControl = CameraController(None, None, None)


# Create the mesh shading material, stored as self.material
self.eee = QQmlEngine()
main_qml = Path(ATHENA_SRC_DIR) / 'qml' / 'main.qml'
self.ccc = QQmlComponent(self.eee, main_qml.as_uri() )
if( self.ccc.status() != QQmlComponent.Ready ):
print("Error loading QML:")
print(self.ccc.errorString())
self.material = self.ccc.create()
# We must set the shader program paths here, because qml doesn't know where ATHENA_DIR is

self.shader = Qt3DRender.QShaderProgram()
shader_path = Path(ATHENA_SRC_DIR) / 'shaders' / 'robustwireframe'
def loadShader(suffix):
return Qt3DRender.QShaderProgram.loadSource( shader_path.with_suffix( suffix ).as_uri() )
self.shader.setVertexShaderCode( loadShader( '.vert' ) )
self.shader.setGeometryShaderCode( loadShader( '.geom' ) )
self.shader.setFragmentShaderCode( loadShader( '.frag' ) )
pass0 = self.material.effect().techniques()[0].renderPasses()[0]
pass0.setShaderProgram(self.shader)
pass1 = self.material.effect().techniques()[0].renderPasses()[1]
pass1.setShaderProgram(self.shader)

self.alpha_param = Qt3DRender.QParameter( self.material )
self.alpha_param = Qt3DRender.QParameter( self.rootEntity )
self.alpha_param.setName('alpha')
self.alpha_param.setValue(1.0)
self.material.addParameter( self.alpha_param )

self.color_param = Qt3DRender.QParameter( self.rootEntity )
self.color_param.setName('flat_color')
self.color_param.setValue( QColor( 97, 188, 188 ) )

self.flat_material = self._athenaMaterial( 'flat' )
self.flat_material.addParameter( self.alpha_param )
self.flat_material.addParameter( self.color_param )

self.gooch_material = self._athenaMaterial( 'gooch' )
self.gooch_material.addParameter( self.alpha_param )

self.setRootEntity(self.rootEntity)

# Each time a mesh is loaded, we create a new Plymesh and add self.material as a component.
# Each time a mesh is loaded, we create a new Plymesh and add a material as a component.
# Old meshes are deleteLater()-ed. A problem with this approach is that the deleted QEntities
# also delete their components (and this seems true even if we try to remove the component first).
# The workaround we use here is to also add self.material as a component of the root entity,
# The workaround we use here is to also add the materials as components of the root entity,
# which keeps Qt3D from deleting it. I don't know if this is the best approach, but it works.
self.rootEntity.addComponent(self.material)
self.rootEntity.addComponent(self.flat_material)
self.rootEntity.addComponent(self.gooch_material)
self.meshEntity = None
self.lastpos = None

def getMaterialParam(self, name):
for param in self.material.parameters():
if param.name() == name:
return param
return None

def setAlpha(self, value):
self.alpha_param.setValue( float(value) / 255.0 )

Expand All @@ -198,11 +214,11 @@ def reloadGeom(self, filepath, mesh_3d):
if( self.meshEntity ):
self.meshEntity.deleteLater()
self.meshEntity = plymesh.PlyMesh(self.rootEntity, self.plydata)
self.meshEntity.addComponent(self.material)

if (mesh_3d):
if( mesh_3d ):
self.meshEntity.addComponent(self.gooch_material)
self.camControl = CameraController3D(self, self.camera(), self.meshEntity.geometry)
else:
self.meshEntity.addComponent(self.flat_material)
self.camControl = CameraController2D(self, self.camera(), self.meshEntity.geometry)
self.camControl.reset()

Expand Down
86 changes: 86 additions & 0 deletions src/shaders/flat_wireframe.frag
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
#version 330 core

uniform struct LightInfo {
vec4 position;
vec3 intensity;
} light;

uniform struct LineInfo {
float width;
vec4 color;
} line;

uniform vec3 flat_color;
uniform float alpha;

in WireframeVertex {
vec3 position;
flat vec3 normal;
noperspective vec4 edgeA;
noperspective vec4 edgeB;
flat int configuration;
} fs_in;

out vec4 fragColor;

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()
{
//vec4 color = vec4( goochModel( fs_in.position, normalize( fs_in.normal ) ), alpha );
//vec4 color = vec4( flat_color.x, flat_color.y, flat_color.z, alpha );

vec4 color = vec4( flat_color, alpha );
fragColor = shadeLine( color );
}
File renamed without changes.
File renamed without changes.
File renamed without changes.

0 comments on commit 9880e95

Please sign in to comment.