first works of omni shadows

This commit is contained in:
2023-02-16 16:57:29 +03:00
parent 69caa98d04
commit 3c9386de63
7 changed files with 328 additions and 54 deletions

View File

@@ -0,0 +1,108 @@
/*
QGL CubeMapArray
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define GL_GLEXT_PROTOTYPES
#include "glcubemaparray.h"
#include <QOpenGLExtraFunctions>
CubeMapArray::CubeMapArray(GLenum format, bool filter) {
target_ = GL_TEXTURE_CUBE_MAP_ARRAY;
format_ = format;
texture_ = 0;
layers_ = 0;
filtering_ = filter;
}
CubeMapArray::~CubeMapArray() {}
void CubeMapArray::init(QOpenGLExtraFunctions * f) {
if (!isInit()) {
f->glGenTextures(1, &texture_);
}
}
void CubeMapArray::destroy(QOpenGLExtraFunctions * f) {
if (texture_ != 0) {
f->glDeleteTextures(1, &texture_);
}
texture_ = 0;
}
void CubeMapArray::reinit() {
texture_ = 0;
layers_ = 0;
}
void CubeMapArray::bind(QOpenGLExtraFunctions * f, int channel) {
f->glActiveTexture(GL_TEXTURE0 + channel);
f->glBindTexture(target_, texture_);
}
void CubeMapArray::release(QOpenGLExtraFunctions * f) {
f->glBindTexture(target_, 0);
}
bool CubeMapArray::resize(QOpenGLExtraFunctions * f, QSize new_size, int layers_count) {
if (new_size.isNull() || layers_count <= 0) return false;
if ((size_ == new_size) && (layers_ >= layers_count)) return false;
size_ = new_size;
layers_ = layers_count;
f->glBindTexture(target_, texture_);
f->glTexParameteri(target_, GL_TEXTURE_WRAP_S, GL_REPEAT);
f->glTexParameteri(target_, GL_TEXTURE_WRAP_T, GL_REPEAT);
if (filtering_) {
f->glTexParameteri(target_, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
f->glTexParameteri(target_, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
f->glTexParameteri(target_, GL_TEXTURE_MAX_ANISOTROPY_EXT, 8);
} else {
f->glTexParameteri(target_, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
f->glTexParameteri(target_, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
}
GLenum bformat = format_;
GLenum btype = GL_UNSIGNED_BYTE;
if (format_ == GL_R16F || format_ == GL_R32F) {
bformat = GL_RED;
btype = GL_FLOAT;
}
f->glTexImage3D(target_, 0, format_, size_.width(), size_.height(), layers_ * 6, 0, bformat, btype, nullptr);
return true;
}
void CubeMapArray::load(QOpenGLExtraFunctions * f, const QImage & image, int layer) {
if (image.isNull() || size_.isNull() || layer < 0 || layer >= layers_) return;
QImage im =
image.mirrored(false, true).scaled(size_, Qt::IgnoreAspectRatio, Qt::SmoothTransformation).convertToFormat(QImage::Format_RGBA8888);
// qDebug() << "CubeMapArray::load image" << image.size() << "to layer" << layer;
// f->glTexSubImage3D(target_, 0, 0, 0, layer, size_.width(), size_.height(), 1, GL_RGBA, GL_UNSIGNED_BYTE, im.constBits());
}
void CubeMapArray::mipmaps(QOpenGLExtraFunctions * f) {
f->glBindTexture(target_, texture_);
f->glGenerateMipmap(target_);
}

View File

@@ -0,0 +1,55 @@
/*
QGL Texture2DArray
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef GLCUBEMAPARRAY_H
#define GLCUBEMAPARRAY_H
#include "gltypes.h"
class QGLENGINE_CORE_EXPORT CubeMapArray {
public:
CubeMapArray(GLenum format, bool filter);
~CubeMapArray();
void init(QOpenGLExtraFunctions * f);
void destroy(QOpenGLExtraFunctions * f);
void reinit();
void bind(QOpenGLExtraFunctions * f, int channel = 0);
void release(QOpenGLExtraFunctions * f);
// returns true if size changed
bool resize(QOpenGLExtraFunctions * f, QSize new_size, int layers_count);
void load(QOpenGLExtraFunctions * f, const QImage & image, int layer);
void mipmaps(QOpenGLExtraFunctions * f);
GLuint ID() const { return texture_; }
bool isInit() const { return texture_ != 0; }
int layersCount() const { return layers_; }
private:
GLenum target_, format_;
GLuint texture_;
QSize size_;
int layers_;
bool filtering_;
};
#endif // GLCUBEMAPARRAY_H

View File

@@ -108,6 +108,7 @@ enum TextureArrayRole {
tarEmpty = 10,
tarMaps = 11,
tarShadowsCone = 12,
tarShadowsOmni = 13,
};
enum EmptyMapRole {
emrWhite = 0,

View File

@@ -40,6 +40,31 @@ Renderer::Renderer(QGLView * view_)
, rend_selection(this)
, tone_proc(this)
, tex_env(view_, 512) {
mat_norm_to_tex_coord.scale(0.5, 0.5);
mat_norm_to_tex_coord.translate(1, 1);
mat_proj_90 = glMatrixPerspective(90., 1., 0.1);
for (int i = 0; i < 6; ++i) {
QMatrix4x4 fvm;
switch (i) {
case 0:
fvm.rotate(-90., QVector3D(0, 1, 0));
fvm.rotate(180., QVector3D(0, 0, 1));
break;
case 1:
fvm.rotate(90., QVector3D(0, 1, 0));
fvm.rotate(180., QVector3D(0, 0, 1));
break;
case 2: fvm.rotate(-90., QVector3D(1, 0, 0)); break;
case 3: fvm.rotate(90., QVector3D(1, 0, 0)); break;
case 4:
fvm.rotate(180., QVector3D(0, 0, 1));
fvm.rotate(180., QVector3D(0, 1, 0));
break;
case 5: fvm.rotate(180., QVector3D(0, 0, 1)); break;
}
mat_faces[i] = fvm;
}
quad = Primitive::plane(2., 2.);
cam_light = new Light();
cam_light->intensity = 0.75;
@@ -61,10 +86,12 @@ Renderer::Renderer(QGLView * view_)
shader_files[srFinalPass] = "ds_final.glsl";
shader_files[srTonemapPass] = "ds_tonemap.glsl";
shader_files[srShadowPass] = "shadow.glsl";
shader_files[srShadowConePass] = "shadow.glsl";
shader_files[srShadowOmniPass] = "shadow.glsl";
shader_defines[srGeometrySolidPass] << "SOLID";
shader_defines[srLightSpotPass] << "SPOT";
shader_defines[srShadowOmniPass] << "OMNI";
edit_mode = need_init_shaders = true;
camera_light_mode = QGLView::clmAuto;
@@ -89,6 +116,7 @@ void Renderer::init(int width, int height) {
textures_maps.reinit();
textures_empty.reinit();
shadow_maps_cone.reinit();
shadow_maps_omni.reinit();
resize(width, height);
rend_mat.init(width, height);
rend_service.init(width, height);
@@ -115,6 +143,7 @@ void Renderer::resize(int width, int height) {
void Renderer::reloadShaders() {
__reinit_debug = true;
QMapIterator<ShaderRole, QString> it(shader_files);
qDeleteAll(shaders.values());
shaders.clear();
@@ -122,7 +151,7 @@ void Renderer::reloadShaders() {
shader_fxaa = nullptr;
if (tone_proc.shader_sum) delete tone_proc.shader_sum;
tone_proc.shader_sum = nullptr;
QString dir = ":/shaders/";
QString dir = "./shaders/";
while (it.hasNext()) {
it.next();
loadShadersMulti(shaders[it.key()], dir + it.value(), true, shader_defines.value(it.key()));
@@ -165,9 +194,6 @@ bool Renderer::bindShader(QOpenGLShaderProgram * sp) {
void Renderer::initShaders() {
if (!need_init_shaders) return;
need_init_shaders = false;
// initUniformBuffer(shaders.value(srGeometrySolidPass), &buffer_materials, bpMaterials, "QGLMaterialData");
// initUniformBuffer(shaders.value(srGeometryTransparentPass), &buffer_materials, bpMaterials, "QGLMaterialData");
// initUniformBuffer(shaders.value(srShadowPass), &buffer_materials, bpMaterials, "QGLMaterialData");
QOpenGLShaderProgram * prog = 0;
for (ShaderRole role: {srLightOmniPass, srLightSpotPass}) {
if (!bindShader(role, &prog)) continue;
@@ -188,7 +214,7 @@ void Renderer::initShaders() {
prog->setUniformValue("tex_t_0", 3);
prog->setUniformValue("tex_t_1", 4);
}
for (ShaderRole role: {srGeometrySolidPass, srGeometryTransparentPass, srShadowPass}) {
for (ShaderRole role: {srGeometrySolidPass, srGeometryTransparentPass, srShadowConePass, srShadowOmniPass}) {
if (!bindShader(role, &prog)) continue;
initUniformBuffer(prog, &buffer_materials, bpMaterials, "QGLMaterialData");
setUniformMaps(prog);
@@ -317,16 +343,71 @@ void Renderer::renderLight(int first_wr_buff, bool clear_only) {
prog->setUniformValue("view_mat", cam->viewMatrix().inverted().toGenericMatrix<3, 3>());
prog->setUniformValue("shadow_size", view->shadow_map_size);
prog->setUniformValue("tex_shadows_cone", (int)tarShadowsCone);
prog->setUniformValue("tex_shadows_omni", (int)tarShadowsOmni);
prog->setUniformValue("soft_shadows_enabled", view->soft_shadows);
prog->setUniformValue("soft_shadows_samples", view->soft_shadows_samples);
shadow_maps_cone.bind(view, tarShadowsCone);
shadow_maps_omni.bind(view, tarShadowsOmni);
renderQuad(prog, quad, cam);
}
}
}
void Renderer::renderShadow(int index, Light * light) {
void Renderer::renderConeShadows() {
QOpenGLExtraFunctions * f = view;
QOpenGLShaderProgram * prog = 0;
if (bindShader(srShadowConePass, &prog)) {
glEnableDepth();
textures_empty.bind(f, tarEmpty);
textures_maps.bind(f, tarMaps);
auto cone_ll = cur_lights.value(Light::Cone);
shadow_maps_cone.resize(f, view->shadow_map_size, cone_ll.size());
for (int i = 0; i < cone_ll.size(); ++i) {
Light * l = cone_ll[i];
QMatrix4x4 pm = glMatrixPerspective(l->angle_end, 1., 0.1), om, vm;
om.translate(-l->worldAim());
vm.translate(0., 0., -l->distance());
// vm.rotate(-roll_, 0., 0., 1.);
QMatrix4x4 pmat = l->worldTransform();
pmat(0, 3) = pmat(1, 3) = pmat(2, 3) = 0.;
vm *= pmat.inverted();
auto vpm = pm * (vm * om);
if (l->isCastShadows()) {
prog->setUniformValue("qgl_ViewProjMatrix", vpm);
renderConeShadow(i, l);
}
l->shadow_matrix = mat_norm_to_tex_coord * vpm * mat_camera_fullview_inv;
}
}
}
void Renderer::renderOmniShadows() {
QOpenGLExtraFunctions * f = view;
QOpenGLShaderProgram * prog = 0;
if (bindShader(srShadowOmniPass, &prog)) {
glEnableDepth();
textures_empty.bind(f, tarEmpty);
textures_maps.bind(f, tarMaps);
auto omni_ll = cur_lights.value(Light::Omni);
shadow_maps_omni.resize(f, view->shadow_map_size, omni_ll.size());
for (int i = 0; i < omni_ll.size(); ++i) {
Light * l = omni_ll[i];
QMatrix4x4 om;
om.translate(-l->worldPos());
// vm.translate(0., 0., -l->distance());
// vm.rotate(-roll_, 0., 0., 1.);
if (l->isCastShadows()) {
renderOmniShadow(i, l, prog, om);
}
// l->shadow_matrix = mat_norm_to_tex_coord * vpm * mat_camera_fullview_inv;
}
}
}
void Renderer::renderConeShadow(int index, Light * light) {
Scene & scene(*(view->scene()));
bool force_resize = false;
if (!light->shadow_map.isInit()) {
@@ -336,13 +417,7 @@ void Renderer::renderShadow(int index, Light * light) {
light->shadow_map.resize(view->shadow_map_size, force_resize);
light->shadow_map.bind();
if (!framebufferTextureLayer) {
framebufferTextureLayer = view->context()->getProcAddress("glFramebufferTextureLayer");
}
if (framebufferTextureLayer) {
((PFNGLFRAMEBUFFERTEXTURELAYERPROC)framebufferTextureLayer)(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, shadow_maps_cone.ID(), 0, index);
// glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, shadow_maps_cone.ID(), 0, index);
}
view->glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, shadow_maps_cone.ID(), 0, index);
glDrawBuffer(GL_COLOR_ATTACHMENT0);
glClearFramebuffer();
renderObjects(scene, rpSolid);
@@ -350,6 +425,36 @@ void Renderer::renderShadow(int index, Light * light) {
}
void Renderer::renderOmniShadow(int index, Light * light, QOpenGLShaderProgram * prog, QMatrix4x4 om) {
Scene & scene(*(view->scene()));
bool force_resize = false;
if (!light->shadow_map.isInit()) {
light->shadow_map.reinit(view);
force_resize = true;
}
light->shadow_map.resize(view->shadow_map_size, force_resize);
light->shadow_map.bind();
for (int i = 0; i < 6; ++i) {
QMatrix4x4 vm = mat_proj_90 * mat_faces[i] * om;
prog->setUniformValue("qgl_ViewProjMatrix", vm);
int buff_ind = GL_COLOR_ATTACHMENT0 + i;
view->glFramebufferTextureLayer(GL_FRAMEBUFFER, buff_ind, shadow_maps_omni.ID(), 0, index * 6 + i);
// static GLenum faces[6] = {GL_COLOR_ATTACHMENT0,
// GL_COLOR_ATTACHMENT1,
// GL_COLOR_ATTACHMENT2,
// GL_COLOR_ATTACHMENT3,
// GL_COLOR_ATTACHMENT4,
// GL_COLOR_ATTACHMENT5};
// view->glDrawBuffers(6, faces);
glDrawBuffer(buff_ind);
glClearFramebuffer();
renderObjects(scene, rpSolid);
}
light->shadow_map.release();
}
void Renderer::renderScene() {
timings.clear();
Measurer phase(&timings);
@@ -363,6 +468,7 @@ void Renderer::renderScene() {
QOpenGLShaderProgram * prog = 0;
bool scene_changed = scene.prepare();
cur_lights = scene.lights_used;
mat_camera_fullview_inv = cam->fullViewMatrix().inverted();
scene.destroyUnused(f);
phase.end();
@@ -383,35 +489,14 @@ void Renderer::renderScene() {
}
phase.end();
/// shadows and shadow matrix
phase.begin("shadows");
if (bindShader(srShadowPass, &prog)) {
glEnableDepth();
textures_empty.bind(f, tarEmpty);
textures_maps.bind(f, tarMaps);
auto cam_ivm = cam->fullViewMatrix().inverted();
auto cone_ll = cur_lights.value(Light::Cone);
shadow_maps_cone.resize(f, view->shadow_map_size, cone_ll.size());
QMatrix4x4 mat_vp;
mat_vp.scale(0.5, 0.5);
mat_vp.translate(1, 1);
for (int i = 0; i < cone_ll.size(); ++i) {
Light * l = cone_ll[i];
QMatrix4x4 pm = glMatrixPerspective(l->angle_end, 1., 0.1), om, vm;
om.translate(-l->worldAim());
vm.translate(0., 0., -l->distance());
// vm.rotate(-roll_, 0., 0., 1.);
QMatrix4x4 pmat = l->worldTransform();
pmat(0, 3) = pmat(1, 3) = pmat(2, 3) = 0.;
vm *= pmat.inverted();
auto vpm = pm * (vm * om);
if (l->isCastShadows()) {
prog->setUniformValue("qgl_ViewProjMatrix", vpm);
renderShadow(i, l);
}
l->shadow_matrix = mat_vp * vpm * cam_ivm;
}
}
/// cone shadows and shadow matrix
phase.begin("shadows cone");
renderConeShadows();
phase.end();
/// omni shadows and shadow matrix
phase.begin("shadows omni");
renderOmniShadows();
phase.end();
/// lights
@@ -558,13 +643,29 @@ void Renderer::renderScene() {
// qDebug() << last_img.size();
}
phase.end();
/*
auto cone_ll = cur_lights.value(Light::Cone);
if (!cone_ll.isEmpty()) {
Light * l = cone_ll[0];
l->shadow_map.blit(0, 0, 0, l->shadow_map.rect(), l->shadow_map.rect());
static QOpenGLShaderProgram * tprog = nullptr;
if (tprog && __reinit_debug) {
delete tprog;
tprog = nullptr;
}
*/
if (!tprog) {
loadShadersMulti(tprog, "./shaders/debug.glsl");
tprog->bind();
tprog->setUniformValue("tex_cone", (int)tarShadowsCone);
tprog->setUniformValue("tex_omni", (int)tarShadowsOmni);
QMatrix4x4 mat;
double sz = 0.33;
mat.translate(sz - 1, sz - 1);
mat.scale(sz, sz);
tprog->setUniformValue("qgl_ViewProjMatrix", mat);
}
__reinit_debug = false;
tprog->bind();
shadow_maps_cone.bind(f, tarShadowsCone);
shadow_maps_omni.bind(f, tarShadowsOmni);
quad->draw(f, 1);*/
}

