Skip to content

Commit

Permalink
feat: fix UV error.
Browse files Browse the repository at this point in the history
  • Loading branch information
zzxzzk115 committed Nov 2, 2023
1 parent 03c1d82 commit eea4d7e
Show file tree
Hide file tree
Showing 55 changed files with 34,538 additions and 63 deletions.
Binary file added Media/Showcases/Gouraud_Normal_Texture.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed Media/Showcases/Gouraud_Texture.png
Binary file not shown.
39 changes: 22 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@
>
> - Gouraud Shading
> ![Gouraud](Media/Showcases/Gouraud.png)
> - Gouraud Shading with Texture
> ![GouraudTexture](Media/Showcases/Gouraud_Texture.png)
> - Gouraud Shading with Normal Texture
> ![Gouraud Normal Texture](Media/Showcases/Gouraud_Normal_Texture.png)
## Features

Expand All @@ -39,34 +39,36 @@
```c++
struct GouraudShader : public VGLShaderBase
{
int BindTextureSlot;

int BindDiffuseTextureSlot;
int BindNormalTextureSlot;

Vector3Float UniformLightDirection;
Matrix4 UniformMVP;
Matrix4 UniformMVPIT;

Vector3Float VaryingIntensity;
std::vector<Vector2Float> VaryingUVs {3};

virtual void vert(Vertex& vertex, int vertexIndexInFace, Vector3Float& gl_Position) override
virtual void vert(int faceIndex, int vertexIndexInFace, Vector3Float& gl_Position) override
{
VaryingIntensity[vertexIndexInFace] = std::max(0.0f, UniformLightDirection * vertex.Normal);
VaryingUVs[vertexIndexInFace] = vertex.UV;
gl_Position = UniformMVP * vertex.Position;
VaryingUVs[vertexIndexInFace] = TargetMesh->GetUV(faceIndex, vertexIndexInFace);
gl_Position = UniformMVP * gl_Position;
}

virtual bool frag(Vector3Float bc, VGL::Color& gl_FragColor) override
{
float intensity = VaryingIntensity * bc;
Vector2Float uv = VaryingUVs[0] * bc.X + VaryingUVs[1] * bc.Y + VaryingUVs[2] * bc.Z;
gl_FragColor = sample2D(BindTextureSlot, uv.X, uv.Y) * intensity;
Vector3Float n = (UniformMVPIT * sample2D(BindNormalTextureSlot, uv.X, uv.Y).XYZ()).Normalized();
Vector3Float l = (UniformMVP * UniformLightDirection).Normalized();
float intensity = std::max(0.0f, n * l);
gl_FragColor = sample2D(BindDiffuseTextureSlot, uv.X, uv.Y) * intensity;
return false;
}
};
```

