Add basic texturing support for gltf
This commit is contained in:
@@ -10,62 +10,35 @@ in vec4 v_fragmentPositionDirectionalLightSpace;
|
||||
|
||||
in vec3 v_lightDirectionTangent;
|
||||
in vec3 v_lightPositionTangent0;
|
||||
//in vec3 v_lightPositionTangent1;
|
||||
//in vec3 v_lightPositionTangent2;
|
||||
//in vec3 v_lightPositionTangent3;
|
||||
|
||||
in vec3 v_viewPositionTangent;
|
||||
|
||||
struct Material {
|
||||
sampler2D texture_diffuse0;
|
||||
sampler2D texture_diffuse1;
|
||||
sampler2D texture_specular0;
|
||||
sampler2D texture_normal0;
|
||||
sampler2D texture_height0;
|
||||
sampler2D texture_gloss0;
|
||||
float shininess;
|
||||
struct Material
|
||||
{
|
||||
sampler2D texture_diffuse;
|
||||
sampler2D texture_normal;
|
||||
};
|
||||
uniform Material u_material;
|
||||
|
||||
struct DirectionalLight {
|
||||
struct DirectionalLight
|
||||
{
|
||||
vec3 direction;
|
||||
bool isActive;
|
||||
vec3 color;
|
||||
};
|
||||
uniform DirectionalLight u_directionalLight;
|
||||
|
||||
struct PointLight {
|
||||
struct PointLight
|
||||
{
|
||||
vec3 position;
|
||||
bool isActive;
|
||||
vec3 color;
|
||||
};
|
||||
|
||||
#define NUM_POINT_LIGHTS 1
|
||||
uniform PointLight u_pointLight[NUM_POINT_LIGHTS];
|
||||
|
||||
/*struct SpotLight {
|
||||
bool isActive;
|
||||
vec3 position;
|
||||
vec3 direction;
|
||||
|
||||
float innerCutOff;
|
||||
float outerCutOff;
|
||||
|
||||
float K_q;
|
||||
|
||||
vec3 ambient;
|
||||
vec3 diffuse;
|
||||
vec3 specular;
|
||||
};
|
||||
uniform SpotLight u_spotLight;*/
|
||||
|
||||
uniform mat3 u_normalMatrix;
|
||||
|
||||
// uniform sampler2D u_texture_directionalShadowMap;
|
||||
// uniform samplerCube u_texture_pointShadowMap0;
|
||||
//uniform samplerCube u_texture_pointShadowMap1;
|
||||
//uniform samplerCube u_texture_pointShadowMap2;
|
||||
//uniform samplerCube u_texture_pointShadowMap3;
|
||||
|
||||
// clang-format off
|
||||
vec3 sampleOffsetDirections[20] = vec3[] (
|
||||
vec3( 1, 1, 1), vec3( 1, -1, 1), vec3(-1, -1, 1), vec3(-1, 1, 1),
|
||||
vec3( 1, 1, -1), vec3( 1, -1, -1), vec3(-1, -1, -1), vec3(-1, 1, -1),
|
||||
@@ -73,54 +46,42 @@ vec3 sampleOffsetDirections[20] = vec3[] (
|
||||
vec3( 1, 0, 1), vec3(-1, 0, 1), vec3( 1, 0, -1), vec3(-1, 0, -1),
|
||||
vec3( 0, 1, 1), vec3( 0, -1, 1), vec3( 0, -1, -1), vec3( 0, 1, -1)
|
||||
);
|
||||
|
||||
// uniform bool b_drawShadows;
|
||||
|
||||
// uniform float pointShadowDepthMapFarPlane;
|
||||
// clang-format on
|
||||
|
||||
vec3 directionalLightContribution(DirectionalLight light, vec3 normal, vec3 viewDir);
|
||||
vec3 pointLightContribution(PointLight light, vec3 normal, vec3 fragPos, vec3 viewDir);
|
||||
//vec3 spotLightContribution(PointLight light, vec3 normal, vec3 fragPos, vec3 viewDir);
|
||||
|
||||
void computeShading(
|
||||
vec3 light_ambient, vec3 light_diffuse, vec3 light_specular,
|
||||
vec3 lightDir, vec3 viewDir, vec3 normal,
|
||||
out vec3 ambient, out vec3 diffuse, out vec3 specular
|
||||
);
|
||||
void computeShading(vec3 light_ambient, vec3 light_diffuse, vec3 light_specular, vec3 lightDir, vec3 viewDir,
|
||||
vec3 normal, out vec3 ambient, out vec3 diffuse, out vec3 specular);
|
||||
|
||||
float computeAttenuation(vec3 lightPos, vec3 fragPos, float K_q);
|
||||
|
||||
// float computeDirectionalShadows(vec4 fragPosLightSpace, vec3 normal, vec3 lightDir);
|
||||
// float computePointShadows(vec3 fragPos, vec3 lightPos);
|
||||
|
||||
void main() {
|
||||
|
||||
void main()
|
||||
{
|
||||
vec3 fragmentColor = vec3(0.0f);
|
||||
|
||||
vec3 normal = texture(u_material.texture_normal0, v_texCoord).rgb;
|
||||
vec3 normal = texture(u_material.texture_normal, v_texCoord).rgb;
|
||||
normal = normalize(normal * 2.0 - 1.0);
|
||||
vec3 viewDir = normalize(v_viewPositionTangent - v_fragmentPositionTangent);
|
||||
|
||||
fragmentColor += directionalLightContribution(u_directionalLight, normal, viewDir);
|
||||
|
||||
for(int i = 0; i < NUM_POINT_LIGHTS; i++) {
|
||||
for (int i = 0; i < NUM_POINT_LIGHTS; i++) {
|
||||
fragmentColor += pointLightContribution(u_pointLight[i], normal, v_fragmentPositionTangent, viewDir);
|
||||
}
|
||||
|
||||
// There are currently no spotlights
|
||||
//fragmentColor += spotLightContribution(u_spotLight, normal, v_fragmentPositionTangent, viewDir);
|
||||
// fragmentColor = (v_normal + 1.0f) * 0.5f;
|
||||
fragmentColor = vec3(texture(u_material.texture_diffuse, v_texCoord));
|
||||
|
||||
f_color = vec4(fragmentColor, 1.0f);
|
||||
f_color = vec4(0.95f, 0.16f, 0.33f, 1.0f);
|
||||
}
|
||||
|
||||
vec3 directionalLightContribution(DirectionalLight light, vec3 normal, vec3 viewDir) {
|
||||
|
||||
vec3 directionalLightContribution(DirectionalLight light, vec3 normal, vec3 viewDir)
|
||||
{
|
||||
// Only compute if light source is active
|
||||
if(!light.isActive)
|
||||
if (!light.isActive)
|
||||
return vec3(0.0f);
|
||||
|
||||
//vec3 lightDir = normalize(-light.direction);
|
||||
vec3 lightDir = normalize(-v_lightDirectionTangent);
|
||||
|
||||
vec3 diffuseColor = light.color;
|
||||
@@ -130,17 +91,13 @@ vec3 directionalLightContribution(DirectionalLight light, vec3 normal, vec3 view
|
||||
vec3 ambient, diffuse, specular;
|
||||
computeShading(ambientColor, diffuseColor, specularColor, lightDir, viewDir, normal, ambient, diffuse, specular);
|
||||
|
||||
float shadows = 0.0f;
|
||||
// if(b_drawShadows)
|
||||
// shadows = computeDirectionalShadows(v_fragmentPositionDirectionalLightSpace, normal, lightDir);
|
||||
|
||||
return (ambient + (1.0f - shadows) * (diffuse + specular));
|
||||
return ambient + diffuse + specular;
|
||||
}
|
||||
|
||||
vec3 pointLightContribution(PointLight light, vec3 normal, vec3 fragPos, vec3 viewDir) {
|
||||
|
||||
vec3 pointLightContribution(PointLight light, vec3 normal, vec3 fragPos, vec3 viewDir)
|
||||
{
|
||||
// Only compute if light source is active
|
||||
if(!light.isActive)
|
||||
if (!light.isActive)
|
||||
return vec3(0.0f);
|
||||
|
||||
vec3 lightDir = normalize(v_lightPositionTangent0 - fragPos);
|
||||
@@ -153,123 +110,35 @@ vec3 pointLightContribution(PointLight light, vec3 normal, vec3 fragPos, vec3 vi
|
||||
computeShading(ambientColor, diffuseColor, specularColor, lightDir, viewDir, normal, ambient, diffuse, specular);
|
||||
|
||||
float attenuation = computeAttenuation(v_lightPositionTangent0, fragPos, 0.032f);
|
||||
//ambient *= attenuation;
|
||||
//diffuse *= attenuation;
|
||||
//specular *= attenuation;
|
||||
// ambient *= attenuation;
|
||||
// diffuse *= attenuation;
|
||||
// specular *= attenuation;
|
||||
|
||||
float shadows = 0.0f;
|
||||
// if(b_drawShadows)
|
||||
// shadows = computePointShadows(v_fragmentPosition, light.position);
|
||||
|
||||
return (ambient + (1.0f - shadows) * (diffuse + specular));
|
||||
return ambient + diffuse + specular;
|
||||
}
|
||||
|
||||
/*vec3 spotLightContribution(SpotLight light, vec3 normal, vec3 fragPos, vec3 viewDir) {
|
||||
|
||||
// Only compute if light source is active
|
||||
if(!light.isActive)
|
||||
return vec3(0.0f);
|
||||
|
||||
vec3 lightDir = normalize(light.position - fragPos);
|
||||
|
||||
vec3 ambient, diffuse, specular;
|
||||
computeShading(light.ambient, light.diffuse, light.specular, lightDir, viewDir, normal, ambient, diffuse, specular);
|
||||
|
||||
float attenuation = computeAttenuation(light.position, fragPos, light.K_q);
|
||||
ambient *= attenuation;
|
||||
diffuse *= attenuation;
|
||||
specular *= attenuation;
|
||||
|
||||
float theta = dot(lightDir, normalize(-light.direction));
|
||||
float epsilon = light.innerCutOff - light.outerCutOff;
|
||||
float intensity = clamp((theta - light.outerCutOff) / epsilon, 0.0f, 1.0f);
|
||||
|
||||
diffuse *= intensity;
|
||||
specular *= intensity;
|
||||
|
||||
return (ambient + diffuse + specular);
|
||||
}*/
|
||||
|
||||
void computeShading(
|
||||
vec3 light_ambient, vec3 light_diffuse, vec3 light_specular,
|
||||
vec3 lightDir, vec3 viewDir, vec3 normal,
|
||||
out vec3 ambient, out vec3 diffuse, out vec3 specular) {
|
||||
|
||||
void computeShading(vec3 light_ambient, vec3 light_diffuse, vec3 light_specular, vec3 lightDir, vec3 viewDir,
|
||||
vec3 normal, out vec3 ambient, out vec3 diffuse, out vec3 specular)
|
||||
{
|
||||
// Diffuse shading
|
||||
float diffuseShading = max(dot(normal, lightDir), 0.0f);
|
||||
|
||||
// Specular shading
|
||||
vec3 halfwayDir = normalize(lightDir + viewDir);
|
||||
float specularShading = pow(max(dot(normal, halfwayDir), 0.0f), u_material.shininess);
|
||||
|
||||
vec4 diffuseTex = texture(u_material.texture_diffuse0, v_texCoord);
|
||||
vec4 specularTex = texture(u_material.texture_specular0, v_texCoord);
|
||||
float specularShading = pow(max(dot(normal, halfwayDir), 0.0f), 100.0f);
|
||||
|
||||
vec4 diffuseTex = texture(u_material.texture_diffuse, v_texCoord);
|
||||
// vec4 specularTex = texture(u_material.texture_specular, v_texCoord);
|
||||
|
||||
ambient = light_ambient * vec3(diffuseTex);
|
||||
diffuse = light_diffuse * diffuseShading * vec3(diffuseTex);
|
||||
specular = light_specular * specularShading * vec3(specularTex);
|
||||
|
||||
// specular = light_specular * specularShading * vec3(specularTex);
|
||||
specular = vec3(0.0f);
|
||||
}
|
||||
|
||||
float computeAttenuation(vec3 lightPos, vec3 fragPos, float K_q) {
|
||||
|
||||
float computeAttenuation(vec3 lightPos, vec3 fragPos, float K_q)
|
||||
{
|
||||
float distanceLightFragment = length(lightPos - fragPos);
|
||||
|
||||
return 1.0f / (K_q * distanceLightFragment * distanceLightFragment);
|
||||
|
||||
}
|
||||
|
||||
// float computeDirectionalShadows(vec4 fragPosLightSpace, vec3 normal, vec3 lightDir) {
|
||||
|
||||
// // Perspective divide
|
||||
// vec3 projCoords = fragPosLightSpace.xyz / fragPosLightSpace.w;
|
||||
|
||||
// // Transform from [-1,1] to [0,1]
|
||||
// projCoords *= 0.5f;
|
||||
// projCoords += 0.5f;
|
||||
|
||||
// if(projCoords.z > 1.0f) return 0.0f;
|
||||
|
||||
// float closestDepth = texture(u_texture_directionalShadowMap, projCoords.xy).r;
|
||||
// float currentDepth = projCoords.z;
|
||||
|
||||
// float bias = max(0.05 * (1.0 - dot(normal, lightDir)), 0.005);
|
||||
// bias *= 0.25f;
|
||||
|
||||
// float shadow = 0.0;
|
||||
// vec2 texelSize = 1.0 / textureSize(u_texture_directionalShadowMap, 0);
|
||||
// for(int x = -1; x <= 1; x++) {
|
||||
// for(int y = -1; y <= 1; y++) {
|
||||
// float pcfDepth = texture(u_texture_directionalShadowMap, projCoords.xy + vec2(x, y) * texelSize).r;
|
||||
// shadow += currentDepth - bias > pcfDepth ? 1.0 : 0.0;
|
||||
// }
|
||||
// }
|
||||
// shadow /= 9.0f;
|
||||
|
||||
// return shadow;
|
||||
// }
|
||||
|
||||
// float computePointShadows(vec3 fragPos, vec3 lightPos) {
|
||||
|
||||
// // get vector between fragment position and light position
|
||||
// vec3 fragToLight = fragPos - lightPos;
|
||||
|
||||
// // now get current linear depth as the length between the fragment and light position
|
||||
// float currentDepth = length(fragToLight);
|
||||
|
||||
// float shadow = 0.0;
|
||||
// float bias = 0.05;
|
||||
// int samples = 20;
|
||||
// float viewDistance = length(v_viewPositionTangent - fragPos);
|
||||
// float diskRadius = 0.05;
|
||||
|
||||
// for(int i = 0; i < samples; ++i) {
|
||||
// float closestDepth = texture(u_texture_pointShadowMap0, fragToLight + sampleOffsetDirections[i] * diskRadius).r;
|
||||
// closestDepth *= pointShadowDepthMapFarPlane;
|
||||
// if(currentDepth - bias > closestDepth)
|
||||
// shadow += 1.0;
|
||||
// }
|
||||
|
||||
// shadow /= float(samples);
|
||||
// return shadow;
|
||||
// }
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include "Camera.h"
|
||||
#include "FrameBuffer.h"
|
||||
#include "Helper.h"
|
||||
#include "Light.h"
|
||||
#include "Mesh.h"
|
||||
#include "ShaderProgram.h"
|
||||
#include "Window.h"
|
||||
@@ -25,8 +26,9 @@ Controller::Controller()
|
||||
|
||||
std::string err;
|
||||
std::string warn;
|
||||
bool ret = loader.LoadASCIIFromFile(&m_model, &err, &warn, "glTF/DamagedHelmet.gltf");
|
||||
// bool ret = loader.LoadASCIIFromFile(&m_model, &err, &warn, "minimal.gltf");
|
||||
// bool ret = loader.LoadASCIIFromFile(&m_model, &err, &warn, "WaterBottle/glTF/WaterBottle.gltf");
|
||||
// bool ret = loader.LoadASCIIFromFile(&m_model, &err, &warn, "Lantern/glTF/Lantern.gltf");
|
||||
bool ret = loader.LoadASCIIFromFile(&m_model, &err, &warn, "glTF/ABeautifulGame.gltf");
|
||||
|
||||
if (!warn.empty()) {
|
||||
Log::logger().warn("{}", warn);
|
||||
@@ -49,11 +51,25 @@ Controller::Controller()
|
||||
|
||||
ShaderProgram::unbind();
|
||||
|
||||
std::vector<Texture> textures;
|
||||
for (auto const &texture : m_model.textures) {
|
||||
textures.emplace_back(texture, m_model.images);
|
||||
}
|
||||
m_textures = std::move(textures);
|
||||
|
||||
std::vector<Model> models;
|
||||
for (auto const &mesh : m_model.meshes) {
|
||||
std::vector<Mesh> meshes;
|
||||
for (auto const &primitive : mesh.primitives) {
|
||||
meshes.emplace_back(Mesh({primitive, m_model, locations}, {}));
|
||||
auto const &material = m_model.materials.at(primitive.material);
|
||||
auto baseColorTexture = material.pbrMetallicRoughness.baseColorTexture;
|
||||
std::vector<std::reference_wrapper<const Texture>> textures;
|
||||
|
||||
if (baseColorTexture.index != -1) {
|
||||
textures.push_back(m_textures.at(baseColorTexture.index));
|
||||
}
|
||||
|
||||
meshes.emplace_back(Mesh({primitive, m_model, locations}, textures));
|
||||
}
|
||||
models.emplace_back(Model(mesh.name, std::move(meshes)));
|
||||
}
|
||||
@@ -61,6 +77,10 @@ Controller::Controller()
|
||||
|
||||
std::vector<ModelEntity> entities;
|
||||
for (auto const &node : m_model.nodes) {
|
||||
if (node.mesh == -1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ModelEntity entity(Entity::Prototype(node.name, {}, {}, 1.0F), m_models[static_cast<unsigned>(node.mesh)],
|
||||
defaultProgram);
|
||||
|
||||
@@ -84,8 +104,6 @@ Controller::Controller()
|
||||
entities[child].translate(glm::vec3(node.translation[0], node.translation[1], node.translation[2]));
|
||||
}
|
||||
}
|
||||
|
||||
Log::logger().info("Load node {}.", node.name);
|
||||
}
|
||||
m_entities = std::move(entities);
|
||||
}
|
||||
@@ -95,12 +113,13 @@ void Controller::run()
|
||||
updateExposure(postProcessingProgram);
|
||||
|
||||
m_camera->translate(glm::vec3(0., 1.5, 5.));
|
||||
DirectionalLight light(DirectionalLight::Prototype("", glm::vec3(-0.2, -1.0, -0.3), glm::vec3(1.0f), 10.f),
|
||||
&defaultProgram);
|
||||
|
||||
Log::logger().info("Startup complete. Enter game loop.");
|
||||
|
||||
// This is the game loop
|
||||
while (glfwWindowShouldClose(&m_gameWindow->glfw_window()) == GLFW_FALSE) {
|
||||
|
||||
// --- Timing ---
|
||||
limit_framerate();
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "VertexArray.h"
|
||||
#include "resources/Model.h"
|
||||
#include "Entity.h"
|
||||
#include "resources/Texture.h"
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <memory>
|
||||
@@ -47,6 +48,7 @@ private:
|
||||
|
||||
std::vector<ModelEntity> m_entities;
|
||||
std::vector<Model> m_models;
|
||||
std::vector<Texture> m_textures;
|
||||
|
||||
double m_deltaTime{};
|
||||
float m_exposure = 1.0;
|
||||
|
||||
@@ -22,7 +22,6 @@ public:
|
||||
: name(_name), position(_position), rotation(_rotation), scale(_scale)
|
||||
{
|
||||
}
|
||||
virtual ~Prototype() = default;
|
||||
|
||||
std::string name;
|
||||
glm::vec3 position;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "resources/CubeMap.h"
|
||||
#include "resources/Resource.h"
|
||||
|
||||
#include <glad/gl.h>
|
||||
|
||||
class ShaderProgram;
|
||||
|
||||
@@ -13,7 +13,8 @@ Light::Light(const std::string &name, glm::vec3 color, float intensity, ShaderPr
|
||||
}
|
||||
|
||||
Light::~Light()
|
||||
{}
|
||||
{
|
||||
}
|
||||
|
||||
glm::vec3 Light::getColor()
|
||||
{
|
||||
@@ -45,7 +46,8 @@ void Light::setActive(bool active)
|
||||
|
||||
PointLight::PointLight(Prototype prototype, ShaderProgram *shaderProgram)
|
||||
: Light(prototype.name, prototype.color, prototype.intensity, shaderProgram), m_position(prototype.position)
|
||||
{}
|
||||
{
|
||||
}
|
||||
|
||||
void PointLight::update()
|
||||
{
|
||||
@@ -78,7 +80,9 @@ void PointLight::setPosition(glm::vec3 position)
|
||||
|
||||
DirectionalLight::DirectionalLight(Prototype prototype, ShaderProgram *shaderProgram)
|
||||
: Light(prototype.name, prototype.color, prototype.intensity, shaderProgram), m_direction(prototype.direction)
|
||||
{}
|
||||
{
|
||||
update();
|
||||
}
|
||||
|
||||
void DirectionalLight::update()
|
||||
{
|
||||
|
||||
20
src/Mesh.cpp
20
src/Mesh.cpp
@@ -2,31 +2,20 @@
|
||||
|
||||
#include "ShaderProgram.h"
|
||||
#include "VertexArray.h"
|
||||
#include "resources/ResourceHandler.h"
|
||||
#include "resources/Texture.h"
|
||||
#include <utility>
|
||||
|
||||
Mesh::Mesh(VertexArray vertexArray, std::vector<ResourceId> textures)
|
||||
Mesh::Mesh(VertexArray vertexArray, std::vector<std::reference_wrapper<const Texture>> textures)
|
||||
: m_vertexArray(std::move(vertexArray)), m_textures(std::move(textures))
|
||||
{
|
||||
}
|
||||
|
||||
void Mesh::draw(ShaderProgram const &shaderProgram) const
|
||||
{
|
||||
std::array<uint8_t, static_cast<std::size_t>(TextureType::TEXTURE_TYPE_NUM_ITEMS)> typeNumberCount{};
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
// Bind all textures in order to its texture unit
|
||||
std::size_t textureNum = 0;
|
||||
for (auto textureIt : m_textures) {
|
||||
auto texture = std::static_pointer_cast<Texture>(ResourceHandler::instance().resource(textureIt));
|
||||
TextureType currentTextureType = texture->textureType();
|
||||
|
||||
texture->bind(static_cast<uint8_t>(textureNum), shaderProgram,
|
||||
typeNumberCount.at(static_cast<std::size_t>(currentTextureType)));
|
||||
|
||||
typeNumberCount.at(static_cast<std::size_t>(currentTextureType)) += 1;
|
||||
|
||||
textureIt.get().bind(static_cast<uint8_t>(textureNum), shaderProgram);
|
||||
textureNum++;
|
||||
}
|
||||
|
||||
@@ -38,16 +27,17 @@ void Mesh::draw(ShaderProgram const &shaderProgram) const
|
||||
|
||||
// Unbind all textures
|
||||
for (auto textureIt : m_textures) {
|
||||
auto texture = std::static_pointer_cast<Texture>(ResourceHandler::instance().resource(textureIt));
|
||||
texture->unbind();
|
||||
textureIt.get().unbind();
|
||||
}
|
||||
}
|
||||
|
||||
void Mesh::drawWithoutTextures() const
|
||||
{
|
||||
m_vertexArray.bind();
|
||||
|
||||
glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(m_vertexArray.indicesCount()),
|
||||
static_cast<GLenum>(m_vertexArray.indicesType()), nullptr);
|
||||
|
||||
VertexArray::unbind();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "VertexArray.h"
|
||||
#include "resources/Resource.h"
|
||||
#include "resources/Texture.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
@@ -10,7 +10,7 @@ class ShaderProgram;
|
||||
class Mesh
|
||||
{
|
||||
public:
|
||||
Mesh(VertexArray vertexArray, std::vector<ResourceId> textures);
|
||||
Mesh(VertexArray vertexArray, std::vector<std::reference_wrapper<const Texture>> textures);
|
||||
|
||||
void draw(ShaderProgram const &shaderProgram) const;
|
||||
void drawWithoutTextures() const;
|
||||
@@ -19,5 +19,5 @@ public:
|
||||
|
||||
private:
|
||||
VertexArray m_vertexArray;
|
||||
std::vector<ResourceId> m_textures;
|
||||
std::vector<std::reference_wrapper<const Texture>> m_textures;
|
||||
};
|
||||
|
||||
@@ -14,11 +14,6 @@
|
||||
Scene::Scene(std::vector<std::shared_ptr<ShaderProgram>> shaderPrograms)
|
||||
: m_shaderProgram(*Controller::getShaderProgramByName("defaultProgram", shaderPrograms))
|
||||
{
|
||||
// This will be removed in future when gloss maps are implemented
|
||||
m_shaderProgram.bind();
|
||||
m_shaderProgram.setUniform("u_material.shininess", 100.0f);
|
||||
m_shaderProgram.unbind();
|
||||
|
||||
std::array modelDescriptors{
|
||||
ModelDescriptor{"fallback", "data/res/models/fallback.ffo"},
|
||||
ModelDescriptor{"backpack", "data/res/models/backpack.ffo"},
|
||||
|
||||
@@ -4,53 +4,118 @@
|
||||
#include <cstddef>
|
||||
#include <vector>
|
||||
|
||||
VertexArray::VertexArray(tinygltf::Primitive const &primitive, tinygltf::Model const &model, AttributeLocations &locations)
|
||||
VertexArray::VertexArray(tinygltf::Primitive const &primitive, tinygltf::Model const &model,
|
||||
AttributeLocations &locations)
|
||||
{
|
||||
GLuint vao{};
|
||||
glGenVertexArrays(1, &vao);
|
||||
glBindVertexArray(vao);
|
||||
|
||||
int position_accessor_id = primitive.attributes.at("POSITION");
|
||||
// int normal_accessor = primitive.attributes.at("NORMAL");
|
||||
// int uv_accessor = primitive.attributes.at("TEXCOORD_0");
|
||||
int normal_accessor_id = primitive.attributes.at("NORMAL");
|
||||
int uv_accessor_id = primitive.attributes.at("TEXCOORD_0");
|
||||
int indices_accessor_id = primitive.indices;
|
||||
|
||||
auto const &position_accessor = model.accessors.at(position_accessor_id);
|
||||
auto const &normal_accessor = model.accessors.at(normal_accessor_id);
|
||||
auto const &uv_accessor = model.accessors.at(uv_accessor_id);
|
||||
auto const &indices_accessor = model.accessors.at(indices_accessor_id);
|
||||
|
||||
int position_buffer_view_id = model.accessors[position_accessor_id].bufferView;
|
||||
int normal_buffer_view_id = model.accessors[normal_accessor_id].bufferView;
|
||||
int uv_buffer_view_id = model.accessors[uv_accessor_id].bufferView;
|
||||
int indices_buffer_view_id = model.accessors[indices_accessor_id].bufferView;
|
||||
|
||||
auto const &position_buffer_view = model.bufferViews.at(position_buffer_view_id);
|
||||
auto const &normal_buffer_view = model.bufferViews.at(normal_buffer_view_id);
|
||||
auto const &uv_buffer_view = model.bufferViews.at(uv_buffer_view_id);
|
||||
auto const &indices_buffer_view = model.bufferViews.at(indices_buffer_view_id);
|
||||
|
||||
auto const &position_buffer = model.buffers.at(position_buffer_view.buffer);
|
||||
auto const &normal_buffer = model.buffers.at(normal_buffer_view.buffer);
|
||||
auto const &uv_buffer = model.buffers.at(uv_buffer_view.buffer);
|
||||
auto const &indices_buffer = model.buffers.at(indices_buffer_view.buffer);
|
||||
|
||||
GLuint positionVbo{};
|
||||
glGenBuffers(1, &positionVbo);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, positionVbo);
|
||||
glBufferData(GL_ARRAY_BUFFER, position_buffer_view.byteLength,
|
||||
position_buffer.data.data() + position_buffer_view.byteOffset, GL_STATIC_DRAW);
|
||||
{
|
||||
glGenBuffers(1, &positionVbo);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, positionVbo);
|
||||
glBufferData(GL_ARRAY_BUFFER, position_buffer_view.byteLength,
|
||||
position_buffer.data.data() + position_buffer_view.byteOffset, GL_STATIC_DRAW);
|
||||
|
||||
int size = 1;
|
||||
if (position_accessor.type == TINYGLTF_TYPE_SCALAR) {
|
||||
size = 1;
|
||||
} else if (position_accessor.type == TINYGLTF_TYPE_VEC2) {
|
||||
size = 2;
|
||||
} else if (position_accessor.type == TINYGLTF_TYPE_VEC3) {
|
||||
size = 3;
|
||||
} else if (position_accessor.type == TINYGLTF_TYPE_VEC4) {
|
||||
size = 4;
|
||||
} else {
|
||||
assert(0);
|
||||
int size = 1;
|
||||
if (position_accessor.type == TINYGLTF_TYPE_SCALAR) {
|
||||
size = 1;
|
||||
} else if (position_accessor.type == TINYGLTF_TYPE_VEC2) {
|
||||
size = 2;
|
||||
} else if (position_accessor.type == TINYGLTF_TYPE_VEC3) {
|
||||
size = 3;
|
||||
} else if (position_accessor.type == TINYGLTF_TYPE_VEC4) {
|
||||
size = 4;
|
||||
} else {
|
||||
assert(0);
|
||||
}
|
||||
|
||||
int position_byte_stride = position_accessor.ByteStride(position_buffer_view);
|
||||
glEnableVertexAttribArray(locations.position);
|
||||
glVertexAttribPointer(locations.position, size, position_accessor.componentType,
|
||||
position_accessor.normalized ? GL_TRUE : GL_FALSE, position_byte_stride,
|
||||
(void *)position_accessor.byteOffset);
|
||||
}
|
||||
|
||||
int position_byte_stride = position_accessor.ByteStride(position_buffer_view);
|
||||
glEnableVertexAttribArray(locations.position);
|
||||
glVertexAttribPointer(locations.position, size, position_accessor.componentType,
|
||||
position_accessor.normalized ? GL_TRUE : GL_FALSE, position_byte_stride,
|
||||
(void *)position_accessor.byteOffset);
|
||||
GLuint normalVbo{};
|
||||
{
|
||||
glGenBuffers(1, &normalVbo);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, normalVbo);
|
||||
glBufferData(GL_ARRAY_BUFFER, normal_buffer_view.byteLength,
|
||||
normal_buffer.data.data() + normal_buffer_view.byteOffset, GL_STATIC_DRAW);
|
||||
|
||||
int size = 1;
|
||||
if (normal_accessor.type == TINYGLTF_TYPE_SCALAR) {
|
||||
size = 1;
|
||||
} else if (normal_accessor.type == TINYGLTF_TYPE_VEC2) {
|
||||
size = 2;
|
||||
} else if (normal_accessor.type == TINYGLTF_TYPE_VEC3) {
|
||||
size = 3;
|
||||
} else if (normal_accessor.type == TINYGLTF_TYPE_VEC4) {
|
||||
size = 4;
|
||||
} else {
|
||||
assert(0);
|
||||
}
|
||||
|
||||
int normal_byte_stride = normal_accessor.ByteStride(normal_buffer_view);
|
||||
glEnableVertexAttribArray(locations.normal);
|
||||
glVertexAttribPointer(locations.normal, size, normal_accessor.componentType,
|
||||
normal_accessor.normalized ? GL_TRUE : GL_FALSE, normal_byte_stride,
|
||||
(void *)normal_accessor.byteOffset);
|
||||
}
|
||||
|
||||
GLuint uvVbo{};
|
||||
{
|
||||
glGenBuffers(1, &uvVbo);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, uvVbo);
|
||||
glBufferData(GL_ARRAY_BUFFER, uv_buffer_view.byteLength,
|
||||
uv_buffer.data.data() + uv_buffer_view.byteOffset, GL_STATIC_DRAW);
|
||||
|
||||
int size = 1;
|
||||
if (uv_accessor.type == TINYGLTF_TYPE_SCALAR) {
|
||||
size = 1;
|
||||
} else if (uv_accessor.type == TINYGLTF_TYPE_VEC2) {
|
||||
size = 2;
|
||||
} else if (uv_accessor.type == TINYGLTF_TYPE_VEC3) {
|
||||
size = 3;
|
||||
} else if (uv_accessor.type == TINYGLTF_TYPE_VEC4) {
|
||||
size = 4;
|
||||
} else {
|
||||
assert(0);
|
||||
}
|
||||
|
||||
int uv_byte_stride = uv_accessor.ByteStride(uv_buffer_view);
|
||||
glEnableVertexAttribArray(locations.uv);
|
||||
glVertexAttribPointer(locations.uv, size, uv_accessor.componentType,
|
||||
uv_accessor.normalized ? GL_TRUE : GL_FALSE, uv_byte_stride,
|
||||
(void *)uv_accessor.byteOffset);
|
||||
}
|
||||
|
||||
GLuint ebo{};
|
||||
glGenBuffers(1, &ebo);
|
||||
@@ -63,6 +128,8 @@ VertexArray::VertexArray(tinygltf::Primitive const &primitive, tinygltf::Model c
|
||||
m_vao = vao;
|
||||
m_ebo = ebo;
|
||||
m_positionVbo = positionVbo;
|
||||
m_normalVbo = normalVbo;
|
||||
m_uvVbo = uvVbo;
|
||||
m_indicesCount = indices_accessor.count;
|
||||
m_indicesType = indices_accessor.componentType;
|
||||
}
|
||||
@@ -72,6 +139,8 @@ VertexArray::~VertexArray()
|
||||
glDeleteVertexArrays(1, &m_vao);
|
||||
|
||||
glDeleteBuffers(1, &m_positionVbo);
|
||||
glDeleteBuffers(1, &m_normalVbo);
|
||||
glDeleteBuffers(1, &m_uvVbo);
|
||||
glDeleteBuffers(1, &m_ebo);
|
||||
}
|
||||
|
||||
|
||||
@@ -15,11 +15,15 @@ public:
|
||||
m_indicesType(other.m_indicesType),
|
||||
m_vao(other.m_vao),
|
||||
m_positionVbo(other.m_positionVbo),
|
||||
m_normalVbo(other.m_normalVbo),
|
||||
m_uvVbo(other.m_uvVbo),
|
||||
m_ebo(other.m_ebo)
|
||||
{
|
||||
other.m_ebo = 0;
|
||||
other.m_vao = 0;
|
||||
other.m_positionVbo = 0;
|
||||
other.m_normalVbo = 0;
|
||||
other.m_uvVbo = 0;
|
||||
}
|
||||
|
||||
auto operator=(VertexArray &&other) noexcept -> VertexArray &
|
||||
@@ -28,11 +32,15 @@ public:
|
||||
m_indicesType = other.m_indicesType;
|
||||
m_vao = other.m_vao;
|
||||
m_positionVbo = other.m_positionVbo;
|
||||
m_normalVbo = other.m_normalVbo;
|
||||
m_uvVbo = other.m_uvVbo;
|
||||
m_ebo = other.m_ebo;
|
||||
|
||||
other.m_ebo = 0;
|
||||
other.m_vao = 0;
|
||||
other.m_positionVbo = 0;
|
||||
other.m_normalVbo = 0;
|
||||
other.m_uvVbo = 0;
|
||||
|
||||
return *this;
|
||||
}
|
||||
@@ -55,5 +63,7 @@ private:
|
||||
GLuint m_vao;
|
||||
|
||||
GLuint m_positionVbo;
|
||||
GLuint m_normalVbo;
|
||||
GLuint m_uvVbo;
|
||||
GLuint m_ebo;
|
||||
};
|
||||
|
||||
@@ -11,5 +11,4 @@ public:
|
||||
protected:
|
||||
uint32_t m_textureWidth;
|
||||
uint32_t m_textureHeight;
|
||||
uint32_t m_numComponents;
|
||||
};
|
||||
|
||||
@@ -6,9 +6,6 @@
|
||||
|
||||
TextureCubeMap::TextureCubeMap(const TextureCubeMapDescriptor &descriptor) : AbstractCubeMap(descriptor.path)
|
||||
{
|
||||
// Reserve space in vector so that elements can be accessed explicitly.
|
||||
m_textureBuffers.resize(static_cast<int>(CubeMapFace::CUBEMAP_FACES_NUM_ITEMS));
|
||||
|
||||
stbi_set_flip_vertically_on_load(0);
|
||||
|
||||
glGenTextures(1, &m_glId);
|
||||
@@ -20,7 +17,7 @@ TextureCubeMap::TextureCubeMap(const TextureCubeMapDescriptor &descriptor) : Abs
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
|
||||
|
||||
std::size_t i = 0;
|
||||
std::size_t faceCount = 0;
|
||||
for (const auto &faceName : FACE_NAMES) {
|
||||
std::string texturePath = descriptor.path + faceName;
|
||||
|
||||
@@ -28,43 +25,20 @@ TextureCubeMap::TextureCubeMap(const TextureCubeMapDescriptor &descriptor) : Abs
|
||||
int textureHeight{};
|
||||
int numComponents{};
|
||||
|
||||
auto textureBuffer = stbi_load(texturePath.c_str(), &textureWidth, &textureHeight, &numComponents, 0);
|
||||
auto *textureBuffer = stbi_load(texturePath.c_str(), &textureWidth, &textureHeight, &numComponents, 0);
|
||||
|
||||
m_textureWidth = static_cast<unsigned>(textureWidth);
|
||||
m_textureHeight = static_cast<unsigned>(textureHeight);
|
||||
m_numComponents = static_cast<unsigned>(numComponents);
|
||||
|
||||
if (!textureBuffer) {
|
||||
if (textureBuffer == nullptr) {
|
||||
Log::logger().warn("CubeMap texture {} could not be loaded", texturePath);
|
||||
return;
|
||||
}
|
||||
|
||||
m_textureBuffers[i] = textureBuffer;
|
||||
i++;
|
||||
}
|
||||
GLint internalFormat{};
|
||||
GLenum dataFormat{};
|
||||
|
||||
glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
|
||||
}
|
||||
|
||||
void TextureCubeMap::initialize()
|
||||
{
|
||||
m_initialized = true;
|
||||
|
||||
glGenTextures(1, &m_glId);
|
||||
glBindTexture(GL_TEXTURE_CUBE_MAP, m_glId);
|
||||
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
|
||||
|
||||
int i = 0;
|
||||
for (auto &textureBuffer : m_textureBuffers) {
|
||||
GLint internalFormat;
|
||||
GLenum dataFormat;
|
||||
|
||||
switch (m_numComponents) {
|
||||
switch (numComponents) {
|
||||
case 1:
|
||||
internalFormat = GL_RED;
|
||||
dataFormat = GL_RED;
|
||||
@@ -79,12 +53,13 @@ void TextureCubeMap::initialize()
|
||||
break;
|
||||
}
|
||||
|
||||
glTexImage2D(static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i), 0, internalFormat,
|
||||
glTexImage2D(static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + faceCount), 0, internalFormat,
|
||||
static_cast<GLsizei>(m_textureWidth), static_cast<GLsizei>(m_textureHeight), 0, dataFormat,
|
||||
GL_UNSIGNED_BYTE, textureBuffer);
|
||||
|
||||
stbi_image_free(textureBuffer);
|
||||
i++;
|
||||
|
||||
faceCount++;
|
||||
}
|
||||
|
||||
glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
|
||||
@@ -108,7 +83,6 @@ InternalCubeMap::InternalCubeMap(unsigned int resolution) : AbstractCubeMap("int
|
||||
{
|
||||
m_textureWidth = resolution;
|
||||
m_textureHeight = resolution;
|
||||
m_initialized = true;
|
||||
|
||||
glGenTextures(1, &m_glId);
|
||||
glBindTexture(GL_TEXTURE_CUBE_MAP, m_glId);
|
||||
@@ -121,7 +95,7 @@ InternalCubeMap::InternalCubeMap(unsigned int resolution) : AbstractCubeMap("int
|
||||
|
||||
for (unsigned int i = 0; i < static_cast<int>(CubeMapFace::CUBEMAP_FACES_NUM_ITEMS); i++) {
|
||||
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_DEPTH_COMPONENT24, static_cast<GLsizei>(resolution),
|
||||
static_cast<GLsizei>(resolution), 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
|
||||
static_cast<GLsizei>(resolution), 0, GL_DEPTH_COMPONENT, GL_FLOAT, nullptr);
|
||||
}
|
||||
|
||||
glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
|
||||
|
||||
@@ -41,20 +41,10 @@ class TextureCubeMap : public AbstractCubeMap
|
||||
{
|
||||
public:
|
||||
TextureCubeMap(const TextureCubeMapDescriptor &descriptor);
|
||||
|
||||
protected:
|
||||
void initialize() override;
|
||||
|
||||
private:
|
||||
std::vector<stbi_uc *> m_textureBuffers;
|
||||
};
|
||||
|
||||
class InternalCubeMap : public AbstractCubeMap
|
||||
{
|
||||
public:
|
||||
InternalCubeMap(unsigned int resolution);
|
||||
|
||||
protected:
|
||||
void initialize() override
|
||||
{}
|
||||
};
|
||||
|
||||
@@ -13,11 +13,6 @@ auto Resource::id() const -> ResourceId
|
||||
return m_id;
|
||||
}
|
||||
|
||||
auto Resource::isInitialized() const -> bool
|
||||
{
|
||||
return m_initialized;
|
||||
}
|
||||
|
||||
auto Resource::resourcePath() const -> const std::filesystem::path &
|
||||
{
|
||||
return m_path;
|
||||
|
||||
@@ -18,13 +18,7 @@ public:
|
||||
|
||||
[[nodiscard]] auto id() const -> ResourceId;
|
||||
[[nodiscard]] auto resourcePath() const -> const std::filesystem::path &;
|
||||
|
||||
protected:
|
||||
[[nodiscard]] auto isInitialized() const -> bool;
|
||||
virtual void initialize() = 0;
|
||||
|
||||
bool m_initialized = false;
|
||||
|
||||
|
||||
private:
|
||||
ResourceId m_id;
|
||||
static ResourceId s_idCounter;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#include "ResourceHandler.h"
|
||||
#include "../util/Log.h"
|
||||
#include "CubeMap.h"
|
||||
#include "Texture.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
@@ -20,7 +19,6 @@ auto ResourceHandler::registerResource(Param const &...param) -> ResourceId
|
||||
return resource->id();
|
||||
}
|
||||
|
||||
template ResourceId ResourceHandler::registerResource<Texture>(TextureDescriptor const &);
|
||||
template ResourceId ResourceHandler::registerResource<TextureCubeMap>(TextureCubeMapDescriptor const &);
|
||||
template ResourceId ResourceHandler::registerResource<InternalCubeMap>(int const &);
|
||||
|
||||
@@ -30,38 +28,9 @@ auto ResourceHandler::resource(const ResourceId resourceId) const -> std::shared
|
||||
|
||||
if (resourceIt != m_resources.end()) {
|
||||
auto resource = resourceIt->second;
|
||||
|
||||
if (!resource->isInitialized()) {
|
||||
resource->initialize();
|
||||
}
|
||||
|
||||
return resource;
|
||||
}
|
||||
|
||||
Log::logger().warn("Could not find resource with id {}", resourceId);
|
||||
return {};
|
||||
}
|
||||
|
||||
auto ResourceHandler::resource(const std::string &name) const -> std::shared_ptr<Resource>
|
||||
{
|
||||
auto resourceIt = std::find_if(m_resources.begin(), m_resources.end(), [&name](const auto &resource) {
|
||||
if (auto namedResource = std::dynamic_pointer_cast<NamedResource>(resource.second)) {
|
||||
return namedResource->name() == name;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
if (resourceIt != m_resources.end()) {
|
||||
auto resource = resourceIt->second;
|
||||
|
||||
if (!resource->isInitialized()) {
|
||||
resource->initialize();
|
||||
}
|
||||
|
||||
return resource;
|
||||
}
|
||||
|
||||
Log::logger().warn("Could not find resource with unique name \"{}\"", name);
|
||||
return {};
|
||||
}
|
||||
|
||||
@@ -14,7 +14,6 @@ public:
|
||||
auto registerResource(Param const &...param) -> ResourceId;
|
||||
|
||||
[[nodiscard]] auto resource(ResourceId resourceId) const -> std::shared_ptr<Resource>;
|
||||
[[nodiscard]] auto resource(const std::string &name) const -> std::shared_ptr<Resource>;
|
||||
|
||||
private:
|
||||
ResourceHandler() = default;
|
||||
|
||||
@@ -4,34 +4,76 @@
|
||||
|
||||
#include <stb/stb_image.h>
|
||||
|
||||
Texture::Texture(const TextureDescriptor &descriptor)
|
||||
: AbstractTexture(descriptor.path), m_textureType(descriptor.textureType)
|
||||
// Texture::Texture(const TextureDescriptor &descriptor) : m_textureType(descriptor.textureType)
|
||||
// {
|
||||
// stbi_set_flip_vertically_on_load(1);
|
||||
|
||||
// int textureWidth{};
|
||||
// int textureHeight{};
|
||||
// int numComponents{};
|
||||
|
||||
// m_textureBuffer = stbi_load(resourcePath().c_str(), &textureWidth, &textureHeight, &numComponents, 0);
|
||||
|
||||
// m_textureWidth = static_cast<unsigned>(textureWidth);
|
||||
// m_textureHeight = static_cast<unsigned>(textureHeight);
|
||||
|
||||
// if (m_textureBuffer == nullptr) {
|
||||
// Log::logger().warn("Texture {} could not be loaded", resourcePath().string());
|
||||
// }
|
||||
|
||||
// GLenum internalFormat{};
|
||||
// GLenum dataFormat{};
|
||||
|
||||
// switch (numComponents) {
|
||||
// case 1:
|
||||
// internalFormat = GL_RED;
|
||||
// dataFormat = GL_RED;
|
||||
// break;
|
||||
// case 3:
|
||||
// internalFormat = (m_textureType == TextureType::Diffuse) ? GL_SRGB8 : GL_RGB8;
|
||||
// dataFormat = GL_RGB;
|
||||
// break;
|
||||
// case 4:
|
||||
// internalFormat = (m_textureType == TextureType::Diffuse) ? GL_SRGB8_ALPHA8 : GL_RGBA8;
|
||||
// dataFormat = GL_RGBA;
|
||||
// break;
|
||||
// }
|
||||
|
||||
// // Push texture to grahics card
|
||||
// glGenTextures(1, &m_glId);
|
||||
// glBindTexture(GL_TEXTURE_2D, m_glId);
|
||||
|
||||
// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
||||
// glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS, -2.0F);
|
||||
|
||||
// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||
// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||
|
||||
// glTexImage2D(GL_TEXTURE_2D, 0, static_cast<GLint>(internalFormat), static_cast<GLsizei>(m_textureWidth),
|
||||
// static_cast<GLsizei>(m_textureHeight), 0, dataFormat, GL_UNSIGNED_BYTE, m_textureBuffer);
|
||||
// glGenerateMipmap(GL_TEXTURE_2D);
|
||||
|
||||
// glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
// stbi_image_free(m_textureBuffer);
|
||||
// }
|
||||
|
||||
Texture::Texture(tinygltf::Texture const &texture, std::span<tinygltf::Image> images)
|
||||
{
|
||||
stbi_set_flip_vertically_on_load(1);
|
||||
auto sampler = texture.sampler;
|
||||
auto const &image = images[texture.source];
|
||||
|
||||
int textureWidth{};
|
||||
int textureHeight{};
|
||||
int numComponents{};
|
||||
m_textureType = TextureType::Diffuse;
|
||||
|
||||
m_textureBuffer = stbi_load(resourcePath().c_str(), &textureWidth, &textureHeight, &numComponents, 0);
|
||||
|
||||
m_textureWidth = static_cast<unsigned>(textureWidth);
|
||||
m_textureHeight = static_cast<unsigned>(textureHeight);
|
||||
m_numComponents = static_cast<unsigned>(numComponents);
|
||||
|
||||
if (m_textureBuffer == nullptr) {
|
||||
Log::logger().warn("Texture {} could not be loaded", resourcePath().string());
|
||||
}
|
||||
}
|
||||
|
||||
void Texture::initialize()
|
||||
{
|
||||
m_initialized = true;
|
||||
uint32_t width = image.width;
|
||||
uint32_t height = image.height;
|
||||
unsigned int components = image.component;
|
||||
|
||||
GLenum internalFormat{};
|
||||
GLenum dataFormat{};
|
||||
|
||||
switch (m_numComponents) {
|
||||
switch (components) {
|
||||
case 1:
|
||||
internalFormat = GL_RED;
|
||||
dataFormat = GL_RED;
|
||||
@@ -46,7 +88,6 @@ void Texture::initialize()
|
||||
break;
|
||||
}
|
||||
|
||||
// Push texture to grahics card
|
||||
glGenTextures(1, &m_glId);
|
||||
glBindTexture(GL_TEXTURE_2D, m_glId);
|
||||
|
||||
@@ -57,13 +98,11 @@ void Texture::initialize()
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, static_cast<GLint>(internalFormat), static_cast<GLsizei>(m_textureWidth),
|
||||
static_cast<GLsizei>(m_textureHeight), 0, dataFormat, GL_UNSIGNED_BYTE, m_textureBuffer);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, static_cast<GLint>(internalFormat), static_cast<GLsizei>(width),
|
||||
static_cast<GLsizei>(height), 0, dataFormat, GL_UNSIGNED_BYTE, image.image.data());
|
||||
glGenerateMipmap(GL_TEXTURE_2D);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
stbi_image_free(m_textureBuffer);
|
||||
}
|
||||
|
||||
auto Texture::textureType() const -> TextureType
|
||||
@@ -71,26 +110,17 @@ auto Texture::textureType() const -> TextureType
|
||||
return m_textureType;
|
||||
}
|
||||
|
||||
void Texture::bind(uint8_t textureUnit, ShaderProgram const &shaderProgram, uint8_t textureTypeNum) const
|
||||
void Texture::bind(uint8_t textureUnit, ShaderProgram const &shaderProgram) const
|
||||
{
|
||||
std::string uniformName = "texture_";
|
||||
|
||||
switch (m_textureType) {
|
||||
|
||||
case TextureType::Diffuse:
|
||||
uniformName += "diffuse" + std::to_string(textureTypeNum);
|
||||
break;
|
||||
case TextureType::Specular:
|
||||
uniformName += "specular" + std::to_string(textureTypeNum);
|
||||
uniformName += "diffuse";
|
||||
break;
|
||||
case TextureType::Normal:
|
||||
uniformName += "normal" + std::to_string(textureTypeNum);
|
||||
break;
|
||||
case TextureType::Height:
|
||||
uniformName += "height" + std::to_string(textureTypeNum);
|
||||
break;
|
||||
case TextureType::Gloss:
|
||||
uniformName += "gloss" + std::to_string(textureTypeNum);
|
||||
uniformName += "normal";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -104,7 +134,7 @@ void Texture::bind(uint8_t textureUnit, ShaderProgram const &shaderProgram, uint
|
||||
glBindTexture(GL_TEXTURE_2D, m_glId);
|
||||
}
|
||||
|
||||
void Texture::unbind() const
|
||||
void Texture::unbind()
|
||||
{
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
}
|
||||
|
||||
@@ -1,34 +1,32 @@
|
||||
#pragma once
|
||||
|
||||
#include "AbstractTexture.h"
|
||||
#include "TextureType.h"
|
||||
|
||||
#include <stb/stb_image.h>
|
||||
#include <glad/gl.h>
|
||||
#include <span>
|
||||
#include <string>
|
||||
#include <tiny_gltf.h>
|
||||
|
||||
class ShaderProgram;
|
||||
|
||||
struct TextureDescriptor
|
||||
{
|
||||
std::string path;
|
||||
TextureType textureType;
|
||||
};
|
||||
// struct TextureDescriptor
|
||||
// {
|
||||
// std::string path;
|
||||
// TextureType textureType;
|
||||
// };
|
||||
|
||||
class Texture : public AbstractTexture
|
||||
class Texture
|
||||
{
|
||||
public:
|
||||
Texture(const TextureDescriptor &descriptor);
|
||||
// Texture(const TextureDescriptor &descriptor);
|
||||
Texture(tinygltf::Texture const &texture, std::span<tinygltf::Image> images);
|
||||
|
||||
[[nodiscard]] auto textureType() const -> TextureType;
|
||||
|
||||
void bind(uint8_t textureUnit, ShaderProgram const &shaderProgram, uint8_t textureTypeNum) const;
|
||||
void unbind() const override;
|
||||
|
||||
protected:
|
||||
void initialize() override;
|
||||
void bind(uint8_t textureUnit, ShaderProgram const &shaderProgram) const;
|
||||
static void unbind();
|
||||
|
||||
private:
|
||||
stbi_uc *m_textureBuffer;
|
||||
|
||||
TextureType m_textureType;
|
||||
GLuint m_glId = 0;
|
||||
};
|
||||
@@ -3,9 +3,6 @@
|
||||
enum class TextureType
|
||||
{
|
||||
Diffuse,
|
||||
Specular,
|
||||
Normal,
|
||||
Height,
|
||||
Gloss,
|
||||
TEXTURE_TYPE_NUM_ITEMS
|
||||
};
|
||||
@@ -1,3 +0,0 @@
|
||||
add_executable(obj-converter main.cpp)
|
||||
|
||||
target_link_libraries(obj-converter assimp glm)
|
||||
@@ -1,29 +0,0 @@
|
||||
NUM_TEXTURES
|
||||
TYPE_DIFFUSE
|
||||
TYPE_DIFFUSE
|
||||
TYPE_SPECULAR
|
||||
TYPE_NORMAL
|
||||
TYPE_HEIGHT
|
||||
./diffuse0.jpg000000000000
|
||||
./diffuse1.jpg000000000000
|
||||
./specular.jpg000000000000
|
||||
./normal.jpg00000000000000
|
||||
./height.jpg00000000000000
|
||||
NUM_VERTICES
|
||||
NUM_INDICES
|
||||
NUM_TEXTUREIDS
|
||||
<mesh1_vertexdata>
|
||||
<mesh1_indexdata>
|
||||
<mesh1_textureiddata>
|
||||
NUM_VERTICES
|
||||
NUM_INDICES
|
||||
NUM_TEXTUREIDS
|
||||
<mesh2_vertexdata>
|
||||
<mesh2_indexdata>
|
||||
<mesh2_textureiddata>
|
||||
NUM_VERTICES
|
||||
NUM_INDICES
|
||||
NUM_TEXTUREIDS
|
||||
<mesh3_vertexdata>
|
||||
<mesh3_indexdata>
|
||||
<mesh3_textureiddata>
|
||||
261
tools/main.cpp
261
tools/main.cpp
@@ -1,261 +0,0 @@
|
||||
/*
|
||||
|
||||
This is the tool to generate model files for the Fall-Fever game. It's used to
|
||||
reduce loading time of the game, and also to reduce runtime dependencies (libassimp).
|
||||
|
||||
The model files do not support material colors; only textures at this point.
|
||||
All path strings are 128 elements long.
|
||||
|
||||
*/
|
||||
|
||||
#include <assimp/Importer.hpp>
|
||||
#include <assimp/scene.h>
|
||||
#include <assimp/postprocess.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <cassert>
|
||||
#include <fstream>
|
||||
|
||||
#include "../src/definitions/models.h"
|
||||
#include "../src/resources/TextureTypes.h"
|
||||
#include "primitiveModel.h"
|
||||
|
||||
void processNode(aiNode *node, const aiScene *scene, Model *model);
|
||||
Mesh processMesh(aiMesh *mesh, const aiScene *scene, Model *model);
|
||||
std::vector<Texture> loadMaterialTextures(aiMaterial *mat, aiTextureType type, uint8_t textureType, Mesh *mesh,
|
||||
Model *model);
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
|
||||
if(argc <= 1) {
|
||||
std::cout << "Usage: " << argv[0] << " <Modelfiles>" << std::endl;
|
||||
}
|
||||
|
||||
std::vector<std::string> modelSources;
|
||||
|
||||
for(int i = 0; i < argc - 1; i++) {
|
||||
modelSources.push_back(argv[i+1]);
|
||||
}
|
||||
|
||||
Assimp::Importer importer;
|
||||
|
||||
for(auto it = modelSources.begin(); it != modelSources.end(); it++) {
|
||||
unsigned int flags =
|
||||
aiProcess_Triangulate |
|
||||
aiProcess_FlipUVs |
|
||||
aiProcess_PreTransformVertices |
|
||||
aiProcess_GenNormals |
|
||||
aiProcess_OptimizeMeshes |
|
||||
aiProcess_OptimizeGraph |
|
||||
aiProcess_JoinIdenticalVertices |
|
||||
aiProcess_ImproveCacheLocality |
|
||||
aiProcess_CalcTangentSpace;
|
||||
|
||||
const aiScene* scene = importer.ReadFile((*it).c_str(), flags);
|
||||
|
||||
if(!scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode) {
|
||||
std::cout << "ERROR::ASSIMP::" << importer.GetErrorString() << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
Model currentModel;
|
||||
if(((*it).find('/')) < (*it).length()) {
|
||||
// source includes a /
|
||||
currentModel.m_workingPath = (*it).substr(0, (*it).find_last_of('/'));
|
||||
} else {
|
||||
currentModel.m_workingPath = ".";
|
||||
}
|
||||
|
||||
processNode(scene->mRootNode, scene, ¤tModel);
|
||||
|
||||
std::string filenameWithoutExtension = (*it).substr(0, (*it).find_last_of('.'));
|
||||
std::string outputFilename = filenameWithoutExtension + ".ffo";
|
||||
|
||||
std::ofstream output(outputFilename, std::ios::out | std::ios::binary);
|
||||
|
||||
uint32_t numTextures = currentModel.textures.size();
|
||||
output.write((char*) &numTextures, sizeof(uint32_t));
|
||||
|
||||
// Write texture types in order
|
||||
for(auto it1 = currentModel.textures.begin(); it1 != currentModel.textures.end(); it1++) {
|
||||
uint32_t currentTextureType = (*it1).textureType;
|
||||
output.write((char*) ¤tTextureType, sizeof(uint32_t));
|
||||
}
|
||||
|
||||
// Write texture sources
|
||||
for(auto it1 = currentModel.textures.begin(); it1 != currentModel.textures.end(); it1++) {
|
||||
for(unsigned int i = 0; i < 128; i++) {
|
||||
if(i < (*it1).pathToTexture.size()) {
|
||||
uint8_t character = (*it1).pathToTexture[i];
|
||||
output.write((char*) &character, sizeof(uint8_t));
|
||||
} else {
|
||||
uint8_t character = 0;
|
||||
output.write((char*) &character, sizeof(uint8_t));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// Write meshes
|
||||
uint32_t numMeshes = currentModel.m_meshes.size();
|
||||
output.write((char*) &numMeshes, sizeof(uint32_t));
|
||||
for (auto it1 = currentModel.m_meshes.begin(); it1 != currentModel.m_meshes.end(); it1++) {
|
||||
uint32_t numVertices = (*it1).vertices.size();
|
||||
uint32_t numIndices = (*it1).indices.size();
|
||||
uint32_t numTextureIds = (*it1).textureIds.size();
|
||||
|
||||
output.write((char*) &numVertices, sizeof(uint32_t));
|
||||
output.write((char*) &numIndices, sizeof(uint32_t));
|
||||
output.write((char*) &numTextureIds, sizeof(uint32_t));
|
||||
|
||||
Vertex *vertexData = (*it1).vertices.data();
|
||||
output.write((char*) vertexData, numVertices * sizeof(Vertex));
|
||||
|
||||
uint32_t *indexData = (*it1).indices.data();
|
||||
output.write((char*) indexData, numIndices * sizeof(uint32_t));
|
||||
|
||||
uint32_t *textureIdData = (*it1).textureIds.data();
|
||||
output.write((char*) textureIdData, numTextureIds * sizeof(uint32_t));
|
||||
}
|
||||
|
||||
output.close();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void processNode(aiNode *node, const aiScene *scene, Model* model) {
|
||||
|
||||
// Push the node's meshes into the mesh vector
|
||||
for(uint32_t i = 0; i < node->mNumMeshes; i++) {
|
||||
aiMesh *mesh = scene->mMeshes[node->mMeshes[i]];
|
||||
model->m_meshes.push_back(processMesh(mesh, scene, model));
|
||||
}
|
||||
|
||||
// Process child nodes too
|
||||
for(uint32_t i = 0; i < node->mNumChildren; i++) {
|
||||
processNode(node->mChildren[i], scene, model);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Mesh processMesh(aiMesh *mesh, const aiScene *scene, Model *model) {
|
||||
std::vector<Vertex> vertices;
|
||||
std::vector<uint32_t> indices;
|
||||
std::vector<Texture> textures;
|
||||
Mesh currentMesh;
|
||||
|
||||
for(uint32_t i = 0; i < mesh->mNumVertices; i++) {
|
||||
Vertex vertex;
|
||||
|
||||
// Position
|
||||
glm::vec3 vector;
|
||||
vector.x = mesh->mVertices[i].x;
|
||||
vector.y = mesh->mVertices[i].y;
|
||||
vector.z = mesh->mVertices[i].z;
|
||||
vertex.position = vector;
|
||||
|
||||
// Normals
|
||||
vector.x = mesh->mNormals[i].x;
|
||||
vector.y = mesh->mNormals[i].y;
|
||||
vector.z = mesh->mNormals[i].z;
|
||||
vertex.normalVec = vector;
|
||||
|
||||
// Tangents
|
||||
vector.x = mesh->mTangents[i].x;
|
||||
vector.y = mesh->mTangents[i].y;
|
||||
vector.z = mesh->mTangents[i].z;
|
||||
vertex.tangentVec = vector;
|
||||
|
||||
// Bitangents
|
||||
vector.x = mesh->mBitangents[i].x;
|
||||
vector.y = mesh->mBitangents[i].y;
|
||||
vector.z = mesh->mBitangents[i].z;
|
||||
vertex.bitangentVec = vector;
|
||||
|
||||
// Texture UV mapping
|
||||
if(mesh->mTextureCoords[0]) {
|
||||
glm::vec2 vec;
|
||||
vec.x = mesh->mTextureCoords[0][i].x;
|
||||
vec.y = mesh->mTextureCoords[0][i].y;
|
||||
vertex.textureCoords = vec;
|
||||
} else {
|
||||
vertex.textureCoords = glm::vec2(0.0f, 0.0f);
|
||||
}
|
||||
|
||||
vertices.push_back(vertex);
|
||||
}
|
||||
|
||||
// Indices
|
||||
for(uint32_t i = 0; i < mesh->mNumFaces; i++) {
|
||||
aiFace face = mesh->mFaces[i];
|
||||
for(uint32_t j = 0; j < face.mNumIndices; j++) {
|
||||
indices.push_back(face.mIndices[j]);
|
||||
}
|
||||
}
|
||||
|
||||
// Material
|
||||
if(mesh->mMaterialIndex > 0) {
|
||||
aiMaterial *material = scene->mMaterials[mesh->mMaterialIndex];
|
||||
|
||||
std::vector<Texture> diffuseMaps = loadMaterialTextures(
|
||||
material, aiTextureType_DIFFUSE, static_cast<int>(TextureType::Diffuse), ¤tMesh, model);
|
||||
textures.insert(textures.end(), diffuseMaps.begin(), diffuseMaps.end());
|
||||
|
||||
std::vector<Texture> specularMaps = loadMaterialTextures(
|
||||
material, aiTextureType_SPECULAR, static_cast<int>(TextureType::Specular), ¤tMesh, model);
|
||||
textures.insert(textures.end(), specularMaps.begin(), specularMaps.end());
|
||||
|
||||
std::vector<Texture> normalMaps = loadMaterialTextures(
|
||||
material, aiTextureType_HEIGHT, static_cast<int>(TextureType::Normal), ¤tMesh, model);
|
||||
textures.insert(textures.end(), normalMaps.begin(), normalMaps.end());
|
||||
|
||||
// Not entirely sure if aiTextureType_HEIGHT is correct
|
||||
std::vector<Texture> heightMaps = loadMaterialTextures(
|
||||
material, aiTextureType_HEIGHT, static_cast<int>(TextureType::Height), ¤tMesh, model);
|
||||
textures.insert(textures.end(), heightMaps.begin(), heightMaps.end());
|
||||
}
|
||||
|
||||
currentMesh.vertices = vertices;
|
||||
currentMesh.indices = indices;
|
||||
|
||||
return currentMesh;
|
||||
}
|
||||
|
||||
std::vector<Texture> loadMaterialTextures(aiMaterial *mat, aiTextureType type, uint8_t textureType, Mesh *mesh,
|
||||
Model *model)
|
||||
{
|
||||
|
||||
std::vector<Texture> textures;
|
||||
for(uint32_t i = 0; i < mat->GetTextureCount(type); i++) {
|
||||
aiString filename;
|
||||
mat->GetTexture(type, i, &filename);
|
||||
|
||||
std::string currentPath = model->m_workingPath + '/' + filename.C_Str();
|
||||
|
||||
bool skip = 0;
|
||||
for(uint32_t j = 0; j < model->textures.size(); j++) {
|
||||
if(std::strcmp(model->textures[j].pathToTexture.c_str(), currentPath.c_str()) == 0) {
|
||||
textures.push_back(model->textures[j]);
|
||||
skip = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(!skip) {
|
||||
Texture texture;
|
||||
texture.pathToTexture = currentPath;
|
||||
texture.textureType = textureType;
|
||||
// textureIds start at 0, but vector elements start at 1.
|
||||
texture.m_textureId = model->textures.size();
|
||||
|
||||
model->textures.push_back(texture);
|
||||
|
||||
// Add newest texture id to mesh
|
||||
mesh->textureIds.push_back(texture.m_textureId);
|
||||
}
|
||||
}
|
||||
|
||||
return textures;
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
struct Texture
|
||||
{
|
||||
std::string pathToTexture;
|
||||
uint32_t textureType;
|
||||
uint32_t m_textureId;
|
||||
};
|
||||
|
||||
struct Mesh
|
||||
{
|
||||
std::vector<Vertex> vertices;
|
||||
std::vector<uint32_t> indices;
|
||||
std::vector<uint32_t> textureIds;
|
||||
};
|
||||
|
||||
struct Model
|
||||
{
|
||||
std::vector<Texture> textures;
|
||||
std::vector<Mesh> m_meshes;
|
||||
std::string m_workingPath;
|
||||
};
|
||||
Reference in New Issue
Block a user