[OpenGL] 练习:简单的物体描边效果

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/ZJU_fish1996/article/details/82919098

开发环境:Qt, OpenGL

        主要是为了练习glsl写的一个小例子,本身没有什么难度。

        思路一:进行两次绘制。在顶点着色器中,第一次只绘制背面,将顶点沿着法线方向进行移动,可以使物体"膨胀"起来,使用描边的纯色填充,第一次渲出来的图像就是一个稍大一点的纯色物体。第二次正常绘制正面,此时尚未进行清屏,所以第二次绘制结果会叠加在第一次的结果上。

        按照这一思路实现效果后,发现一个比较严重的缺陷,面与面之间法线差值较大的时候,会在顶点处产生缝隙,对于像正方体这样棱角比较分明的物体特别明显,所以之后又采用了第二种方法。

        思路二:进行两次绘制。在顶点着色器中,第一次先沿视线方向,将物体靠近摄像机,然后再转换到投影空间,使用描边的纯色填充。第二次正常绘制正面。

        如上图,第二种思路下,缝隙的现象已经好了不少,只是边的粗细在有些角度下有点不一致。

以下代码为沿法线膨胀的部分:

void MainWidget::initializeGL()
{
    initializeOpenGLFunctions();

    glClearColor(0, 0, 0, 1);

    glEnable(GL_DEPTH_TEST);
    glEnable(GL_CULL_FACE);

    QOpenGLShader* stroke_v_pass0 = new QOpenGLShader(QOpenGLShader::Vertex);
    QOpenGLShader* stroke_v_pass1 = new QOpenGLShader(QOpenGLShader::Vertex);
    QOpenGLShader* stroke_f = new QOpenGLShader(QOpenGLShader::Fragment);

    stroke_v_pass0->compileSourceFile(":/stroke_v_pass0.glsl");
    stroke_v_pass1->compileSourceFile(":/stroke_v_pass1.glsl");
    stroke_f->compileSourceFile(":/stroke_f_pass0.glsl");

    program.addShader(stroke_v_pass0);
    program.addShader(stroke_f);
    program.link();

    program2.addShader(stroke_v_pass1);
    program2.addShader(stroke_f);
    program2.link();

    geometries = new GeometryEngine;

    timer.start(12, this);
}

void MainWidget::resizeGL(int w, int h)
{
    float aspect = float(w) / float(h ? h : 1);
    const qreal zNear = 1.0, zFar = 10.0, fov = 45.0;
    projection.setToIdentity();
    projection.perspective(fov, aspect, zNear, zFar);
}

void MainWidget::paintGL()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    QVector3D trans(0,0, -7.0);

    QMatrix4x4 mvMatrix;
    mvMatrix.translate(trans);
    mvMatrix.rotate(rotation);

    glCullFace(GL_FRONT);

    program.bind();

    QMatrix4x4 IT_mvMatrix;
    IT_mvMatrix = mvMatrix.transposed();
    IT_mvMatrix = IT_mvMatrix.inverted();
    program.setUniformValue("ModelViewMatrix", mvMatrix);
    program.setUniformValue("IT_ModelViewMatrix", IT_mvMatrix);
    program.setUniformValue("ProjectMatrix", projection);

    QVector3D strokeColor = {1.0f,0.0f,0.0f};
    program.setUniformValue("strokeColor", strokeColor);

    geometries->drawCubeGeometry(&program);

    glCullFace(GL_BACK);

    program.release();
    program2.bind();
    program2.setUniformValue("ModelViewMatrix", mvMatrix);
    program.setUniformValue("IT_ModelViewMatrix", IT_mvMatrix);
    program2.setUniformValue("ProjectMatrix", projection);

    QVector3D ambient = {0.2f,0.2f,0.2f};
    program2.setUniformValue("ambient", ambient);

    QVector3D LightLocation = {10.0f,9.0f,8.0f};
    program2.setUniformValue("lightLocation", LightLocation);

    QVector3D DiffuseColor = {0.8f,0.8f,0.8f};
    program2.setUniformValue("diffuseColor", DiffuseColor);

    QVector3D LightColor = {0.8f,0.8f,1.0f};
    program2.setUniformValue("lightColor", LightColor);

    geometries->drawCubeGeometry(&program2);
}
// stroke_v_pass0.glsl

#ifdef GL_ES
// Set default precision to medium
precision mediump int;
precision mediump float;
#endif

uniform mat4 ModelViewMatrix;
uniform mat4 IT_ModelViewMatrix;
uniform mat4 ProjectMatrix;

uniform vec3 strokeColor;

attribute vec4 a_position;
attribute vec3 a_normal;

varying vec3 v_color;

void main()
{
    vec3 normal = mat3(IT_ModelViewMatrix) * a_normal;
    gl_Position = ModelViewMatrix * a_position;
    gl_Position = ProjectMatrix * (gl_Position  + normalize(vec4(normal, 0)) * 0.1);
    v_color = strokeColor;
}
#ifdef GL_ES
// Set default precision to medium
precision mediump int;
precision mediump float;
#endif

uniform mat4 ProjectMatrix;
uniform mat4 ModelViewMatrix;
uniform mat4 IT_ModelViewMatrix;

uniform vec3 ambient;
uniform vec3 lightLocation;
uniform vec3 diffuseColor;
uniform vec3 lightColor;

attribute vec4 a_position;
attribute vec3 a_normal;

varying vec3 v_color;

void main()
{
    vec3 worldLightDir = normalize(lightLocation);
    vec3 worldNormal = normalize(mat3(IT_ModelViewMatrix) * a_normal);
    vec3 diffuse = diffuseColor * clamp(dot(worldNormal, worldLightDir),0.0,1.0);

    gl_Position = ProjectMatrix * ModelViewMatrix * a_position;
    v_color = diffuse + ambient;
}
// stroke_f_pass0.glsl

#ifdef GL_ES
// Set default precision to medium
precision mediump int;
precision mediump float;
#endif

varying vec3 v_color;

void main()
{
    gl_FragColor = vec4(v_color, 1.0f);
}

猜你喜欢

转载自blog.csdn.net/ZJU_fish1996/article/details/82919098