diff --git a/movement/3d_fps/all.texture_profiles b/movement/3d_fps/all.texture_profiles new file mode 100644 index 0000000..5b0d776 --- /dev/null +++ b/movement/3d_fps/all.texture_profiles @@ -0,0 +1,18 @@ +path_settings { + path: "**" + profile: "Default" +} +profiles { + name: "Default" + platforms { + os: OS_ID_GENERIC + formats { + format: TEXTURE_FORMAT_RGBA + compression_level: BEST + compression_type: COMPRESSION_TYPE_DEFAULT + } + mipmaps: false + max_texture_size: 0 + premultiply_alpha: true + } +} diff --git a/movement/3d_fps/collection.png b/movement/3d_fps/collection.png new file mode 100644 index 0000000..0ba97f5 Binary files /dev/null and b/movement/3d_fps/collection.png differ diff --git a/movement/3d_fps/example.md b/movement/3d_fps/example.md new file mode 100644 index 0000000..7c58b29 --- /dev/null +++ b/movement/3d_fps/example.md @@ -0,0 +1,53 @@ +--- +tags: movement +title: First-person 3D camera and movement +brief: Control a first-person camera using WASD and mouse to look with cursor lock. +author: Defold Foundation +scripts: character_controller.script +thumbnail: collection.png +--- + +This example shows how to build a simple first-person controller for a 3D scene. You can look around with the mouse and move on the XZ plane using the keyboard (WSAD). + +## What you'll learn? +- How to implement a FPP camera with mouse to look around. +- How to lock/unlock the mouse cursor for immersive camera control. +- How to move on a simple XZ plane logic with keyboard input. + +## Controls +| Input | Action | +|------------------------|------------------------------------------------------| +| Left mouse click | Lock the cursor and enable mouse look | +| Mouse movement | Rotate camera | +| `Esc` | Unlock the cursor | +| `W`/`S`/`A`/`D` | Move forward/backward/left/right on the ground plane | + +## How it works? +When the cursor is locked, the script reads mouse movement deltas and rotates the camera accordingly. Movement is normalized to keep a consistent speed in all directions and is clamped within a square area so you cannot wander off the demo scene. + +Example collection consists of 3 main parts: + +- `character` - The player character game object includes: + - A *script* `character_controller.script` component that implements mouse look, cursor lock/unlock, and WASD movement. + - A *camera* component configured with perspective projection. + +- `scene` - the models used to create a basic 3D environment: + - Ground plane scaled to form a walkable area with prototype texture + - Walls built from simple cube models with prototype textures + - Some decorative trees + +- `gui` - An on-screen GUI with short instructions. + +![](collection.png) + +### Assets +Tree models with textures by Kay Louseberg: https://kaylousberg.itch.io/kaykit-forest +Prototype textures for Defold by Visionaire: https://github.com/Thevisionaire1/3Deforms + +## Script + +Tuning parameters are defined at the top of `character_controller.script`: +- `look_sensitivity` (degrees per pixel) controls how fast the camera rotates +- `move_speed` (world units per second) controls walking speed +- `move_limit` (half-size in world units) clamps movement within bounds + diff --git a/movement/3d_fps/example/3d_fps.collection b/movement/3d_fps/example/3d_fps.collection new file mode 100644 index 0000000..565e96c --- /dev/null +++ b/movement/3d_fps/example/3d_fps.collection @@ -0,0 +1,600 @@ +name: "3d_fps" +scale_along_z: 0 +embedded_instances { + id: "character" + data: "components {\n" + " id: \"character_controller\"\n" + " component: \"/example/character_controller.script\"\n" + "}\n" + "embedded_components {\n" + " id: \"camera\"\n" + " type: \"camera\"\n" + " data: \"aspect_ratio: 1.0\\n" + "fov: 0.7854\\n" + "near_z: 0.1\\n" + "far_z: 10.0\\n" + "auto_aspect_ratio: 1\\n" + "\"\n" + "}\n" + "" + position { + y: 0.3 + } +} +embedded_instances { + id: "scene" + children: "ground" + children: "trees" + children: "wall" + children: "wall1" + children: "wall2" + children: "wall3" + data: "" +} +embedded_instances { + id: "ground" + data: "components {\n" + " id: \"plane\"\n" + " component: \"/example/assets/models/plane.model\"\n" + " rotation {\n" + " x: -0.70710677\n" + " w: 0.70710677\n" + " }\n" + "}\n" + "" + scale3 { + x: 5.0 + z: 5.0 + } +} +embedded_instances { + id: "trees" + data: "components {\n" + " id: \"tree\"\n" + " component: \"/example/assets/models/tree_1_B.model\"\n" + " position {\n" + " x: 43.333332\n" + " z: -26.666668\n" + " }\n" + "}\n" + "components {\n" + " id: \"tree1\"\n" + " component: \"/example/assets/models/tree_2_E.model\"\n" + " position {\n" + " x: 6.666666\n" + " z: 10.0\n" + " }\n" + "}\n" + "components {\n" + " id: \"tree2\"\n" + " component: \"/example/assets/models/tree_3_A.model\"\n" + " position {\n" + " x: 54.0\n" + " z: 10.0\n" + " }\n" + "}\n" + "components {\n" + " id: \"tree3\"\n" + " component: \"/example/assets/models/tree_1_B.model\"\n" + " position {\n" + " x: 13.333333\n" + " z: 19.999998\n" + " }\n" + "}\n" + "components {\n" + " id: \"tree4\"\n" + " component: \"/example/assets/models/tree_2_D.model\"\n" + " position {\n" + " x: 40.0\n" + " z: 22.0\n" + " }\n" + "}\n" + "components {\n" + " id: \"tree6\"\n" + " component: \"/example/assets/models/tree_2_E.model\"\n" + " position {\n" + " x: 35.0\n" + " z: -25.0\n" + " }\n" + "}\n" + "components {\n" + " id: \"tree7\"\n" + " component: \"/example/assets/models/tree_2_D.model\"\n" + " position {\n" + " x: 60.0\n" + " z: -18.0\n" + " }\n" + "}\n" + "components {\n" + " id: \"tree8\"\n" + " component: \"/example/assets/models/tree_2_E.model\"\n" + " position {\n" + " x: 60.0\n" + " }\n" + "}\n" + "components {\n" + " id: \"tree9\"\n" + " component: \"/example/assets/models/tree_2_D.model\"\n" + " position {\n" + " x: 14.0\n" + " z: -12.0\n" + " }\n" + "}\n" + "components {\n" + " id: \"tree10\"\n" + " component: \"/example/assets/models/tree_2_E.model\"\n" + " position {\n" + " x: 23.333332\n" + " z: 25.0\n" + " }\n" + "}\n" + "components {\n" + " id: \"tree11\"\n" + " component: \"/example/assets/models/tree_1_B.model\"\n" + " position {\n" + " x: 5.0\n" + " z: -10.0\n" + " }\n" + "}\n" + "components {\n" + " id: \"tree12\"\n" + " component: \"/example/assets/models/tree_2_D.model\"\n" + " position {\n" + " x: 5.0\n" + " z: 26.0\n" + " }\n" + " rotation {\n" + " y: 0.70710677\n" + " w: 0.70710677\n" + " }\n" + "}\n" + "components {\n" + " id: \"tree13\"\n" + " component: \"/example/assets/models/tree_2_D.model\"\n" + " position {\n" + " x: 26.0\n" + " z: -20.0\n" + " }\n" + " rotation {\n" + " y: 0.38268343\n" + " w: 0.9238795\n" + " }\n" + "}\n" + "components {\n" + " id: \"tree14\"\n" + " component: \"/example/assets/models/tree_2_E.model\"\n" + " position {\n" + " x: 15.000002\n" + " z: 3.333333\n" + " }\n" + " rotation {\n" + " y: 0.70710677\n" + " w: 0.70710677\n" + " }\n" + "}\n" + "components {\n" + " id: \"tree15\"\n" + " component: \"/example/assets/models/tree_3_A.model\"\n" + " position {\n" + " x: 45.0\n" + " z: -24.0\n" + " }\n" + " rotation {\n" + " y: 0.38268343\n" + " w: 0.9238795\n" + " }\n" + "}\n" + "components {\n" + " id: \"tree5\"\n" + " component: \"/example/assets/models/tree_2_D.model\"\n" + " position {\n" + " x: 54.0\n" + " z: 20.0\n" + " }\n" + " rotation {\n" + " y: 0.8660254\n" + " w: 0.5\n" + " }\n" + "}\n" + "" + position { + x: -5.0 + } + scale3 { + x: 0.15 + y: 0.15 + z: 0.15 + } +} +embedded_instances { + id: "wall2" + data: "components {\n" + " id: \"cube\"\n" + " component: \"/example/assets/models/cube_blue.model\"\n" + "}\n" + "components {\n" + " id: \"cube1\"\n" + " component: \"/example/assets/models/cube_white.model\"\n" + " position {\n" + " x: 1.0\n" + " }\n" + "}\n" + "components {\n" + " id: \"cube2\"\n" + " component: \"/example/assets/models/cube_white.model\"\n" + " position {\n" + " x: -1.0\n" + " }\n" + "}\n" + "components {\n" + " id: \"cube3\"\n" + " component: \"/example/assets/models/cube_orange.model\"\n" + " position {\n" + " x: 2.0\n" + " }\n" + "}\n" + "components {\n" + " id: \"cube4\"\n" + " component: \"/example/assets/models/cube_orange.model\"\n" + " position {\n" + " x: -2.0\n" + " }\n" + "}\n" + "components {\n" + " id: \"cube5\"\n" + " component: \"/example/assets/models/cube_white.model\"\n" + " position {\n" + " x: 3.0\n" + " }\n" + "}\n" + "components {\n" + " id: \"cube6\"\n" + " component: \"/example/assets/models/cube_white.model\"\n" + " position {\n" + " x: -3.0\n" + " }\n" + "}\n" + "components {\n" + " id: \"cube7\"\n" + " component: \"/example/assets/models/cube_blue.model\"\n" + " position {\n" + " x: 4.0\n" + " }\n" + "}\n" + "components {\n" + " id: \"cube8\"\n" + " component: \"/example/assets/models/cube_blue.model\"\n" + " position {\n" + " x: -4.0\n" + " }\n" + "}\n" + "components {\n" + " id: \"cube9\"\n" + " component: \"/example/assets/models/cube_white.model\"\n" + " position {\n" + " x: 5.0\n" + " }\n" + "}\n" + "components {\n" + " id: \"cube10\"\n" + " component: \"/example/assets/models/cube_white.model\"\n" + " position {\n" + " x: -5.0\n" + " }\n" + "}\n" + "" + position { + y: 0.125 + z: 1.5 + } + scale3 { + x: 0.25 + y: 0.25 + z: 0.25 + } +} +embedded_instances { + id: "gui" + data: "components {\n" + " id: \"example\"\n" + " component: \"/example/example.gui\"\n" + "}\n" + "" +} +embedded_instances { + id: "wall" + data: "components {\n" + " id: \"cube\"\n" + " component: \"/example/assets/models/cube_blue.model\"\n" + "}\n" + "components {\n" + " id: \"cube1\"\n" + " component: \"/example/assets/models/cube_white.model\"\n" + " position {\n" + " x: 1.0\n" + " }\n" + "}\n" + "components {\n" + " id: \"cube2\"\n" + " component: \"/example/assets/models/cube_white.model\"\n" + " position {\n" + " x: -1.0\n" + " }\n" + "}\n" + "components {\n" + " id: \"cube3\"\n" + " component: \"/example/assets/models/cube_orange.model\"\n" + " position {\n" + " x: 2.0\n" + " }\n" + "}\n" + "components {\n" + " id: \"cube4\"\n" + " component: \"/example/assets/models/cube_orange.model\"\n" + " position {\n" + " x: -2.0\n" + " }\n" + "}\n" + "components {\n" + " id: \"cube5\"\n" + " component: \"/example/assets/models/cube_white.model\"\n" + " position {\n" + " x: 3.0\n" + " }\n" + "}\n" + "components {\n" + " id: \"cube6\"\n" + " component: \"/example/assets/models/cube_white.model\"\n" + " position {\n" + " x: -3.0\n" + " }\n" + "}\n" + "components {\n" + " id: \"cube7\"\n" + " component: \"/example/assets/models/cube_blue.model\"\n" + " position {\n" + " x: 4.0\n" + " }\n" + "}\n" + "components {\n" + " id: \"cube8\"\n" + " component: \"/example/assets/models/cube_blue.model\"\n" + " position {\n" + " x: -4.0\n" + " }\n" + "}\n" + "components {\n" + " id: \"cube9\"\n" + " component: \"/example/assets/models/cube_white.model\"\n" + " position {\n" + " x: 5.0\n" + " }\n" + "}\n" + "components {\n" + " id: \"cube10\"\n" + " component: \"/example/assets/models/cube_white.model\"\n" + " position {\n" + " x: -5.0\n" + " }\n" + "}\n" + "components {\n" + " id: \"cube11\"\n" + " component: \"/example/assets/models/cube_white.model\"\n" + " position {\n" + " x: 6.0\n" + " }\n" + "}\n" + "components {\n" + " id: \"cube12\"\n" + " component: \"/example/assets/models/cube_white.model\"\n" + " position {\n" + " x: -6.0\n" + " }\n" + "}\n" + "" + position { + x: -1.5 + y: 0.125 + } + rotation { + y: 0.70710677 + w: 0.70710677 + } + scale3 { + x: 0.25 + y: 0.25 + z: 0.25 + } +} +embedded_instances { + id: "wall1" + data: "components {\n" + " id: \"cube\"\n" + " component: \"/example/assets/models/cube_blue.model\"\n" + "}\n" + "components {\n" + " id: \"cube1\"\n" + " component: \"/example/assets/models/cube_white.model\"\n" + " position {\n" + " x: 1.0\n" + " }\n" + "}\n" + "components {\n" + " id: \"cube2\"\n" + " component: \"/example/assets/models/cube_white.model\"\n" + " position {\n" + " x: -1.0\n" + " }\n" + "}\n" + "components {\n" + " id: \"cube3\"\n" + " component: \"/example/assets/models/cube_orange.model\"\n" + " position {\n" + " x: 2.0\n" + " }\n" + "}\n" + "components {\n" + " id: \"cube4\"\n" + " component: \"/example/assets/models/cube_orange.model\"\n" + " position {\n" + " x: -2.0\n" + " }\n" + "}\n" + "components {\n" + " id: \"cube5\"\n" + " component: \"/example/assets/models/cube_white.model\"\n" + " position {\n" + " x: 3.0\n" + " }\n" + "}\n" + "components {\n" + " id: \"cube6\"\n" + " component: \"/example/assets/models/cube_white.model\"\n" + " position {\n" + " x: -3.0\n" + " }\n" + "}\n" + "components {\n" + " id: \"cube7\"\n" + " component: \"/example/assets/models/cube_blue.model\"\n" + " position {\n" + " x: 4.0\n" + " }\n" + "}\n" + "components {\n" + " id: \"cube8\"\n" + " component: \"/example/assets/models/cube_blue.model\"\n" + " position {\n" + " x: -4.0\n" + " }\n" + "}\n" + "components {\n" + " id: \"cube9\"\n" + " component: \"/example/assets/models/cube_white.model\"\n" + " position {\n" + " x: 5.0\n" + " }\n" + "}\n" + "components {\n" + " id: \"cube10\"\n" + " component: \"/example/assets/models/cube_white.model\"\n" + " position {\n" + " x: -5.0\n" + " }\n" + "}\n" + "components {\n" + " id: \"cube11\"\n" + " component: \"/example/assets/models/cube_white.model\"\n" + " position {\n" + " x: 6.0\n" + " }\n" + "}\n" + "components {\n" + " id: \"cube12\"\n" + " component: \"/example/assets/models/cube_white.model\"\n" + " position {\n" + " x: -6.0\n" + " }\n" + "}\n" + "" + position { + x: 1.5 + y: 0.125 + } + rotation { + y: 0.70710677 + w: 0.70710677 + } + scale3 { + x: 0.25 + y: 0.25 + z: 0.25 + } +} +embedded_instances { + id: "wall3" + data: "components {\n" + " id: \"cube\"\n" + " component: \"/example/assets/models/cube_blue.model\"\n" + "}\n" + "components {\n" + " id: \"cube1\"\n" + " component: \"/example/assets/models/cube_white.model\"\n" + " position {\n" + " x: 1.0\n" + " }\n" + "}\n" + "components {\n" + " id: \"cube2\"\n" + " component: \"/example/assets/models/cube_white.model\"\n" + " position {\n" + " x: -1.0\n" + " }\n" + "}\n" + "components {\n" + " id: \"cube3\"\n" + " component: \"/example/assets/models/cube_orange.model\"\n" + " position {\n" + " x: 2.0\n" + " }\n" + "}\n" + "components {\n" + " id: \"cube4\"\n" + " component: \"/example/assets/models/cube_orange.model\"\n" + " position {\n" + " x: -2.0\n" + " }\n" + "}\n" + "components {\n" + " id: \"cube5\"\n" + " component: \"/example/assets/models/cube_white.model\"\n" + " position {\n" + " x: 3.0\n" + " }\n" + "}\n" + "components {\n" + " id: \"cube6\"\n" + " component: \"/example/assets/models/cube_white.model\"\n" + " position {\n" + " x: -3.0\n" + " }\n" + "}\n" + "components {\n" + " id: \"cube7\"\n" + " component: \"/example/assets/models/cube_blue.model\"\n" + " position {\n" + " x: 4.0\n" + " }\n" + "}\n" + "components {\n" + " id: \"cube8\"\n" + " component: \"/example/assets/models/cube_blue.model\"\n" + " position {\n" + " x: -4.0\n" + " }\n" + "}\n" + "components {\n" + " id: \"cube9\"\n" + " component: \"/example/assets/models/cube_white.model\"\n" + " position {\n" + " x: 5.0\n" + " }\n" + "}\n" + "components {\n" + " id: \"cube10\"\n" + " component: \"/example/assets/models/cube_white.model\"\n" + " position {\n" + " x: -5.0\n" + " }\n" + "}\n" + "" + position { + y: 0.125 + z: -1.5 + } + scale3 { + x: 0.25 + y: 0.25 + z: 0.25 + } +} diff --git a/movement/3d_fps/example/assets/default.font b/movement/3d_fps/example/assets/default.font new file mode 100644 index 0000000..59a60aa --- /dev/null +++ b/movement/3d_fps/example/assets/default.font @@ -0,0 +1,5 @@ +font: "/builtins/fonts/vera_mo_bd.ttf" +material: "/builtins/fonts/font-df.material" +size: 48 +output_format: TYPE_DISTANCE_FIELD +characters: " !\"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~" diff --git a/movement/3d_fps/example/assets/models/Tree_1_B_Color1.bin b/movement/3d_fps/example/assets/models/Tree_1_B_Color1.bin new file mode 100644 index 0000000..f86d850 Binary files /dev/null and b/movement/3d_fps/example/assets/models/Tree_1_B_Color1.bin differ diff --git a/movement/3d_fps/example/assets/models/Tree_1_B_Color1.gltf b/movement/3d_fps/example/assets/models/Tree_1_B_Color1.gltf new file mode 100644 index 0000000..8a258ad --- /dev/null +++ b/movement/3d_fps/example/assets/models/Tree_1_B_Color1.gltf @@ -0,0 +1,136 @@ +{ + "asset" : { + "generator" : "Khronos glTF Blender I/O v3.4.50", + "version" : "2.0" + }, + "scene" : 0, + "scenes" : [ + { + "name" : "Scene", + "nodes" : [ + 0 + ] + } + ], + "nodes" : [ + { + "mesh" : 0, + "name" : "Tree_1_B_Color1" + } + ], + "materials" : [ + { + "name" : "forest", + "pbrMetallicRoughness" : { + "baseColorTexture" : { + "index" : 0 + }, + "metallicFactor" : 0, + "roughnessFactor" : 0.6000000238418579 + } + } + ], + "meshes" : [ + { + "name" : "Tree_1_B_Color1", + "primitives" : [ + { + "attributes" : { + "POSITION" : 0, + "TEXCOORD_0" : 1, + "NORMAL" : 2 + }, + "indices" : 3, + "material" : 0 + } + ] + } + ], + "textures" : [ + { + "sampler" : 0, + "source" : 0 + } + ], + "images" : [ + { + "mimeType" : "image/png", + "name" : "forest_texture", + "uri" : "forest_texture.png" + } + ], + "accessors" : [ + { + "bufferView" : 0, + "componentType" : 5126, + "count" : 475, + "max" : [ + 2.217304229736328, + 4.588586807250977, + 1.722744107246399 + ], + "min" : [ + -1.7895218133926392, + -0.3410367965698242, + -1.7227431535720825 + ], + "type" : "VEC3" + }, + { + "bufferView" : 1, + "componentType" : 5126, + "count" : 475, + "type" : "VEC2" + }, + { + "bufferView" : 2, + "componentType" : 5126, + "count" : 475, + "type" : "VEC3" + }, + { + "bufferView" : 3, + "componentType" : 5123, + "count" : 1908, + "type" : "SCALAR" + } + ], + "bufferViews" : [ + { + "buffer" : 0, + "byteLength" : 5700, + "byteOffset" : 0, + "target" : 34962 + }, + { + "buffer" : 0, + "byteLength" : 3800, + "byteOffset" : 5700, + "target" : 34962 + }, + { + "buffer" : 0, + "byteLength" : 5700, + "byteOffset" : 9500, + "target" : 34962 + }, + { + "buffer" : 0, + "byteLength" : 3816, + "byteOffset" : 15200, + "target" : 34963 + } + ], + "samplers" : [ + { + "magFilter" : 9729, + "minFilter" : 9987 + } + ], + "buffers" : [ + { + "byteLength" : 19016, + "uri" : "Tree_1_B_Color1.bin" + } + ] +} diff --git a/movement/3d_fps/example/assets/models/Tree_2_D_Color1.bin b/movement/3d_fps/example/assets/models/Tree_2_D_Color1.bin new file mode 100644 index 0000000..104f060 Binary files /dev/null and b/movement/3d_fps/example/assets/models/Tree_2_D_Color1.bin differ diff --git a/movement/3d_fps/example/assets/models/Tree_2_D_Color1.gltf b/movement/3d_fps/example/assets/models/Tree_2_D_Color1.gltf new file mode 100644 index 0000000..5504123 --- /dev/null +++ b/movement/3d_fps/example/assets/models/Tree_2_D_Color1.gltf @@ -0,0 +1,136 @@ +{ + "asset" : { + "generator" : "Khronos glTF Blender I/O v3.4.50", + "version" : "2.0" + }, + "scene" : 0, + "scenes" : [ + { + "name" : "Scene", + "nodes" : [ + 0 + ] + } + ], + "nodes" : [ + { + "mesh" : 0, + "name" : "Tree_2_D_Color1" + } + ], + "materials" : [ + { + "name" : "forest", + "pbrMetallicRoughness" : { + "baseColorTexture" : { + "index" : 0 + }, + "metallicFactor" : 0, + "roughnessFactor" : 0.6000000238418579 + } + } + ], + "meshes" : [ + { + "name" : "Tree_2_D_Color1", + "primitives" : [ + { + "attributes" : { + "POSITION" : 0, + "TEXCOORD_0" : 1, + "NORMAL" : 2 + }, + "indices" : 3, + "material" : 0 + } + ] + } + ], + "textures" : [ + { + "sampler" : 0, + "source" : 0 + } + ], + "images" : [ + { + "mimeType" : "image/png", + "name" : "forest_texture", + "uri" : "forest_texture.png" + } + ], + "accessors" : [ + { + "bufferView" : 0, + "componentType" : 5126, + "count" : 761, + "max" : [ + 2.2887001037597656, + 7.694401264190674, + 1.6433088779449463 + ], + "min" : [ + -2.450906991958618, + -0.39324718713760376, + -2.391054391860962 + ], + "type" : "VEC3" + }, + { + "bufferView" : 1, + "componentType" : 5126, + "count" : 761, + "type" : "VEC2" + }, + { + "bufferView" : 2, + "componentType" : 5126, + "count" : 761, + "type" : "VEC3" + }, + { + "bufferView" : 3, + "componentType" : 5123, + "count" : 4284, + "type" : "SCALAR" + } + ], + "bufferViews" : [ + { + "buffer" : 0, + "byteLength" : 9132, + "byteOffset" : 0, + "target" : 34962 + }, + { + "buffer" : 0, + "byteLength" : 6088, + "byteOffset" : 9132, + "target" : 34962 + }, + { + "buffer" : 0, + "byteLength" : 9132, + "byteOffset" : 15220, + "target" : 34962 + }, + { + "buffer" : 0, + "byteLength" : 8568, + "byteOffset" : 24352, + "target" : 34963 + } + ], + "samplers" : [ + { + "magFilter" : 9729, + "minFilter" : 9987 + } + ], + "buffers" : [ + { + "byteLength" : 32920, + "uri" : "Tree_2_D_Color1.bin" + } + ] +} diff --git a/movement/3d_fps/example/assets/models/Tree_2_E_Color1.bin b/movement/3d_fps/example/assets/models/Tree_2_E_Color1.bin new file mode 100644 index 0000000..45daa2e Binary files /dev/null and b/movement/3d_fps/example/assets/models/Tree_2_E_Color1.bin differ diff --git a/movement/3d_fps/example/assets/models/Tree_2_E_Color1.gltf b/movement/3d_fps/example/assets/models/Tree_2_E_Color1.gltf new file mode 100644 index 0000000..ced796a --- /dev/null +++ b/movement/3d_fps/example/assets/models/Tree_2_E_Color1.gltf @@ -0,0 +1,136 @@ +{ + "asset" : { + "generator" : "Khronos glTF Blender I/O v3.4.50", + "version" : "2.0" + }, + "scene" : 0, + "scenes" : [ + { + "name" : "Scene", + "nodes" : [ + 0 + ] + } + ], + "nodes" : [ + { + "mesh" : 0, + "name" : "Tree_2_E_Color1" + } + ], + "materials" : [ + { + "name" : "forest", + "pbrMetallicRoughness" : { + "baseColorTexture" : { + "index" : 0 + }, + "metallicFactor" : 0, + "roughnessFactor" : 0.6000000238418579 + } + } + ], + "meshes" : [ + { + "name" : "Tree_2_E_Color1", + "primitives" : [ + { + "attributes" : { + "POSITION" : 0, + "TEXCOORD_0" : 1, + "NORMAL" : 2 + }, + "indices" : 3, + "material" : 0 + } + ] + } + ], + "textures" : [ + { + "sampler" : 0, + "source" : 0 + } + ], + "images" : [ + { + "mimeType" : "image/png", + "name" : "forest_texture", + "uri" : "forest_texture.png" + } + ], + "accessors" : [ + { + "bufferView" : 0, + "componentType" : 5126, + "count" : 833, + "max" : [ + 3.106861114501953, + 8.355417251586914, + 2.8980064392089844 + ], + "min" : [ + -2.944042682647705, + -0.43637216091156006, + -2.7789015769958496 + ], + "type" : "VEC3" + }, + { + "bufferView" : 1, + "componentType" : 5126, + "count" : 833, + "type" : "VEC2" + }, + { + "bufferView" : 2, + "componentType" : 5126, + "count" : 833, + "type" : "VEC3" + }, + { + "bufferView" : 3, + "componentType" : 5123, + "count" : 4680, + "type" : "SCALAR" + } + ], + "bufferViews" : [ + { + "buffer" : 0, + "byteLength" : 9996, + "byteOffset" : 0, + "target" : 34962 + }, + { + "buffer" : 0, + "byteLength" : 6664, + "byteOffset" : 9996, + "target" : 34962 + }, + { + "buffer" : 0, + "byteLength" : 9996, + "byteOffset" : 16660, + "target" : 34962 + }, + { + "buffer" : 0, + "byteLength" : 9360, + "byteOffset" : 26656, + "target" : 34963 + } + ], + "samplers" : [ + { + "magFilter" : 9729, + "minFilter" : 9987 + } + ], + "buffers" : [ + { + "byteLength" : 36016, + "uri" : "Tree_2_E_Color1.bin" + } + ] +} diff --git a/movement/3d_fps/example/assets/models/Tree_3_A_Color1.bin b/movement/3d_fps/example/assets/models/Tree_3_A_Color1.bin new file mode 100644 index 0000000..8c0b9e2 Binary files /dev/null and b/movement/3d_fps/example/assets/models/Tree_3_A_Color1.bin differ diff --git a/movement/3d_fps/example/assets/models/Tree_3_A_Color1.gltf b/movement/3d_fps/example/assets/models/Tree_3_A_Color1.gltf new file mode 100644 index 0000000..047955b --- /dev/null +++ b/movement/3d_fps/example/assets/models/Tree_3_A_Color1.gltf @@ -0,0 +1,136 @@ +{ + "asset" : { + "generator" : "Khronos glTF Blender I/O v3.4.50", + "version" : "2.0" + }, + "scene" : 0, + "scenes" : [ + { + "name" : "Scene", + "nodes" : [ + 0 + ] + } + ], + "nodes" : [ + { + "mesh" : 0, + "name" : "Tree_3_A_Color1" + } + ], + "materials" : [ + { + "name" : "forest", + "pbrMetallicRoughness" : { + "baseColorTexture" : { + "index" : 0 + }, + "metallicFactor" : 0, + "roughnessFactor" : 0.6000000238418579 + } + } + ], + "meshes" : [ + { + "name" : "Tree_3_A_Color1", + "primitives" : [ + { + "attributes" : { + "POSITION" : 0, + "TEXCOORD_0" : 1, + "NORMAL" : 2 + }, + "indices" : 3, + "material" : 0 + } + ] + } + ], + "textures" : [ + { + "sampler" : 0, + "source" : 0 + } + ], + "images" : [ + { + "mimeType" : "image/png", + "name" : "forest_texture", + "uri" : "forest_texture.png" + } + ], + "accessors" : [ + { + "bufferView" : 0, + "componentType" : 5126, + "count" : 746, + "max" : [ + 1.5410791635513306, + 3.245279550552368, + 1.5465989112854004 + ], + "min" : [ + -1.552119255065918, + -0.26131799817085266, + -1.5465991497039795 + ], + "type" : "VEC3" + }, + { + "bufferView" : 1, + "componentType" : 5126, + "count" : 746, + "type" : "VEC2" + }, + { + "bufferView" : 2, + "componentType" : 5126, + "count" : 746, + "type" : "VEC3" + }, + { + "bufferView" : 3, + "componentType" : 5123, + "count" : 2934, + "type" : "SCALAR" + } + ], + "bufferViews" : [ + { + "buffer" : 0, + "byteLength" : 8952, + "byteOffset" : 0, + "target" : 34962 + }, + { + "buffer" : 0, + "byteLength" : 5968, + "byteOffset" : 8952, + "target" : 34962 + }, + { + "buffer" : 0, + "byteLength" : 8952, + "byteOffset" : 14920, + "target" : 34962 + }, + { + "buffer" : 0, + "byteLength" : 5868, + "byteOffset" : 23872, + "target" : 34963 + } + ], + "samplers" : [ + { + "magFilter" : 9729, + "minFilter" : 9987 + } + ], + "buffers" : [ + { + "byteLength" : 29740, + "uri" : "Tree_3_A_Color1.bin" + } + ] +} diff --git a/movement/3d_fps/example/assets/models/cube_blue.model b/movement/3d_fps/example/assets/models/cube_blue.model new file mode 100644 index 0000000..c393251 --- /dev/null +++ b/movement/3d_fps/example/assets/models/cube_blue.model @@ -0,0 +1,10 @@ +mesh: "/builtins/assets/meshes/cube.dae" +name: "cube_white" +materials { + name: "default" + material: "/example/materials/model_instanced_cube.material" + textures { + sampler: "tex0" + texture: "/example/assets/textures/1024x1024_texture_blue.png" + } +} diff --git a/movement/3d_fps/example/assets/models/cube_orange.model b/movement/3d_fps/example/assets/models/cube_orange.model new file mode 100644 index 0000000..6e3f81a --- /dev/null +++ b/movement/3d_fps/example/assets/models/cube_orange.model @@ -0,0 +1,10 @@ +mesh: "/builtins/assets/meshes/cube.dae" +name: "cube_white" +materials { + name: "default" + material: "/example/materials/model_instanced_cube.material" + textures { + sampler: "tex0" + texture: "/example/assets/textures/1024x1024_texture_orange.png" + } +} diff --git a/movement/3d_fps/example/assets/models/cube_white.model b/movement/3d_fps/example/assets/models/cube_white.model new file mode 100644 index 0000000..062aafd --- /dev/null +++ b/movement/3d_fps/example/assets/models/cube_white.model @@ -0,0 +1,10 @@ +mesh: "/builtins/assets/meshes/cube.dae" +name: "cube_white" +materials { + name: "default" + material: "/example/materials/model_instanced_cube.material" + textures { + sampler: "tex0" + texture: "/example/assets/textures/1024x1024_texture_white.png" + } +} diff --git a/movement/3d_fps/example/assets/models/plane.model b/movement/3d_fps/example/assets/models/plane.model new file mode 100644 index 0000000..5a1babc --- /dev/null +++ b/movement/3d_fps/example/assets/models/plane.model @@ -0,0 +1,10 @@ +mesh: "/builtins/assets/meshes/quad_2x2.dae" +name: "plane" +materials { + name: "default" + material: "/example/materials/model_instanced_floor.material" + textures { + sampler: "tex0" + texture: "/example/assets/textures/1024x1024_texture_white.png" + } +} diff --git a/movement/3d_fps/example/assets/models/tree_1_B.model b/movement/3d_fps/example/assets/models/tree_1_B.model new file mode 100644 index 0000000..18ef9e5 --- /dev/null +++ b/movement/3d_fps/example/assets/models/tree_1_B.model @@ -0,0 +1,10 @@ +mesh: "/example/assets/models/Tree_1_B_Color1.gltf" +name: "rock_L" +materials { + name: "forest" + material: "/example/materials/model_lit.material" + textures { + sampler: "tex0" + texture: "/example/assets/textures/forest_texture.png" + } +} diff --git a/movement/3d_fps/example/assets/models/tree_2_D.model b/movement/3d_fps/example/assets/models/tree_2_D.model new file mode 100644 index 0000000..f5f252c --- /dev/null +++ b/movement/3d_fps/example/assets/models/tree_2_D.model @@ -0,0 +1,10 @@ +mesh: "/example/assets/models/Tree_2_D_Color1.gltf" +name: "rock_L" +materials { + name: "forest" + material: "/example/materials/model_lit.material" + textures { + sampler: "tex0" + texture: "/example/assets/textures/forest_texture.png" + } +} diff --git a/movement/3d_fps/example/assets/models/tree_2_E.model b/movement/3d_fps/example/assets/models/tree_2_E.model new file mode 100644 index 0000000..d7e9bf8 --- /dev/null +++ b/movement/3d_fps/example/assets/models/tree_2_E.model @@ -0,0 +1,10 @@ +mesh: "/example/assets/models/Tree_2_E_Color1.gltf" +name: "rock_L" +materials { + name: "forest" + material: "/example/materials/model_lit.material" + textures { + sampler: "tex0" + texture: "/example/assets/textures/forest_texture.png" + } +} diff --git a/movement/3d_fps/example/assets/models/tree_3_A.model b/movement/3d_fps/example/assets/models/tree_3_A.model new file mode 100644 index 0000000..2e300fc --- /dev/null +++ b/movement/3d_fps/example/assets/models/tree_3_A.model @@ -0,0 +1,10 @@ +mesh: "/example/assets/models/Tree_3_A_Color1.gltf" +name: "rock_L" +materials { + name: "forest" + material: "/example/materials/model_lit.material" + textures { + sampler: "tex0" + texture: "/example/assets/textures/forest_texture.png" + } +} diff --git a/movement/3d_fps/example/assets/textures/1024x1024_texture_blue.png b/movement/3d_fps/example/assets/textures/1024x1024_texture_blue.png new file mode 100644 index 0000000..92f39f3 Binary files /dev/null and b/movement/3d_fps/example/assets/textures/1024x1024_texture_blue.png differ diff --git a/movement/3d_fps/example/assets/textures/1024x1024_texture_orange.png b/movement/3d_fps/example/assets/textures/1024x1024_texture_orange.png new file mode 100644 index 0000000..3e9af54 Binary files /dev/null and b/movement/3d_fps/example/assets/textures/1024x1024_texture_orange.png differ diff --git a/movement/3d_fps/example/assets/textures/1024x1024_texture_white.png b/movement/3d_fps/example/assets/textures/1024x1024_texture_white.png new file mode 100644 index 0000000..f1e7af1 Binary files /dev/null and b/movement/3d_fps/example/assets/textures/1024x1024_texture_white.png differ diff --git a/movement/3d_fps/example/assets/textures/example.atlas b/movement/3d_fps/example/assets/textures/example.atlas new file mode 100644 index 0000000..4a5beb9 --- /dev/null +++ b/movement/3d_fps/example/assets/textures/example.atlas @@ -0,0 +1,4 @@ +images { + image: "/example/assets/textures/larger.png" +} +extrude_borders: 2 diff --git a/movement/3d_fps/example/assets/textures/forest_texture.png b/movement/3d_fps/example/assets/textures/forest_texture.png new file mode 100644 index 0000000..3674554 Binary files /dev/null and b/movement/3d_fps/example/assets/textures/forest_texture.png differ diff --git a/movement/3d_fps/example/assets/textures/larger.png b/movement/3d_fps/example/assets/textures/larger.png new file mode 100755 index 0000000..4f5d733 Binary files /dev/null and b/movement/3d_fps/example/assets/textures/larger.png differ diff --git a/movement/3d_fps/example/character_controller.script b/movement/3d_fps/example/character_controller.script new file mode 100644 index 0000000..14434cd --- /dev/null +++ b/movement/3d_fps/example/character_controller.script @@ -0,0 +1,129 @@ +-- First-person 3D camera controller + +-- Tuning parameters +local look_sensitivity = 0.15 -- degrees of camera rotation per 1 pixel of mouse movement +local move_speed = 0.5 -- world units per second for camera movement on XZ plane +local move_limit = 1.25 -- bounds (half-size) for camera movement on XZ to keep it in a square area + +function init(self) + -- Acquire input focus to receive input events from the engine + msg.post(".", "acquire_input_focus") + + -- Mouse lock state: when true, mouse deltas rotate the camera + self.mouse_locked = false + + -- Initialize yaw/pitch from current rotation (stored in degrees in Defold) + self.yaw = go.get(".", "euler.y") + self.pitch = go.get(".", "euler.x") + + -- Input state for continuous movement (WASD) + self.input = { + forward = false, + backward = false, + left = false, + right = false, + } +end + +function update(self, dt) + -- Clamp pitch to avoid flipping the camera upside down + if self.pitch > 89 then self.pitch = 89 end + if self.pitch < -89 then self.pitch = -89 end + + -- Apply rotation directly via Euler angles (in degrees) + go.set(".", "euler", vmath.vector3(self.pitch, self.yaw, 0)) + + -- Build desired movement direction on XZ plane from input flags + local x = (self.input.right and 1 or 0) - (self.input.left and 1 or 0) + local z = (self.input.backward and 1 or 0) - (self.input.forward and 1 or 0) + + -- If there is any movement input, move the camera + if x ~= 0 or z ~= 0 then + -- Local space direction (camera space) + local local_dir = vmath.vector3(x, 0, z) + local len = math.sqrt(local_dir.x * local_dir.x + local_dir.z * local_dir.z) + + if len > 0 then + -- Normalize to keep speed consistent diagonally + local_dir.x = local_dir.x / len + local_dir.z = local_dir.z / len + + -- Convert the yaw to a quaternion + local q_yaw = vmath.quat_rotation_y(math.rad(self.yaw)) + + -- Convert local movement to world space using current yaw + local world_dir = vmath.rotate(q_yaw, local_dir) + + -- Get the current position of the character + local pos = go.get_position() + + -- Integrate the position + pos.x = pos.x + world_dir.x * move_speed * dt + pos.z = pos.z + world_dir.z * move_speed * dt + + -- Clamp the position within the square bounds + if pos.x > move_limit then pos.x = move_limit end + if pos.x < -move_limit then pos.x = -move_limit end + if pos.z > move_limit then pos.z = move_limit end + if pos.z < -move_limit then pos.z = -move_limit end + + -- Set the new position + go.set_position(pos) + end + end +end + +-- Pre-hashed input action ids (must match project input bindings) +local KEY_W = hash("key_w") +local KEY_S = hash("key_s") +local KEY_A = hash("key_a") +local KEY_D = hash("key_d") +local KEY_ESC = hash("key_esc") +local TOUCH = hash("touch") +local MOUSE_BUTTON_1 = hash("mouse_button_1") + +function on_input(self, action_id, action) + -- Mouse look when locked: engine provides action.dx/dy even while cursor is locked + if self.mouse_locked and (action.dx or action.dy) then + -- Rotate the camera based on the mouse movement + self.yaw = self.yaw - (action.dx or 0) * look_sensitivity + self.pitch = self.pitch + (action.dy or 0) * look_sensitivity + end + + -- Lock on first click (touch or left mouse button) + if not self.mouse_locked and action.pressed + and (action_id == TOUCH or action_id == MOUSE_BUTTON_1) then + -- Lock the mouse + window.set_mouse_lock(true) + self.mouse_locked = true + end + + -- WSAD - Continuous movement input state (pressed/released) + if action_id == KEY_W then + -- Set the forward input flag to true if the W key is pressed + if action.pressed then self.input.forward = true end + if action.released then self.input.forward = false end + end + if action_id == KEY_S then + -- Set the backward input flag to true if the S key is pressed + if action.pressed then self.input.backward = true end + if action.released then self.input.backward = false end + end + if action_id == KEY_A then + -- Set the left input flag to true if the A key is pressed + if action.pressed then self.input.left = true end + if action.released then self.input.left = false end + end + if action_id == KEY_D then + -- Set the right input flag to true if the D key is pressed + if action.pressed then self.input.right = true end + if action.released then self.input.right = false end + end + + -- ESC unlocks the mouse so the cursor is free again + if action_id == KEY_ESC and action.pressed then + -- Unlock the mouse + window.set_mouse_lock(false) + self.mouse_locked = false + end +end diff --git a/movement/3d_fps/example/example.gui b/movement/3d_fps/example/example.gui new file mode 100644 index 0000000..e1c0ccb --- /dev/null +++ b/movement/3d_fps/example/example.gui @@ -0,0 +1,71 @@ +fonts { + name: "default" + font: "/example/assets/default.font" +} +textures { + name: "example" + texture: "/example/assets/textures/example.atlas" +} +nodes { + position { + x: 350.0 + y: 100.0 + } + size { + x: 600.0 + y: 100.0 + } + type: TYPE_BOX + id: "bg" + inherit_alpha: true + size_mode: SIZE_MODE_AUTO +} +nodes { + position { + x: 100.0 + y: 100.0 + } + scale { + x: 0.7 + y: 0.7 + } + color { + x: 0.2 + y: 0.302 + z: 0.702 + } + type: TYPE_BOX + texture: "example/larger" + id: "box" + inherit_alpha: true + size_mode: SIZE_MODE_AUTO +} +nodes { + position { + x: 150.0 + y: 100.0 + } + scale { + x: 0.4 + y: 0.4 + } + size { + x: 200.0 + y: 100.0 + } + color { + x: 0.2 + y: 0.302 + z: 0.702 + } + type: TYPE_TEXT + text: "Click to lock in mouse. ESC to unlock.\n" + "Then move mouse around to rotate camera.\n" + "Use WSAD keys to move around." + font: "default" + id: "text" + pivot: PIVOT_W + inherit_alpha: true +} +material: "/builtins/materials/gui.material" +adjust_reference: ADJUST_REFERENCE_PARENT diff --git a/movement/3d_fps/example/materials/model_instanced_cube.fp b/movement/3d_fps/example/materials/model_instanced_cube.fp new file mode 100644 index 0000000..ea92a2f --- /dev/null +++ b/movement/3d_fps/example/materials/model_instanced_cube.fp @@ -0,0 +1,31 @@ +#version 140 + +in highp vec4 var_position; +in mediump vec3 var_normal; +in mediump vec2 var_texcoord0; +in mediump vec4 var_light; + +out vec4 out_fragColor; + +uniform mediump sampler2D tex0; + +uniform fs_uniforms +{ + mediump vec4 tint; +}; + +void main() +{ + // Pre-multiply alpha since all runtime textures already are + vec4 tint_pm = vec4(tint.xyz * tint.w, tint.w); + vec4 color = texture(tex0, var_texcoord0.xy) * tint_pm; + + // Lighting + vec3 ambient_light = vec3(0.8); + vec3 L = normalize(var_light.xyz - var_position.xyz); + float diff = max(dot(var_normal, L), 0.0); + vec3 lighting = clamp(ambient_light + diff, 0.0, 1.0); + + out_fragColor = vec4(color.rgb * lighting, 1.0); +} + diff --git a/movement/3d_fps/example/materials/model_instanced_cube.material b/movement/3d_fps/example/materials/model_instanced_cube.material new file mode 100644 index 0000000..743d7a9 --- /dev/null +++ b/movement/3d_fps/example/materials/model_instanced_cube.material @@ -0,0 +1,47 @@ +name: "model_instanced" +tags: "model" +vertex_program: "/example/materials/model_instanced_floor.vp" +fragment_program: "/example/materials/model_instanced_floor.fp" +vertex_space: VERTEX_SPACE_LOCAL +vertex_constants { + name: "mtx_view" + type: CONSTANT_TYPE_VIEW +} +vertex_constants { + name: "mtx_proj" + type: CONSTANT_TYPE_PROJECTION +} +vertex_constants { + name: "light" + type: CONSTANT_TYPE_USER + value { + x: 10.0 + y: 10.0 + z: -10.0 + w: 1.0 + } +} +vertex_constants { + name: "zoom" + type: CONSTANT_TYPE_USER + value { + x: 0.5 + } +} +fragment_constants { + name: "tint" + type: CONSTANT_TYPE_USER + value { + x: 1.0 + y: 1.0 + z: 1.0 + w: 1.0 + } +} +samplers { + name: "tex0" + wrap_u: WRAP_MODE_REPEAT + wrap_v: WRAP_MODE_REPEAT + filter_min: FILTER_MODE_MIN_LINEAR + filter_mag: FILTER_MODE_MAG_LINEAR +} diff --git a/movement/3d_fps/example/materials/model_instanced_cube.vp b/movement/3d_fps/example/materials/model_instanced_cube.vp new file mode 100644 index 0000000..f3d3b7a --- /dev/null +++ b/movement/3d_fps/example/materials/model_instanced_cube.vp @@ -0,0 +1,40 @@ +#version 140 + +// Positions can be world or local space, since world and normal +// matrices are identity for world vertex space materials. +// If world vertex space is selected, you can remove the +// normal matrix multiplication for optimal performance. + +in highp vec4 position; +in mediump vec2 texcoord0; +in mediump vec3 normal; + +// When 'mtx_world' and 'mtx_normal' is specified as attributes, +// instanced rendering is automatically triggered. +// To read more about instancing in Defold, navigate to +// https://defold.com/manuals/material/#instancing +in mediump mat4 mtx_world; +in mediump mat4 mtx_normal; + +out highp vec4 var_position; +out mediump vec3 var_normal; +out mediump vec2 var_texcoord0; +out mediump vec4 var_light; + +uniform vs_uniforms +{ + mediump mat4 mtx_view; + mediump mat4 mtx_proj; + mediump vec4 light; + mediump vec4 zoom; +}; + +void main() +{ + vec4 p = mtx_view * mtx_world * vec4(position.xyz, 1.0); + var_light = mtx_view * vec4(light.xyz, 1.0); + var_position = p; + var_texcoord0 = texcoord0 * zoom.x; + var_normal = normalize((mtx_normal * vec4(normal, 0.0)).xyz); + gl_Position = mtx_proj * p; +} diff --git a/movement/3d_fps/example/materials/model_instanced_floor.fp b/movement/3d_fps/example/materials/model_instanced_floor.fp new file mode 100644 index 0000000..ea92a2f --- /dev/null +++ b/movement/3d_fps/example/materials/model_instanced_floor.fp @@ -0,0 +1,31 @@ +#version 140 + +in highp vec4 var_position; +in mediump vec3 var_normal; +in mediump vec2 var_texcoord0; +in mediump vec4 var_light; + +out vec4 out_fragColor; + +uniform mediump sampler2D tex0; + +uniform fs_uniforms +{ + mediump vec4 tint; +}; + +void main() +{ + // Pre-multiply alpha since all runtime textures already are + vec4 tint_pm = vec4(tint.xyz * tint.w, tint.w); + vec4 color = texture(tex0, var_texcoord0.xy) * tint_pm; + + // Lighting + vec3 ambient_light = vec3(0.8); + vec3 L = normalize(var_light.xyz - var_position.xyz); + float diff = max(dot(var_normal, L), 0.0); + vec3 lighting = clamp(ambient_light + diff, 0.0, 1.0); + + out_fragColor = vec4(color.rgb * lighting, 1.0); +} + diff --git a/movement/3d_fps/example/materials/model_instanced_floor.material b/movement/3d_fps/example/materials/model_instanced_floor.material new file mode 100644 index 0000000..0838163 --- /dev/null +++ b/movement/3d_fps/example/materials/model_instanced_floor.material @@ -0,0 +1,47 @@ +name: "model_instanced" +tags: "model" +vertex_program: "/example/materials/model_instanced_floor.vp" +fragment_program: "/example/materials/model_instanced_floor.fp" +vertex_space: VERTEX_SPACE_LOCAL +vertex_constants { + name: "mtx_view" + type: CONSTANT_TYPE_VIEW +} +vertex_constants { + name: "mtx_proj" + type: CONSTANT_TYPE_PROJECTION +} +vertex_constants { + name: "light" + type: CONSTANT_TYPE_USER + value { + x: 10.0 + y: 10.0 + z: -10.0 + w: 1.0 + } +} +vertex_constants { + name: "zoom" + type: CONSTANT_TYPE_USER + value { + x: 20.0 + } +} +fragment_constants { + name: "tint" + type: CONSTANT_TYPE_USER + value { + x: 1.0 + y: 1.0 + z: 1.0 + w: 1.0 + } +} +samplers { + name: "tex0" + wrap_u: WRAP_MODE_REPEAT + wrap_v: WRAP_MODE_REPEAT + filter_min: FILTER_MODE_MIN_LINEAR + filter_mag: FILTER_MODE_MAG_LINEAR +} diff --git a/movement/3d_fps/example/materials/model_instanced_floor.vp b/movement/3d_fps/example/materials/model_instanced_floor.vp new file mode 100644 index 0000000..f3d3b7a --- /dev/null +++ b/movement/3d_fps/example/materials/model_instanced_floor.vp @@ -0,0 +1,40 @@ +#version 140 + +// Positions can be world or local space, since world and normal +// matrices are identity for world vertex space materials. +// If world vertex space is selected, you can remove the +// normal matrix multiplication for optimal performance. + +in highp vec4 position; +in mediump vec2 texcoord0; +in mediump vec3 normal; + +// When 'mtx_world' and 'mtx_normal' is specified as attributes, +// instanced rendering is automatically triggered. +// To read more about instancing in Defold, navigate to +// https://defold.com/manuals/material/#instancing +in mediump mat4 mtx_world; +in mediump mat4 mtx_normal; + +out highp vec4 var_position; +out mediump vec3 var_normal; +out mediump vec2 var_texcoord0; +out mediump vec4 var_light; + +uniform vs_uniforms +{ + mediump mat4 mtx_view; + mediump mat4 mtx_proj; + mediump vec4 light; + mediump vec4 zoom; +}; + +void main() +{ + vec4 p = mtx_view * mtx_world * vec4(position.xyz, 1.0); + var_light = mtx_view * vec4(light.xyz, 1.0); + var_position = p; + var_texcoord0 = texcoord0 * zoom.x; + var_normal = normalize((mtx_normal * vec4(normal, 0.0)).xyz); + gl_Position = mtx_proj * p; +} diff --git a/movement/3d_fps/example/materials/model_lit.fp b/movement/3d_fps/example/materials/model_lit.fp new file mode 100644 index 0000000..98b81e1 --- /dev/null +++ b/movement/3d_fps/example/materials/model_lit.fp @@ -0,0 +1,31 @@ +#version 140 + +in highp vec4 var_position; +in mediump vec3 var_normal; +in mediump vec2 var_texcoord0; +in mediump vec4 var_light; + +out vec4 out_fragColor; + +uniform mediump sampler2D tex0; + +uniform fs_uniforms +{ + mediump vec4 tint; +}; + +void main() +{ + // Pre-multiply alpha since all runtime textures already are + vec4 tint_pm = vec4(tint.xyz * tint.w, tint.w); + vec4 color = texture(tex0, var_texcoord0.xy) * tint_pm; + + // Diffuse light calculations + vec3 ambient_light = vec3(0.8); + vec3 diff_light = vec3(normalize(var_light.xyz - var_position.xyz)); + diff_light = max(dot(var_normal,diff_light), 0.0) + ambient_light; + diff_light = clamp(diff_light, 0.0, 1.0); + + out_fragColor = vec4(color.rgb*diff_light,1.0); +} + diff --git a/movement/3d_fps/example/materials/model_lit.material b/movement/3d_fps/example/materials/model_lit.material new file mode 100644 index 0000000..18a4717 --- /dev/null +++ b/movement/3d_fps/example/materials/model_lit.material @@ -0,0 +1,40 @@ +name: "model" +tags: "model" +vertex_program: "/example/materials/model_lit.vp" +fragment_program: "/example/materials/model_lit.fp" +vertex_space: VERTEX_SPACE_LOCAL +vertex_constants { + name: "mtx_view" + type: CONSTANT_TYPE_VIEW +} +vertex_constants { + name: "mtx_proj" + type: CONSTANT_TYPE_PROJECTION +} +vertex_constants { + name: "light" + type: CONSTANT_TYPE_USER + value { + x: 10.0 + y: 10.0 + z: -10.0 + w: 1.0 + } +} +fragment_constants { + name: "tint" + type: CONSTANT_TYPE_USER + value { + x: 1.0 + y: 1.0 + z: 1.0 + w: 1.0 + } +} +samplers { + name: "tex0" + wrap_u: WRAP_MODE_CLAMP_TO_EDGE + wrap_v: WRAP_MODE_CLAMP_TO_EDGE + filter_min: FILTER_MODE_MIN_LINEAR + filter_mag: FILTER_MODE_MAG_LINEAR +} diff --git a/movement/3d_fps/example/materials/model_lit.vp b/movement/3d_fps/example/materials/model_lit.vp new file mode 100644 index 0000000..b722be6 --- /dev/null +++ b/movement/3d_fps/example/materials/model_lit.vp @@ -0,0 +1,39 @@ +#version 140 + +// Positions can be world or local space, since world and normal +// matrices are identity for world vertex space materials. +// If world vertex space is selected, you can remove the +// normal matrix multiplication for optimal performance. + +in highp vec4 position; +in mediump vec2 texcoord0; +in mediump vec3 normal; + +// When 'mtx_world' and 'mtx_normal' is specified as attributes, +// instanced rendering is automatically triggered. +// To read more about instancing in Defold, navigate to +// https://defold.com/manuals/material/#instancing +in mediump mat4 mtx_world; +in mediump mat4 mtx_normal; + +out highp vec4 var_position; +out mediump vec3 var_normal; +out mediump vec2 var_texcoord0; +out mediump vec4 var_light; + +uniform vs_uniforms +{ + mediump mat4 mtx_view; + mediump mat4 mtx_proj; + mediump vec4 light; +}; + +void main() +{ + vec4 p = mtx_view * mtx_world * vec4(position.xyz, 1.0); + var_light = mtx_view * vec4(light.xyz, 1.0); + var_position = p; + var_texcoord0 = texcoord0; + var_normal = normalize((mtx_normal * vec4(normal, 0.0)).xyz); + gl_Position = mtx_proj * p; +} diff --git a/movement/3d_fps/game.project b/movement/3d_fps/game.project new file mode 100644 index 0000000..adcf018 --- /dev/null +++ b/movement/3d_fps/game.project @@ -0,0 +1,68 @@ +[project] +title = 3D Basic Movement +version = 0.1 +dependencies = + +[bootstrap] +main_collection = /example/3d_fps.collectionc +render = /builtins/render/default.renderc + +[input] +game_binding = /builtins/input/all.input_bindingc +repeat_interval = 0.05 +use_accelerometer = 0 + +[display] +width = 720 +height = 720 +high_dpi = 1 + +[physics] +scale = 0.02 +gravity_y = -500.0 + +[script] +shared_state = 1 + +[collection_proxy] +max_count = 256 + +[label] +subpixels = 1 + +[sprite] +subpixels = 1 +max_count = 32765 + +[windows] +iap_provider = + +[android] +package = com.defold.examples + +[ios] +bundle_identifier = com.defold.examples + +[osx] +bundle_identifier = com.defold.examples + +[html5] +show_fullscreen_button = 0 +show_made_with_defold = 0 +scale_mode = no_scale +heap_size = 64 + +[graphics] +texture_profiles = /all.texture_profiles + +[collection] +max_instances = 32765 + +[particle_fx] +max_emitter_count = 1024 + +[render] +clear_color_blue = 1.0 +clear_color_green = 1.0 +clear_color_red = 1.0 + diff --git a/movement/3d_fps/thumbnail.png b/movement/3d_fps/thumbnail.png new file mode 100644 index 0000000..d4f7d21 Binary files /dev/null and b/movement/3d_fps/thumbnail.png differ