Add basic texturing support for gltf

This commit is contained in:
2022-10-11 22:03:17 +02:00
parent 9ebdb74e22
commit 91a34e28c5
25 changed files with 281 additions and 696 deletions

View File

@@ -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;
// }

View File

@@ -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();

View File

@@ -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;

View File

@@ -22,7 +22,6 @@ public:
: name(_name), position(_position), rotation(_rotation), scale(_scale)
{
}
virtual ~Prototype() = default;
std::string name;
glm::vec3 position;

View File

@@ -1,6 +1,7 @@
#pragma once
#include "resources/CubeMap.h"
#include "resources/Resource.h"
#include <glad/gl.h>
class ShaderProgram;

View File

@@ -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()
{

View File

@@ -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();
}

View File

@@ -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;
};

View File

@@ -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"},

View File

@@ -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);
}

View File

@@ -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;
};

View File

@@ -11,5 +11,4 @@ public:
protected:
uint32_t m_textureWidth;
uint32_t m_textureHeight;
uint32_t m_numComponents;
};

View File

@@ -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);

View File

@@ -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
{}
};

View File

@@ -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;

View File

@@ -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;

View File

@@ -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 {};
}

View File

@@ -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;

View File

@@ -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);
}

View File

@@ -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;
};

View File

@@ -3,9 +3,6 @@
enum class TextureType
{
Diffuse,
Specular,
Normal,
Height,
Gloss,
TEXTURE_TYPE_NUM_ITEMS
};

View File

@@ -1,3 +0,0 @@
add_executable(obj-converter main.cpp)
target_link_libraries(obj-converter assimp glm)

View File

@@ -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>

View File

@@ -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, &currentModel);
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*) &currentTextureType, 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), &currentMesh, model);
textures.insert(textures.end(), diffuseMaps.begin(), diffuseMaps.end());
std::vector<Texture> specularMaps = loadMaterialTextures(
material, aiTextureType_SPECULAR, static_cast<int>(TextureType::Specular), &currentMesh, model);
textures.insert(textures.end(), specularMaps.begin(), specularMaps.end());
std::vector<Texture> normalMaps = loadMaterialTextures(
material, aiTextureType_HEIGHT, static_cast<int>(TextureType::Normal), &currentMesh, 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), &currentMesh, 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;
}

View File

@@ -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;
};