球是学习光照的很好参照物,也是因为如此上一篇更新了一个球的文章。这章利用上一章的成果,学习opengl中的各种光照效果以及在每片元渲染。本章主要介绍在qt中如何实现这些,将这些效果集成到qt的开发生态里面
先看一下效果
主框架和上一篇的球一样,不一样的是shader部分,两个球的示例工程cpp部分有一些变化,窗体、渲染器的声明与实现与前除了定向光与每片元渲染,其余是一样的,以散向光为例,如下;
#ifndef WIDGET_H
#define WIDGET_H
#include <QOpenGLWidget>
#include "diffuserender.h"
class Widget : public QOpenGLWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = 0);
~Widget();
protected:
void initializeGL() override;
void paintGL() override;
void resizeGL(int w, int h) override;
void wheelEvent(QWheelEvent *event) override;
private:
DiffuseRender m_render;
QMatrix4x4 m_proMatrix,m_modelMatrix;
QVector3D m_eye,m_center,m_lightLocation;
};
#endif // WIDGET_H
#include "widget.h"
#include <QWheelEvent>
Widget::Widget(QWidget *parent)
: QOpenGLWidget(parent),
m_eye(0,0,2),
m_center(0,0,-1),
m_lightLocation(2,1,1)
{
}
Widget::~Widget()
{
}
void Widget::initializeGL()
{
m_render.initialize(0.8);
}
void Widget::paintGL()
{
QOpenGLExtraFunctions *f = QOpenGLContext::currentContext()->extraFunctions();
f->glClearColor(0.0, 0.0, 0.0, 0.0);
f->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
m_modelMatrix.rotate(30,0,1,0);
QMatrix4x4 camera;
camera.lookAt(m_eye,m_center,QVector3D{0,1,2});
m_render.render(f,m_proMatrix,camera,m_modelMatrix,m_lightLocation);
}
void Widget::resizeGL(int w, int h)
{
m_proMatrix.setToIdentity();
m_proMatrix.perspective(45,float(w)/h,0.01f,100.0f);
}
void Widget::wheelEvent(QWheelEvent *event)
{
if (! event->pixelDelta().isNull()) {
m_eye.setZ(m_eye.z() + event->pixelDelta().y()); //重置视点z值
} else if (!event->angleDelta().isNull()) {
m_eye.setZ(m_eye.z() + (event->angleDelta() / 120).y()); //重置视点z值
}
event->accept();
update();
}
渲染器部分
#ifndef DIFFUSERENDER_H
#define DIFFUSERENDER_H
#include <QOpenGLExtraFunctions>
#include <QOpenGLShaderProgram>
#include <QOpenGLBuffer>
#define PI 3.14159265f
class DiffuseRender
{
public:
DiffuseRender() = default;
void initialize(float r);
void render(QOpenGLExtraFunctions *f,QMatrix4x4 &projM,QMatrix4x4 & camera,QMatrix4x4 &model,QVector3D &lightLocation);
private:
QOpenGLShaderProgram m_program;
QOpenGLBuffer m_vbo;
QVector<GLfloat> m_points;
float m_r;
};
#endif // DIFFUSERENDER_H
#include "diffuserender.h"
void DiffuseRender::initialize(float r)
{
m_program.addCacheableShaderFromSourceFile(QOpenGLShader::Vertex,"vsrc.vsh");
m_program.addCacheableShaderFromSourceFile(QOpenGLShader::Fragment,"fsrc.fsh");
m_program.link();
m_r = r;
int angleSpan = 10; //弧度 = 角度 * PI / 180
for(int vAngle = -90; vAngle < 90; vAngle = vAngle + angleSpan){ //生成球面顶点
for(int hAngle = 0; hAngle <= 360; hAngle = hAngle + angleSpan){
float x0 = r * ::cos(vAngle * PI / 180) * ::cos(hAngle * PI / 180);
float y0 = r * ::cos(vAngle * PI / 180) * ::sin(hAngle * PI / 180);
float z0 = r * ::sin(vAngle * PI / 180);
float x1 = r * ::cos(vAngle * PI / 180) * ::cos((hAngle + angleSpan) * PI / 180);
float y1 = r * ::cos(vAngle * PI / 180) * ::sin((hAngle + angleSpan) * PI / 180);
float z1 = r * ::sin(vAngle * PI / 180);
float x2 = r * ::cos((vAngle + angleSpan) * PI / 180) * ::cos((hAngle + angleSpan) * PI / 180);
float y2 = r * ::cos((vAngle + angleSpan) * PI / 180) * ::sin((hAngle + angleSpan) * PI / 180);
float z2 = r * ::sin((vAngle + angleSpan) * PI / 180);
float x3 = r * ::cos((vAngle + angleSpan) * PI / 180) * ::cos(hAngle * PI / 180);
float y3 = r * ::cos((vAngle + angleSpan) * PI / 180) * ::sin(hAngle * PI / 180);
float z3 = r * ::sin((vAngle + angleSpan) * PI / 180);
m_points << x1 << y1 << z1 << x3 << y3 << z3
<< x0 << y0 << z0 << x1 << y1 << z1
<< x2 << y2 << z2 << x3 << y3 << z3;
}
}
m_vbo.create();
m_vbo.bind();
m_vbo.allocate(m_points.constData(),m_points.count() * sizeof GLfloat);
}
void DiffuseRender::render(QOpenGLExtraFunctions *f, QMatrix4x4 &projM, QMatrix4x4 &camera, QMatrix4x4 &model, QVector3D &lightLocation)
{
f->glEnable(GL_DEPTH_TEST);
f->glEnable(GL_CULL_FACE);
m_program.bind();
m_vbo.bind();
m_program.setUniformValue("uPMatrix",projM);
m_program.setUniformValue("camMatrix",camera);
m_program.setUniformValue("uMMatrix",model);
m_program.setUniformValue("uR",m_r);
m_program.setUniformValue("uLightLocation",lightLocation);
m_program.enableAttributeArray(0);
m_program.enableAttributeArray(1);
m_program.setAttributeBuffer(0,GL_FLOAT,0,3,0);
m_program.setAttributeBuffer(1,GL_FLOAT,0,3,0);
f->glDrawArrays(GL_TRIANGLES,0,m_points.count() / 3);
m_program.disableAttributeArray(0);
m_program.disableAttributeArray(1);
m_vbo.release();
m_program.release();
f->glDisable(GL_DEPTH_TEST);
f->glDisable(GL_CULL_FACE);
}
shader部分就不一样了,
环境光的shader如下
#version 330
uniform mat4 uPMatrix,camMatrix,uMMatrix;
layout (location = 0) in vec3 aPosition;
smooth out vec3 vPosition;
smooth out vec4 vambient;
void main(void)
{
gl_Position = uPMatrix * camMatrix *uMMatrix * vec4(aPosition,1);
vPosition = aPosition;
vambient = vec4(0.30,0.30,0.15,1.0);
}
#version 330
uniform float uR;
in vec3 vPosition;
in vec4 vambient;
out vec4 fragColor;
void main(void)
{
vec3 color;
float n = 8.0;
float span = 2.0 * uR / n;
int i = int((vPosition.x + uR) / span);
int j = int((vPosition.y + uR) / span);
int k = int((vPosition.z + uR) / span);
int whichColor = int(mod(float(i+j+k),2.0));
if(whichColor == 1){
color = vec3(0.678,0.231,0.129);
}else{
color = vec3(1.0,1.0,1.0);
}
fragColor = vec4(color,0) * vambient;
}
散射光shader如下
#version 330
uniform mat4 uPMatrix,camMatrix,uMMatrix;
uniform vec3 uLightLocation;
layout (location = 0) in vec3 aPosition;
layout (location = 1) in vec3 aNormal;
smooth out vec3 vPosition;
smooth out vec4 vdiffuse;
void pointLight(in vec3 normal,inout vec4 diffuse,in vec4 lightDiffuse){
vec3 normalTarget = aPosition + normal;
vec3 newNormal = normalize((uMMatrix * vec4(normalTarget, 1)).xyz -(uMMatrix * vec4(aPosition,1)).xyz);
vec3 vp = normalize(uLightLocation - (uMMatrix * vec4(aPosition,1)).xyz);
float nDotViewPosition = max(0.0,dot(newNormal,vp));
diffuse = lightDiffuse * nDotViewPosition;
}
void main(void)
{
gl_Position = uPMatrix * camMatrix *uMMatrix * vec4(aPosition,1);
vec4 diffuseTemp = vec4(0.0,0.0,0.0,0.0);
pointLight(aNormal,diffuseTemp,vec4(0.8,0.8,0.8,1.0));
vdiffuse = diffuseTemp;
vPosition = aPosition;
}
#version 330
uniform float uR;
in vec3 vPosition;
in vec4 vambient;
in vec4 vdiffuse;
out vec4 fragColor;
void main(void)
{
vec3 color;
float n = 8.0;
float span = 2.0 * uR / n;
int i = int((vPosition.x + uR) / span);
int j = int((vPosition.y + uR) / span);
int k = int((vPosition.z + uR) / span);
int whichColor = int(mod(float(i+j+k),2.0));
if(whichColor == 1){
color = vec3(0.678,0.231,0.129);
}else{
color = vec3(1.0,1.0,1.0);
}
fragColor = vec4(color,0) * vdiffuse;
}
高光的shader如下
#version 330
uniform float uR;
in vec3 vPosition;
in vec4 vambient;
in vec4 vdiffuse;
out vec4 fragColor;
void main(void)
{
vec3 color;
float n = 8.0;
float span = 2.0 * uR / n;
int i = int((vPosition.x + uR) / span);
int j = int((vPosition.y + uR) / span);
int k = int((vPosition.z + uR) / span);
int whichColor = int(mod(float(i+j+k),2.0));
if(whichColor == 1){
color = vec3(0.678,0.231,0.129);
}else{
color = vec3(1.0,1.0,1.0);
}
fragColor = vec4(color,0) * vdiffuse;
}
#version 330
uniform float uR;
in vec3 vPosition;
in vec3 vSpecular;
out vec4 fragColor;
void main(void)
{
vec3 color;
float n = 8.0;
float span = 2.0 * uR / n;
int i = int((vPosition.x + uR) / span);
int j = int((vPosition.y + uR) / span);
int k = int((vPosition.z + uR) / span);
int whichColor = int(mod(float(i+j+k),2.0));
if(whichColor == 1){
color = vec3(0.678,0.231,0.129);
}else{
color = vec3(1.0,1.0,1.0);
}
fragColor = vec4(color,1.0) * vec4(vSpecular,1.0);
}
混合光的shader如下
#version 330
uniform mat4 uPMatrix,uVMatrix,uMMatrix;
uniform vec3 uCamera,uLightLocation;
layout (location = 0) in vec3 aPosition;
layout (location = 1) in vec3 aNormal;
smooth out vec3 vPosition;
smooth out vec4 vAmbient,vDiffuse,vSpecular;
void pointLight(in vec3 normal,inout vec4 ambient,inout vec4 diffuse,inout vec4 specular,in vec4 lightAmbient,in vec4 lightDiffuse,in vec4 lightSpecular,in float shininess){
ambient = lightAmbient;
vec3 normalTarget = aPosition + normal;
vec3 newNormal = normalize((uMMatrix * vec4(normalTarget,1)).xyz - (uMMatrix * vec4(aPosition,1)).xyz);
vec3 eye = normalize(uCamera - (uMMatrix * vec4(aPosition,1)).xyz);
vec3 vp = normalize(uLightLocation - (uMMatrix * vec4(aPosition,1)).xyz);
vec3 halfVector = normalize(eye + vp);
float nDotViewPotision = max(0.0,dot(newNormal,vp));
diffuse = lightDiffuse * nDotViewPotision;
float nDotViewHalfVector = dot(newNormal,halfVector);
float powerFactor = max(0.0,pow(nDotViewHalfVector,shininess));
specular = lightSpecular * powerFactor;
}
void main(void)
{
gl_Position = uPMatrix * uVMatrix * uMMatrix * vec4(aPosition,1);
vec4 ambient = vec4(0.0,0.0,0.0,0.0),diffuse = vec4(0.0,0.0,0.0,0.0),specular = vec4(0.0,0.0,0.0,0.0);
pointLight(aNormal,ambient,diffuse,specular,vec4(0.15,0.15,0.15,1),vec4(0.8,0.8,0.8,1),vec4(0.7,0.7,0.7,1),50.0);
vPosition = aPosition;
vAmbient = ambient;
vDiffuse = diffuse;
vSpecular = specular;
}
#version 330
uniform float uR;
in vec3 vPosition;
in vec4 vAmbient,vDiffuse,vSpecular;
out vec4 fragColor;
void main(void)
{
vec3 color;
float n = 8.0;
float span = 2.0 * uR / n;
int i = int((vPosition.x + uR) / span);
int j = int((vPosition.y + uR) / span);
int k = int((vPosition.z + uR) / span);
int whichColor = int(mod(float(i+j+k),2.0));
if(whichColor == 1){
color = vec3(0.678,0.231,0.129);
}else{
color = vec3(1.0,1.0,1.0);
}
fragColor = vec4(color,1.0) * (vAmbient + vDiffuse + vSpecular);
}
光照的计算工式就不说了,网上一搜一大把。
gitlab地址为
https://gitlab.com/gitHubwhl562916378/ambient.git
https://gitlab.com/gitHubwhl562916378/diffuse.git
https://gitlab.com/gitHubwhl562916378/specular.git