diff --git a/src/program.cpp b/src/program.cpp index 613cc3c..ba81315 100644 --- a/src/program.cpp +++ b/src/program.cpp @@ -25,8 +25,8 @@ void runProgram(GLFWwindow* window, CommandLineOptions options) glEnable(GL_CULL_FACE); //enable alpha - glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glEnable(GL_BLEND); // Set default colour after clearing the colour buffer glClearColor(0.3f, 0.5f, 0.8f, 1.0f); diff --git a/src/renderlogic.cpp b/src/renderlogic.cpp index fa738fe..7ba8f72 100644 --- a/src/renderlogic.cpp +++ b/src/renderlogic.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -119,7 +120,14 @@ void updateFrame(GLFWwindow* window, int windowWidth, int windowHeight) { } // 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* transparent_nodes=nullptr, bool do_recursive=true) { struct Light { // lights as stored in the shader // coordinates in MV space vec3 position; // MV @@ -158,7 +166,11 @@ void renderNode(SceneNode* node, Gloom::Shader* parent_shader) { switch(node->nodeType) { 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 glUniformMatrix4fv(s->location("MVP") , 1, GL_FALSE, glm::value_ptr(node->MVP)); 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; } + if (do_recursive) for(SceneNode* child : node->children) { - renderNode(child, node_shader); + renderNode(child, node_shader, transparent_nodes, true); } } // draw void renderFrame(GLFWwindow* window, int windowWidth, int windowHeight) { glViewport(0, 0, windowWidth, windowHeight); - + + static vector transparent_nodes; + transparent_nodes.clear(); + // 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); } diff --git a/src/scene.cpp b/src/scene.cpp index 3a1a472..8d4f69d 100644 --- a/src/scene.cpp +++ b/src/scene.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -73,11 +74,31 @@ void init_scene(CommandLineOptions options) { 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}; //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 { 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 @@ -85,20 +106,18 @@ void init_scene(CommandLineOptions options) { { 4, Material().no_colors().reflection_mapped(&t_reflection, 1.0)},// Mirror //{ 5, Material().diffuse({1.0, 1.0, 1.0})},// Black_Metal //{ 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 //{ 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 //{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 //{12, Material().diffuse({1.0, 1.0, 1.0})},// License_Plate_Frame //{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->scale *= 100; rootNode->children.push_back(carNode); + */ //create the scene: plainNode = createSceneNode(); diff --git a/src/sceneGraph.cpp b/src/sceneGraph.cpp index ca6b5b2..b17de6e 100644 --- a/src/sceneGraph.cpp +++ b/src/sceneGraph.cpp @@ -14,6 +14,7 @@ void SceneNode::setMesh(const Mesh* mesh) { vertexArrayObjectID = cache[mesh]; VAOIndexCount = mesh->indices.size(); isVertexColored = ! mesh->colors.empty(); + m_gemoetry = mesh; } void SceneNode::setTexture( const PNGImage* diffuse, @@ -27,6 +28,7 @@ void SceneNode::setTexture( isNormalMapped = false; isDisplacementMapped = false; isReflectionMapped = false; + t_diffuse = nullptr; } if (diffuse) { @@ -34,6 +36,7 @@ void SceneNode::setTexture( cache[diffuse] = generateTexture(*diffuse); diffuseTextureID = cache[diffuse]; isTextured = true; + t_diffuse = diffuse; } if (normal) { @@ -74,6 +77,22 @@ void SceneNode::setMaterial(const Material& mat, bool recursive) { 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() { return new SceneNode(); diff --git a/src/sceneGraph.hpp b/src/sceneGraph.hpp index 245201b..4aa7042 100644 --- a/src/sceneGraph.hpp +++ b/src/sceneGraph.hpp @@ -42,6 +42,8 @@ struct SceneNode { const PNGImage* reflection=nullptr, bool texture_reset=true); void setMaterial(const Material& mat, bool recursive=false); + bool has_transparancy() const; + SceneNode* clone() const; // this node SceneNodeType nodeType; @@ -57,7 +59,7 @@ struct SceneNode { // The node's position and rotation relative to its parent 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 referencePoint = vec3(0, 0, 0); // center of rotation, in model space @@ -78,7 +80,11 @@ struct SceneNode { uint displacementTextureID; float displacementCoefficient = 0.1; // in units uint reflectionTextureID; - + + // has_transparancy + const Mesh* m_gemoetry = nullptr; + const PNGImage* t_diffuse = nullptr; + // shader flags bool isTextured = false; bool isVertexColored = false; diff --git a/src/utilities/imageLoader.cpp b/src/utilities/imageLoader.cpp index f593885..b1bb906 100644 --- a/src/utilities/imageLoader.cpp +++ b/src/utilities/imageLoader.cpp @@ -58,7 +58,14 @@ PNGImage loadPNGFile(string filename, bool flip_handedness) { image.width = width; image.height = height; image.pixels = pixels; - + + for (uint i = 3; i < pixels.size(); i+=4) { + if (pixels[i] < 255) { + image.has_transparancy = true; + break; + } + } + return image; } diff --git a/src/utilities/imageLoader.hpp b/src/utilities/imageLoader.hpp index 7f61175..9c91bf9 100644 --- a/src/utilities/imageLoader.hpp +++ b/src/utilities/imageLoader.hpp @@ -10,6 +10,7 @@ struct PNGImage { uint width, height; bool repeat_mirrored = false; std::vector pixels; // RGBA + bool has_transparancy = false; }; PNGImage loadPNGFile(std::string filename, bool flip_handedness=false); diff --git a/src/utilities/mesh.h b/src/utilities/mesh.h index ae0bded..2a3e993 100644 --- a/src/utilities/mesh.h +++ b/src/utilities/mesh.h @@ -10,4 +10,6 @@ struct Mesh { std::vector colors; std::vector indices; + + bool has_transparancy = false; // if any of the colors are transparent };