Skip to content

Commit

Permalink
Merge branch 'main' of github.com:gagistech/carcockpit
Browse files Browse the repository at this point in the history
  • Loading branch information
igagis committed Nov 13, 2024
2 parents 9a2c004 + 19e3151 commit 76af28c
Show file tree
Hide file tree
Showing 5 changed files with 101 additions and 65 deletions.
2 changes: 1 addition & 1 deletion .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"name": "(gdb) app",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/src/out/dbg/carcockpit",
"program": "${workspaceFolder}/src/out/dbg/carcockpit-opengles-xorg",
"args": ["--window", "--res-path=../res"],
"stopAtEntry": false,
"cwd": "${workspaceFolder}/src",
Expand Down
74 changes: 45 additions & 29 deletions src/carcockpit/shaders/shader_pbr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.

using namespace ruis::render;

constexpr ruis::vec4 default_light_position{5.0f, 5.0f, 5.0f, 1.0f};
constexpr ruis::vec3 default_light_position{5.0f, 5.0f, 5.0f};
constexpr ruis::vec3 default_light_intensity{2.0f, 2.0f, 2.0f};

shader_pbr::shader_pbr() :
Expand All @@ -44,10 +44,13 @@ shader_pbr::shader_pbr() :
uniform highp mat4 matrix; // mvp matrix
uniform highp mat4 mat4_mv; // modelview matrix
// TODO: remove?
uniform highp mat4 mat4_p; // projection matrix
uniform highp mat3 mat3_n; // normal matrix (mat3)
uniform vec4 light_position;
uniform vec3 light_position;
uniform vec3 light_intensity;
varying highp vec3 light_dir;
Expand All @@ -57,23 +60,27 @@ shader_pbr::shader_pbr() :
void main()
{
// Transform normal and tangent to eye space
vec3 norm = normalize(mat3_n * a2);
vec3 tang = normalize(mat3_n * a3);
vec3 binormal = normalize(mat3_n * a4);
// Matrix for transformation to tangent space
mat3 mat3_to_local = mat3( tang.x, binormal.x, norm.x,
tang.y, binormal.y, norm.y,
tang.z, binormal.z, norm.z ) ;
// Get the position in eye coordinates
vec3 pos = vec3( mat4_mv * a0 );
// Transform light dir. and view dir. to tangent space
light_dir = normalize( mat3_to_local * (light_position.xyz - pos) );
view_dir = mat3_to_local * normalize(-pos);
// Pass along the texture coordinate
vec3 normal = normalize(mat3_n * a2);
vec3 tangent = normalize(mat3_n * a3);
vec3 bitangent = normalize(mat3_n * a4);
// matrix for transformation to tangent space
mat3 mat3_to_tangent = mat3(
tangent.x, bitangent.x, normal.x,
tangent.y, bitangent.y, normal.y,
tangent.z, bitangent.z, normal.z
);
// get the position in eye coordinates
vec3 pos = vec3( mat4_mv * a0 );
// Transform light direction and view direction to tangent space
light_dir = normalize( mat3_to_tangent * (light_position - pos) );
view_dir = mat3_to_tangent * normalize(-pos);
tc = vec2(a1.x, 1.0 - a1.y);
gl_Position = matrix * a0;
}
}
)qwertyuiop",
R"qwertyuiop(
precision highp float;
Expand All @@ -87,24 +94,31 @@ shader_pbr::shader_pbr() :
uniform sampler2D texture2; // roughness map tex
uniform samplerCube texture3; // cube map
uniform vec4 light_position;
uniform vec3 light_position;
uniform vec3 light_intensity;
const vec3 Kd = vec3(0.5, 0.5, 0.5); // Diffuse reflectivity
const vec3 Ka = vec3(0.1, 0.1, 0.1); // Ambient reflectivity
const vec3 Ks = vec3(0.7, 0.7, 0.7); // Specular reflectivity
vec3 phong_model( vec3 norm, vec3 diffuse_reflectivity, float ambient_occlusion, float glossiness, float metalness )
const vec3 Kd = vec3(0.5, 0.5, 0.5); // Diffuse reflectivity
const vec3 Ka = vec3(0.1, 0.1, 0.1); // Ambient reflectivity
const vec3 Ks = vec3(0.7, 0.7, 0.7); // Specular reflectivity
// TODO: is it still called Phong?
vec3 phong_model(
vec3 norm,
vec3 diffuse_reflectivity,
float ambient_occlusion,
float glossiness,
float metalness
)
{
vec3 r_env = reflect( view_dir, norm );
vec3 env_refl = textureCube( texture3, r_env).xyz;
vec3 r = reflect( -light_dir, norm );
float sDotN = max( dot(light_dir, norm) , 0.0 );
vec3 ambient = (Ka) * light_intensity;
vec3 diffuse = max( Kd - metalness, 0.0 ) * sDotN * light_intensity;
vec3 spec = Ks * pow( max( dot(r, view_dir), 0.0 ), glossiness ) * light_intensity;
vec3 ambient = light_intensity * Ka;
vec3 diffuse = light_intensity * max( Kd - metalness, 0.0 ) * sDotN;
vec3 spec = light_intensity * Ks * pow( max( dot(r, view_dir), 0.0 ), glossiness );
return (( ambient + diffuse ) * diffuse_reflectivity + spec ) + (env_refl * metalness);
}
Expand All @@ -114,7 +128,9 @@ shader_pbr::shader_pbr() :
vec3 arm = texture2D( texture2, tc ).xyz;
float gloss = ((1.0 - pow(arm.y, 0.2) ) * 100.0 + 1.0 );
// TODO: why multiply by 2 and subtract 1? Add comment.
vec4 normal4 = 2.0 * texture2D( texture1, tc ) - 1.0;
vec3 normal = normalize(normal4.xyz);
normal = vec3(normal.x, -normal.y, normal.z);
Expand All @@ -129,15 +145,15 @@ shader_pbr::shader_pbr() :
sampler_cube(this->get_uniform("texture3")),
mat4_modelview(this->get_uniform("mat4_mv")),
mat3_normal(this->get_uniform("mat3_n")),
vec4_light_position(this->get_uniform("light_position")),
vec3_light_position(this->get_uniform("light_position")),
vec3_light_intensity(this->get_uniform("light_intensity"))
{}