View File

@@ -57,7 +57,8 @@ class QGLENGINE_CORE_EXPORT Renderer: public RendererBase {
srLightSpotPass,
srFinalPass,
srTonemapPass,
srShadowPass,
srShadowConePass,
srShadowOmniPass,
};
enum OutBufferRole {
obrSolidOmni,
@@ -112,7 +113,10 @@ protected:
void fillObjectsBuffer(const ObjectBaseList & ol, RenderPass pass);
void renderObjects(Scene & scene, RenderPass pass);
void renderLight(int first_wr_buff, bool clear_only);
void renderShadow(int index, Light * light);
void renderConeShadows();
void renderOmniShadows();
void renderConeShadow(int index, Light * light);
void renderOmniShadow(int index, Light * light, QOpenGLShaderProgram * prog, QMatrix4x4 om);
bool bindShader(ShaderRole role, QOpenGLShaderProgram ** ret = 0);
bool bindShader(QOpenGLShaderProgram * sp);
@@ -124,7 +128,7 @@ protected:
private:
float gamma_ = 1.f;
int camera_light_mode, cur_write_plane = 0, prev_write_plane = 0;
bool edit_mode, need_init_shaders, need_render_sum;
bool edit_mode, need_init_shaders, need_render_sum, __reinit_debug;
Framebuffer fbo_ds, fbo_out;
QMap<ShaderRole, QString> shader_files;
QMap<ShaderRole, QStringList> shader_defines;
@@ -143,6 +147,8 @@ private:
QPoint mouse_pos;
QRect mouse_rect;
QMatrix4x4 prev_view, prev_proj;
QMatrix4x4 mat_norm_to_tex_coord, mat_camera_fullview_inv, mat_proj_90;
QMatrix4x4 mat_faces[6];
QMatrix3x3 nm;
QVector4D corner_dirs[4];
QVector<QVector3D> hcontent;
@@ -151,7 +157,6 @@ private:
QImage last_img;
QString timings;
bool is_grabbing = false;
QFunctionPointer framebufferTextureLayer = nullptr;
};
#endif // RENDERER_H

