lots of minor shadow fixes

This commit is contained in:
water111
2025-06-17 22:18:43 -04:00
parent 753d8257be
commit 31e32943f5
5 changed files with 227 additions and 167 deletions
@@ -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<u8> 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());
@@ -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;
@@ -1,24 +1,18 @@
#include "Shadow3CPU.h"
#include <set>
/*
*- `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<tfrag3::ShadowTri>& 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<int>(tri.verts[0]) + num_verts, !highlight);
output->push_index(static_cast<int>(tri.verts[2]) + num_verts, !highlight);
output->push_index(static_cast<int>(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<int>(e.ind[0]) + edge_offset, true);
output->push_index(static_cast<int>(e.ind[1]) + edge_offset, true);
output->push_index(e.ind[0], true);
output->push_index(static_cast<int>(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<int>(e.ind[1]) + edge_offset, true);
output->push_index(static_cast<int>(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<int>(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<tfrag3::ShadowTri>& 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<int>(tri.verts[0]) + num_verts, false);
output->push_index(static_cast<int>(tri.verts[2]) + num_verts, false);
output->push_index(static_cast<int>(tri.verts[1]) + num_verts, false);
} else {
num_1++;
work->tri_flags[i] = 0;
output->push_index(static_cast<int>(tri.verts[0]) + edge_offset, !highlight);
output->push_index(static_cast<int>(tri.verts[1]) + edge_offset, !highlight);
output->push_index(static_cast<int>(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<int>(tri.verts[0]) + num_verts, false);
output->push_index(static_cast<int>(tri.verts[1]) + num_verts, false);
output->push_index(static_cast<int>(tri.verts[2]) + num_verts, false);
}
}
}
// void find_facing_double_tris(const ShadowCPUInput& input,
// ShadowCPUWorkspace* work,
// ShadowCPUOutput* output,
// const std::vector<tfrag3::ShadowTri>& 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<int>(tri.verts[0]) + edge_offset, false);
// output->push_index(static_cast<int>(tri.verts[1]) + edge_offset, false);
// output->push_index(static_cast<int>(tri.verts[2]) + edge_offset, false);
// output->push_index(static_cast<int>(tri.verts[1]) + edge_offset, false);
// output->push_index(static_cast<int>(tri.verts[0]) + edge_offset, false);
// output->push_index(static_cast<int>(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<int>(e.ind[0]) + edge_offset, true);
output->push_index(static_cast<int>(e.ind[1]) + edge_offset, true);
output->push_index(e.ind[0], true);
output->push_index(static_cast<int>(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<int>(e.ind[1]) + edge_offset, true);
output->push_index(static_cast<int>(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<int>(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<int>(e.ind[0]) + edge_offset, true);
output->push_index(static_cast<int>(e.ind[1]) + edge_offset, true);
output->push_index(e.ind[0], true);
output->push_index(static_cast<int>(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<int>(e.ind[1]) + edge_offset, true);
output->push_index(static_cast<int>(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<int>(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;
@@ -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;
@@ -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);
}