- Use OpenGL-like APIs:
```c++
// ... load mesh & texture from disk
// ... load meshes & textures from disk

glViewPort(0, 0, 800, 800);

Expand All @@ -86,15 +88,18 @@

Matrix4 mvp = projectionMatrix * viewMatrix * modelMatrix;

glBindTexture(0, texture);

glBindTexture(0, diffuseTexture);
glBindTexture(1, normalTexture);

GouraudShader shader = {};
shader.UniformMVP = mvp;
shader.UniformMVPIT = mvp.InverseTranspose();
shader.UniformLightDirection = light.GetDirection();
shader.BindTextureSlot = 0;

shader.BindDiffuseTextureSlot = 0;
shader.BindNormalTextureSlot = 1;

glBindShader(0, &shader);

for (int meshIndex = 0; meshIndex < meshes.size(); ++meshIndex)
{
glBindMesh(meshIndex, meshes[meshIndex]);
Expand Down
75 changes: 48 additions & 27 deletions Renderer/Application/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,26 +36,28 @@ void DrawFrameBuffer()

struct GouraudShader : public VGLShaderBase
{
int BindTextureSlot;
int BindDiffuseTextureSlot;
int BindNormalTextureSlot;

Vector3Float UniformLightDirection;
Matrix4 UniformMVP;
Matrix4 UniformMVPIT;

Vector3Float VaryingIntensity;
std::vector<Vector2Float> VaryingUVs {3};

virtual void vert(Vertex& vertex, int vertexIndexInFace, Vector3Float& gl_Position) override
virtual void vert(int faceIndex, int vertexIndexInFace, Vector3Float& gl_Position) override
{
VaryingIntensity[vertexIndexInFace] = std::max(0.0f, UniformLightDirection * vertex.Normal);
VaryingUVs[vertexIndexInFace] = vertex.UV;
gl_Position = UniformMVP * vertex.Position;
VaryingUVs[vertexIndexInFace] = TargetMesh->GetUV(faceIndex, vertexIndexInFace);
gl_Position = UniformMVP * gl_Position;
}

virtual bool frag(Vector3Float bc, VGL::Color& gl_FragColor) override
{
float intensity = VaryingIntensity * bc;
Vector2Float uv = VaryingUVs[0] * bc.X + VaryingUVs[1] * bc.Y + VaryingUVs[2] * bc.Z;
gl_FragColor = sample2D(BindTextureSlot, uv.X, uv.Y) * intensity;
Vector3Float n = (UniformMVPIT * sample2D(BindNormalTextureSlot, uv.X, uv.Y).XYZ()).Normalized();
Vector3Float l = (UniformMVP * UniformLightDirection).Normalized();
float intensity = std::max(0.0f, n * l);
gl_FragColor = sample2D(BindDiffuseTextureSlot, uv.X, uv.Y) * intensity;
return false;
}
};
Expand All @@ -67,7 +69,7 @@ int main()
raylib::Texture targetTexture(renderTexture.GetTexture());

// Load a model from disk
std::string modelFile = "Resources/Models/obj/african_head.obj";
std::string modelFile = "Resources/Models/african_head/african_head.obj";
tinyobj::ObjReaderConfig readerConfig;
readerConfig.mtl_search_path = "./"; // Path to material files

Expand Down Expand Up @@ -98,6 +100,8 @@ int main()
{
VGL::Mesh mesh = {};
mesh.Vertices.resize(attrib.vertices.size());
mesh.Normals.resize(attrib.normals.size());
mesh.TextureCoords.resize(attrib.texcoords.size());

// Loop over faces(polygon)
size_t indexOffset = 0;
Expand All @@ -111,18 +115,16 @@ int main()
int vertexIndex = 0;
for (size_t v = 0; v < fv; v++)
{
Vertex vertex = {};

// access to vertex
tinyobj::index_t idx = shapes[s].mesh.indices[indexOffset + v];
vertexIndex = static_cast<size_t>(idx.vertex_index);
face.Indices.push_back(vertexIndex);

tinyobj::real_t vx = attrib.vertices[3*static_cast<size_t>(idx.vertex_index)+0];
tinyobj::real_t vy = attrib.vertices[3*static_cast<size_t>(idx.vertex_index)+1];
tinyobj::real_t vz = attrib.vertices[3*static_cast<size_t>(idx.vertex_index)+2];

vertex.Position = { vx, vy, vz };
mesh.Vertices[vertexIndex] = { vx, vy, vz };
face.VertexIndices.push_back(vertexIndex);

// Check if `normal_index` is zero or positive. negative = no normal data
if (idx.normal_index >= 0)
Expand All @@ -131,7 +133,10 @@ int main()
tinyobj::real_t ny = attrib.normals[3*static_cast<size_t>(idx.normal_index)+1];
tinyobj::real_t nz = attrib.normals[3*static_cast<size_t>(idx.normal_index)+2];

vertex.Normal = { nx, ny, nz };
auto normalIndex = static_cast<size_t>(idx.normal_index);

mesh.Normals[normalIndex] = { nx, ny, nz };
face.NormalIndices.push_back(normalIndex);
}

// Check if `texcoord_index` is zero or positive. negative = no texcoord data
Expand All @@ -140,15 +145,16 @@ int main()
tinyobj::real_t tx = attrib.texcoords[2*static_cast<size_t>(idx.texcoord_index)+0];
tinyobj::real_t ty = attrib.texcoords[2*static_cast<size_t>(idx.texcoord_index)+1];

vertex.UV = { tx, ty };
auto texCoordIndex = static_cast<size_t>(idx.texcoord_index);

mesh.TextureCoords[texCoordIndex] = { tx, ty };
face.TextureCoordIndices.push_back(texCoordIndex);
}

// Optional: vertex colors
// tinyobj::real_t red = attrib.colors[3*size_t(idx.vertex_index)+0];
// tinyobj::real_t green = attrib.colors[3*size_t(idx.vertex_index)+1];
// tinyobj::real_t blue = attrib.colors[3*size_t(idx.vertex_index)+2];

mesh.Vertices[vertexIndex] = vertex;
}
indexOffset += fv;
mesh.Faces.push_back(face);
Expand All @@ -162,18 +168,30 @@ int main()

SetTargetFPS(60);

// Load a texture image from disk
auto textureImageData = raylib::Image("Resources/Textures/tga/african_head_diffuse.tga");
if (!textureImageData.IsReady())
// Load a diffuse texture image from disk
auto diffuseTextureImageData = raylib::Image("Resources/Textures/african_head/african_head_diffuse.tga");
if (!diffuseTextureImageData.IsReady())
{
std::cerr << "Failed to load texture!!!" << std::endl;
return -2;
}

int diffuseTextureImageWidth = diffuseTextureImageData.width;
int diffuseTextureImageHeight = diffuseTextureImageData.height;
VGL::Color* diffuseTextureColors = (VGL::Color*)LoadImageColors(diffuseTextureImageData);
VGL::Texture2D diffuseTexture(diffuseTextureImageWidth, diffuseTextureImageHeight, diffuseTextureColors);

auto normalTextureImageData = raylib::Image("Resources/Textures/african_head/african_head_nm.tga");
if (!normalTextureImageData.IsReady())
{
std::cerr << "Failed to load texture!!!" << std::endl;
return -2;
}

int textureImageWidth = textureImageData.width;
int textureImageHeight = textureImageData.height;
VGL::Color* textureColors = (VGL::Color*)LoadImageColors(textureImageData);
VGL::Texture2D texture(textureImageWidth, textureImageHeight, textureColors);
int normalTextureImageWidth = normalTextureImageData.width;
int normalTextureImageHeight = normalTextureImageData.height;
VGL::Color* normalTextureColors = (VGL::Color*)LoadImageColors(normalTextureImageData);
VGL::Texture2D normalTexture(normalTextureImageWidth, normalTextureImageHeight, normalTextureColors);

DirectionalLight light(Vector3Float(1, 1, 1).Normalized());

Expand All @@ -185,20 +203,23 @@ int main()
// Camera parameters
Vector3Float eye(1 , 1, 3);
Vector3Float center(0 , 0, 0);
Vector3Float up(0 , 1, 0);
Vector3Float up(0, 1, 0);

Matrix4 modelMatrix = Matrix4::Identity();
Matrix4 viewMatrix = glLookAt(eye, center, up);
Matrix4 projectionMatrix = glProjection(eye, center);

Matrix4 mvp = projectionMatrix * viewMatrix * modelMatrix;

glBindTexture(0, texture);
glBindTexture(0, diffuseTexture);
glBindTexture(1, normalTexture);

GouraudShader shader = {};
shader.UniformMVP = mvp;
shader.UniformMVPIT = mvp.InverseTranspose();
shader.UniformLightDirection = light.GetDirection();
shader.BindTextureSlot = 0;
shader.BindDiffuseTextureSlot = 0;
shader.BindNormalTextureSlot = 1;

glBindShader(0, &shader);

Expand Down
3 changes: 3 additions & 0 deletions Renderer/VGL/include/VGL/Color.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

#pragma once

#include "Vector3.h"
#include <cmath>
#include <stdexcept>

Expand All @@ -27,6 +28,8 @@ namespace VGL
Color operator * (float scalar) const;
Color operator / (float scalar) const;

Vector3Float XYZ() const;

const static Color COLOR_WHITE;
const static Color COLOR_BLACK;
const static Color COLOR_RED;
Expand Down
20 changes: 11 additions & 9 deletions Renderer/VGL/include/VGL/Mesh.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,21 @@ namespace VGL
{
struct TriangleFace
{
std::vector<int> Indices;
};

struct Vertex
{
Vector3Float Position;
Vector3Float Normal;
Vector2Float UV;
std::vector<int> VertexIndices;
std::vector<int> TextureCoordIndices;
std::vector<int> NormalIndices;
};

struct Mesh
{
std::vector<TriangleFace> Faces;
std::vector<Vertex> Vertices;
std::vector<Vector3Float> Vertices;
std::vector<Vector3Float> Normals;
std::vector<Vector2Float> TextureCoords;

Vector2Float GetUV(int faceIndex, int vertexIndexInFace)
{
return TextureCoords[Faces[faceIndex].TextureCoordIndices[vertexIndexInFace]];
}
};
} // namespace VGL
4 changes: 3 additions & 1 deletion Renderer/VGL/include/VGL/VGL.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,11 @@ namespace VGL
{
struct VGLShaderBase
{
Mesh* TargetMesh;

virtual ~VGLShaderBase() = default;

virtual void vert(Vertex& vertex, int vertexIndexInFace, Vector3Float& gl_Position) = 0;
virtual void vert(int faceIndex, int vertexIndexInFace, Vector3Float& gl_Position) = 0;
virtual bool frag(Vector3Float bc, Color& gl_FragColor) = 0;

Color sample2D(int textureSlot, float u, float v);
Expand Down
2 changes: 2 additions & 0 deletions Renderer/VGL/src/Color.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,4 +53,6 @@ namespace VGL
static_cast<unsigned char>(B / scalar),
static_cast<unsigned char>(A / scalar) };
}

Vector3Float Color::XYZ() const { return Vector3Float(R, G, B); }
} // namespace VGL
5 changes: 5 additions & 0 deletions Renderer/VGL/src/Matrix3.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,11 @@ namespace VGL

for (int col = 0; col < 3; col++)
{
if (matrix3.m_Matrix[col][col] == 0.0f)
{
return 0.0f;
}

for (int row = col + 1; row < 3; row++)
{
float factor = matrix3.m_Matrix[row][col] / matrix3.m_Matrix[col][col];
Expand Down
18 changes: 9 additions & 9 deletions Renderer/VGL/src/VGL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,13 @@ namespace VGL
throw std::runtime_error("MeshSlot not found!");
}

if (g_vglState.UsingShader == nullptr)
{
throw std::runtime_error("No shader bound!");
}

auto* mesh = g_vglState.MeshMap[meshSlot];
g_vglState.UsingShader->TargetMesh = mesh;

for (int faceIndex = 0; faceIndex < mesh->Faces.size(); ++faceIndex)
{
Expand All @@ -85,16 +91,10 @@ namespace VGL
Vector3Float screenCoords[3];
for (int v = 0; v < 3; ++v)
{
auto& vertex = mesh->Vertices[face.Indices[v]];

if (g_vglState.UsingShader == nullptr)
{
throw std::runtime_error("No shader bound!");
}
auto vertexPosition = mesh->Vertices[face.VertexIndices[v]];

Vector3Float position;
g_vglState.UsingShader->vert(vertex, v, position);
screenCoords[v] = g_vglState.ViewportMatrix * position;
g_vglState.UsingShader->vert(faceIndex, v, vertexPosition);
screenCoords[v] = g_vglState.ViewportMatrix * vertexPosition;
}
Triangle3D::DrawInterpolated(screenCoords, g_vglState.UsingShader);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6354,3 +6354,4 @@ f 1200/1246/1200 1220/1281/1220 1198/1247/1198
f 1201/1249/1201 1200/1246/1200 1199/1245/1199
f 1201/1249/1201 1202/1248/1202 1200/1246/1200
# 2492 faces

Loading

0 comments on commit eea4d7e

Please sign in to comment.