Add support for transparent mesh sorting

This commit is contained in:
Peder Bergebakken Sundt 2019-03-22 00:04:50 +01:00
parent 2ade6919d1
commit 97adb2fd3b
8 changed files with 101 additions and 14 deletions

View File

@ -25,8 +25,8 @@ void runProgram(GLFWwindow* window, CommandLineOptions options)
glEnable(GL_CULL_FACE); glEnable(GL_CULL_FACE);
//enable alpha //enable alpha
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
// Set default colour after clearing the colour buffer // Set default colour after clearing the colour buffer
glClearColor(0.3f, 0.5f, 0.8f, 1.0f); glClearColor(0.3f, 0.5f, 0.8f, 1.0f);

View File

@ -10,6 +10,7 @@
#include <glm/vec3.hpp> #include <glm/vec3.hpp>
#include <iostream> #include <iostream>
#include <string> #include <string>
#include <algorithm>
#include <utilities/glfont.h> #include <utilities/glfont.h>
#include <utilities/shader.hpp> #include <utilities/shader.hpp>
#include <utilities/timeutils.h> #include <utilities/timeutils.h>
@ -119,7 +120,14 @@ void updateFrame(GLFWwindow* window, int windowWidth, int windowHeight) {
} }
// traverses and renders one and one node // traverses and renders one and one node
void renderNode(SceneNode* node, Gloom::Shader* parent_shader) { struct NodeDistShader{
SceneNode* node;
Gloom::Shader* s;
float dist;
NodeDistShader(SceneNode* node, Gloom::Shader* s, float dist)
: node(node), s(s), dist(dist) {}
};
void renderNode(SceneNode* node, Gloom::Shader* parent_shader, vector<NodeDistShader>* transparent_nodes=nullptr, bool do_recursive=true) {
struct Light { // lights as stored in the shader struct Light { // lights as stored in the shader
// coordinates in MV space // coordinates in MV space
vec3 position; // MV vec3 position; // MV
@ -158,7 +166,11 @@ void renderNode(SceneNode* node, Gloom::Shader* parent_shader) {
switch(node->nodeType) { switch(node->nodeType) {
case GEOMETRY: case GEOMETRY:
if(node->vertexArrayObjectID != -1) { if (transparent_nodes!=nullptr && node->has_transparancy()) {
// defer to sorted pass later on
transparent_nodes->emplace_back(node, node_shader, (float)glm::length(vec3(node->MVP*vec4(0,0,0,1))));
}
else if(node->vertexArrayObjectID != -1) {
// load uniforms // load uniforms
glUniformMatrix4fv(s->location("MVP") , 1, GL_FALSE, glm::value_ptr(node->MVP)); glUniformMatrix4fv(s->location("MVP") , 1, GL_FALSE, glm::value_ptr(node->MVP));
glUniformMatrix4fv(s->location("MV") , 1, GL_FALSE, glm::value_ptr(node->MV)); glUniformMatrix4fv(s->location("MV") , 1, GL_FALSE, glm::value_ptr(node->MV));
@ -203,16 +215,37 @@ void renderNode(SceneNode* node, Gloom::Shader* parent_shader) {
break; break;
} }
if (do_recursive)
for(SceneNode* child : node->children) { for(SceneNode* child : node->children) {
renderNode(child, node_shader); renderNode(child, node_shader, transparent_nodes, true);
} }
} }
// draw // draw
void renderFrame(GLFWwindow* window, int windowWidth, int windowHeight) { void renderFrame(GLFWwindow* window, int windowWidth, int windowHeight) {
glViewport(0, 0, windowWidth, windowHeight); glViewport(0, 0, windowWidth, windowHeight);
static vector<NodeDistShader> transparent_nodes;
transparent_nodes.clear();
// externs from scene.hpp, they must have shaders set // externs from scene.hpp, they must have shaders set
renderNode(rootNode, nullptr); renderNode(rootNode, nullptr, &transparent_nodes);
// sort and render transparent node, sorted by distance from camera
std::sort(
transparent_nodes.begin(),
transparent_nodes.end(),
[](NodeDistShader a, NodeDistShader b) {
return a.dist > b.dist;
});
glDepthMask(GL_FALSE);
//glDisable(GL_DEPTH_TEST);
for (NodeDistShader a : transparent_nodes)
renderNode(a.node, a.s, nullptr, false);
std::cout << transparent_nodes.size() << std::endl;
glDepthMask(GL_TRUE);
//glEnable(GL_DEPTH_TEST);
renderNode(hudNode, nullptr); renderNode(hudNode, nullptr);
} }

View File

@ -5,6 +5,7 @@
#include <chrono> #include <chrono>
#include <glad/glad.h> #include <glad/glad.h>
#include <iostream> #include <iostream>
#include <cstdlib>
#include <utilities/imageLoader.hpp> #include <utilities/imageLoader.hpp>
#include <utilities/modelLoader.hpp> #include <utilities/modelLoader.hpp>
#include <utilities/mesh.h> #include <utilities/mesh.h>
@ -73,11 +74,31 @@ void init_scene(CommandLineOptions options) {
rootNode->children.push_back(lightNode[i]); rootNode->children.push_back(lightNode[i]);
} }
//treeNode = loadModelScene("../res/models/fur_tree/scene.gltf"); //treeNode = loadModelScene("../res/models/fur_tree", "scene.gltf");
//treeNode->position = {300, 800, 10}; //treeNode->position = {300, 800, 10};
//rootNode->children.push_back(treeNode); //rootNode->children.push_back(treeNode);
carNode = loadModelScene("../res/models/beetle/scene.gltf", { //uint i = 30;
//while (i--) {
// SceneNode* asd = treeNode->clone();
// asd->position.x = (std::rand() % 10000) / 10;
// asd->position.y = (std::rand() % 10000) / 10;
// rootNode->children.push_back(asd);
//}
grassNode = loadModelScene("../res/models/single_grass", "scene.gltf");
grassNode->position = {400, 400, 15};
rootNode->children.push_back(grassNode);
for (uint i = 100; i--;) {
SceneNode* asd = grassNode->clone();
asd->position.x = (std::rand() % 10000) / 10;
asd->position.y = (std::rand() % 10000) / 10;
rootNode->children.push_back(asd);
}
/*
carNode = loadModelScene("../res/models/beetle", "scene.gltf", {
{ 0, Material().diffuse({0.0, 0.0, 1.0}).diffuse_only().reflection_mapped(&t_reflection, 0.15)},// Blue_Metal { 0, Material().diffuse({0.0, 0.0, 1.0}).diffuse_only().reflection_mapped(&t_reflection, 0.15)},// Blue_Metal
{ 1, Material().diffuse(vec3(0.85)).emissive(vec3(0.1)).reflection_mapped(&t_reflection, -1.0)},// Metal (decals) { 1, Material().diffuse(vec3(0.85)).emissive(vec3(0.1)).reflection_mapped(&t_reflection, -1.0)},// Metal (decals)
//{ 2, Material().diffuse({1.0, 1.0, 1.0})},// Front_Light_Glass //{ 2, Material().diffuse({1.0, 1.0, 1.0})},// Front_Light_Glass
@ -85,20 +106,18 @@ void init_scene(CommandLineOptions options) {
{ 4, Material().no_colors().reflection_mapped(&t_reflection, 1.0)},// Mirror { 4, Material().no_colors().reflection_mapped(&t_reflection, 1.0)},// Mirror
//{ 5, Material().diffuse({1.0, 1.0, 1.0})},// Black_Metal //{ 5, Material().diffuse({1.0, 1.0, 1.0})},// Black_Metal
//{ 6, Material().diffuse({1.0, 1.0, 1.0})},// Plastic //{ 6, Material().diffuse({1.0, 1.0, 1.0})},// Plastic
// { 7, Material().diffuse(vec3(0.2)).emissive(vec3(0.25)).specular(vec3(1.0), 70).reflection_mapped(&t_reflection, -0.8)},// Window_Glass
{ 7, Material().diffuse(vec3(0.2)).emissive(vec3(0.25)).specular(vec3(1.0), 70).reflection_mapped(&t_reflection, -0.8)},// Window_Glass { 7, Material().diffuse(vec3(0.2)).emissive(vec3(0.25)).specular(vec3(1.0), 70).reflection_mapped(&t_reflection, -0.8)},// Window_Glass
//{ 8, Material().diffuse({1.0, 1.0, 1.0})},// Material //{ 8, Material().diffuse({1.0, 1.0, 1.0})},// Material
{ 9, Material().diffuse(vec3(1.0)).emissive(vec3(0.2)).specular(vec3(0.4), 70).reflection_mapped(&t_reflection, -1.0)},// Glossy_metal { 9, Material().diffuse(vec3(1.0)).emissive(vec3(0.2)).specular(vec3(0.4), 70).reflection_mapped(&t_reflection, -1.0)},// Glossy_metal
//{10, Material().diffuse({1.0, 1.0, 1.0})},// Rogh_Metal //{10, Material().diffuse({1.0, 1.0, 1.0})},// Rogh_Metal
// {11, Material().no_colors().reflection_mapped(&t_reflection, 1.0)},// License_Plate_Metal
{11, Material().no_colors().reflection_mapped(&t_reflection, 1.0)},// License_Plate_Metal {11, Material().no_colors().reflection_mapped(&t_reflection, 1.0)},// License_Plate_Metal
//{12, Material().diffuse({1.0, 1.0, 1.0})},// License_Plate_Frame //{12, Material().diffuse({1.0, 1.0, 1.0})},// License_Plate_Frame
//{13, Material().diffuse({1.0, 1.0, 1.0})},// //{13, Material().diffuse({1.0, 1.0, 1.0})},//
}); });
//carNode->setMaterial(Material().reflection_mapped(&t_reflection, 0.0).no_colors().no_texture_reset(), true);
carNode->position = {500, 500, 100}; carNode->position = {500, 500, 100};
carNode->scale *= 100; carNode->scale *= 100;
rootNode->children.push_back(carNode); rootNode->children.push_back(carNode);
*/
//create the scene: //create the scene:
plainNode = createSceneNode(); plainNode = createSceneNode();

View File

@ -14,6 +14,7 @@ void SceneNode::setMesh(const Mesh* mesh) {
vertexArrayObjectID = cache[mesh]; vertexArrayObjectID = cache[mesh];
VAOIndexCount = mesh->indices.size(); VAOIndexCount = mesh->indices.size();
isVertexColored = ! mesh->colors.empty(); isVertexColored = ! mesh->colors.empty();
m_gemoetry = mesh;
} }
void SceneNode::setTexture( void SceneNode::setTexture(
const PNGImage* diffuse, const PNGImage* diffuse,
@ -27,6 +28,7 @@ void SceneNode::setTexture(
isNormalMapped = false; isNormalMapped = false;
isDisplacementMapped = false; isDisplacementMapped = false;
isReflectionMapped = false; isReflectionMapped = false;
t_diffuse = nullptr;
} }
if (diffuse) { if (diffuse) {
@ -34,6 +36,7 @@ void SceneNode::setTexture(
cache[diffuse] = generateTexture(*diffuse); cache[diffuse] = generateTexture(*diffuse);
diffuseTextureID = cache[diffuse]; diffuseTextureID = cache[diffuse];
isTextured = true; isTextured = true;
t_diffuse = diffuse;
} }
if (normal) { if (normal) {
@ -74,6 +77,22 @@ void SceneNode::setMaterial(const Material& mat, bool recursive) {
child->setMaterial(mat, true); child->setMaterial(mat, true);
} }
bool SceneNode::has_transparancy() const {
return opacity < 1.0
|| t_diffuse && t_diffuse->has_transparancy
|| m_gemoetry && m_gemoetry->has_transparancy;
}
SceneNode* SceneNode::clone() const {
SceneNode* out = new SceneNode();
*out = *this;
out->children.clear();
for (SceneNode* child : children) {
out->children.push_back(child->clone());
}
return out;
}
SceneNode* createSceneNode() { SceneNode* createSceneNode() {
return new SceneNode(); return new SceneNode();

View File

@ -42,6 +42,8 @@ struct SceneNode {
const PNGImage* reflection=nullptr, const PNGImage* reflection=nullptr,
bool texture_reset=true); bool texture_reset=true);
void setMaterial(const Material& mat, bool recursive=false); void setMaterial(const Material& mat, bool recursive=false);
bool has_transparancy() const;
SceneNode* clone() const;
// this node // this node
SceneNodeType nodeType; SceneNodeType nodeType;
@ -57,7 +59,7 @@ struct SceneNode {
// The node's position and rotation relative to its parent // The node's position and rotation relative to its parent
vec3 position = vec3(0, 0, 0); vec3 position = vec3(0, 0, 0);
vec3 rotation = vec3(0, 0, 0); // also used as spot-target vec3 rotation = vec3(0, 0, 0);
vec3 scale = vec3(1, 1, 1); vec3 scale = vec3(1, 1, 1);
vec3 referencePoint = vec3(0, 0, 0); // center of rotation, in model space vec3 referencePoint = vec3(0, 0, 0); // center of rotation, in model space
@ -78,7 +80,11 @@ struct SceneNode {
uint displacementTextureID; uint displacementTextureID;
float displacementCoefficient = 0.1; // in units float displacementCoefficient = 0.1; // in units
uint reflectionTextureID; uint reflectionTextureID;
// has_transparancy
const Mesh* m_gemoetry = nullptr;
const PNGImage* t_diffuse = nullptr;
// shader flags // shader flags
bool isTextured = false; bool isTextured = false;
bool isVertexColored = false; bool isVertexColored = false;

View File

@ -58,7 +58,14 @@ PNGImage loadPNGFile(string filename, bool flip_handedness) {
image.width = width; image.width = width;
image.height = height; image.height = height;
image.pixels = pixels; image.pixels = pixels;
for (uint i = 3; i < pixels.size(); i+=4) {
if (pixels[i] < 255) {
image.has_transparancy = true;
break;
}
}
return image; return image;
} }

View File

@ -10,6 +10,7 @@ struct PNGImage {
uint width, height; uint width, height;
bool repeat_mirrored = false; bool repeat_mirrored = false;
std::vector<unsigned char> pixels; // RGBA std::vector<unsigned char> pixels; // RGBA
bool has_transparancy = false;
}; };
PNGImage loadPNGFile(std::string filename, bool flip_handedness=false); PNGImage loadPNGFile(std::string filename, bool flip_handedness=false);

View File

@ -10,4 +10,6 @@ struct Mesh {
std::vector<glm::vec4> colors; std::vector<glm::vec4> colors;
std::vector<unsigned int> indices; std::vector<unsigned int> indices;
bool has_transparancy = false; // if any of the colors are transparent
}; };