diff options
| author | tech kaczynski <tk@techkaczynski.dev> | 2026-11-04 05:56:35 +1000 |
|---|---|---|
| committer | tech kaczynski <tk@techkaczynski.dev> | 2026-11-04 05:56:35 +1000 |
| commit | ea84213ece95e3ef8ff7f0095cee73ee6bdd0f9a (patch) | |
| tree | 32a502e72438ba0c6b6fa00dbd9dbdf3603fe7e3 | |
| parent | e5560f69e11051a85c1d54780a59a4fbd83d8ed9 (diff) | |
added convex hull and trimesh colliders. Fixed physics edit mode bugs. Added debug drawing for all supported collision types.
| -rw-r--r-- | editor.c | 207 | ||||
| -rw-r--r-- | ent.c | 184 | ||||
| -rw-r--r-- | env.c | 1 | ||||
| -rw-r--r-- | physics.h | 1 | ||||
| -rw-r--r-- | res.c | 27 | ||||
| -rw-r--r-- | res/mdl/psx-characters/male/rigged/male1.glb | bin | 0 -> 409632 bytes | |||
| -rw-r--r-- | res/mdl/psx-characters/male/rigged/male1.raylib.glb | bin | 0 -> 409632 bytes | |||
| -rw-r--r-- | res/mdl/psx-trees/dead_tree_rt_1.glb | bin | 0 -> 302660 bytes | |||
| -rw-r--r-- | res/mdl/psx-trees/dead_tree_rt_2.glb | bin | 0 -> 80152 bytes | |||
| -rw-r--r-- | res/mdl/psx-trees/small_tree_rt_1.glb | bin | 0 -> 16040 bytes | |||
| -rw-r--r-- | res/mdl/psx-trees/tree_rt_1.glb | bin | 0 -> 58664 bytes | |||
| -rw-r--r-- | res/mdl/psx-trees/tree_rt_2.glb | bin | 0 -> 159940 bytes | |||
| -rw-r--r-- | res/mdl/psx-trees/tree_rt_2_1.glb | bin | 0 -> 158828 bytes | |||
| -rw-r--r-- | res/mdl/psx-trees/tree_rt_3.glb | bin | 0 -> 178696 bytes | |||
| -rw-r--r-- | res/mdl/psx-trees/tree_rt_4.glb | bin | 0 -> 415296 bytes | |||
| -rw-r--r-- | res/save/scene.fgs | bin | 14764 -> 172800 bytes | |||
| -rw-r--r-- | res/sdr/mdl_foliage.vs | 23 | ||||
| -rw-r--r-- | res/sdr/mdl_skinned_vtx_lit.vs | 59 |
18 files changed, 463 insertions, 39 deletions
@@ -3184,24 +3184,19 @@ panel_properties(EditorPanelContainer container, bool input) { main_cam.input = false; main_cam.update = false; - u64 id = entity_id_from_pid(ent->pid); - - f32 view_height = 10.0f * - tanf(main_cam.perspective_fov * - DEG2RAD * 0.5f); - - cam_focus(entity_world_pos(id), 5.0f, view_height); - ed.physics_pid = ent->pid; ed.physics_body = -1; ed.physics_shape = -1; ed.physics_scroll = (Vec2){0}; ed.prev_mode = ed.mode; + ed.panel[ED_PNL_LEFT].enabled = true; + ed.panel[ED_PNL_RIGHT].enabled = true; ed.mode = ED_MODE_PHYSICS; ed.panel[ED_PNL_LEFT].type = ED_PNL_TYPE_PHYSICS_ELEMENTS; ed.panel[ED_PNL_RIGHT].type = ED_PNL_TYPE_PHYSICS_PROPERTIES; + editor_focus_selection(); edit.focus = 0; add_open = false; @@ -4251,6 +4246,66 @@ panel_physics_shape(PanelEdit *edit, Rect row, } static void +physics_shape_model_geometry( + PhysicsShape *shape, + const Model *model, + u32 point_cnt, + u32 idx_cnt) { + bool trimesh = shape->tag == PHYS_SHAPE_STATIC_TRIMESH; + + Vec3 *points = malloc(point_cnt * sizeof(*points)); + u32 *indices = NULL; + + if (trimesh) { + indices = malloc(idx_cnt * sizeof(*indices)); + } + + if (!points || (trimesh && !indices)) { + perror("model collision allocation failed"); + exit(EXIT_FAILURE); + } + + u32 point_offset = 0; + u32 index_offset = 0; + + for (int i = 0; i < model->meshCount; ++i) { + const Mesh *mesh = &model->meshes[i]; + + for (int v = 0; v < mesh->vertexCount; ++v) { + points[point_offset + v] = (Vec3){ + mesh->vertices[v * 3], + mesh->vertices[v * 3 + 1], + mesh->vertices[v * 3 + 2], + }; + } + + if (trimesh) { + u32 count = (u32)mesh->triangleCount * 3; + + for (u32 k = 0; k < count; ++k) { + u32 index = mesh->indices + ? (u32)mesh->indices[k] + : k; + + indices[index_offset++] = point_offset + index; + } + } + + point_offset += (u32)mesh->vertexCount; + } + + if (trimesh) { + shape->TriMesh.points = points; + shape->TriMesh.indices = indices; + shape->TriMesh.point_cnt = point_cnt; + shape->TriMesh.idx_cnt = idx_cnt; + } else { + shape->ConvexHull.points = points; + shape->ConvexHull.point_cnt = point_cnt; + } +} + +static void panel_physics_properties(EditorPanelContainer container, bool input) { Rect bounds = ed.panel[container].bounds; @@ -4518,10 +4573,20 @@ panel_physics_properties(EditorPanelContainer container, bool input) { } bool fit_model = GuiButton(info, "Add Model Box"); + + info.y += 30; + bool add_hull = GuiButton(info, "Add Model Hull"); + + info.y += 30; + if (body->mode != PHYS_MODE_STATIC) { + GuiSetState(STATE_DISABLED); + } + + bool add_trimesh = GuiButton(info, "Add Model Trimesh"); GuiSetState(button_state); Model *model = NULL; - if (fit_model) { + if (fit_model || add_hull || add_trimesh) { Asset *asset = asset_get(ent->mdl.key); if (asset && asset->tag == ASSET_TAG_MODEL && asset->mdl.meshCount > 0) { @@ -4529,6 +4594,35 @@ panel_physics_properties(EditorPanelContainer container, bool input) { } } + u32 point_cnt = 0; + u32 idx_cnt = 0; + + if (model && (add_hull || add_trimesh)) { + for (int i = 0; i < model->meshCount; ++i) { + Mesh *mesh = &model->meshes[i]; + + if (!mesh->vertices || + mesh->vertexCount <= 0) { + model = NULL; + break; + } + + point_cnt += (u32)mesh->vertexCount; + idx_cnt += (u32)mesh->triangleCount * 3; + } + + if (point_cnt < (add_trimesh ? 3u : 4u) || + (add_trimesh && idx_cnt < 3)) { + model = NULL; + } + + if (!model) { + TraceLog(LOG_WARNING, + "model has no usable " + "collision geometry"); + } + } + if (add_box || add_sphere || add_capsule || add_cylinder || model) { edit.focus = 0; @@ -4584,7 +4678,7 @@ panel_physics_properties(EditorPanelContainer container, bool input) { shape->Cylinder.height = 1.0f; } - if (model) { + if (model && fit_model) { Model local_model = *model; local_model.transform = MatrixIdentity(); @@ -4608,6 +4702,22 @@ panel_physics_properties(EditorPanelContainer container, bool input) { shape->rot); } + if (model && (add_hull || add_trimesh)) { + PhysicsShape *shape = + &body->shapes[body->shape_cnt]; + + shape->tag = add_trimesh + ? PHYS_SHAPE_STATIC_TRIMESH + : PHYS_SHAPE_CONVEX_HULL; + + shape->rot = QuaternionInvert(body->rot); + shape->pos = Vector3RotateByQuaternion( + Vector3Negate(body->pos), shape->rot); + + physics_shape_model_geometry( + shape, model, point_cnt, idx_cnt); + } + body->shape_cnt++; action_commit(&action); @@ -5435,6 +5545,36 @@ gizmo_scale(void) { } static void +physics_draw_hull(b3ShapeId shape_id, Color colour) { + if (!b3Shape_IsValid(shape_id)) { + return; + } + + const b3HullData *hull = b3Shape_GetHull(shape_id); + const b3Vec3 *points = b3GetHullPoints(hull); + const b3HullHalfEdge *edges = b3GetHullEdges(hull); + b3BodyId body_id = b3Shape_GetBody(shape_id); + + for (int i = 0; i < hull->edgeCount; ++i) { + const b3HullHalfEdge *edge = &edges[i]; + + /* Each edge has two halves; draw it once. */ + if (i > edge->twin) { + continue; + } + + b3Pos a = b3Body_GetWorldPoint( + body_id, points[edge->origin]); + b3Pos b = b3Body_GetWorldPoint( + body_id, points[edges[edge->twin].origin]); + + DrawLine3D( + (Vec3){a.x, a.y, a.z}, + (Vec3){b.x, b.y, b.z}, colour); + } +} + +static void physics_draw_shapes(u64 id) { Entity *ent = entity_get(id); if (!ent) { @@ -5496,6 +5636,53 @@ physics_draw_shapes(u64 id) { QuaternionToMatrix(rotation), MatrixTranslate(center.x, center.y, center.z)); + if (shape->tag == PHYS_SHAPE_CONVEX_HULL) { + PhysicsBodyRuntime *bodies = + ent->phys.runtime.bodies; + + if (bodies && bodies[i].shapes) { + physics_draw_hull(bodies[i].shapes[j], + colour); + } + continue; + } + + if (shape->tag == PHYS_SHAPE_STATIC_TRIMESH) { + const Vec3 *points = shape->TriMesh.points; + const u32 *indices = shape->TriMesh.indices; + u32 point_cnt = shape->TriMesh.point_cnt; + + if (!points || !indices) { + continue; + } + + for (u32 k = 0; + k + 2 < shape->TriMesh.idx_cnt; + k += 3) { + u32 ia = indices[k]; + u32 ib = indices[k + 1]; + u32 ic = indices[k + 2]; + + if (ia >= point_cnt || + ib >= point_cnt || + ic >= point_cnt) { + continue; + } + + Vec3 a = Vector3Transform(points[ia], + world); + Vec3 b = Vector3Transform(points[ib], + world); + Vec3 c = Vector3Transform(points[ic], + world); + + DrawLine3D(a, b, colour); + DrawLine3D(b, c, colour); + DrawLine3D(c, a, colour); + } + continue; + } + rlPushMatrix(); rlMultMatrixf(MatrixToFloat(transform)); @@ -275,7 +275,9 @@ entity_draw_mdl(u64 id) { Vec2 uv_scale = {1, 1}; Vec2 uv_offset = {0, 0}; - cstr shader_key = "default"; + cstr shader_key = mdl->meshes[i].boneCount > 0 + ? "skinned" + : "default"; if (mat_idx < model->mat_cnt) { const MaterialOverride *override; @@ -292,7 +294,12 @@ entity_draw_mdl(u64 id) { } if (override->shader_key) { - shader_key = override->shader_key; + if (strcmp(override->shader_key, + "default") != 0 && + strcmp(shader_key, + "skinned") != 0) { + shader_key = override->shader_key; + } } } @@ -326,18 +333,18 @@ entity_draw_mdl(u64 id) { (u8)((int)colour.a * tint.a / 255), }; - /* Preserve DrawModel's GPU skinning support. */ - // int loc = SHADER_LOC_MATRIX_BONETRANSFORMS; - // if (material.shader.locs != NULL && - // material.shader.locs[loc] != -1 && - // mdl->boneMatrices != NULL) { - // rlEnableShader(material.shader.id); - // rlSetUniformMatrices( - // material.shader.locs[loc], - // mdl->boneMatrices, - // mdl->skeleton.boneCount - // ); - // } + if (strcmp(shader_key, "skinned") == 0 && + mdl->boneMatrices != NULL) { + int loc = fun_shader_uniform(shader_key, + "boneMatrices"); + + rlEnableShader(material.shader.id); + rlSetUniformMatrices( + loc, + mdl->boneMatrices, + mdl->skeleton.boneCount + ); + } bool nocull = strcmp(shader_key, "alpha_cutoff_nocull") == 0 || @@ -607,6 +614,18 @@ entity_physics_clear(PhysicsCmp *phys) { if (b3Body_IsValid(bdy->id)) { b3DestroyBody(bdy->id); } + + if (bdy->meshes) { + for (u32 j = 0; + j < phys->bodies[i].shape_cnt; + ++j) { + if (bdy->meshes[j]) { + b3DestroyMesh(bdy->meshes[j]); + } + } + } + + free(bdy->meshes); free(bdy->shapes); } } @@ -629,10 +648,12 @@ physics_build_shapes(u64 id, u32 body_index) { runtime->shapes = calloc( body->shape_cnt, sizeof(*runtime->shapes)); + runtime->meshes = calloc( + body->shape_cnt, sizeof(*runtime->meshes)); - if (!runtime->shapes) { - perror("physics shape handles allocation failed"); - exit(EXIT_FAILURE); + if (!runtime->shapes || !runtime->meshes) { + perror("physics shape allocation failed"); + exit(1); } Matrix entity_world = entity_world_matrix(id); @@ -826,6 +847,135 @@ physics_build_shapes(u64 id, u32 body_index) { break; } + case PHYS_SHAPE_CONVEX_HULL: + case PHYS_SHAPE_STATIC_TRIMESH: { + bool trimesh = shape->tag == PHYS_SHAPE_STATIC_TRIMESH; + if (trimesh && body->mode != PHYS_MODE_STATIC) { + TraceLog(LOG_WARNING, + "trimesh requires a static body"); + break; + } + + Vec3 *source = trimesh + ? shape->TriMesh.points + : shape->ConvexHull.points; + + u32 point_cnt = trimesh + ? shape->TriMesh.point_cnt + : shape->ConvexHull.point_cnt; + + if (!source || point_cnt < (trimesh ? 3u : 4u) || + point_cnt > INT32_MAX) { + break; + } + + b3Vec3 *points = malloc(point_cnt * sizeof(*points)); + if (!points) { + perror("physics points allocation failed"); + exit(EXIT_FAILURE); + } + + /* Bake the full transform into body-local geometry. */ + for (u32 k = 0; k < point_cnt; ++k) { + Vec3 point = + Vector3Transform(source[k], world); + point = Vector3RotateByQuaternion( + Vector3Subtract(point, pos), + inverse_rot); + + points[k] = (b3Vec3){ + point.x, point.y, point.z, + }; + } + + if (!trimesh) { + b3HullData *hull = + b3CreateHull( + points, + (int)point_cnt, + (int)point_cnt); + + if (hull) { + runtime->shapes[j] = + b3CreateTransformedHullShape( + runtime->id, + &def, + hull, + b3Transform_identity, + (b3Vec3){1, 1, 1}); + + b3DestroyHull(hull); + } else { + TraceLog(LOG_WARNING, + "convex hull creation failed"); + } + + free(points); + break; + } + + u32 idx_cnt = shape->TriMesh.idx_cnt; + if (!shape->TriMesh.indices || + idx_cnt < 3 || idx_cnt % 3 != 0 || + idx_cnt > INT32_MAX) { + free(points); + break; + } + + int32_t *indices = malloc(idx_cnt * sizeof(*indices)); + if (!indices) { + perror("physics indices allocation failed"); + exit(EXIT_FAILURE); + } + + u32 k = 0; + for (; k < idx_cnt; ++k) { + u32 index = shape->TriMesh.indices[k]; + if (index >= point_cnt) { + break; + } + indices[k] = (int32_t)index; + } + + if (k != idx_cnt) { + TraceLog(LOG_WARNING, + "triangle mesh index out of range"); + free(indices); + free(points); + break; + } + + b3MeshDef mesh_def = {0}; + mesh_def.vertices = points; + mesh_def.vertexCount = (int)point_cnt; + mesh_def.indices = indices; + mesh_def.triangleCount = (int)(idx_cnt / 3); + mesh_def.identifyEdges = true; + + /* Preserve outward winding when the transform mirrors geometry. */ + mesh_def.clockWiseWinding = Vector3DotProduct( + Vector3CrossProduct( + (Vec3){world.m0, world.m1, world.m2}, + (Vec3){world.m4, world.m5, world.m6}), + (Vec3){world.m8, world.m9, world.m10}) < 0; + + b3MeshData *mesh = b3CreateMesh(&mesh_def, NULL, 0); + + free(indices); + free(points); + + if (!mesh) { + TraceLog(LOG_WARNING, + "triangle mesh creation failed"); + break; + } + + runtime->meshes[j] = mesh; + runtime->shapes[j] = b3CreateMeshShape( + runtime->id, &def, mesh, (b3Vec3){1, 1, 1}); + break; + } + default: break; } @@ -267,6 +267,7 @@ void env_update(void) { sky_update_lighting(); env_update_shader("default"); + env_update_shader("skinned"); env_update_shader("alpha_cutoff"); env_update_shader("alpha_cutoff_nocull"); env_update_shader("foliage"); @@ -141,6 +141,7 @@ typedef struct { u64 entity_id; b3BodyId id; b3ShapeId *shapes; // count is stored in PhysicsCmp + b3MeshData **meshes; // same count, null for non mesh types } PhysicsBodyRuntime; typedef struct { @@ -37,8 +37,29 @@ asset_load_data(cstr key) { return false; } + bool skinned = mdl.skeleton.boneCount > 0 && + mdl.skeleton.bindPose != NULL; + + cstr sdr_key = skinned ? "skinned" : "default"; + for (int i = 0; i < mdl.materialCount; ++i) { - mdl.materials[i].shader = shader_get("default")->sdr; + mdl.materials[i].shader = shader_get(sdr_key)->sdr; + } + + if (skinned) { + int anim_count = 0; + ModelAnimation *anims = + LoadModelAnimations(key, &anim_count); + + if (anim_count > 0) { + UpdateModelAnimation(mdl, anims[0], 0.0f); + } + + UnloadModelAnimations(anims, anim_count); + } + + for (int i = 0; i < mdl.materialCount; ++i) { + mdl.materials[i].shader = shader_get(sdr_key)->sdr; } asset->tag = ASSET_TAG_MODEL; @@ -148,6 +169,10 @@ res_init(void) { "res/sdr/mdl_vtx_lit.vs", "res/sdr/mdl_vtx_lit.fs"); + fun_shader_create("skinned", + "res/sdr/mdl_skinned_vtx_lit.vs", + "res/sdr/mdl_vtx_lit.fs"); + fun_shader_create("alpha_cutoff", "res/sdr/mdl_vtx_lit.vs", "res/sdr/mdl_vtx_lit_cutoff.fs"); diff --git a/res/mdl/psx-characters/male/rigged/male1.glb b/res/mdl/psx-characters/male/rigged/male1.glb Binary files differnew file mode 100644 index 0000000..69272c1 --- /dev/null +++ b/res/mdl/psx-characters/male/rigged/male1.glb diff --git a/res/mdl/psx-characters/male/rigged/male1.raylib.glb b/res/mdl/psx-characters/male/rigged/male1.raylib.glb Binary files differnew file mode 100644 index 0000000..283a3d2 --- /dev/null +++ b/res/mdl/psx-characters/male/rigged/male1.raylib.glb diff --git a/res/mdl/psx-trees/dead_tree_rt_1.glb b/res/mdl/psx-trees/dead_tree_rt_1.glb Binary files differnew file mode 100644 index 0000000..fec0486 --- /dev/null +++ b/res/mdl/psx-trees/dead_tree_rt_1.glb diff --git a/res/mdl/psx-trees/dead_tree_rt_2.glb b/res/mdl/psx-trees/dead_tree_rt_2.glb Binary files differnew file mode 100644 index 0000000..0523544 --- /dev/null +++ b/res/mdl/psx-trees/dead_tree_rt_2.glb diff --git a/res/mdl/psx-trees/small_tree_rt_1.glb b/res/mdl/psx-trees/small_tree_rt_1.glb Binary files differnew file mode 100644 index 0000000..632de9d --- /dev/null +++ b/res/mdl/psx-trees/small_tree_rt_1.glb diff --git a/res/mdl/psx-trees/tree_rt_1.glb b/res/mdl/psx-trees/tree_rt_1.glb Binary files differnew file mode 100644 index 0000000..0c7fa93 --- /dev/null +++ b/res/mdl/psx-trees/tree_rt_1.glb diff --git a/res/mdl/psx-trees/tree_rt_2.glb b/res/mdl/psx-trees/tree_rt_2.glb Binary files differnew file mode 100644 index 0000000..881f7d8 --- /dev/null +++ b/res/mdl/psx-trees/tree_rt_2.glb diff --git a/res/mdl/psx-trees/tree_rt_2_1.glb b/res/mdl/psx-trees/tree_rt_2_1.glb Binary files differnew file mode 100644 index 0000000..8c9669c --- /dev/null +++ b/res/mdl/psx-trees/tree_rt_2_1.glb diff --git a/res/mdl/psx-trees/tree_rt_3.glb b/res/mdl/psx-trees/tree_rt_3.glb Binary files differnew file mode 100644 index 0000000..2ec3314 --- /dev/null +++ b/res/mdl/psx-trees/tree_rt_3.glb diff --git a/res/mdl/psx-trees/tree_rt_4.glb b/res/mdl/psx-trees/tree_rt_4.glb Binary files differnew file mode 100644 index 0000000..19963e1 --- /dev/null +++ b/res/mdl/psx-trees/tree_rt_4.glb diff --git a/res/save/scene.fgs b/res/save/scene.fgs Binary files differindex ae27721..b07fae4 100644 --- a/res/save/scene.fgs +++ b/res/save/scene.fgs diff --git a/res/sdr/mdl_foliage.vs b/res/sdr/mdl_foliage.vs index 1198009..366290a 100644 --- a/res/sdr/mdl_foliage.vs +++ b/res/sdr/mdl_foliage.vs @@ -27,20 +27,21 @@ out vec4 frag_colour; out vec3 frag_lighting; void main() { - vec3 world_normal = normalize((matNormal * vec4(vertexNormal, 0.0)).xyz); + vec3 canopy_center = vec3(0.0, 4.0, 0.0); + vec3 canopy_normal = vertexNormal; + vec3 offset = vertexPosition - canopy_center; - // float sun_diffuse = abs(dot(world_normal, sun_direction)); - // float moon_diffuse = abs(dot(world_normal, moon_direction)); + if (dot(offset, offset) > 0.0001) { + canopy_normal = normalize(offset); + } - // for stronger shading, use 0.3 + 0.7 * abs(...) - // float sun_diffuse = 0.5 + 0.5 * abs(dot(world_normal, sun_direction)); - // float moon_diffuse = 0.5 + 0.5 * abs(dot(world_normal, moon_direction)); - float sun_diffuse = abs(dot(world_normal, sun_direction)); - float moon_diffuse = abs(dot(world_normal, moon_direction)); + vec3 world_normal = normalize((matNormal * vec4(canopy_normal, 0.0)).xyz); - // hack to fix lighting at midday - float midday = smoothstep(0.7, 1.0, sun_direction.y); - sun_diffuse = mix(sun_diffuse, 0.65, midday); + float sun_facing = dot(world_normal, sun_direction); + float moon_facing = dot(world_normal, moon_direction); + + float sun_diffuse = max(sun_facing, 0.0) + 0.1 * max(-sun_facing, 0.0); + float moon_diffuse = max(moon_facing, 0.0) + 0.1 * max(-moon_facing, 0.0); vec3 ambient_light = ambient_colour * ambient_intensity; vec3 sun_light = sun_colour * sun_intensity * sun_diffuse; diff --git a/res/sdr/mdl_skinned_vtx_lit.vs b/res/sdr/mdl_skinned_vtx_lit.vs new file mode 100644 index 0000000..a6da15e --- /dev/null +++ b/res/sdr/mdl_skinned_vtx_lit.vs @@ -0,0 +1,59 @@ +#version 330 + +in vec3 vertexPosition; +in vec2 vertexTexCoord; +in vec3 vertexNormal; +in vec4 vertexColor; + +uniform mat4 mvp; +uniform mat4 matNormal; + +uniform vec3 sun_direction; +uniform vec3 sun_colour; +uniform float sun_intensity; + +uniform vec3 moon_direction; +uniform vec3 moon_colour; +uniform float moon_intensity; + +uniform vec3 ambient_colour; +uniform float ambient_intensity; + +uniform vec2 uv_tiling; +uniform vec2 uv_offset; + +out vec2 frag_texcoord; +out vec4 frag_colour; +out vec3 frag_lighting; +out vec3 frag_normal; + +in vec4 vertexBoneIndices; +in vec4 vertexBoneWeights; + +uniform mat4 boneMatrices[64]; + +void main() { + mat4 skin = + vertexBoneWeights.x * boneMatrices[int(vertexBoneIndices.x)] + + vertexBoneWeights.y * boneMatrices[int(vertexBoneIndices.y)] + + vertexBoneWeights.z * boneMatrices[int(vertexBoneIndices.z)] + + vertexBoneWeights.w * boneMatrices[int(vertexBoneIndices.w)]; + + vec4 position = skin * vec4(vertexPosition, 1.0); + vec3 normal = (skin * vec4(vertexNormal, 0.0)).xyz; + vec3 world_normal = normalize((matNormal * vec4(normal, 0.0)).xyz); + + float sun_diffuse = max(dot(world_normal, sun_direction), 0.0); + float moon_diffuse = max(dot(world_normal, moon_direction), 0.0); + + vec3 ambient_light = ambient_colour * ambient_intensity; + vec3 sun_light = sun_colour * sun_intensity * sun_diffuse; + vec3 moon_light = moon_colour * moon_intensity * moon_diffuse; + + frag_lighting = ambient_light + sun_light + moon_light; + frag_texcoord = vertexTexCoord * uv_tiling + uv_offset; + frag_colour = vertexColor; + frag_normal = world_normal; + + gl_Position = mvp * position; +} |