void shader_pbr::render(
const ruis::render::vertex_array& va,
const r4::matrix4<float>& mvp,
const r4::matrix4<float>& modelview,
const r4::matrix4<float>& projection,
const r4::matrix4<float>& projection, // TODO: remove?
const ruis::render::texture_2d& tex_color,
const ruis::render::texture_2d& tex_normal,
const ruis::render::texture_2d& tex_roughness,
Expand Down Expand Up @@ -169,7 +185,7 @@ void shader_pbr::render(
normal.invert();
normal.transpose();

this->set_uniform4f(this->vec4_light_position, light_pos[0], light_pos[1], light_pos[2], light_pos[3]);
this->set_uniform3f(this->vec3_light_position, light_pos[0], light_pos[1], light_pos[2]);
this->set_uniform3f(this->vec3_light_intensity, light_int[0], light_int[1], light_int[2]);
this->set_uniform_matrix4f(this->mat4_modelview, modelview);
this->set_uniform_matrix3f(mat3_normal, normal);
Expand Down
3 changes: 2 additions & 1 deletion src/carcockpit/shaders/shader_pbr.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,11 @@ class shader_pbr : public ruis::render::opengles::shader_base
GLint mat4_modelview;
GLint mat3_normal;

GLint vec4_light_position;
GLint vec3_light_position;
GLint vec3_light_intensity;

shader_pbr();

void render(
const ruis::render::vertex_array& va,
const r4::matrix4<float>& mvp,
Expand Down
4 changes: 2 additions & 2 deletions src/carcockpit/shaders/shader_phong.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@ shader_phong::shader_phong() :
void main(void)
{
tc0 = vec2(a1.x, 1.0 - a1.y);
norm = normalize( mat3_n * a2 );
pos = vec3( mat4_mv * a0 );
norm = normalize( mat3_n * a2 );
pos = vec3( mat4_mv * a0 );
gl_Position = matrix * a0;
}
)qwertyuiop",
Expand Down
83 changes: 51 additions & 32 deletions src/ruis/render/scene/gltf_loader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -630,10 +630,10 @@ utki::shared_ref<ruis::render::vertex_array> gltf_loader::create_vao_with_tangen
std::vector<ruis::vec3> bitangents; // texture y-axis

tangents.resize(num_vertices);
std::fill(tangents.begin(), tangents.end(), ruis::vec3(0, 0, 0));
std::ranges::fill(tangents, ruis::vec3(0, 0, 0));

bitangents.resize(num_vertices);
std::fill(bitangents.begin(), bitangents.end(), ruis::vec3(0, 0, 0));
std::ranges::fill(bitangents, ruis::vec3(0, 0, 0));

// Calculate the vertex tangents and bitangents.
for (uint32_t i = 0; i < num_triangles; ++i) {
Expand All @@ -652,30 +652,51 @@ utki::shared_ref<ruis::render::vertex_array> gltf_loader::create_vao_with_tangen
auto edge1 = p1 - p0;
auto edge2 = p2 - p0;

auto tex_edge_1 = t1 - t0;
auto tex_edge_2 = t2 - t0;

// Calculate the triangle face tangent and bitangent.

auto det = tex_edge_1.cross(tex_edge_2);

constexpr auto epsilon = ruis::real(1e-6f);
auto tex_edge1 = t1 - t0;
auto tex_edge2 = t2 - t0;

// Calculate the triangle tangent and bitangent.
//
// We want to map vectors (1, 0) and (0, 1) from texture space to 3d space (to tangent and bitangent vectors).
//
// vec2 te1, te2 : triangle edges in texture space
// vec3 e1, e2 : triangle edges in 3d space
//
// Vectors (1, 0) and (0, 1) as a linear combination of te1 and te2:
//
// (1, 0) = te1 * a11 + te2 * a21
// (0, 1) = te1 * a12 + te2 * a22
//
// We need to solve these equations for a11, a12, a21, a22. The system of equations can be written in matrix
// form:
//
// | te1.x te2.x | * | a11 a12 | = | 1 0 | <-> T * A = I
// | te1.y te2.y | | a21 a22 | | 0 1 |
//
// Solving this matrix equation is actually finding a right inverse matrix A for matrix T.
//
// Then, tangent and bitangent vectors are linear combinations of e1 and e2 with same aXX coefficients.
//
// tangent = e1 * a11 + e2 * a21
// bitangent = e1 * a12 + e2 * a22

auto t = r4::matrix<ruis::real, 2, 2>(
tex_edge1, // row 0
tex_edge2 // row 1
)
.transpose(); // rows become columns

constexpr auto epsilon = ruis::real(1e-5f);

auto tangent = ruis::vec3(1, 0, 0);
auto bitangent = ruis::vec3(0, 1, 0);

using std::abs;
if (abs(det) >= epsilon) {
auto det_reciprocal = ruis::real(1) / det;

// TODO: figure out what is happening here and refactor with vector ops
tangent[0] = (tex_edge_2[1] * edge1[0] - tex_edge_1[1] * edge2[0]) * det_reciprocal;
tangent[1] = (tex_edge_2[1] * edge1[1] - tex_edge_1[1] * edge2[1]) * det_reciprocal;
tangent[2] = (tex_edge_2[1] * edge1[2] - tex_edge_1[1] * edge2[2]) * det_reciprocal;
if (abs(t.det()) >= epsilon) {
auto a = t.inv();

bitangent[0] = (-tex_edge_2[0] * edge1[0] + tex_edge_1[0] * edge2[0]) * det_reciprocal;
bitangent[1] = (-tex_edge_2[0] * edge1[1] + tex_edge_1[0] * edge2[1]) * det_reciprocal;
bitangent[2] = (-tex_edge_2[0] * edge1[2] + tex_edge_1[0] * edge2[2]) * det_reciprocal;
tangent = edge1 * a[0][0] + edge2 * a[1][0];
bitangent = edge1 * a[0][1] + edge2 * a[1][1];
}

// Accumulate the tangents and bitangents.
Expand All @@ -691,25 +712,23 @@ utki::shared_ref<ruis::render::vertex_array> gltf_loader::create_vao_with_tangen

// Orthogonalize and normalize the vertex tangents.
for (uint32_t i = 0; i < num_vertices; ++i) {
// Gram-Schmidt orthogonalize tangent with normal.
// Tangent and bitangent are not necessarily ortogonal to each other, but those have to be
// ortogonal to the normal.

auto n_dot_t = normals[i] * tangents[i]; // dot product
// Ortogonalize the tangent and bitangent to the normal.

tangents[i] -= normals[i] * n_dot_t;
tangents[i] -= normals[i].dot(tangents[i]) * normals[i];
bitangents[i] -= normals[i].dot(bitangents[i]) * normals[i];

tangents[i].normalize();
bitangents[i].normalize();

ruis::vec3 bitangent_other = normals[i].cross(tangents[i]);

auto b_dot_b = bitangent_other * bitangents[i];

auto sign = b_dot_b < ruis::real(0) ? ruis::real(-1) : ruis::real(1);

bitangents[i] = bitangent_other * sign;
// TODO: The triangle in texture space can be wound in different direction than in object space,
// need to flip the tangent basis to make normals from normal map point towards triangle normal direction.
}

auto tangents_vbo = factory_v.create_vertex_buffer(utki::make_span(tangents));
auto bitangents_vbo = factory_v.create_vertex_buffer(utki::make_span(bitangents));
auto tangents_vbo = factory_v.create_vertex_buffer(tangents);
auto bitangents_vbo = factory_v.create_vertex_buffer(bitangents);

auto vao = factory_v.create_vertex_array(
{utki::shared_ref<ruis::render::vertex_buffer>(position_accessor.get().vbo),
Expand Down

0 comments on commit 76af28c

Please sign in to comment.