阴影映射(Shadow Map)的研究(五)
我成功地将别人的例子加以改进,使用QOpenGLWidget作为渲染窗口,将阴影映射渲染了出来。目前可以确定的是,使用OpenGL ES 2.0作为渲染的接口要求,能够让目前绝大多数机器都能够顺利兼容,但是囿于渲染窗口,可能在某些平台上表现不好。如果移植到Qt Quick 2,这样能够支持的平台就更多了。现在我将这些接口统统使用Qt的方式实现了,移植到Qt Quick 2也很简单。
这里主要参考的是OpenGLUnderQML这个例子,自定义了一个QQuickItem的子类,使其作为渲染的视图。紧接着,定义了多个TexturedCube,指定相关属性,并且使用专用的TexturedCubeRenderer负责渲染,最后将这些类导出至QML环境中。这样就可以使用QML来编写场景了。这种方法,在Qt 3D中广泛使用,它也将成为我以后开发3D应用的脚本描述方式。例子与上一个例子的显示差别并不大,目前只实现了阴影映射这个功能,有感兴趣的同行们可以使用这个例子进行扩展,实现自己想要的效果。
作为参考范例,贴出Cube类的代码:
Cube.h
#ifndef MYCUBE_H
#define MYCUBE_H
#include <QUrl>
#include <QVector3D>
#include <QObject>
class View;
class CubeRenderer;
class Cube: public QObject
{
Q_OBJECT
Q_PROPERTY( qreal length READ length WRITE setLength NOTIFY lengthChanged )
Q_PROPERTY( QUrl source READ source WRITE setSource NOTIFY sourceChanged )
Q_PROPERTY( QVector3D translate READ translate WRITE setTranslate NOTIFY translateChanged )
public:
explicit Cube( QObject* parent = Q_NULLPTR );
void initialize( void );
void render( void );
void renderShadow( void );
void sync( void );
void release( void );
void setView( View* view ) { m_view = view; }
qreal length( void ) { return m_length; }
void setLength( qreal length );
QUrl source( void ) { return m_source; }
void setSource( const QUrl& source );
QVector3D translate( void ) { return m_translate; }
void setTranslate( const QVector3D& translate );
friend class CubeRenderer;
signals:
void lengthChanged( void );
void sourceChanged( void );
void translateChanged( void );
protected:
qreal m_length;
QUrl m_source;
QVector3D m_translate;
bool m_lengthIsDirty: 1;
bool m_sourceIsDirty: 1;
bool m_translateIsDirty: 1;
View* m_view;
CubeRenderer* m_renderer;
};
#endif // MYCUBE_H
Cube.cpp
#include <math.h>
#include <QOpenGLFunctions>
#include <QOpenGLBuffer>
#include <QOpenGLShaderProgram>
#include <QOpenGLTexture>
#include <QQmlFile>
#include "View.h"
#include "Cube.h"
#define VERTEX_COUNT 36
#define CUBE_LENGTH 25.0
#define TEXTURE_UNIT GL_TEXTURE0
#define SHADOW_TEXTURE_UNIT GL_TEXTURE1
static void canonicalPosition( QVector3D& position )
{
if ( !qFuzzyIsNull( position.x( ) ) )
position.setX( position.x( ) / fabsf( position.x( ) ) );
if ( !qFuzzyIsNull( position.y( ) ) )
position.setY( position.y( ) / fabsf( position.y( ) ) );
if ( !qFuzzyIsNull( position.z( ) ) )
position.setZ( position.z( ) / fabsf( position.z( ) ) );
}
class CubeRenderer: protected QOpenGLFunctions
{
struct Vertex
{
void set( const QVector3D& _position, const