Skip to content
Snippets Groups Projects
Commit 064279fb authored by Mathias Paulin's avatar Mathias Paulin :speech_balloon:
Browse files

Add a wireframe pass

parent 78d48ba2
No related branches found
No related tags found
No related merge requests found
Showing
with 515 additions and 55 deletions
......@@ -40,6 +40,7 @@ set(sources
RadiumNBR/Passes/LocalLightPass.cpp
RadiumNBR/Passes/TransparencyPass.cpp
RadiumNBR/Passes/VolumePass.cpp
RadiumNBR/Passes/WireframePass.cpp
)
set(public_headers
RadiumNBR/NodeBasedRendererMacro.hpp
......@@ -55,6 +56,7 @@ set(public_headers
RadiumNBR/Passes/LocalLightPass.hpp
RadiumNBR/Passes/TransparencyPass.hpp
RadiumNBR/Passes/VolumePass.hpp
RadiumNBR/Passes/WireframePass.hpp
)
set(headers
......
......@@ -41,7 +41,7 @@ RadiumNBR::Gui::RendererPanel* buildRadiumNBRGui( NodeBasedRenderer* renderer,
100 );
controlPanel->addOption( " Wireframe rendering", [renderer, appUpdateCallback]( bool b ) {
renderer->enableWireframe( b );
renderer->wireframeMode( b );
appUpdateCallback();
} );
......
......@@ -23,6 +23,7 @@ using namespace Ra::Core::Utils; // log
#include <RadiumNBR/Passes/LocalLightPass.hpp>
#include <RadiumNBR/Passes/TransparencyPass.hpp>
#include <RadiumNBR/Passes/VolumePass.hpp>
#include <RadiumNBR/Passes/WireframePass.hpp>
#include <globjects/Framebuffer.h>
......@@ -218,15 +219,39 @@ void NodeBasedRenderer::initPasses() {
m_volumelightPass->initializePass( m_width, m_height, m_shaderProgramManager );
}
// Build the sequence of passes
/***
* Option - Render in wireframe
* Render all objects as wireframe
* Render in white over an existing depth buffer
*/
{
m_wireframePass = std::make_shared<WireframePass>(
&m_allRenderObjects, NodeBasedRendererPasses::WIREFRAME_PASS );
m_wireframePass->setResourcesDir( resourcesPath );
m_wireframePass->setInputs( *depthTexture );
m_wireframePass->setOutput( *colorTexture );
m_wireframePass->initializePass( m_width, m_height, m_shaderProgramManager );
}
// Build the sequence of active passes
m_renderPasses.emplace_back( m_clearPass );
m_clearPass->activate();
m_renderPasses.emplace_back( m_zPrePass );
m_zPrePass->activate();
m_renderPasses.emplace_back( m_aoPass );
m_aoPass->activate();
m_renderPasses.emplace_back( m_emissivityPass );
m_emissivityPass->activate();
m_renderPasses.emplace_back( m_envlightPass );
m_envlightPass->activate();
m_renderPasses.emplace_back( m_locallightPass );
m_locallightPass->activate();
m_renderPasses.emplace_back( m_transparencyPass );
m_transparencyPass->activate();
m_renderPasses.emplace_back( m_volumelightPass );
m_volumelightPass->activate();
m_renderPasses.emplace_back( m_wireframePass );
// Add intermediate textures to the texture explorer
for ( const auto& p : m_renderPasses )
......@@ -334,7 +359,7 @@ void NodeBasedRenderer::updateStepInternal( const ViewingParameters& renderData
// that one ca factorizes some evaluations.
for ( auto& rp : m_renderPasses )
{
rp->update();
if ( rp->isActive() ) { rp->update(); }
}
}
......@@ -346,61 +371,11 @@ void NodeBasedRenderer::renderInternal( const ViewingParameters& renderData ) {
}
// Run each pass, in order.
for ( const auto& rp : m_renderPasses )
{ rp->execute( renderData ); }
// ------------ to be removed from here to end function
#if 0
if ( m_wireframe )
{
// m_fbo->bind();
glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
glEnable( GL_LINE_SMOOTH );
glLineWidth( 1.f );
glEnable( GL_POLYGON_OFFSET_LINE );
glPolygonOffset( -1.0f, -1.1f );
// Light pass
GL_ASSERT( glDepthFunc( GL_LEQUAL ) );
GL_ASSERT( glEnable( GL_BLEND ) );
GL_ASSERT( glBlendFunc( GL_ONE, GL_ONE ) );
GL_ASSERT( glDrawBuffers( 1, buffers ) ); // Draw color texture
if ( m_lightmanagers[0]->count() > 0 )
{
// for ( const auto& l : m_lights )
for ( size_t i = 0; i < m_lightmanagers[0]->count(); ++i )
{
const auto l = m_lightmanagers[0]->getLight( i );
RenderParameters wireframepassParams;
l->getRenderParameters( wireframepassParams );
for ( const auto& ro : m_fancyRenderObjects )
{
ro->render( wireframepassParams, renderData, RenderTechnique::LIGHTING_OPAQUE );
}
// This will not work for the moment . skipping wireframe rendering of transparent
// objects
# if 0
for ( const auto& ro : m_transparentRenderObjects)
{
ro->render( wireframepassParams, viewingParameters, RenderTechnique::LIGHTING_OPAQUE );
}
# endif
}
if (rp->isActive()) {
rp->execute( renderData );
}
else
{ LOG( logINFO ) << "Wireframe : no light sources, unable to render"; }
glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
glDisable( GL_POLYGON_OFFSET_LINE );
}
// Restore state
GL_ASSERT( glDepthFunc( GL_LESS ) );
GL_ASSERT( glDisable( GL_BLEND ) );
m_fbo->unbind();
#endif
}
// Draw debug stuff, do not overwrite depth map but do depth testing
......@@ -530,6 +505,7 @@ void NodeBasedRenderer::setEnvMap( const std::string& files ) {
{
m_clearPass->setEnvMap( nullptr );
m_envlightPass->setEnvMap( nullptr );
m_envlightPass->deactivate();
m_volumelightPass->setEnvMap( nullptr );
m_hasEnvMap = false;
}
......@@ -548,6 +524,7 @@ void NodeBasedRenderer::setEnvMap( const std::string& files ) {
auto e = std::make_shared<EnvMap>( files, t, true );
m_clearPass->setEnvMap( e );
m_envlightPass->setEnvMap( e );
m_envlightPass->activate();
m_volumelightPass->setEnvMap( e );
m_hasEnvMap = true;
}
......@@ -578,4 +555,28 @@ void NodeBasedRenderer::setAoSamplingDensity( int d ) {
if ( m_aoPass ) { m_aoPass->setSampler( std::move( sphereSampler ) ); }
}
void NodeBasedRenderer::wireframeMode( bool status ) {
enableWireframe( status );
if ( m_wireframe ) {
m_wireframePass->activate();
m_aoPass->deactivate();
m_emissivityPass->deactivate();
m_envlightPass->deactivate();
m_locallightPass->deactivate();
m_transparencyPass->deactivate();
m_volumelightPass->deactivate();
} else {
m_wireframePass->deactivate();
m_aoPass->activate();
m_emissivityPass->activate();
m_envlightPass->activate();
m_locallightPass->activate();
m_transparencyPass->activate();
m_volumelightPass->activate();
}
}
} // namespace RadiumNBR
......@@ -22,6 +22,7 @@ class EnvLightPass;
class LocalLightPass;
class VolumeLightingPass;
class TransparencyPass;
class WireframePass;
/** Advanced renderer for the Radium Engine
* This class implements a forward rendering algorithm with Z-prepass, multipass light accumulation
......@@ -50,6 +51,7 @@ class NodeBasedRenderer_LIBRARY_API NodeBasedRenderer : public Ra::Engine::Rende
int getAoSamplingDensity() const;
void setAoSamplingDensity( int d );
void setEnvStrength( int s );
void wireframeMode( bool status );
protected:
void initializeInternal() override;
......@@ -88,6 +90,7 @@ class NodeBasedRenderer_LIBRARY_API NodeBasedRenderer : public Ra::Engine::Rende
EMISSIVITY_PASS,
LIGHTING_TRANSPARENT_PASS,
LIGHTING_VOLUME_PASS,
WIREFRAME_PASS,
NUM_PASSES
};
#endif
......@@ -138,8 +141,12 @@ class NodeBasedRenderer_LIBRARY_API NodeBasedRenderer : public Ra::Engine::Rende
/// The transparency (Order independant transparency) pass
std::shared_ptr<TransparencyPass> m_transparencyPass;
/// The transparency (Order independant transparency) pass
std::shared_ptr<WireframePass> m_wireframePass;
/// Is an envmap attached to the renderer
bool m_hasEnvMap{ false };
};
} // namespace RadiumNBR
......@@ -110,6 +110,9 @@ void EnvLightPass::execute( const Ra::Engine::Data::ViewingParameters& viewParam
for ( const auto& ro : *m_objectsToRender )
{ ro->render( m_passParams, viewParams, passIndex() ); }
// Beware of the state left by the pass
GL_ASSERT( glDisable( GL_BLEND ) );
}
bool EnvLightPass::buildRenderTechnique( const Ra::Engine::Rendering::RenderObject* ro,
......
#include <RadiumNBR/Passes/WireframePass.hpp>
#ifdef PASSES_LOG
# include <Core/Utils/Log.hpp>
using namespace Ra::Core::Utils; // log
#endif
#include <Engine/Data/Material.hpp>
#include <Engine/Data/ShaderConfigFactory.hpp>
#include <Engine/Data/ShaderProgramManager.hpp>
#include <Engine/Data/Texture.hpp>
#include <Engine/Rendering/RenderObject.hpp>
#include <globjects/Framebuffer.h>
#ifdef ADVANCED_WIREFRAME
#include <Engine/Data/Mesh.hpp>
#include <Engine/Data/ViewingParameters.hpp>
#endif
namespace RadiumNBR {
using namespace gl;
static const GLenum buffers[] = { GL_COLOR_ATTACHMENT0 };
WireframePass::WireframePass( const std::vector<RenderObjectPtr>* objectsToRender,
const Ra::Core::Utils::Index& idx ) :
RenderPass( "Wireframe pass", idx, objectsToRender ) {}
WireframePass::~WireframePass() = default;
bool WireframePass::initializePass( size_t /* width */,
size_t /* height */,
Ra::Engine::Data::ShaderProgramManager* shaderMngr ) {
m_shaderMngr = shaderMngr;
m_fbo = std::make_unique<globjects::Framebuffer>();
return true;
}
void WireframePass::setInputs( const SharedTextures& depthBuffer ) {
addImportedTextures( { "WireframePass::Depth", depthBuffer.second } );
}
void WireframePass::setOutput( const SharedTextures& colorBuffer ) {
m_outputTexture = colorBuffer;
}
bool WireframePass::update() {
#ifdef ADVANCED_WIREFRAME
// build the wireframe representation of all drawn objects
m_wireframes.clear();
for ( const auto& ro : *m_objectsToRender )
{
std::shared_ptr<Ra::Engine::Data::LineMesh> disp;
using trimesh = Ra::Engine::Data::IndexedGeometry<Ra::Core::Geometry::TriangleMesh>;
using polymesh = Ra::Engine::Data::IndexedGeometry<Ra::Core::Geometry::PolyMesh>;
auto displayable = ro->getMesh();
auto tm = std::dynamic_pointer_cast<trimesh>( displayable );
auto tp = std::dynamic_pointer_cast<polymesh>( displayable );
bool drawable;
Ra::Core::Geometry::LineMesh lines;
Ra::Core::Geometry::LineMesh::IndexContainerType indices;
if ( tm )
{
drawable = tm->getRenderMode() ==
Ra::Engine::Data::AttribArrayDisplayable::MeshRenderMode::RM_TRIANGLES;
if ( drawable )
{
lines.setVertices( tm->getCoreGeometry().vertices() );
for ( const auto& index : tm->getCoreGeometry().getIndices() )
{
for ( unsigned int i = 0; i < 3; ++i )
{
int i1 = index[i];
int i2 = index[( i + 1 ) % 3];
if ( i1 > i2 ) std::swap( i1, i2 );
indices.emplace_back( i1, i2 );
}
}
}
}
if ( tp )
{
drawable = tp->getRenderMode() ==
Ra::Engine::Data::AttribArrayDisplayable::MeshRenderMode::RM_TRIANGLES;
if ( drawable )
{
drawable = tp->getRenderMode() ==
Ra::Engine::Data::AttribArrayDisplayable::MeshRenderMode::RM_TRIANGLES;
lines.setVertices( tp->getCoreGeometry().vertices() );
for ( const auto& index : tp->getCoreGeometry().getIndices() )
{
auto s = index.size();
for ( unsigned int i = 0; i < s; ++i )
{
int i1 = index[i];
int i2 = index[( i + 1 ) % s];
if ( i1 > i2 ) std::swap( i1, i2 );
indices.emplace_back( i1, i2 );
}
}
}
}
if ( drawable )
{
std::sort( indices.begin(),
indices.end(),
[]( const Ra::Core::Geometry::LineMesh::IndexType& a,
const Ra::Core::Geometry::LineMesh::IndexType& b ) {
return a[0] < b[0] || ( a[0] == b[0] && a[1] < b[1] );
} );
indices.erase( std::unique( indices.begin(), indices.end() ), indices.end() );
lines.setIndices( std::move( indices ) );
disp = std::make_shared<Ra::Engine::Data::LineMesh>( std::string( "wireframe" ),
std::move( lines ) );
disp->updateGL();
m_wireframes[ro.get()] = disp;
}
else
{
disp.reset();
m_wireframes[ro.get()] = { nullptr };
}
}
#endif
return true;
}
void WireframePass::resize( size_t width, size_t height ) {
#ifdef ADVANCED_WIREFRAME
m_width = width;
m_height = height;
#endif
// Only resize the owned textures. Imported one are resized by their owner
for ( auto& t : m_localTextures )
{
t.second->resize( width, height );
}
for ( auto& t : m_sharedTextures )
{
t.second->resize( width, height );
}
m_fbo->bind();
m_fbo->attachTexture( GL_DEPTH_ATTACHMENT, m_importedTextures["WireframePass::Depth"]->texture() );
m_fbo->attachTexture( GL_COLOR_ATTACHMENT0, m_outputTexture.second->texture() );
#ifdef PASSES_LOG
if ( m_fbo->checkStatus() != GL_FRAMEBUFFER_COMPLETE )
{ LOG( logERROR ) << "FBO Error (EmissivityPass::resize): " << m_fbo->checkStatus(); }
#endif
// finished with fbo, undbind to bind default
globjects::Framebuffer::unbind();
}
void WireframePass::execute( const Ra::Engine::Data::ViewingParameters& viewParams ) const {
m_fbo->bind();
// only draw into 1 buffers (Color)
GL_ASSERT( glDrawBuffers( 1, buffers ) );
GL_ASSERT( glDepthMask( GL_FALSE ) );
GL_ASSERT( glColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE ) );
GL_ASSERT( glEnable( GL_DEPTH_TEST ) );
GL_ASSERT( glDepthFunc( GL_LEQUAL ) );
GL_ASSERT( glEnable( GL_BLEND ) );
#ifdef ADVANCED_WIREFRAME_SHADER
glBlendEquationSeparate( GL_FUNC_ADD, GL_FUNC_ADD );
glBlendFuncSeparate( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ZERO );
glPolygonOffset( -4.f, -2.f );
glEnable( GL_POLYGON_OFFSET_FILL );
//glDisable( GL_POLYGON_OFFSET_FILL );
#else
GL_ASSERT( glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ) );
glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
glEnable( GL_LINE_SMOOTH );
glLineWidth( 1.f );
glEnable( GL_POLYGON_OFFSET_LINE );
glPolygonOffset( 1.1f, 3.0f );
#endif
for ( const auto& ro : *m_objectsToRender )
{
#ifdef ADVANCED_WIREFRAME
auto it = m_wireframes.find( ro.get() );
if ( it != m_wireframes.end() ) {
auto wro = it->second;
auto shader = m_shaderMngr->getShaderProgram( "WireframePass::WireframeProgram" );
if ( wro && shader ) {
shader->bind();
Ra::Core::Matrix4 modelMatrix = ro->getTransformAsMatrix();
shader->setUniform( "transform.proj", viewParams.projMatrix );
shader->setUniform( "transform.view", viewParams.viewMatrix );
shader->setUniform( "transform.model", modelMatrix );
shader->setUniform( "viewport", Ra::Core::Vector2 {m_width, m_height} );
wro->render( shader );
GL_CHECK_ERROR;
}
}
#else
ro->render( m_passParams, viewParams, passIndex() );
#endif
}
#ifdef ADVANCED_WIREFRAME_SHADER
glDisable( GL_POLYGON_OFFSET_FILL );
#else
glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
glDisable( GL_POLYGON_OFFSET_LINE );
#endif
GL_ASSERT( glDisable( GL_BLEND ) );
}
bool WireframePass::buildRenderTechnique( const Ra::Engine::Rendering::RenderObject* ro,
Ra::Engine::Rendering::RenderTechnique& rt ) {
std::string resourcesRootDir = getResourcesDir();
auto mat = const_cast<Ra::Engine::Rendering::RenderObject*>( ro )->getMaterial();
// Volumes are not used in WireframePass
if ( mat->getMaterialAspect() == Ra::Engine::Data::Material::MaterialAspect::MAT_DENSITY )
{ return false; }
if ( auto cfg = Ra::Engine::Data::ShaderConfigurationFactory::getConfiguration(
{ "WireframePass::WireframeProgram" } ) )
{ rt.setConfiguration( *cfg, passIndex() ); }
else
{
#ifdef ADVANCED_WIREFRAME_SHADER
Ra::Engine::Data::ShaderConfiguration theConfig{
{ "WireframePass::WireframeProgram" },
resourcesRootDir + "Shaders/WireframePass/Advanced/wireframe.vert.glsl",
resourcesRootDir + "Shaders/WireframePass/Advanced/wireframe.frag.glsl" };
theConfig.addShader(Ra::Engine::Data::ShaderType_GEOMETRY,
resourcesRootDir + "Shaders/WireframePass/Advanced/wireframe.geom.glsl");
#else
// Build the shader configuration
Ra::Engine::Data::ShaderConfiguration theConfig{
{ "WireframePass::WireframeProgram" },
resourcesRootDir + "Shaders/WireframePass/Basic/wireframepass.vert.glsl",
resourcesRootDir + "Shaders/WireframePass/Basic/wireframepass.frag.glsl" };
#endif
// Add to the ShaderConfigManager
Ra::Engine::Data::ShaderConfigurationFactory::addConfiguration( theConfig );
// Add to the RenderTechnique
rt.setConfiguration( theConfig, passIndex() );
}
rt.setParametersProvider( mat, passIndex() );
return true;
}
} // namespace RadiumNBR
#pragma once
#include <RadiumNBR/RenderPass.hpp>
#include <Core/Utils/Color.hpp>
#define ADVANCED_WIREFRAME
#define ADVANCED_WIREFRAME_SHADER
#ifdef ADVANCED_WIREFRAME
#include <Engine/Data/DisplayableObject.hpp>
#endif
namespace Ra::Engine::Data {
class ShaderProgram;
} // namespace Ra::Engine::Data
namespace globjects {
class Framebuffer;
}
namespace RadiumNBR {
/// Render pass that draws objects as wireframe over an existing framebuffer
class WireframePass : public RenderPass
{
public:
WireframePass( const std::vector<RenderObjectPtr>* objectsToRender,
const Ra::Core::Utils::Index& idx );
~WireframePass() override;
bool buildRenderTechnique( const Ra::Engine::Rendering::RenderObject* ro,
Ra::Engine::Rendering::RenderTechnique& rt ) override;
bool initializePass( size_t width,
size_t height,
Ra::Engine::Data::ShaderProgramManager* shaderMngr ) override;
bool update() override;
void resize( size_t width, size_t height ) override;
void execute( const Ra::Engine::Data::ViewingParameters& viewParams ) const override;
/// Add the output colorBuffer
void setOutput( const SharedTextures& colorBuffer );
/// These inputs must be computed before executing this pass : depth buffer
void setInputs( const SharedTextures& depthBuffer );
private:
/// The framebuffer used to render this pass
std::unique_ptr<globjects::Framebuffer> m_fbo{ nullptr };
/// The Shader manager to use when building shaders
Ra::Engine::Data::ShaderProgramManager* m_shaderMngr{ nullptr };
/// The color texture for output.Stored here for easy access.
SharedTextures m_outputTexture;
#ifdef ADVANCED_WIREFRAME
using WireMap = std::map<Ra::Engine::Rendering::RenderObject*, std::shared_ptr<Ra::Engine::Data::Displayable>>;
WireMap m_wireframes;
bool m_wireframeAa {true};
Ra::Core::Utils::Color m_wireframeColor {Ra::Core::Utils::Color::White()};
uint m_width {0};
uint m_height {0};
#endif
};
} // namespace RadiumNBR
......@@ -115,6 +115,15 @@ class NodeBasedRenderer_LIBRARY_API RenderPass
/// Return the index of the current pass in the renderer
[[nodiscard]] inline const Ra::Core::Utils::Index& passIndex() const { return m_idx; }
/// activate the pass
inline void activate() { m_active = true; }
/// deactivate the pass
inline void deactivate() { m_active = false; }
// is the pass active ?
[[nodiscard]] inline bool isActive() { return m_active; }
/// @todo : Having protected member is a bad idea
/// @see https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#c133-avoid-protected-data
protected:
......@@ -142,5 +151,7 @@ class NodeBasedRenderer_LIBRARY_API RenderPass
/// The base resources directory
std::string resourceDir{ "./" };
bool m_active{false};
};
} // namespace RadiumNBR
in vec4 gColor;
out vec4 fragColor;
in float pixelWidthDiv2;
const float PI = 3.1415926535897932384626433832795;
// AA is one pixel wide after pixelWidth of fully filled.
float aa( in float dist ) {
float R = sqrt( 2. * .5 * .5 );
float s = sign( dist );
float d = max( min( dist - pixelWidthDiv2 + s * R, R ), -R );
float theta = 2. * acos( max( min( d / R, 1. ), -1 ) );
return clamp( R * R / 2. * ( theta - sin( theta ) ) / ( R * R * PI ), 0., 1. );
}
void main() {
float a = aa( gColor.a ) * aa( -gColor.a );
fragColor = vec4( vec3( .8, .9, 1. ), a );
}
layout( lines ) in;
layout( triangle_strip, max_vertices = 4 ) out;
in gl_PerVertex {
vec4 gl_Position;
float gl_PointSize;
float gl_ClipDistance[];
}
gl_in[];
out gl_PerVertex {
vec4 gl_Position;
float gl_PointSize;
float gl_ClipDistance[];
};
in vec4 vPosition[2];
// in vec4 vColor[2];
out vec4 gColor;
out float pixelWidthDiv2;
uniform vec2 viewport;
vec4 vColor[2];
void main() {
vec3 vp = vec3( viewport, 1. );
// clip space
vec4 css0 = gl_in[0].gl_Position;
vec4 css1 = gl_in[1].gl_Position;
// coherent clip space
vec4 scss0 = css0 * css1.w;
vec4 scss1 = css1 * css0.w;
vec3 dir = ( scss1 - scss0 ).xyz;
float pixelWidth = 1.8;
const float border = 4.;
vec3 slope = normalize( vec3( -dir.y, dir.x, 0 ) );
vec4 n = vec4( vec3( pixelWidth + border ) / vp * slope, 0 );
vec4 a = vec4( ( scss0 + n * scss0.w ) );
vec4 b = vec4( ( scss0 - n * scss0.w ) );
vec4 c = vec4( ( scss1 + n * scss0.w ) );
vec4 d = vec4( ( scss1 - n * scss0.w ) );
pixelWidthDiv2 = pixelWidth / 2.;
vColor[0] = vec4( vec3( .7 ), -pixelWidthDiv2 - border / 2. );
vColor[1] = vec4( vec3( .7 ), +pixelWidthDiv2 + border / 2. );
gColor = vColor[0];
gl_Position = a;
EmitVertex();
gColor = vColor[1];
gl_Position = b;
EmitVertex();
gColor = vColor[0];
gl_Position = c;
EmitVertex();
gColor = vColor[1];
gl_Position = d;
EmitVertex();
EndPrimitive();
}
#include "TransformStructs.glsl"
layout( location = 0 ) in vec3 in_position;
out vec4 vPosition;
uniform Transform transform;
void main() {
mat4 mvp = transform.proj * transform.view * transform.model;
vec4 pos = mvp * vec4( in_position.xyz, 1.0 );
gl_Position = pos;
vPosition = pos;
}
out vec4 fragColor;
void main() {
fragColor = vec4( vec3( .5, .6, .7 ), .5 );
}
#include "TransformStructs.glsl"
layout( location = 0 ) in vec3 in_position;
uniform Transform transform;
void main() {
mat4 mvp = transform.proj * transform.view * transform.model;
vec4 pos = mvp * vec4( in_position.xyz, 1.0 );
gl_Position = pos;
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment