From 31e32943f569731673f13fcc259d3e656fbfc244 Mon Sep 17 00:00:00 2001 From: water111 Date: Tue, 17 Jun 2025 22:18:43 -0400 Subject: [PATCH] lots of minor shadow fixes --- .../opengl_renderer/foreground/Shadow3.cpp | 78 +++-- .../opengl_renderer/foreground/Shadow3.h | 2 +- .../opengl_renderer/foreground/Shadow3CPU.cpp | 286 ++++++++++-------- .../opengl_renderer/foreground/Shadow3CPU.h | 2 +- .../opengl_renderer/shaders/shadow3.vert | 26 +- 5 files changed, 227 insertions(+), 167 deletions(-) diff --git a/game/graphics/opengl_renderer/foreground/Shadow3.cpp b/game/graphics/opengl_renderer/foreground/Shadow3.cpp index 4370f3e7ee..eddbe01ba5 100644 --- a/game/graphics/opengl_renderer/foreground/Shadow3.cpp +++ b/game/graphics/opengl_renderer/foreground/Shadow3.cpp @@ -35,7 +35,6 @@ Shadow3::Shadow3(ShaderLibrary& shaders) { m_uniforms.origin = glGetUniformLocation(id, "origin"); m_uniforms.top_plane = glGetUniformLocation(id, "top_plane"); m_uniforms.bottom_plane = glGetUniformLocation(id, "bottom_plane"); - m_uniforms.bottom_cap = glGetUniformLocation(id, "bottom_cap"); } std::vector temp(MAX_SHADER_BONE_VECTORS * sizeof(math::Vector4f)); @@ -117,10 +116,11 @@ void Shadow3::draw_model(SharedRenderState* render_state, .debug_highlight_tri = m_debug_tri, }; calc_shadow_indices(input, &m_cpu_workspace, &m_cpu_output); - + glBindBuffer(GL_UNIFORM_BUFFER, m_opengl.bones_buffer); glBindBufferRange(GL_UNIFORM_BUFFER, 1, m_opengl.bones_buffer, sizeof(math::Vector4f) * request->bone_idx, 128 * 16 * 4); const auto* geo = request->model.model; + // printf("draw %s\n", geo->name.c_str()); set_uniform(m_uniforms.origin, request->origin); set_uniform(m_uniforms.top_plane, request->top_plane); @@ -153,18 +153,12 @@ void Shadow3::draw_model(SharedRenderState* render_state, out.weight = m_cpu_workspace.dual_vertices[i].w(); } - for (int i = 0; i < m_cpu_output.num_f0_indices; i++) { - m_cpu_output.f0_indices[i] -= model->first_vertex; - } - for (int i = 0; i < m_cpu_output.num_f1_indices; i++) { - m_cpu_output.f1_indices[i] -= model->first_vertex; - } glEnable(GL_DEPTH_TEST); glDisable(GL_BLEND); glDepthFunc(GL_GEQUAL); glDepthMask(GL_TRUE); - // glEnable(GL_CULL_FACE); - // glCullFace(GL_BACK); + glEnable(GL_CULL_FACE); + glCullFace(m_cull_back ? GL_BACK : GL_FRONT); glBindBuffer(GL_ARRAY_BUFFER, m_opengl.debug_verts); glBufferData(GL_ARRAY_BUFFER, num_verts * 2 * sizeof(tfrag3::ShadowVertex), verts.data(), GL_DYNAMIC_DRAW); @@ -207,15 +201,28 @@ void Shadow3::draw_model(SharedRenderState* render_state, glDepthFunc(GL_GEQUAL); glDepthMask(GL_FALSE); // no depth writes. - glEnable(GL_CULL_FACE); - glCullFace(GL_FRONT); - glStencilFunc(GL_ALWAYS, 0, 0); // always pass stencil - glStencilOp(GL_KEEP, GL_INCR, GL_KEEP); // increment on depth fail - glDrawElements(GL_TRIANGLES, m_cpu_output.num_indices, GL_UNSIGNED_INT, nullptr); - glCullFace(GL_BACK); - glStencilFunc(GL_ALWAYS, 0, 0); - glStencilOp(GL_KEEP, GL_DECR, GL_KEEP); // decrement on depth pass. - glDrawElements(GL_TRIANGLES, m_cpu_output.num_indices, GL_UNSIGNED_INT, nullptr); + if (false) { + glEnable(GL_CULL_FACE); + glCullFace(GL_BACK); + glStencilFunc(GL_ALWAYS, 0, 0); // always pass stencil + glStencilOp(GL_KEEP, GL_KEEP, GL_INCR); // increment on depth fail + glDrawElements(GL_TRIANGLES, m_cpu_output.num_indices, GL_UNSIGNED_INT, nullptr); + glCullFace(GL_FRONT); + glStencilFunc(GL_ALWAYS, 0, 0); + glStencilOp(GL_KEEP, GL_KEEP, GL_DECR); // decrement on depth pass. + glDrawElements(GL_TRIANGLES, m_cpu_output.num_indices, GL_UNSIGNED_INT, nullptr); + } else { + glEnable(GL_CULL_FACE); + glCullFace(GL_FRONT); + glStencilFunc(GL_ALWAYS, 0, 0); // always pass stencil + glStencilOp(GL_KEEP, GL_INCR, GL_KEEP); // increment on depth fail + glDrawElements(GL_TRIANGLES, m_cpu_output.num_indices, GL_UNSIGNED_INT, nullptr); + glCullFace(GL_BACK); + glStencilFunc(GL_ALWAYS, 0, 0); + glStencilOp(GL_KEEP, GL_DECR, GL_KEEP); // decrement on depth pass. + glDrawElements(GL_TRIANGLES, m_cpu_output.num_indices, GL_UNSIGNED_INT, nullptr); + } + glDisable(GL_CULL_FACE); } } @@ -238,6 +245,11 @@ void Shadow3::finish(SharedRenderState* render_state, ScopedProfilerNode& prof) glBlendEquation(GL_FUNC_ADD); glDepthMask(GL_TRUE); glDisable(GL_STENCIL_TEST); + + glBindVertexArray(0); + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + glBindBuffer(GL_UNIFORM_BUFFER, 0); } void Shadow3::flush_requests(SharedRenderState* render_state, ScopedProfilerNode& prof) { @@ -258,6 +270,7 @@ void Shadow3::flush_requests(SharedRenderState* render_state, ScopedProfilerNode for (auto& c : m_level_chains) { if (!c.head) continue; + // printf("in level %s\n", c.level->level->level_name.c_str()); setup_for_level(render_state, c.level); ShadowRequest* iter = c.head; while (iter) { @@ -288,21 +301,19 @@ void Shadow3::first_time_setup(SharedRenderState* render_state) { void Shadow3::draw_debug_window() { ImGui::Checkbox("hacks", &m_hacks); ImGui::Checkbox("near_plane", &m_near_plane_hack); + ImGui::Checkbox("back?", &m_cull_back); ImGui::InputInt("Tri", &m_debug_tri); } void Shadow3::render_jak1(DmaFollower& dma, SharedRenderState* render_state, ScopedProfilerNode& prof) { - printf("Jak1 shadow render\n"); m_did_first_time_setup = false; while (dma.current_tag_offset() != render_state->next_bucket) { - auto dmatag = dma.current_tag(); + // auto dmatag = dma.current_tag(); auto data = dma.read_and_advance(); - int run_idx = 0; if (data.vifcode0().kind == VifCode::Kind::PC_PORT) { - printf(" Run %d start\n", run_idx); u32 next = data.data_offset; while (next) { Jak1ShadowRequest game_request; @@ -312,7 +323,7 @@ void Shadow3::render_jak1(DmaFollower& dma, char name[128]; strncpy(name, (const char*)(g_ee_main_mem) + 4 + game_request.geo_name, 128); name[127] = 0; - printf(" draw %s\n", name); + // printf(" draw %s\n", name); auto model = render_state->loader->get_shadow_model(name); if (!model) { @@ -362,8 +373,6 @@ void Shadow3::render_jak1(DmaFollower& dma, // grab the next request and link it to the chain for the level. auto& request = m_requests[m_next_request++]; - request.next = chain->head; - chain->head = &request; request.model = *model; // the origin of "light" for the shadow is found by starting at the "center" point @@ -400,7 +409,7 @@ void Shadow3::render_jak1(DmaFollower& dma, } // skip drawing if the camera is below the lower clipping plane - if (kCullWhenUnderPlane & game_request.settings.flags) { + if (!m_hacks && (kCullWhenUnderPlane & game_request.settings.flags)) { if (render_state->camera_pos.xyz().dot(request.bottom_plane.xyz()) + request.bottom_plane.w() < 0) { @@ -410,14 +419,17 @@ void Shadow3::render_jak1(DmaFollower& dma, } } + request.next = chain->head; + chain->head = &request; + // detect if the origin is below the clipping plane and if so, move it up. const float dot = request.bottom_plane.xyz().dot(request.origin); if (dot + request.bottom_plane.w() > 0) { // printf(" the origin is below the clipping plane, moving it up.\n"); - // printf(" center was %s\n", game_request.settings.center.to_string_aligned().c_str()); - // printf(" dir was %s\n", game_request.settings.shadow_dir.to_string_aligned().c_str()); - // printf(" locus %f\n", game_request.settings.dist_to_locus); - // printf(" bottom plane was %s\n", + // printf(" center was %s\n", + // game_request.settings.center.to_string_aligned().c_str()); printf(" dir was %s\n", + // game_request.settings.shadow_dir.to_string_aligned().c_str()); printf(" locus %f\n", + // game_request.settings.dist_to_locus); printf(" bottom plane was %s\n", // game_request.settings.bot_plane.to_string_aligned().c_str()); // printf(" adjusted bottom plane was %s\n", // request.bottom_plane.to_string_aligned().c_str()); @@ -454,6 +466,10 @@ void Shadow3::render_jak1(DmaFollower& dma, request.bottom_plane = rotate_plane(request.bottom_plane); request.origin = transform(request.origin); + math::Vector3f up_rt_w = math::Vector3f(0, 1, 0); + math::Vector3f up_rt_cam = rotate(up_rt_w); + // printf("ups: %f\n", up_rt_cam.dot(request.bottom_plane.xyz())); + // printf("plane offset after: %f\n", // transform(game_request.settings.center).dot(request.bottom_plane.xyz()) + // request.bottom_plane.w()); diff --git a/game/graphics/opengl_renderer/foreground/Shadow3.h b/game/graphics/opengl_renderer/foreground/Shadow3.h index b70180a00e..e0e5382b96 100644 --- a/game/graphics/opengl_renderer/foreground/Shadow3.h +++ b/game/graphics/opengl_renderer/foreground/Shadow3.h @@ -81,11 +81,11 @@ class Shadow3 { GLuint bottom_plane = 0; GLuint top_plane = 0; GLuint origin = 0; - GLuint bottom_cap = 0; } m_uniforms; bool m_did_first_time_setup = false; bool m_hacks = false; + bool m_cull_back = false; bool m_near_plane_hack = false; int m_debug_tri = 0; diff --git a/game/graphics/opengl_renderer/foreground/Shadow3CPU.cpp b/game/graphics/opengl_renderer/foreground/Shadow3CPU.cpp index 7dce3c9e37..f26638f79a 100644 --- a/game/graphics/opengl_renderer/foreground/Shadow3CPU.cpp +++ b/game/graphics/opengl_renderer/foreground/Shadow3CPU.cpp @@ -1,24 +1,18 @@ #include "Shadow3CPU.h" -#include - -/* -*- `xform-verts` transform mesh vertices into camera space (no perspective) -- `init-vars` transform settings to camera space -- `calc-dual-verts` project vertices to plane -- `scissor-top` (only executed if shdf03 is set), clip vertices to top plane, if above -- `scissor-edges`, clip vertices to near plane -- `find-facing-single-tris`, set face bit to indicate orientation, cull backward ones -- `find-single-edges`, find edges that, when extruded, should be drawn -- `find-facing-double-tris`, set face bit indicate orientation. double sided tris, so no culling -- `find-double-edges`, find edges to extrude from the double-sided tris -- `add-verts` -- `add-facing-single-tris` -- `add-single-edges` -- `add-double-tris` -- `add-double-edges` -*/ +// This file generates indices with correct face orientations for a shadow volume. +// As usual, Naughty Dog has a few tricks. +// You can have double-sided triangles - basically infinitely thin geometry that casts a shadow. +// It is also okay to have holes in your mesh of single-sided triangles as long as no light ray +// would enter or exit your "volume" through the gap first or last. +// (so you should only have gaps for weird internal areas that would never have an effect on the +// final shadow) It is always safe to eliminate triangles that are fully enclosed within another +// closed volume. +/** + * Since the shadow mesh has skeletal animation, we must compute the vertex positions on the CPU to + * determine the shadow volume. There's no way around this other than geometry shaders. + */ void transform_vertices(const ShadowCPUInput& input, ShadowCPUWorkspace* work) { struct Bone { math::Vector4f mat[4]; @@ -29,6 +23,7 @@ void transform_vertices(const ShadowCPUInput& input, ShadowCPUWorkspace* work) { math::Vector4f* out_ptr = work->vertices; const Bone* first_bone_ptr = (const Bone*)(3 * 8 * 4 * sizeof(float) + input.bones); + // vertices influenced by one bone for (int i = 0; i < input.model->num_one_bone_vertices; i++) { const Bone& bone = first_bone_ptr[vertex_ptr->mats[0]]; *out_ptr = bone.mat[3] + // @@ -39,6 +34,7 @@ void transform_vertices(const ShadowCPUInput& input, ShadowCPUWorkspace* work) { out_ptr++; } + // vertices influenced by two bones. for (int i = 0; i < input.model->num_two_bone_vertices; i++) { const Bone& bone0 = first_bone_ptr[vertex_ptr->mats[0]]; math::Vector4f p0 = bone0.mat[3] + // @@ -59,6 +55,12 @@ void transform_vertices(const ShadowCPUInput& input, ShadowCPUWorkspace* work) { } } +/** + * Compute the projection of each vertex onto the "bottom plane". This is another ND trick. + * Instead of doing the traditional thing of making an infinite volume, they effectively clip + * the mesh against some plane that sits (ideally) slightly below the ground. This avoids the issue + * of casting shadows on the "wrong side of the ground", and reduces fill. + */ void calc_dual_verts(const ShadowCPUInput& input, ShadowCPUWorkspace* work) { int num_verts = input.model->num_one_bone_vertices + input.model->num_two_bone_vertices; for (int i = 0; i < num_verts; i++) { @@ -70,140 +72,185 @@ void calc_dual_verts(const ShadowCPUInput& input, ShadowCPUWorkspace* work) { } } +/** + * Another ND trick: clip the mesh against some plane slightly above the ground. I think this just + * reduces fill. + */ void scissor_top(const ShadowCPUInput& input, ShadowCPUWorkspace* work) { // TODO } +/** + * Clip against the near plane. I'm not sure why this is needed, but it may be another fill-reducing + * trick, or maybe just allows them to avoid scissoring against the near plane in the VU program. + */ void scissor_edges(const ShadowCPUInput& input, ShadowCPUWorkspace* work) { // TODO } +/** + * Add "cap" triangles. These are either triangles in the original mesh that point toward the light, + * and their projection to the bottom plane. + */ void find_facing_single_tris(const ShadowCPUInput& input, ShadowCPUWorkspace* work, ShadowCPUOutput* output, const std::vector& tris) { + const int num_verts = input.model->num_one_bone_vertices + input.model->num_two_bone_vertices; + for (size_t i = 0; i < tris.size(); i++) { + const auto& tri = tris[i]; + // recompute normal after transformation: + math::Vector3f v0 = work->vertices[tri.verts[0]].xyz(); + math::Vector3f v1 = work->vertices[tri.verts[1]].xyz(); + math::Vector3f v2 = work->vertices[tri.verts[2]].xyz(); + math::Vector3f n = (v1 - v0).cross(v2 - v0); + + bool highlight = i == input.debug_highlight_tri; + if (n.dot(input.light_dir) < 0.f) { + work->tri_flags[i] = 1; + // facing toward the light, add the triangle as it appears in the original mesh + output->push_index(tri.verts[0], !highlight); + output->push_index(tri.verts[1], !highlight); + output->push_index(tri.verts[2], !highlight); + // and the projection. This triangle has the normal pointing the other way, since it closes + // the volume, so the indices are flipping. + output->push_index(static_cast(tri.verts[0]) + num_verts, !highlight); + output->push_index(static_cast(tri.verts[2]) + num_verts, !highlight); + output->push_index(static_cast(tri.verts[1]) + num_verts, !highlight); + } else { + // facing away from the light. + work->tri_flags[i] = 0; + } + } +} + +/** + * Build walls. A wall will happen on an edge between a facing and non-facing tri. + * Or, if there is no second tri, there will be a wall whenever the first tri is facing. + */ +void find_single_edges(const ShadowCPUInput& input, + ShadowCPUWorkspace* work, + ShadowCPUOutput* output) { int edge_offset = input.model->num_one_bone_vertices + input.model->num_two_bone_vertices; - int num_0 = 0; - int num_1 = 0; + for (size_t i = 0; i < input.model->single_edges.size(); i++) { + const auto& e = input.model->single_edges[i]; + const u8 f0 = work->tri_flags[e.tri[0]]; + const auto t1 = e.tri[1]; + + bool flip = false; // set if the edge orientation is backward. + if (t1 == 255) { + if (f0 == 0) { // only one tri, skip if not facing + continue; + } + // if facing, then the edge is already oriented the right way! + } else { + const u8 f1 = work->tri_flags[e.tri[1]]; + if (f0 == f1) { // both tris face the same way - no wall needed. + continue; + } + flip = f0 == 0; // ND convention here for edge direction. + // this is somewhat of an odd convention because it seems like edges on singles + // are backward. oh well. + } + + if (!flip) { + output->push_index(e.ind[0], true); + output->push_index(static_cast(e.ind[0]) + edge_offset, true); + output->push_index(static_cast(e.ind[1]) + edge_offset, true); + + output->push_index(e.ind[0], true); + output->push_index(static_cast(e.ind[1]) + edge_offset, true); + output->push_index(e.ind[1], true); + } else { + output->push_index(e.ind[0], true); + output->push_index(static_cast(e.ind[1]) + edge_offset, true); + output->push_index(static_cast(e.ind[0]) + edge_offset, true); + + output->push_index(e.ind[0], true); + output->push_index(e.ind[1], true); + output->push_index(static_cast(e.ind[1]) + edge_offset, true); + } + } +} +/** + * Add cap triangles for double triangles. One side is always facing! + */ +void find_facing_double_tris(const ShadowCPUInput& input, + ShadowCPUWorkspace* work, + ShadowCPUOutput* output, + const std::vector& tris) { + const int num_verts = input.model->num_one_bone_vertices + input.model->num_two_bone_vertices; + const int flag_offset = 0; + for (size_t i = 0; i < tris.size(); i++) { const auto& tri = tris[i]; math::Vector3f v0 = work->vertices[tri.verts[0]].xyz(); math::Vector3f v1 = work->vertices[tri.verts[1]].xyz(); math::Vector3f v2 = work->vertices[tri.verts[2]].xyz(); math::Vector3f n = (v1 - v0).cross(v2 - v0); - bool highlight = i == input.debug_highlight_tri; if (n.dot(input.light_dir) < 0.f) { - num_0++; - work->tri_flags[i] = 1; - output->push_index(tri.verts[0], !highlight); - output->push_index(tri.verts[1], !highlight); - output->push_index(tri.verts[2], !highlight); + work->tri_flags[i + flag_offset] = 1; + // treat this as a normal single-sided triangle that is facing. + output->push_index(tri.verts[0], false); + output->push_index(tri.verts[1], false); + output->push_index(tri.verts[2], false); + output->push_index(static_cast(tri.verts[0]) + num_verts, false); + output->push_index(static_cast(tri.verts[2]) + num_verts, false); + output->push_index(static_cast(tri.verts[1]) + num_verts, false); } else { - num_1++; - work->tri_flags[i] = 0; - output->push_index(static_cast(tri.verts[0]) + edge_offset, !highlight); - output->push_index(static_cast(tri.verts[1]) + edge_offset, !highlight); - output->push_index(static_cast(tri.verts[2]) + edge_offset, !highlight); + work->tri_flags[i + flag_offset] = 0; + // we need to flip vertices to face the light. + output->push_index(tri.verts[0], false); + output->push_index(tri.verts[2], false); + output->push_index(tri.verts[1], false); + output->push_index(static_cast(tri.verts[0]) + num_verts, false); + output->push_index(static_cast(tri.verts[1]) + num_verts, false); + output->push_index(static_cast(tri.verts[2]) + num_verts, false); } } } -// void find_facing_double_tris(const ShadowCPUInput& input, -// ShadowCPUWorkspace* work, -// ShadowCPUOutput* output, -// const std::vector& tris) { -// int edge_offset = input.model->num_one_bone_vertices + input.model->num_two_bone_vertices; -// const int flag_offset = input.model->double_tris.size(); -// int num_0 = 0; -// int num_1 = 0; -// for (size_t i = 0; i < tris.size(); i++) { -// const auto& tri = tris[i]; -// math::Vector3f v0 = work->vertices[tri.verts[0]].xyz(); -// math::Vector3f v1 = work->vertices[tri.verts[1]].xyz(); -// math::Vector3f v2 = work->vertices[tri.verts[2]].xyz(); -// math::Vector3f n = (v1 - v0).cross(v2 - v0); -// if (n.dot(input.light_dir) < 0.f) { -// num_0++; -// work->tri_flags[i + flag_offset] = 1; -// -// } else { -// num_1++; -// work->tri_flags[i + flag_offset] = 0; -// } -// -// output->push_index(tri.verts[0], false); -// output->push_index(tri.verts[1], false); -// output->push_index(tri.verts[2], false); -// output->push_index(tri.verts[1], false); -// output->push_index(tri.verts[0], false); -// output->push_index(tri.verts[2], false); -// output->push_index(static_cast(tri.verts[0]) + edge_offset, false); -// output->push_index(static_cast(tri.verts[1]) + edge_offset, false); -// output->push_index(static_cast(tri.verts[2]) + edge_offset, false); -// output->push_index(static_cast(tri.verts[1]) + edge_offset, false); -// output->push_index(static_cast(tri.verts[0]) + edge_offset, false); -// output->push_index(static_cast(tri.verts[2]) + edge_offset, false); -// } -// } - -void find_single_edges(const ShadowCPUInput& input, +void find_double_edges(const ShadowCPUInput& input, ShadowCPUWorkspace* work, ShadowCPUOutput* output) { - int num_weird = 0; - int num_0 = 0; - int num_1 = 0; int edge_offset = input.model->num_one_bone_vertices + input.model->num_two_bone_vertices; - for (size_t i = 0; i < input.model->single_edges.size(); i++) { - const auto& e = input.model->single_edges[i]; - bool skip = false; - bool out_back = false; + for (size_t i = 0; i < input.model->double_edges.size(); i++) { + const auto& e = input.model->double_edges[i]; + const u8 f0 = work->tri_flags[e.tri[0]]; + const auto t1 = e.tri[1]; - if (e.tri[1] == 255) { - out_back = true; - skip = work->tri_flags[e.tri[0]] == 0; - num_weird++; + auto add = [&](bool flip) { + if (flip) { + output->push_index(e.ind[0], true); + output->push_index(static_cast(e.ind[0]) + edge_offset, true); + output->push_index(static_cast(e.ind[1]) + edge_offset, true); + + output->push_index(e.ind[0], true); + output->push_index(static_cast(e.ind[1]) + edge_offset, true); + output->push_index(e.ind[1], true); + } else { + output->push_index(e.ind[0], true); + output->push_index(static_cast(e.ind[1]) + edge_offset, true); + output->push_index(static_cast(e.ind[0]) + edge_offset, true); + + output->push_index(e.ind[0], true); + output->push_index(e.ind[1], true); + output->push_index(static_cast(e.ind[1]) + edge_offset, true); + } + }; + + if (t1 == 255) { + add(f0 == 1); } else { - u8 f0 = work->tri_flags[e.tri[0]]; - u8 f1 = work->tri_flags[e.tri[1]]; - - if (f0 == f1) { - skip = true; - } else { - if (f0 == 1) { - out_back = true; - num_0++; - } else { - num_1++; - } - } - } - - if (!skip) { - if (out_back) { - output->push_index(e.ind[0], true); - output->push_index(static_cast(e.ind[0]) + edge_offset, true); - output->push_index(static_cast(e.ind[1]) + edge_offset, true); - - output->push_index(e.ind[0], true); - output->push_index(static_cast(e.ind[1]) + edge_offset, true); - output->push_index(e.ind[1], true); - } else { - output->push_index(e.ind[0], true); - output->push_index(static_cast(e.ind[1]) + edge_offset, true); - output->push_index(static_cast(e.ind[0]) + edge_offset, true); - - output->push_index(e.ind[0], true); - output->push_index(e.ind[1], true); - output->push_index(static_cast(e.ind[1]) + edge_offset, true); - } + const u8 f1 = work->tri_flags[e.tri[1]]; + ASSERT(f0 != 77); + ASSERT(f1 != 77); + add(f0 == 1); + add(f1 != 1); } } } -void find_facing_double_tris() {} - -void find_double_edges() {} - void calc_shadow_indices(const ShadowCPUInput& input, ShadowCPUWorkspace* work, ShadowCPUOutput* output) { @@ -222,7 +269,8 @@ void calc_shadow_indices(const ShadowCPUInput& input, scissor_edges(input, work); find_facing_single_tris(input, work, output, input.model->single_tris); find_single_edges(input, work, output); - // find_facing_double_tris(input, work, output, input.model->double_tris); + find_facing_double_tris(input, work, output, input.model->double_tris); + find_double_edges(input, work, output); for (int i = 0; i < output->num_indices; i++) { output->indices[i] += input.model->first_vertex; diff --git a/game/graphics/opengl_renderer/foreground/Shadow3CPU.h b/game/graphics/opengl_renderer/foreground/Shadow3CPU.h index e7d53b3c63..3861ce4046 100644 --- a/game/graphics/opengl_renderer/foreground/Shadow3CPU.h +++ b/game/graphics/opengl_renderer/foreground/Shadow3CPU.h @@ -14,7 +14,7 @@ struct ShadowCPUInput { }; struct ShadowCPUOutput { - static constexpr int kMaxIndices = (256 * 3) + (256 * 3 * 2); + static constexpr int kMaxIndices = (256 * 3 * 2) + (256 * 3 * 2); void push_index(u32 i, bool facing) { indices[num_indices++] = i; diff --git a/game/graphics/opengl_renderer/shaders/shadow3.vert b/game/graphics/opengl_renderer/shaders/shadow3.vert index 5ea713652e..c5396aedb9 100644 --- a/game/graphics/opengl_renderer/shaders/shadow3.vert +++ b/game/graphics/opengl_renderer/shaders/shadow3.vert @@ -15,13 +15,10 @@ uniform vec3 debug_color; uniform vec4 bottom_plane; uniform vec4 top_plane; uniform vec3 origin; -uniform bool bottom_cap; // output out vec4 vtx_color; -int offset = 0; - struct MercMatrixData { mat4 X; }; @@ -62,6 +59,7 @@ vec4 scissor(vec4 p, vec4 plane) { } void main() { + float w_debug = 7; vec4 p = vec4(position_in, 1); vec4 vtx_pos; @@ -69,25 +67,23 @@ void main() { // debug hack! vtx_pos = vec4(position_in, weight_in); } else { - vtx_pos = -bones[mats[0] + offset].X * p * weight_in; + vtx_pos = bones[mats[0]].X * p * weight_in; - if (weight_in > 1) { - vtx_pos += -bones[mats[1] + offset].X * p * (1.f - weight_in); + if (weight_in < 1) { + vtx_pos += bones[mats[1]].X * p * (1.f - weight_in); } - - if (bottom_cap) { + w_debug = vtx_pos.w; + if ((flags & uint(1)) != 0) { vtx_pos = dual(vtx_pos, bottom_plane); } else { - if ((flags & uint(1)) != 0) { - vtx_pos = dual(vtx_pos, bottom_plane); - } else { - vtx_pos = scissor(vtx_pos, top_plane); - } + vtx_pos = scissor(vtx_pos, top_plane); } } - vec4 transformed = perspective_matrix * vtx_pos; + + + vec4 transformed = perspective_matrix * -vtx_pos; float Q = fog_constants.x / transformed[3]; @@ -103,5 +99,5 @@ void main() { gl_Position = transformed; - vtx_color = vec4(debug_color, 0.5); + vtx_color = vec4(debug_color, w_debug); }