View File

@@ -37,7 +37,8 @@ RendererBase::RendererBase(QGLView * view_)
, buffer_lights_pos(GL_UNIFORM_BUFFER, GL_STREAM_DRAW)
, textures_empty(GL_RGBA, false)
, textures_maps(GL_RGBA, true)
, shadow_maps_cone(GL_R32F, false) {
, shadow_maps_cone(GL_R32F, false)
, shadow_maps_omni(GL_R32F, false) {
textures_manager = new TextureManager(view);
maps_size = QSize(1024, 1024);
maps_hash = 0;
@@ -62,6 +63,7 @@ void RendererBase::initTextureArrays() {
im.fill(0xFF8080);
textures_empty.load(f, im, emrBlue);
shadow_maps_cone.init(f);
shadow_maps_omni.init(f);
}

View File

@@ -20,6 +20,7 @@
#define RENDERER_BASE_H
#include "glbuffer.h"
#include "glcubemaparray.h"
#include "glshaders_types.h"
#include "gltexturearray.h"
#include "measurer.h"
@@ -59,6 +60,7 @@ protected:
Buffer buffer_materials;
Buffer buffer_lights, buffer_lights_pos;
Texture2DArray textures_empty, textures_maps, shadow_maps_cone;
CubeMapArray shadow_maps_omni;
QSize maps_size;
uint maps_hash;
GLuint tex_coeff[2];