diff --git a/HERRY-M--HERRY-E/textures/nx.png b/HERRY-M--HERRY-E/textures/nx.png index 1a14c16a689202adbf22a191fc9b05b4ac7f510d..5f63333812b1b790e232da886afc0abd2080005b 100644 Binary files a/HERRY-M--HERRY-E/textures/nx.png and b/HERRY-M--HERRY-E/textures/nx.png differ diff --git a/HERRY-M--HERRY-E/textures/ny.png b/HERRY-M--HERRY-E/textures/ny.png index d77138e830e5d485af7fa83cf8cfe1360d733c68..5bf9c7b0a4e5896f33283861528f186dc0a62945 100644 Binary files a/HERRY-M--HERRY-E/textures/ny.png and b/HERRY-M--HERRY-E/textures/ny.png differ diff --git a/HERRY-M--HERRY-E/textures/nz.png b/HERRY-M--HERRY-E/textures/nz.png index 83d4752c18e0849d5a934199881c3a945aefba72..836e3b73fc50b9c5565004de2f94735433fa2512 100644 Binary files a/HERRY-M--HERRY-E/textures/nz.png and b/HERRY-M--HERRY-E/textures/nz.png differ diff --git a/HERRY-M--HERRY-E/textures/px.png b/HERRY-M--HERRY-E/textures/px.png index 4c2b4ce32be4981ef330c8d24569e5fc6817abb8..5ea16ed7e2087b45600b5b1b1eadaee4560a3a3d 100644 Binary files a/HERRY-M--HERRY-E/textures/px.png and b/HERRY-M--HERRY-E/textures/px.png differ diff --git a/HERRY-M--HERRY-E/textures/py.png b/HERRY-M--HERRY-E/textures/py.png index 3016164bf0bb12f57a65b5a3faf86d808468a341..628e2cfd6a167f77af65195344842e1e57432712 100644 Binary files a/HERRY-M--HERRY-E/textures/py.png and b/HERRY-M--HERRY-E/textures/py.png differ diff --git a/HERRY-M--HERRY-E/textures/pz.png b/HERRY-M--HERRY-E/textures/pz.png index a165fbdfd90a6ec902b3df192e8d47e7f2a8eba0..e88825fc005dda7d3420b1a618c1f588aa646d3c 100644 Binary files a/HERRY-M--HERRY-E/textures/pz.png and b/HERRY-M--HERRY-E/textures/pz.png differ diff --git a/NIRRENGARTEN/3Dmodel/Peanut Butter/peanutButter.mtl b/NIRRENGARTEN/3Dmodel/Peanut Butter/peanutButter.mtl new file mode 100644 index 0000000000000000000000000000000000000000..607d39ed60cb5b74dead9a18048a23cf748d3cee --- /dev/null +++ b/NIRRENGARTEN/3Dmodel/Peanut Butter/peanutButter.mtl @@ -0,0 +1,11 @@ +# Created by Kenney (www.kenney.nl) + +newmtl brownDark + Kd 0.60 0.22 0.11 + +newmtl brownLight + Kd 0.98 0.65 0.37 + +newmtl white + Kd 0.15 0.71 0.45 + diff --git a/NIRRENGARTEN/3Dmodel/Peanut Butter/peanutButter.obj b/NIRRENGARTEN/3Dmodel/Peanut Butter/peanutButter.obj new file mode 100644 index 0000000000000000000000000000000000000000..e340638ce97f87c3ab9a60ddd2d9b41c653f236b --- /dev/null +++ b/NIRRENGARTEN/3Dmodel/Peanut Butter/peanutButter.obj @@ -0,0 +1,382 @@ +# Created by Kenney (www.kenney.nl) + +mtllib peanutButter.mtl + +g peanutButter + +v 0.08019084 0.261 0.08019084 +v 1.082867E-15 0.261 0.113407 +v 0.08019084 0.2958 0.08019084 +v 1.082867E-15 0.2958 0.113407 +v 0.08019084 0.2958 -0.08019084 +v 0.08019084 0.261 -0.08019084 +v 0.113407 0.2958 0 +v 0.113407 0.261 0 +v -0.08019084 0.261 -0.08019084 +v 1.082867E-15 0.261 -0.113407 +v -0.08019084 0.2958 -0.08019084 +v 1.082867E-15 0.2958 -0.113407 +v -0.08019084 0.261 0.08019084 +v -0.08019084 0.2958 0.08019084 +v -0.113407 0.261 0 +v -0.113407 0.2958 0 +v 0.08444745 0.2784 7.219114E-16 +v 0.05971336 0.2784 0.05971336 +v 0.05971336 0.2784 -0.05971336 +v 1.443823E-15 0.2784 -0.08444745 +v 1.443823E-15 0.2784 0.08444745 +v -0.05971336 0.2784 -0.05971336 +v -0.05971336 0.2784 0.05971336 +v -0.08444745 0.2784 7.219114E-16 +v 1.082867E-15 0.2958 -0.09706604 +v -0.06863604 0.2958 -0.06863604 +v 1.082867E-15 0.2958 0.09706604 +v 0.06863604 0.2958 0.06863604 +v -0.09706604 0.2958 0 +v 0.09706604 0.2958 0 +v -0.06863604 0.2958 0.06863604 +v 0.06863604 0.2958 -0.06863604 +v -0.1002762 0.261 0 +v -0.07090598 0.261 0.07090598 +v -0.07090598 0.261 -0.07090598 +v 1.082867E-15 0.261 0.1002762 +v 0.07090598 0.261 0.07090598 +v 1.082867E-15 0.261 -0.1002762 +v 0.07090598 0.261 -0.07090598 +v 0.1002762 0.261 0 +v 0.117972 0.2262 0 +v 0.0834188 0.2262 0.0834188 +v 0.1002762 0.2436 0 +v 0.07090598 0.2436 0.07090598 +v -0.07090598 0.2436 -0.07090598 +v -0.1002762 0.2436 0 +v 7.219114E-16 0.2262 0.117972 +v 1.082867E-15 0.2436 0.1002762 +v 0.0834188 0.2262 -0.0834188 +v 0.07090598 0.2436 -0.07090598 +v 1.082867E-15 0.2436 -0.1002762 +v -0.07090598 0.2436 0.07090598 +v -0.0834188 0.2262 -0.0834188 +v -0.117972 0.2262 0 +v -0.0834188 0.2262 0.0834188 +v 7.219114E-16 0.2262 -0.117972 +v 0.0834188 0.202275 0.0834188 +v 7.219114E-16 0.202275 0.117972 +v 0.117972 0.0348 0 +v 0.1044 0 7.219114E-16 +v 0.0834188 0.0348 0.0834188 +v 0.07382195 0 0.07382195 +v -0.0834188 0.202275 0.0834188 +v -3.609557E-16 0 0.1044 +v -0.07382195 0 0.07382195 +v 7.219114E-16 0.0348 0.117972 +v -0.0834188 0.0348 0.0834188 +v -3.609557E-16 0 -0.1044 +v 0.07382195 0 -0.07382195 +v 7.219114E-16 0.0348 -0.117972 +v 0.0834188 0.0348 -0.0834188 +v -0.07382195 0 -0.07382195 +v -0.1044 0 7.219114E-16 +v 0.117972 0.058725 0 +v 0.0834188 0.058725 0.0834188 +v 7.219114E-16 0.058725 0.117972 +v -0.0834188 0.0348 -0.0834188 +v -0.0834188 0.058725 -0.0834188 +v 7.219114E-16 0.058725 -0.117972 +v -0.117972 0.0348 0 +v -0.117972 0.058725 0 +v -0.0834188 0.058725 0.0834188 +v 7.219114E-16 0.202275 -0.117972 +v 0.0834188 0.202275 -0.0834188 +v 0.117972 0.202275 0 +v 0.0834188 0.058725 -0.0834188 +v -0.0834188 0.202275 -0.0834188 +v -0.117972 0.202275 0 + +vn 0.7071068 0 0.7071068 +vn 0 0 1 +vn 0.7071068 0 -0.7071068 +vn 1 0 0 +vn -0.7071068 0 -0.7071068 +vn 0 0 -1 +vn -0.7071068 0 0.7071068 +vn -1 0 0 +vn 0 1 0 +vn 0 0.5870768 0.8095312 +vn 0.572425 0.5870768 0.572425 +vn 0 0.5870768 -0.8095312 +vn -0.572425 0.5870768 -0.572425 +vn 0.8095312 0.5870768 0 +vn -0.8095312 0.5870768 0 +vn 0.572425 0.5870768 -0.572425 +vn -0.572425 0.5870768 0.572425 +vn 0 -1 0 +vn 0.7011221 0.7130412 0 +vn 0.4957682 0.7130412 0.4957682 +vn 0 0.7130412 0.7011221 +vn 0.4957682 0.7130412 -0.4957682 +vn -0.4957682 0.7130412 -0.4957682 +vn -0.7011221 0.7130412 0 +vn -0.4957682 0.7130412 0.4957682 +vn 0 0.7130412 -0.7011221 +vn 0.9316545 -0.3633452 0 +vn 0.6587793 -0.3633452 0.6587793 +vn 0 -0.3633452 0.9316545 +vn -0.6587793 -0.3633452 0.6587793 +vn 0 -0.3633452 -0.9316545 +vn 0.6587793 -0.3633452 -0.6587793 +vn -0.6587793 -0.3633452 -0.6587793 +vn -0.9316545 -0.3633452 0 + +vt 1.708621 10.27559 +vt -1.708621 10.27559 +vt 1.708621 11.64567 +vt -1.708621 11.64567 +vt -3.324703 2.842171E-14 +vt -2.35092 2.35092 +vt -2.35092 -2.35092 +vt -5.684342E-14 -3.324703 +vt -5.684342E-14 3.324703 +vt 2.35092 -2.35092 +vt 2.35092 2.35092 +vt 3.324703 2.842171E-14 +vt 1.272309 10.81547 +vt -1.272309 10.81547 +vt 1.462424 11.64005 +vt -1.462424 11.64005 +vt -4.464842 0 +vt -3.15712 3.15712 +vt -3.947882 0 +vt -3.15712 -3.15712 +vt -2.791574 2.791574 +vt -2.791574 -2.791574 +vt 4.263256E-14 3.947882 +vt 4.263256E-14 4.464842 +vt 2.791574 2.791574 +vt 3.15712 3.15712 +vt 4.263256E-14 -4.464842 +vt 4.263256E-14 -3.947882 +vt 2.791574 -2.791574 +vt 3.15712 -3.15712 +vt 3.947882 0 +vt 4.464842 0 +vt 2.702207 -2.702207 +vt -4.263256E-14 -3.821497 +vt 3.821497 0 +vt -4.263256E-14 -4.464842 +vt -2.702207 -2.702207 +vt 2.702207 2.702207 +vt -3.821497 0 +vt -2.702207 2.702207 +vt -4.263256E-14 4.464842 +vt -4.263256E-14 3.821497 +vt 1.777399 3.55187 +vt -1.777399 3.55187 +vt 1.510789 4.491853 +vt -1.510789 4.491853 +vt -1.510789 9.590551 +vt -1.510789 10.27559 +vt 1.510789 9.590551 +vt 1.510789 10.27559 +vt 1.777399 7.963583 +vt -1.777399 7.963583 +vt 1.777399 8.905512 +vt -1.777399 8.905512 +vt 1.777399 2.743532 +vt 1.572919 1.287231 +vt -1.777399 2.743532 +vt -1.572919 1.287231 +vt 4.110236 2.842171E-14 +vt 2.906376 -2.906376 +vt 2.906376 2.906376 +vt -1.421085E-14 4.110236 +vt -1.421085E-14 -4.110236 +vt -2.906376 2.906376 +vt -2.906376 -2.906376 +vt -4.110236 2.842171E-14 +vt 1.777399 2.312008 +vt 1.777399 1.370079 +vt -1.777399 2.312008 +vt -1.777399 1.370079 + +usemtl brownDark + +f 3/3/1 2/2/2 1/1/1 +f 2/2/2 3/3/1 4/4/2 +f 7/4/4 6/1/3 5/3/3 +f 6/1/3 7/4/4 8/2/4 +f 11/3/5 10/2/6 9/1/5 +f 10/2/6 11/3/5 12/4/6 +f 4/3/2 13/2/7 2/1/2 +f 13/2/7 4/3/2 14/4/7 +f 12/3/6 6/2/3 10/1/6 +f 6/2/3 12/3/6 5/4/3 +f 3/4/1 8/1/4 7/3/4 +f 8/1/4 3/4/1 1/2/1 +f 15/1/8 11/4/5 9/2/5 +f 11/4/5 15/1/8 16/3/8 +f 19/7/9 18/6/9 17/5/9 +f 18/6/9 19/7/9 20/8/9 +f 18/6/9 20/8/9 21/9/9 +f 21/9/9 20/8/9 22/10/9 +f 21/9/9 22/10/9 23/11/9 +f 23/11/9 22/10/9 24/12/9 +f 25/15/10 22/14/11 20/13/10 +f 22/14/11 25/15/10 26/16/11 +f 27/15/12 18/14/13 21/13/12 +f 18/14/13 27/15/12 28/16/13 +f 29/16/14 22/13/11 26/15/11 +f 22/13/11 29/16/14 24/14/14 +f 17/14/15 28/15/13 30/16/15 +f 28/15/13 17/14/15 18/13/13 +f 31/16/16 24/13/14 29/15/14 +f 24/13/14 31/16/16 23/14/16 +f 32/15/17 20/14/10 19/13/17 +f 20/14/10 32/15/17 25/16/10 +f 13/1/7 16/4/8 15/2/8 +f 16/4/8 13/1/7 14/3/7 +f 19/14/17 30/15/15 32/16/17 +f 30/15/15 19/14/17 17/13/15 +f 31/15/16 21/14/12 23/13/16 +f 21/14/12 31/15/16 27/16/12 +f 33/19/18 13/18/18 15/17/18 +f 9/20/18 33/19/18 15/17/18 +f 34/21/18 13/18/18 33/19/18 +f 9/20/18 35/22/18 33/19/18 +f 36/23/18 13/18/18 34/21/18 +f 36/23/18 2/24/18 13/18/18 +f 37/25/18 2/24/18 36/23/18 +f 37/25/18 1/26/18 2/24/18 +f 10/27/18 35/22/18 9/20/18 +f 10/27/18 38/28/18 35/22/18 +f 10/27/18 39/29/18 38/28/18 +f 6/30/18 39/29/18 10/27/18 +f 40/31/18 1/26/18 37/25/18 +f 6/30/18 40/31/18 39/29/18 +f 1/26/18 40/31/18 8/32/18 +f 40/31/18 6/30/18 8/32/18 +f 25/34/9 11/30/9 26/33/9 +f 26/33/9 11/30/9 29/35/9 +f 25/34/9 12/36/9 11/30/9 +f 29/35/9 11/30/9 16/32/9 +f 32/37/9 12/36/9 25/34/9 +f 14/26/9 29/35/9 16/32/9 +f 32/37/9 5/20/9 12/36/9 +f 14/26/9 31/38/9 29/35/9 +f 30/39/9 5/20/9 32/37/9 +f 5/20/9 30/39/9 7/17/9 +f 30/39/9 3/18/9 7/17/9 +f 3/18/9 30/39/9 28/40/9 +f 4/41/9 31/38/9 14/26/9 +f 3/18/9 28/40/9 4/41/9 +f 4/41/9 27/42/9 31/38/9 +f 4/41/9 28/40/9 27/42/9 + +usemtl brownLight + +f 43/45/19 42/44/20 41/43/19 +f 42/44/20 43/45/19 44/46/20 +f 46/49/8 35/48/5 45/47/5 +f 35/48/5 46/49/8 33/50/8 +f 44/45/20 47/44/21 42/43/20 +f 47/44/21 44/45/20 48/46/21 +f 49/43/22 43/46/19 41/44/19 +f 43/46/19 49/43/22 50/45/22 +f 38/50/6 50/47/3 51/49/6 +f 50/47/3 38/50/6 39/48/3 +f 52/49/7 33/48/8 46/47/8 +f 33/48/8 52/49/7 34/50/7 +f 53/44/23 46/45/24 45/46/23 +f 46/45/24 53/44/23 54/43/24 +f 37/48/1 43/49/4 40/50/4 +f 43/49/4 37/48/1 44/47/1 +f 35/50/5 51/47/6 45/49/5 +f 51/47/6 35/50/5 38/48/6 +f 36/50/2 52/47/7 48/49/2 +f 52/47/7 36/50/2 34/48/7 +f 52/46/25 47/43/21 48/45/21 +f 47/43/21 52/46/25 55/44/25 +f 40/48/4 50/49/3 39/50/3 +f 50/49/3 40/48/4 43/47/4 +f 37/50/1 48/47/2 44/49/1 +f 48/47/2 37/50/1 36/48/2 +f 46/46/24 55/43/25 52/45/25 +f 55/43/25 46/46/24 54/44/24 +f 56/43/26 50/46/22 49/44/22 +f 50/46/22 56/43/26 51/45/26 +f 56/44/26 45/45/23 51/46/26 +f 45/45/23 56/44/26 53/43/23 +f 42/53/1 58/52/2 57/51/1 +f 58/52/2 42/53/1 47/54/2 +f 61/57/28 60/56/27 59/55/27 +f 60/56/27 61/57/28 62/58/28 +f 47/53/2 63/52/7 58/51/2 +f 63/52/7 47/53/2 55/54/7 +f 66/55/29 65/58/30 64/56/29 +f 65/58/30 66/55/29 67/57/30 +f 70/55/31 69/58/32 68/56/31 +f 69/58/32 70/55/31 71/57/32 +f 62/61/18 69/60/18 60/59/18 +f 69/60/18 62/61/18 64/62/18 +f 69/60/18 64/62/18 68/63/18 +f 68/63/18 64/62/18 65/64/18 +f 68/63/18 65/64/18 72/65/18 +f 72/65/18 65/64/18 73/66/18 +f 75/69/1 59/68/4 74/67/4 +f 59/68/4 75/69/1 61/70/1 +f 75/67/1 66/70/2 61/68/1 +f 66/70/2 75/67/1 76/69/2 +f 78/67/5 70/70/6 77/68/5 +f 70/70/6 78/67/5 79/69/6 +f 67/68/7 81/69/8 80/70/8 +f 81/69/8 67/68/7 82/67/7 +f 56/53/6 84/52/3 83/51/6 +f 84/52/3 56/53/6 49/54/3 +f 41/54/4 84/51/3 49/53/3 +f 84/51/3 41/54/4 85/52/4 +f 74/69/4 71/68/3 86/67/3 +f 71/68/3 74/69/4 59/70/4 +f 79/67/6 71/70/3 70/68/6 +f 71/70/3 79/67/6 86/69/3 +f 77/55/33 68/58/31 72/56/33 +f 68/58/31 77/55/33 70/57/31 +f 88/51/8 53/54/5 87/52/5 +f 53/54/5 88/51/8 54/53/8 +f 61/55/28 64/58/29 62/56/28 +f 64/58/29 61/55/28 66/57/29 +f 59/57/27 69/56/32 71/55/32 +f 69/56/32 59/57/27 60/58/27 +f 73/58/34 67/55/30 80/57/34 +f 67/55/30 73/58/34 65/56/30 +f 80/68/8 78/69/5 77/70/5 +f 78/69/5 80/68/8 81/67/8 +f 76/67/2 67/70/7 66/68/2 +f 67/70/7 76/67/2 82/69/7 +f 42/54/1 85/51/4 41/53/4 +f 85/51/4 42/54/1 57/52/1 +f 53/53/5 83/52/6 87/51/5 +f 83/52/6 53/53/5 56/54/6 +f 63/51/7 54/54/8 88/52/8 +f 54/54/8 63/51/7 55/53/7 +f 72/58/33 80/55/34 77/57/33 +f 80/55/34 72/58/33 73/56/34 + +usemtl green + +f 57/52/1 74/67/4 85/51/4 +f 74/67/4 57/52/1 75/69/1 +f 83/51/6 86/69/3 79/67/6 +f 86/69/3 83/51/6 84/52/3 +f 58/51/2 82/69/7 76/67/2 +f 82/69/7 58/51/2 63/52/7 +f 85/52/4 86/67/3 84/51/3 +f 86/67/3 85/52/4 74/69/4 +f 87/51/5 79/69/6 78/67/5 +f 79/69/6 87/51/5 83/52/6 +f 82/67/7 88/52/8 81/69/8 +f 88/52/8 82/67/7 63/51/7 +f 81/67/8 87/52/5 78/69/5 +f 87/52/5 81/67/8 88/51/8 +f 57/51/1 76/69/2 75/67/1 +f 76/69/2 57/51/1 58/52/2 + diff --git a/NIRRENGARTEN/checklistProjet.md b/NIRRENGARTEN/checklistProjet.md new file mode 100644 index 0000000000000000000000000000000000000000..224626ee4df5e3f7b6d8328f3f960822b85a46bb --- /dev/null +++ b/NIRRENGARTEN/checklistProjet.md @@ -0,0 +1,20 @@ +- [x] Esthetisme +- [x] Mise en page de la page web +- [ ] Paragraphe(s) d'explications techniques +- [x] Légèreté du dossier (<2Mo) (pour l'instant + que push ce qui necesaire) +- [x] Géométrie +- [x] Couleur +- [x] Transparence +- [x] Eclairage +- [x] Ombres +- [x] Position de la caméra +- [ ] Brouillard +- [x] Effet miroir +- [x] Texture classique +- [x] Texture avec transparence +- [x] Sprites +- [x] Environment map +- [x] Skybox +- [x] Animations +- [x] normal maps +- [x] Interaction par GUI diff --git a/NIRRENGARTEN/crow.js b/NIRRENGARTEN/crow.js new file mode 100644 index 0000000000000000000000000000000000000000..0ad0233eaf56899977bee87ee72434f44fa96a99 --- /dev/null +++ b/NIRRENGARTEN/crow.js @@ -0,0 +1,60 @@ +import * as THREE from 'three'; + +/** Adds crows to the scene */ +export class Crow { + static async addCrows(scene, count = 100) { + const shape = new THREE.Shape(); + shape.moveTo(0, 0); + shape.lineTo(-1, 2); + shape.lineTo(0, 1.5); + shape.lineTo(1, 2); + shape.lineTo(0, 0); + + const extrudeSettings = { + depth: 0.2, + bevelEnabled: false + }; + + // body of the crow + const crowGeometry = new THREE.ExtrudeGeometry(shape, extrudeSettings); + const crowMaterial = new THREE.MeshLambertMaterial({ color: 0x000000 }); + + // wing of the crow + const wingGeometry = new THREE.BoxGeometry(1.0, 0.5, 0.1); + const wingMaterial = new THREE.MeshLambertMaterial({ color: 0x000000 }); + + for (let i = 0; i < count; i++) { + const crow = new THREE.Mesh(crowGeometry, crowMaterial); + + // Enable shadows for crow body + crow.castShadow = true; + crow.receiveShadow = true; + + //setup both wings for the crow + const leftWing = new THREE.Mesh(wingGeometry, wingMaterial); + leftWing.position.set(-0.9, 1.8, 0); + leftWing.rotation.z = 0.4; + // Enable shadows for wings + leftWing.castShadow = true; + leftWing.receiveShadow = true; + crow.add(leftWing); + + const rightWing = new THREE.Mesh(wingGeometry, wingMaterial); + rightWing.position.set(0.9, 1.8, 0); + rightWing.rotation.z = -0.4; + // Enable shadows for wings + rightWing.castShadow = true; + rightWing.receiveShadow = true; + crow.add(rightWing); + + // Random position in the sky + crow.position.set( + (Math.random() - Math.random()) * 500, + Math.random() * 200, + (Math.random() - Math.random()) * 500 + ); + + scene.add(crow); + } + } +} \ No newline at end of file diff --git a/NIRRENGARTEN/img.jpg b/NIRRENGARTEN/img.jpg index d642e136257de4fb317a18f7c422126216665b16..a140327d761eff04d1528b226af07f70b677d278 100644 Binary files a/NIRRENGARTEN/img.jpg and b/NIRRENGARTEN/img.jpg differ diff --git a/NIRRENGARTEN/img/height.jpg b/NIRRENGARTEN/img/height.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a023a9230274b39cfaf176e7ace38396a33e4b87 Binary files /dev/null and b/NIRRENGARTEN/img/height.jpg differ diff --git a/NIRRENGARTEN/img/normal.png b/NIRRENGARTEN/img/normal.png new file mode 100644 index 0000000000000000000000000000000000000000..122aa5aff41b1967d7abf02b0f1bc736ad334394 Binary files /dev/null and b/NIRRENGARTEN/img/normal.png differ diff --git a/NIRRENGARTEN/img/skybox/day_nx.png b/NIRRENGARTEN/img/skybox/day_nx.png new file mode 100644 index 0000000000000000000000000000000000000000..73887d913ac77b48be483204d570abc1a4ae4eb1 Binary files /dev/null and b/NIRRENGARTEN/img/skybox/day_nx.png differ diff --git a/NIRRENGARTEN/img/skybox/day_ny.png b/NIRRENGARTEN/img/skybox/day_ny.png new file mode 100644 index 0000000000000000000000000000000000000000..f84f3cd8f1728052c400dba6390d61105aa4eeaa Binary files /dev/null and b/NIRRENGARTEN/img/skybox/day_ny.png differ diff --git a/NIRRENGARTEN/img/skybox/day_nz.png b/NIRRENGARTEN/img/skybox/day_nz.png new file mode 100644 index 0000000000000000000000000000000000000000..821f070efbc6789b24ca5a162def7464a7754174 Binary files /dev/null and b/NIRRENGARTEN/img/skybox/day_nz.png differ diff --git a/NIRRENGARTEN/img/skybox/day_px.png b/NIRRENGARTEN/img/skybox/day_px.png new file mode 100644 index 0000000000000000000000000000000000000000..0f29b4aad053b804fc8b8ff56198b21b3c058831 Binary files /dev/null and b/NIRRENGARTEN/img/skybox/day_px.png differ diff --git a/NIRRENGARTEN/img/skybox/day_py.png b/NIRRENGARTEN/img/skybox/day_py.png new file mode 100644 index 0000000000000000000000000000000000000000..774afeb3e011ea7f0d8baa8e5f4f1b6873321d48 Binary files /dev/null and b/NIRRENGARTEN/img/skybox/day_py.png differ diff --git a/NIRRENGARTEN/img/skybox/day_pz.png b/NIRRENGARTEN/img/skybox/day_pz.png new file mode 100644 index 0000000000000000000000000000000000000000..b3a0a3d1b1ff7c860b9e6dd5918cc27ddb3f111e Binary files /dev/null and b/NIRRENGARTEN/img/skybox/day_pz.png differ diff --git a/NIRRENGARTEN/index.html b/NIRRENGARTEN/index.html index 76e27dc119783f47da855d49712c43bab0798e9a..f5c42e9024ed583059106759e8d3b94a1b708885 100644 --- a/NIRRENGARTEN/index.html +++ b/NIRRENGARTEN/index.html @@ -1 +1,44 @@ -Le travail n'a pas encore commencé!!! \ No newline at end of file +<!DOCTYPE html> +<html> + +<head> + <meta charset="UTF-8"> + <title>Champs de blé aux corbeaux</title> + <link rel="stylesheet" href="style.css"> +</head> + +<body> + <!-- API importe du site de Three.js --> + <script async src="https://unpkg.com/es-module-shims@1.3.6/dist/es-module-shims.js"></script> + <script type="importmap"> + { + "imports": + { + "three": "https://threejs.org/build/three.module.js", + "three/addons/": "https://threejs.org/examples/jsm/" + } + } +</script> + <!-- JQuery pour afficher les erreurs --> + <script type="text/javascript" src="https://code.jquery.com/jquery-3.5.1.min.js"></script> + <!-- Un titre centre --> + <h1 class="centre">Champs de blé aux corbeau (WIP)</h1> +<div class="render"> + <img class="background" src="img/Champs2BleOcorbeaux.jpg"> + <div id="webGL" class="centre"></div> + <!-- Mon script avec un chemin relatif --> + <script type="module" src="paint.js"></script> + </div> + + <div class="divider"></div> + + <div class="tableau"> + <img class="tableau-img" src="img/Champs2BleOcorbeaux.jpg" alt="tableau du champs"> + <div class="tableau-presentation"> + <p>Super stylé le tableau</p> + </div> + </div> + +</body> + +</html> \ No newline at end of file diff --git a/NIRRENGARTEN/new_wheat.js b/NIRRENGARTEN/new_wheat.js new file mode 100644 index 0000000000000000000000000000000000000000..47cfd11d78adb0af64de8b99623f358db30c49b9 --- /dev/null +++ b/NIRRENGARTEN/new_wheat.js @@ -0,0 +1,348 @@ +import * as THREE from "three"; + +class NewWheat { + // Create a wheat field with instanced meshes + static createDynamicWheatField(scene, camera, options = {}, isInRiver) { + // Default options + const config = { + chunkSize: 20, // Size of each terrain chunk + renderDistance: 3, // How many chunks to render in each direction + density: 0.3, // Plants per square unit + variations: 3, // Number of different wheat stalk models + windIntensity: 0.2, + windFrequency: 0.4, + ...options, + }; + + // Create container for all wheat-related objects + const fieldContainer = new THREE.Group(); + scene.add(fieldContainer); + + // Create ground plane with larger size to match render distance + // const groundSize = config.chunkSize * (config.renderDistance * 2 + 1); + // const groundGeometry = new THREE.PlaneGeometry(groundSize, groundSize); + // const groundMaterial = new THREE.MeshStandardMaterial({ + // color: 0x7c6b4c, + // roughness: 0.8, + // metalness: 0.1, + // }); + // const ground = new THREE.Mesh(groundGeometry, groundMaterial); + // ground.rotation.x = -Math.PI / 2; // Rotate to be horizontal + // ground.receiveShadow = true; + // fieldContainer.add(ground); + + // Create wheat stalk geometries (several variations) + const wheatGeometries = []; + for (let i = 0; i < config.variations; i++) { + wheatGeometries.push(NewWheat.createWheatStalkGeometry(i)); + } + + // Set up instanced meshes for wheat variations + const stalksPerChunk = Math.floor( + config.chunkSize * config.chunkSize * config.density, + ); + const totalChunks = Math.pow(config.renderDistance * 2 + 1, 2); + const totalStalks = stalksPerChunk * totalChunks; + const stalksPerVariation = Math.ceil(totalStalks / config.variations); + + const wheatMaterial = new THREE.MeshStandardMaterial({ + color: 0xdfd087, + roughness: 0.7, + metalness: 0.1, + }); + + const wheatInstances = []; + + // Create instanced meshes for each geometry variation + wheatGeometries.forEach((geometry, index) => { + const instancedMesh = new THREE.InstancedMesh( + geometry, + wheatMaterial, + stalksPerVariation, + ); + instancedMesh.castShadow = true; + + fieldContainer.add(instancedMesh); + wheatInstances.push(instancedMesh); + }); + + // Map to track which chunks have been generated + const generatedChunks = new Map(); + + // Helper to get chunk coordinates from world position + const getChunkCoords = (x, z) => { + const chunkX = Math.floor(x / config.chunkSize); + const chunkZ = Math.floor(z / config.chunkSize); + return { chunkX, chunkZ }; + }; + + // Generate a chunk of wheat at the specified chunk coordinates + const generateChunk = (chunkX, chunkZ) => { + const chunkKey = `${chunkX},${chunkZ}`; + + // Skip if chunk already exists + if (generatedChunks.has(chunkKey)) return; + + const dummy = new THREE.Object3D(); + const chunkInstances = []; + + // Calculate world space boundaries of this chunk + const startX = chunkX * config.chunkSize; + const startZ = chunkZ * config.chunkSize; + const endX = startX + config.chunkSize; + const endZ = startZ + config.chunkSize; + if (isInRiver(startX, startZ) || isInRiver(endX, endZ)) { + return; + } + + // Fill chunk with wheat stalks + let localIndex = 0; + + for (let x = startX; x < endX; x += 1 / config.density) { + for (let z = startZ; z < endZ; z += 1 / config.density) { + // Add some randomness to position + const posX = x + (Math.random() - 0.5) * 0.5; + const posZ = z + (Math.random() - 0.5) * 0.5; + + // Don't place wheat on every possible position (natural look) + if (Math.random() > 0.7) continue; + + // Position wheat stalk + dummy.position.set(posX, 0, posZ); + + // Random rotation around Y axis + dummy.rotation.y = Math.random() * Math.PI * 2; + + // Random scaling (height and width) + const scale = 0.8 + Math.random() * 0.4; + dummy.scale.set(scale, scale * (0.8 + Math.random() * 0.4), scale); + + dummy.updateMatrix(); + + // Store instance data to be added to mesh + chunkInstances.push({ + meshIndex: localIndex % config.variations, + matrix: dummy.matrix.clone(), + }); + + localIndex++; + } + } + + // Add chunk metadata to map + generatedChunks.set(chunkKey, { + instances: chunkInstances, + lastUpdated: Date.now(), + }); + + // Update instanced meshes + updateInstancedMeshes(); + }; + + // Remove a chunk at the specified chunk coordinates + const removeChunk = (chunkX, chunkZ) => { + const chunkKey = `${chunkX},${chunkZ}`; + if (generatedChunks.has(chunkKey)) { + generatedChunks.delete(chunkKey); + updateInstancedMeshes(); + } + }; + + // Update all instanced meshes based on currently generated chunks + const updateInstancedMeshes = () => { + // Reset all instance counters + const instanceCounters = Array(config.variations).fill(0); + + // Collect all instances + for (const chunk of generatedChunks.values()) { + for (const instance of chunk.instances) { + const meshIndex = instance.meshIndex; + const instanceIndex = instanceCounters[meshIndex]++; + + if (instanceIndex < stalksPerVariation) { + wheatInstances[meshIndex].setMatrixAt( + instanceIndex, + instance.matrix, + ); + } + } + } + + // Update matrices and visibility + wheatInstances.forEach((instances, index) => { + instances.count = Math.min(instanceCounters[index], stalksPerVariation); + instances.instanceMatrix.needsUpdate = true; + }); + }; + + // Update the visible chunks based on camera position + const updateVisibleChunks = () => { + // Get camera position + const camPos = new THREE.Vector3(); + camera.getWorldPosition(camPos); + + // Get chunk coordinates for camera position + const { chunkX: camChunkX, chunkZ: camChunkZ } = getChunkCoords( + camPos.x, + camPos.z, + ); + + // Calculate camera view direction on xz plane + const viewDirection = new THREE.Vector3(0, 0, -1); + viewDirection.applyQuaternion(camera.quaternion); + viewDirection.y = 0; + viewDirection.normalize(); + + // Track which chunks should be visible + const visibleChunks = new Set(); + + // Add chunks in render distance (with emphasis on view direction) + for (let dx = -config.renderDistance; dx <= config.renderDistance; dx++) { + for ( + let dz = -config.renderDistance; + dz <= config.renderDistance; + dz++ + ) { + // Calculate distance from camera chunk + const distance = Math.sqrt(dx * dx + dz * dz); + + // Skip if beyond render distance + if (distance > config.renderDistance) continue; + + // Calculate direction to this chunk + const dirX = dx === 0 ? 0 : dx / Math.abs(dx); + const dirZ = dz === 0 ? 0 : dz / Math.abs(dz); + const dirVec = new THREE.Vector3(dirX, 0, dirZ).normalize(); + + // Calculate dot product with view direction + const dotProduct = viewDirection.dot(dirVec); + + // Prioritize chunks in front of camera + if (distance <= 1 || dotProduct > -0.5) { + const chunkX = camChunkX + dx; + const chunkZ = camChunkZ + dz; + const chunkKey = `${chunkX},${chunkZ}`; + + visibleChunks.add(chunkKey); + + // Generate chunk if it doesn't exist + if (!generatedChunks.has(chunkKey)) { + generateChunk(chunkX, chunkZ); + } + } + } + } + + // Remove chunks that are no longer visible + for (const chunkKey of generatedChunks.keys()) { + if (!visibleChunks.has(chunkKey)) { + const [chunkX, chunkZ] = chunkKey.split(",").map(Number); + removeChunk(chunkX, chunkZ); + } + } + + // Update ground position to follow camera + }; + + // Wind animation function + const animateWind = (time, strength) => { + wheatInstances.forEach((instances) => { + const dummy = new THREE.Object3D(); + + for (let i = 0; i < instances.count; i++) { + // Get current matrix + instances.getMatrixAt(i, dummy.matrix); + dummy.matrix.decompose(dummy.position, dummy.quaternion, dummy.scale); + + // Apply wind effect - calculate wind based on position and time + const windX = Math.sin(dummy.position.x * strength + time) * strength; + const windZ = + Math.sin(dummy.position.z * strength + time * 0.7) * strength; + + // Get original rotation (store it in quaternion) + const originalRotation = new THREE.Euler().setFromQuaternion( + dummy.quaternion, + ); + + // Apply wind bending + dummy.rotation.set( + originalRotation.x + windX, + originalRotation.y, + originalRotation.z + windZ, + ); + + // Update matrix + dummy.updateMatrix(); + instances.setMatrixAt(i, dummy.matrix); + } + + instances.instanceMatrix.needsUpdate = true; + }); + }; + + // Generate initial chunks around starting position + updateVisibleChunks(); + + return { + fieldContainer, + animateWind, + updateVisibleChunks, + }; + } + // Helper function to create a wheat stalk geometry + static createWheatStalkGeometry(variation = 0) { + // Stem + const stemGeometry = new THREE.CylinderGeometry(0.02, 0.03, 1.5, 4, 3); + stemGeometry.translate(0, 0.75, 0); + + // Top grain part + let headGeometry; + + switch (variation % 3) { + case 0: + // Standard wheat head + headGeometry = new THREE.CylinderGeometry(0.04, 0.02, 0.3, 6, 1); + headGeometry.translate(0, 1.65, 0); + break; + case 1: + // Slightly bent wheat head + headGeometry = new THREE.CylinderGeometry(0.04, 0.02, 0.35, 6, 1); + headGeometry.translate(0, 1.65, 0); + headGeometry.rotateZ(Math.PI * 0.05); + break; + case 2: + // Different shape + headGeometry = new THREE.ConeGeometry(0.05, 0.4, 6, 1); + headGeometry.translate(0, 1.7, 0); + break; + } + + // Combine geometries + const mergedGeometry = new THREE.BufferGeometry(); + + // Merge stem and head + const stemPositions = stemGeometry.getAttribute("position").array; + const headPositions = headGeometry.getAttribute("position").array; + + const positions = new Float32Array( + stemPositions.length + headPositions.length, + ); + positions.set(stemPositions, 0); + positions.set(headPositions, stemPositions.length); + + mergedGeometry.setAttribute( + "position", + new THREE.BufferAttribute(positions, 3), + ); + + // Compute normals and UVs + mergedGeometry.computeVertexNormals(); + + return mergedGeometry; + } + + // Call init function when ready + // initWheatFieldDemo(); +} + +export { NewWheat }; diff --git a/NIRRENGARTEN/paint.js b/NIRRENGARTEN/paint.js new file mode 100644 index 0000000000000000000000000000000000000000..0a76d987e5c4cc6df712ebefadb9ea6ad619cdfb --- /dev/null +++ b/NIRRENGARTEN/paint.js @@ -0,0 +1,332 @@ +"use strict"; +import * as THREE from "three"; +import { OBJLoader } from "three/addons/loaders/OBJLoader.js"; +import { MTLLoader } from "three/addons/loaders/MTLLoader.js"; +import { OrbitControls } from "three/addons/controls/OrbitControls.js"; +import { Reflector } from 'three/addons/objects/Reflector.js'; + +import { dat } from "./lib/dat.gui.min.js"; +import { Coordinates } from "./lib/Coordinates.js"; +import { Wheat } from "./wheat.js"; +import { Sun } from "./sun.js"; +import { Skybox } from "./skybox.js"; +import { Crow } from "./crow.js"; +import { NewWheat } from "./new_wheat.js"; +import { River } from "./river.js"; + +Wheat.getModel(); + +var camera, renderer; +window.scene = new THREE.Scene(); + +var cameraControls, effectController; +var clock = new THREE.Clock(); +var gridX = false; +var gridY = false; +var gridZ = false; +var axes = false; +var ground = true; +var chunkSize = 40; +var renderDistance = 4; +var density = 1.25; +var windIntensity = 0.0025; +var displacementScale = 2; + +//TODO faudra faire en sorte de dupliquer pour avoir un vrai champ +function addWheatField() { + Wheat.render(10, scene); +} + +let _animateWind, _updateVisibleChunks; + +function addNewWheat(isInRiver) { + const { fieldContainer, animateWind, updateVisibleChunks } = + NewWheat.createDynamicWheatField( + scene, + camera, + { + chunkSize: chunkSize, + renderDistance: renderDistance, + density: density, + windIntensity: windIntensity, + }, + isInRiver, + ); + _updateVisibleChunks = updateVisibleChunks; + _animateWind = animateWind; + + fieldContainer.traverse(child => { + if (child.isInstancedMesh) { + child.castShadow = true; + child.receiveShadow = true; + } + }); +} + +function addElMordjene() { + var mtlLoader = new MTLLoader(); + mtlLoader.setPath("3Dmodel/Peanut Butter/"); + mtlLoader.load("peanutButter.mtl", function (materials) { + materials.preload(); + var objLoader = new OBJLoader(); + objLoader.setMaterials(materials); + objLoader.setPath("3Dmodel/Peanut Butter/"); + objLoader.load("peanutButter.obj", function (object) { + object.traverse(function (child) { + if (child instanceof THREE.Mesh) { + // usage de copilot + var geometry = new THREE.BufferGeometry(); + geometry.copy(child.geometry); + geometry.computeVertexNormals(); + geometry.castShadow = true; + geometry.recieveShadow = true; + geometry.scale(10, 10, 10); + child.geometry = geometry; + } + }); + object.position.y = 2; + scene.add(object); + }); + }); +} + +/** Ajoute la portion de mirroir qui reflette a la verticale */ +function addMirror() { + let geometry = new THREE.PlaneGeometry(160, 900); + var verticalMirror = new Reflector(geometry, { + clipBias: 0.003, + textureWidth: window.innerWidth * window.devicePixelRatio, + textureHeight: window.innerHeight * window.devicePixelRatio, + color: 0xc1cbcb, + }); + verticalMirror.rotation.x = - Math.PI /-1.4 ; + verticalMirror.position.y = -200; + verticalMirror.position.x = 30; + verticalMirror.position.z = 400; + scene.add(verticalMirror); + + + +} + +function init() { + var canvasWidth = 846; + var canvasHeight = 494; + var canvasRatio = canvasWidth / canvasHeight; + + // RENDERER + renderer = new THREE.WebGLRenderer({ antialias: true }); + renderer.gammaInput = true; + renderer.gammaOutput = true; + renderer.shadowMap.enabled = true; + renderer.shadowMap.type = THREE.PCFSoftShadowMap; + + renderer.setSize(canvasWidth, canvasHeight); + renderer.setClearColor(0xaaaaaa, 1.0); + + // CAMERA + camera = new THREE.PerspectiveCamera(45, canvasRatio, 1, 40000); + camera.position.set(-20, 12, -20); + // CONTROLS + cameraControls = new OrbitControls(camera, renderer.domElement); + cameraControls.target.set(0, 6, 0); + + setupGui(); + fillScene(); +} +function addToDOM() { + var container = document.getElementById("webGL"); + var canvas = container.getElementsByTagName("canvas"); + if (canvas.length > 0) { + container.removeChild(canvas[0]); + } + container.appendChild(renderer.domElement); +} +let riverAmplitude = 3; +let riverFrequency = 0.1; +let riverWidth = 10; +function fillScene() { + // SCENE + scene = new THREE.Scene(); + scene.fog = new THREE.Fog(0x808080, 8000, 12000); + // LIGHTS + var ambientLight = new THREE.AmbientLight(0xffffff); + + var spotlight = new THREE.SpotLight(0xffffff, 2); + spotlight.position.set(10, 80, 10); + spotlight.angle = Math.PI / 6; + spotlight.penumbra = 0.3; + + spotlight.shadow.mapSize.width = 1024; + spotlight.shadow.mapSize.height = 1024; + spotlight.shadow.camera.near = 10; + spotlight.shadow.camera.far = 200; + spotlight.shadow.bias = -0.001; + spotlight.shadow.normalBias = 0.02; + + spotlight.castShadow = true; + + scene.add(spotlight); + + scene.add(ambientLight); + + if (ground) { + var groundBase = new THREE.PlaneGeometry(500, 500, 128, 128); + + const textureLoader = new THREE.TextureLoader(); + + var groundMat = new THREE.MeshStandardMaterial({ + color: "#ad8a1f", + normalMap: textureLoader.load("img/normal.png"), + normalScale: new THREE.Vector2(1.0, 1.0), + displacementMap: textureLoader.load("img/height.jpg"), + displacementScale: displacementScale, + roughness: 0.6, + metalness: 0.2, + }); + var newGround = new THREE.Mesh(groundBase, groundMat); + newGround.receiveShadow = true; + newGround.rotation.x = (-90 * Math.PI) / 180; + newGround.material.needsUpdate = true; + + scene.add(newGround); + + scene.add(newGround); + } + if (gridX) { + Coordinates.drawGrid({ size: 1000, scale: 0.01 }); + } + if (gridY) { + Coordinates.drawGrid({ size: 1000, scale: 0.01, orientation: "y" }); + } + if (gridZ) { + Coordinates.drawGrid({ size: 1000, scale: 0.01, orientation: "z" }); + } + + let howMuch = 8; + + /*for (let i = 0; i < howMuch * howMuch; i++) { + Wheat.createDifferentWheat(i % 3); + Wheat.renderWheat( + ((i % howMuch) - howMuch / 2) * 8.5, + 0, + (i / howMuch - howMuch / 2) * 8.5, + scene, + ); + }*/ + let { obj, isInRiver } = River.createRiverMesh( + { + chunkSize: chunkSize, + renderDistance: renderDistance, + riverAmplitude: riverAmplitude, + riverFrequency: riverFrequency, + riverWidth: riverWidth, + }, + new THREE.MeshLambertMaterial({ color: 0x0000ff }), + ); + obj.position.y = 3; + scene.add(obj); + Sun.addSun(scene); + addElMordjene(); + let crowsGroup = new THREE.Group(); + crowsGroup.name = "crowsGroup"; + scene.add(crowsGroup); + updateCrowCrows(effectController.crowCount); + density: 0.3, riverWidth; + + addNewWheat((x) => false); + addMirror(); + Skybox.addSkybox(scene, "day"); + + let obje = new THREE.Mesh( + new THREE.SphereGeometry(1, 32, 16), + new THREE.MeshBasicMaterial({ + color: 0xff0000, + opacity: 0.2, + transparent: true, + }), + ); + obje.position.set(0, 10, 0); + scene.add(obje); +} + +function animate() { + window.requestAnimationFrame(animate); + + _updateVisibleChunks(); + + const time = clock.getElapsedTime(); + _animateWind(time, effectController.windIntensity); + + render(); +} + +function render() { + var delta = clock.getDelta(); + cameraControls.update(delta); + if ( + effectController.newGridX !== gridX || + effectController.newGridY !== gridY || + effectController.newGridZ !== gridZ || + effectController.newGround !== ground || + effectController.newAxes !== axes + ) { + gridX = effectController.newGridX; + gridY = effectController.newGridY; + gridZ = effectController.newGridZ; + ground = effectController.newGround; + axes = effectController.newAxes; + + fillScene(); + } + renderer.render(scene, camera); +} + +function setupGui() { + effectController = { + newGridX: gridX, + newGridY: gridY, + newGridZ: gridZ, + newGround: ground, + windIntensity: windIntensity, + crowCount: 100, // Initial crow count + }; + + var gui = new dat.GUI(); + gui.add(effectController, "newGridX").name("Show XZ grid"); + gui.add(effectController, "newGridY").name("Show YZ grid"); + gui.add(effectController, "newGridZ").name("Show XY grid"); + gui.add(effectController, "newGround").name("Show ground"); + gui.add(effectController, "windIntensity").name("Wind intensity"); + + // Add a slider to control the crow count + gui + .add(effectController, "crowCount", 0, 200, 1) + .name("Crow Count") + .onChange(function (value) { + updateCrowCrows(value); + }); +} + +function updateCrowCrows(count) { + let group = scene.getObjectByName("crowsGroup"); + if (group) { + group.clear(); + } else { + group = new THREE.Group(); + group.name = "crowsGroup"; + scene.add(group); + } + + Crow.addCrows(group, count); +} +try { + init(); + addToDOM(); + animate(); +} catch (e) { + var errorReport = + "Your program encountered an unrecoverable error, can not draw on canvas. Error was:<br/><br/>"; + $("#container").append(errorReport + e); + console.log(e); +} diff --git a/NIRRENGARTEN/river.js b/NIRRENGARTEN/river.js new file mode 100755 index 0000000000000000000000000000000000000000..416cdf4e1daa5da75263bfa1a7dd6ca4aef36781 --- /dev/null +++ b/NIRRENGARTEN/river.js @@ -0,0 +1,113 @@ +import * as THREE from "three"; + +class River { + static getRiverXPosition = (z, config) => { + return config.riverAmplitude * Math.sin(z * config.riverFrequency); + }; + + static createRiverMesh(config, material) { + // Define river bounds + // debugger; + const riverLength = + config.chunkSize * (config.renderDistance * 2 + 1) * 1.5; // Make river longer than visible area + const halfLength = riverLength / 2; + + // Create river path points + const points = []; + const segments = 40; + + for (let i = 0; i <= segments; i++) { + const z = -halfLength + i * (riverLength / segments); + const x = River.getRiverXPosition(z, config); + points.push(new THREE.Vector2(x, z)); + } + + // Create river shape + const shape = new THREE.Shape(); + + // Define river path + const path = new THREE.Path(points); + + // Create geometry from path with width + const geometry = new THREE.BufferGeometry(); + const positions = []; + const indices = []; + + // Create vertices on both sides of the path + for (let i = 0; i < points.length; i++) { + const point = points[i]; + + // Calculate tangent vector (perpendicular to path direction) + let tangentX, tangentZ; + + if (i === 0) { + // First point - use direction to next point + tangentX = points[i + 1].y - point.y; + tangentZ = -(points[i + 1].x - point.x); + } else if (i === points.length - 1) { + // Last point - use direction from previous point + tangentX = points[i].y - points[i - 1].y; + tangentZ = -(points[i].x - points[i - 1].x); + } else { + // Middle points - average of directions + tangentX = points[i + 1].y - points[i - 1].y; + tangentZ = -(points[i + 1].x - points[i - 1].x); + } + + // Normalize tangent + const len = Math.sqrt(tangentX * tangentX + tangentZ * tangentZ); + tangentX /= len; + tangentZ /= len; + + // Calculate points on both sides of the path + const halfWidth = config.riverWidth / 2; + + // Left bank + positions.push( + point.x - tangentX * halfWidth, + 0, + point.y - tangentZ * halfWidth, + ); + + // Right bank + positions.push( + point.x + tangentX * halfWidth, + 0, + point.y + tangentZ * halfWidth, + ); + } + + // Create indices for triangles + for (let i = 0; i < points.length - 1; i++) { + const topLeft = i * 2; + const topRight = i * 2 + 1; + const bottomLeft = (i + 1) * 2; + const bottomRight = (i + 1) * 2 + 1; + + // First triangle (top-left, bottom-left, bottom-right) + indices.push(topLeft, bottomLeft, bottomRight); + + // Second triangle (top-left, bottom-right, top-right) + indices.push(topLeft, bottomRight, topRight); + } + + // Set geometry attributes + geometry.setAttribute( + "position", + new THREE.Float32BufferAttribute(positions, 3), + ); + geometry.setIndex(indices); + geometry.computeVertexNormals(); + const isInRiver = (x, z) => { + const riverCenterX = this.getRiverXPosition(z, config); + const halfWidth = config.riverWidth / 2; + return Math.abs(x - riverCenterX) < halfWidth; + }; + // Create mesh + const riverMesh = new THREE.Mesh(geometry, material); + + return { obj: riverMesh, isInRiver: isInRiver }; + } +} + +export { River }; diff --git a/NIRRENGARTEN/skybox.js b/NIRRENGARTEN/skybox.js new file mode 100644 index 0000000000000000000000000000000000000000..296c3bf9905c5c223389888b54c9fce789a3bb7e --- /dev/null +++ b/NIRRENGARTEN/skybox.js @@ -0,0 +1,67 @@ +import * as THREE from "three"; + +class Skybox { + static async addSkybox(scene, nomFichier) { + let skyboxGeo, skybox; + let skyboxImage = nomFichier; + + function createPathStrings(filename) { + const basePath = `./img/skybox/`; + const baseFilename = basePath + filename; + const fileType = filename == nomFichier ? '.png' : '.jpg'; + // side 1,3,up,2,4,down + // en mode face a droite puis a gauche, celle du haut, face a en face, face derriere, face du bas + const sides = ['px', 'nx', 'py', 'ny', 'pz', 'nz']; + const pathStings = sides.map(side => { + return baseFilename + '_' + side + fileType; + }); + return pathStings; + } + + function createMaterialArray(filename) { + const skyboxImagepaths = createPathStrings(filename); + const materialArray = skyboxImagepaths.map(image => { + let texture = new THREE.TextureLoader().load(image); + + return new THREE.MeshBasicMaterial({ map: texture, side: THREE.BackSide }); + }); + return materialArray; + + } + const materialArray = createMaterialArray(skyboxImage); + + //on peut modif la taille pour avoir une skybox plus large ou moins large + skyboxGeo = new THREE.BoxGeometry(10000, 10000, 10000); + skybox = new THREE.Mesh(skyboxGeo, materialArray); + + scene.add(skybox); + + // add une env map pour la reflection + + const loader = new THREE.CubeTextureLoader(); + loader.setPath('./img/skybox/'); + + var textureCube = loader.load( + [ + skyboxImage + '_px.png', + skyboxImage + '_nx.png', + skyboxImage + '_py.png', + skyboxImage + '_ny.png', + skyboxImage + '_pz.png', + skyboxImage + '_nz.png']); + + scene.background = textureCube; + + var geometry = new THREE.IcosahedronGeometry(5, 15); + var sphereMaterial = new THREE.MeshBasicMaterial({ envMap: textureCube }); + var sphereMesh = new THREE.Mesh(geometry, sphereMaterial); + sphereMesh.position.y = 10; + sphereMesh.position.x = 30; + sphereMesh.position.z = 25; + scene.add(sphereMesh); + } +} + +export { Skybox }; + + diff --git a/NIRRENGARTEN/style.css b/NIRRENGARTEN/style.css new file mode 100644 index 0000000000000000000000000000000000000000..45ae8c78d6f0eeb2c7722cf6ddb85590a1134d48 --- /dev/null +++ b/NIRRENGARTEN/style.css @@ -0,0 +1,37 @@ +body { + margin: 0; +} + +canvas { + width: 80%; + height: 40%; + margin: auto; + border-radius: 20px; +} + +.render{ + display: flex; + +} + +.centre { + text-align: center; +} + +.divider{ + margin: 50px +} + +.tableau{ + flex-wrap: wrap; + flex-direction: column; + +} +.tableau-presentation{ + display: flex; +} +.tableau-img{ + display: flex; + width: 380px; + height: 242px; +} \ No newline at end of file diff --git a/NIRRENGARTEN/sun.js b/NIRRENGARTEN/sun.js new file mode 100644 index 0000000000000000000000000000000000000000..738570dbd0cb19a41d124c77414fa5c0927651de --- /dev/null +++ b/NIRRENGARTEN/sun.js @@ -0,0 +1,40 @@ +import * as THREE from "three"; + +class Sun { + static async addSun(scene) { + const geometry = new THREE.SphereGeometry(15, 32, 16); + const material = new THREE.MeshBasicMaterial({color: 0xd2efff}); + const sphere = new THREE.Mesh(geometry, material); + + sphere.position.set(-50, 200, -200); + + const light = new THREE.DirectionalLight(0xffffff, 1.5); + light.position.copy(sphere.position); + light.castShadow = true; + + light.shadow.mapSize.width = 4096; + light.shadow.mapSize.height = 4096; + + light.shadow.camera.left = -500; + light.shadow.camera.right = 500; + light.shadow.camera.top = 500; + light.shadow.camera.bottom = -500; + light.shadow.camera.near = 10; + light.shadow.camera.far = 1000; + + light.shadow.bias = -0.0001; + light.shadow.normalBias = 0.02; + + const target = new THREE.Object3D(); + target.position.set(0, 0, 0); + scene.add(target); + light.target = target; + + scene.add(sphere); + scene.add(light); + + return { sunSphere: sphere, sunLight: light }; + } +} + +export {Sun}; \ No newline at end of file diff --git a/NIRRENGARTEN/wheat.js b/NIRRENGARTEN/wheat.js new file mode 100644 index 0000000000000000000000000000000000000000..3c164c022501efb657289c00033a3a177c22f14a --- /dev/null +++ b/NIRRENGARTEN/wheat.js @@ -0,0 +1,112 @@ +import { OBJLoader } from "three/addons/loaders/OBJLoader.js"; +import { MTLLoader } from "three/addons/loaders/MTLLoader.js"; +import * as THREE from "three"; + +/** Manages the Wheat */ +class Wheat { + static texture; + static async getTexture() { + return; + if (Wheat.texture == null) { + Wheat.texture = await new Promise((res, rej) => { + var mtlLoader = new MTLLoader(); + mtlLoader.setPath("3Dmodel/Field of wheat/"); + mtlLoader.load("FieldOfWheat.mtl", res, () => {}, rej); + }); + Wheat.texture.preload(); + } + return Wheat.texture; + } + + static async createDifferentWheat(variation = 0) { + const stemGeometry = new THREE.CylinderGeometry(0.02, 0.03, 1.5, 4, 3); + stemGeometry.translate(0, 0.75, 0); + + // Top grain part + let headGeometry; + + switch (variation % 3) { + case 0: + // Standard wheat head + headGeometry = new THREE.CylinderGeometry(0.04, 0.02, 0.3, 6, 1); + headGeometry.translate(0, 1.65, 0); + break; + case 1: + // Slightly bent wheat head + headGeometry = new THREE.CylinderGeometry(0.04, 0.02, 0.35, 6, 1); + headGeometry.translate(0, 1.65, 0); + headGeometry.rotateZ(Math.PI * 0.05); + break; + case 2: + // Different shape + headGeometry = new THREE.ConeGeometry(0.05, 0.4, 6, 1); + headGeometry.translate(0, 1.7, 0); + break; + } + + // Combine geometries + const mergedGeometry = new THREE.BufferGeometry(); + + // Merge stem and head + const stemPositions = stemGeometry.getAttribute("position").array; + const headPositions = headGeometry.getAttribute("position").array; + + const positions = new Float32Array( + stemPositions.length + headPositions.length, + ); + positions.set(stemPositions, 0); + positions.set(headPositions, stemPositions.length); + + mergedGeometry.setAttribute( + "position", + new THREE.BufferAttribute(positions, 3), + ); + + // Compute normals and UVs + mergedGeometry.computeVertexNormals(); + + this.model = mergedGeometry; + + return mergedGeometry; + } + + static model; + + static async getModel() { + return; + if (Wheat.model == null) { + let objLoader = new OBJLoader(); + let txt = await Wheat.getTexture(); + // let txt = new THREE.MeshBasicMaterial({ color: 0xffffff }); + console.log(txt); + await objLoader.setMaterials(txt); + objLoader.setPath("3Dmodel/Field of wheat/"); + Wheat.model = await new Promise((res, rej) => + objLoader.load("FieldOfWheat.obj", res, function () {}, rej), + ); + Wheat.model.traverse(function (child) { + if (child instanceof THREE.Mesh) { + // usage de copilot + var geometry = new THREE.BufferGeometry(); + geometry.copy(child.geometry); + geometry.computeVertexNormals(); + geometry.castShadow = true; + geometry.recieveShadow = true; + geometry.scale(1, 1, 1); + child.geometry = geometry; + } + }); + } + return Wheat.model; + } + + static async renderWheat(x, y, z, scene) { + let model = await Wheat.getModel(); + model.position.x = x; + model.position.y = y; + model.position.z = z; + scene.add(model); + } +} + +export { Wheat }; diff --git a/PHILIPPON-CHAMPROUX/3Dmodel/Peanut Butter/peanutButter.mtl b/PHILIPPON-CHAMPROUX/3Dmodel/Peanut Butter/peanutButter.mtl new file mode 100644 index 0000000000000000000000000000000000000000..607d39ed60cb5b74dead9a18048a23cf748d3cee --- /dev/null +++ b/PHILIPPON-CHAMPROUX/3Dmodel/Peanut Butter/peanutButter.mtl @@ -0,0 +1,11 @@ +# Created by Kenney (www.kenney.nl) + +newmtl brownDark + Kd 0.60 0.22 0.11 + +newmtl brownLight + Kd 0.98 0.65 0.37 + +newmtl white + Kd 0.15 0.71 0.45 + diff --git a/PHILIPPON-CHAMPROUX/3Dmodel/Peanut Butter/peanutButter.obj b/PHILIPPON-CHAMPROUX/3Dmodel/Peanut Butter/peanutButter.obj new file mode 100644 index 0000000000000000000000000000000000000000..e340638ce97f87c3ab9a60ddd2d9b41c653f236b --- /dev/null +++ b/PHILIPPON-CHAMPROUX/3Dmodel/Peanut Butter/peanutButter.obj @@ -0,0 +1,382 @@ +# Created by Kenney (www.kenney.nl) + +mtllib peanutButter.mtl + +g peanutButter + +v 0.08019084 0.261 0.08019084 +v 1.082867E-15 0.261 0.113407 +v 0.08019084 0.2958 0.08019084 +v 1.082867E-15 0.2958 0.113407 +v 0.08019084 0.2958 -0.08019084 +v 0.08019084 0.261 -0.08019084 +v 0.113407 0.2958 0 +v 0.113407 0.261 0 +v -0.08019084 0.261 -0.08019084 +v 1.082867E-15 0.261 -0.113407 +v -0.08019084 0.2958 -0.08019084 +v 1.082867E-15 0.2958 -0.113407 +v -0.08019084 0.261 0.08019084 +v -0.08019084 0.2958 0.08019084 +v -0.113407 0.261 0 +v -0.113407 0.2958 0 +v 0.08444745 0.2784 7.219114E-16 +v 0.05971336 0.2784 0.05971336 +v 0.05971336 0.2784 -0.05971336 +v 1.443823E-15 0.2784 -0.08444745 +v 1.443823E-15 0.2784 0.08444745 +v -0.05971336 0.2784 -0.05971336 +v -0.05971336 0.2784 0.05971336 +v -0.08444745 0.2784 7.219114E-16 +v 1.082867E-15 0.2958 -0.09706604 +v -0.06863604 0.2958 -0.06863604 +v 1.082867E-15 0.2958 0.09706604 +v 0.06863604 0.2958 0.06863604 +v -0.09706604 0.2958 0 +v 0.09706604 0.2958 0 +v -0.06863604 0.2958 0.06863604 +v 0.06863604 0.2958 -0.06863604 +v -0.1002762 0.261 0 +v -0.07090598 0.261 0.07090598 +v -0.07090598 0.261 -0.07090598 +v 1.082867E-15 0.261 0.1002762 +v 0.07090598 0.261 0.07090598 +v 1.082867E-15 0.261 -0.1002762 +v 0.07090598 0.261 -0.07090598 +v 0.1002762 0.261 0 +v 0.117972 0.2262 0 +v 0.0834188 0.2262 0.0834188 +v 0.1002762 0.2436 0 +v 0.07090598 0.2436 0.07090598 +v -0.07090598 0.2436 -0.07090598 +v -0.1002762 0.2436 0 +v 7.219114E-16 0.2262 0.117972 +v 1.082867E-15 0.2436 0.1002762 +v 0.0834188 0.2262 -0.0834188 +v 0.07090598 0.2436 -0.07090598 +v 1.082867E-15 0.2436 -0.1002762 +v -0.07090598 0.2436 0.07090598 +v -0.0834188 0.2262 -0.0834188 +v -0.117972 0.2262 0 +v -0.0834188 0.2262 0.0834188 +v 7.219114E-16 0.2262 -0.117972 +v 0.0834188 0.202275 0.0834188 +v 7.219114E-16 0.202275 0.117972 +v 0.117972 0.0348 0 +v 0.1044 0 7.219114E-16 +v 0.0834188 0.0348 0.0834188 +v 0.07382195 0 0.07382195 +v -0.0834188 0.202275 0.0834188 +v -3.609557E-16 0 0.1044 +v -0.07382195 0 0.07382195 +v 7.219114E-16 0.0348 0.117972 +v -0.0834188 0.0348 0.0834188 +v -3.609557E-16 0 -0.1044 +v 0.07382195 0 -0.07382195 +v 7.219114E-16 0.0348 -0.117972 +v 0.0834188 0.0348 -0.0834188 +v -0.07382195 0 -0.07382195 +v -0.1044 0 7.219114E-16 +v 0.117972 0.058725 0 +v 0.0834188 0.058725 0.0834188 +v 7.219114E-16 0.058725 0.117972 +v -0.0834188 0.0348 -0.0834188 +v -0.0834188 0.058725 -0.0834188 +v 7.219114E-16 0.058725 -0.117972 +v -0.117972 0.0348 0 +v -0.117972 0.058725 0 +v -0.0834188 0.058725 0.0834188 +v 7.219114E-16 0.202275 -0.117972 +v 0.0834188 0.202275 -0.0834188 +v 0.117972 0.202275 0 +v 0.0834188 0.058725 -0.0834188 +v -0.0834188 0.202275 -0.0834188 +v -0.117972 0.202275 0 + +vn 0.7071068 0 0.7071068 +vn 0 0 1 +vn 0.7071068 0 -0.7071068 +vn 1 0 0 +vn -0.7071068 0 -0.7071068 +vn 0 0 -1 +vn -0.7071068 0 0.7071068 +vn -1 0 0 +vn 0 1 0 +vn 0 0.5870768 0.8095312 +vn 0.572425 0.5870768 0.572425 +vn 0 0.5870768 -0.8095312 +vn -0.572425 0.5870768 -0.572425 +vn 0.8095312 0.5870768 0 +vn -0.8095312 0.5870768 0 +vn 0.572425 0.5870768 -0.572425 +vn -0.572425 0.5870768 0.572425 +vn 0 -1 0 +vn 0.7011221 0.7130412 0 +vn 0.4957682 0.7130412 0.4957682 +vn 0 0.7130412 0.7011221 +vn 0.4957682 0.7130412 -0.4957682 +vn -0.4957682 0.7130412 -0.4957682 +vn -0.7011221 0.7130412 0 +vn -0.4957682 0.7130412 0.4957682 +vn 0 0.7130412 -0.7011221 +vn 0.9316545 -0.3633452 0 +vn 0.6587793 -0.3633452 0.6587793 +vn 0 -0.3633452 0.9316545 +vn -0.6587793 -0.3633452 0.6587793 +vn 0 -0.3633452 -0.9316545 +vn 0.6587793 -0.3633452 -0.6587793 +vn -0.6587793 -0.3633452 -0.6587793 +vn -0.9316545 -0.3633452 0 + +vt 1.708621 10.27559 +vt -1.708621 10.27559 +vt 1.708621 11.64567 +vt -1.708621 11.64567 +vt -3.324703 2.842171E-14 +vt -2.35092 2.35092 +vt -2.35092 -2.35092 +vt -5.684342E-14 -3.324703 +vt -5.684342E-14 3.324703 +vt 2.35092 -2.35092 +vt 2.35092 2.35092 +vt 3.324703 2.842171E-14 +vt 1.272309 10.81547 +vt -1.272309 10.81547 +vt 1.462424 11.64005 +vt -1.462424 11.64005 +vt -4.464842 0 +vt -3.15712 3.15712 +vt -3.947882 0 +vt -3.15712 -3.15712 +vt -2.791574 2.791574 +vt -2.791574 -2.791574 +vt 4.263256E-14 3.947882 +vt 4.263256E-14 4.464842 +vt 2.791574 2.791574 +vt 3.15712 3.15712 +vt 4.263256E-14 -4.464842 +vt 4.263256E-14 -3.947882 +vt 2.791574 -2.791574 +vt 3.15712 -3.15712 +vt 3.947882 0 +vt 4.464842 0 +vt 2.702207 -2.702207 +vt -4.263256E-14 -3.821497 +vt 3.821497 0 +vt -4.263256E-14 -4.464842 +vt -2.702207 -2.702207 +vt 2.702207 2.702207 +vt -3.821497 0 +vt -2.702207 2.702207 +vt -4.263256E-14 4.464842 +vt -4.263256E-14 3.821497 +vt 1.777399 3.55187 +vt -1.777399 3.55187 +vt 1.510789 4.491853 +vt -1.510789 4.491853 +vt -1.510789 9.590551 +vt -1.510789 10.27559 +vt 1.510789 9.590551 +vt 1.510789 10.27559 +vt 1.777399 7.963583 +vt -1.777399 7.963583 +vt 1.777399 8.905512 +vt -1.777399 8.905512 +vt 1.777399 2.743532 +vt 1.572919 1.287231 +vt -1.777399 2.743532 +vt -1.572919 1.287231 +vt 4.110236 2.842171E-14 +vt 2.906376 -2.906376 +vt 2.906376 2.906376 +vt -1.421085E-14 4.110236 +vt -1.421085E-14 -4.110236 +vt -2.906376 2.906376 +vt -2.906376 -2.906376 +vt -4.110236 2.842171E-14 +vt 1.777399 2.312008 +vt 1.777399 1.370079 +vt -1.777399 2.312008 +vt -1.777399 1.370079 + +usemtl brownDark + +f 3/3/1 2/2/2 1/1/1 +f 2/2/2 3/3/1 4/4/2 +f 7/4/4 6/1/3 5/3/3 +f 6/1/3 7/4/4 8/2/4 +f 11/3/5 10/2/6 9/1/5 +f 10/2/6 11/3/5 12/4/6 +f 4/3/2 13/2/7 2/1/2 +f 13/2/7 4/3/2 14/4/7 +f 12/3/6 6/2/3 10/1/6 +f 6/2/3 12/3/6 5/4/3 +f 3/4/1 8/1/4 7/3/4 +f 8/1/4 3/4/1 1/2/1 +f 15/1/8 11/4/5 9/2/5 +f 11/4/5 15/1/8 16/3/8 +f 19/7/9 18/6/9 17/5/9 +f 18/6/9 19/7/9 20/8/9 +f 18/6/9 20/8/9 21/9/9 +f 21/9/9 20/8/9 22/10/9 +f 21/9/9 22/10/9 23/11/9 +f 23/11/9 22/10/9 24/12/9 +f 25/15/10 22/14/11 20/13/10 +f 22/14/11 25/15/10 26/16/11 +f 27/15/12 18/14/13 21/13/12 +f 18/14/13 27/15/12 28/16/13 +f 29/16/14 22/13/11 26/15/11 +f 22/13/11 29/16/14 24/14/14 +f 17/14/15 28/15/13 30/16/15 +f 28/15/13 17/14/15 18/13/13 +f 31/16/16 24/13/14 29/15/14 +f 24/13/14 31/16/16 23/14/16 +f 32/15/17 20/14/10 19/13/17 +f 20/14/10 32/15/17 25/16/10 +f 13/1/7 16/4/8 15/2/8 +f 16/4/8 13/1/7 14/3/7 +f 19/14/17 30/15/15 32/16/17 +f 30/15/15 19/14/17 17/13/15 +f 31/15/16 21/14/12 23/13/16 +f 21/14/12 31/15/16 27/16/12 +f 33/19/18 13/18/18 15/17/18 +f 9/20/18 33/19/18 15/17/18 +f 34/21/18 13/18/18 33/19/18 +f 9/20/18 35/22/18 33/19/18 +f 36/23/18 13/18/18 34/21/18 +f 36/23/18 2/24/18 13/18/18 +f 37/25/18 2/24/18 36/23/18 +f 37/25/18 1/26/18 2/24/18 +f 10/27/18 35/22/18 9/20/18 +f 10/27/18 38/28/18 35/22/18 +f 10/27/18 39/29/18 38/28/18 +f 6/30/18 39/29/18 10/27/18 +f 40/31/18 1/26/18 37/25/18 +f 6/30/18 40/31/18 39/29/18 +f 1/26/18 40/31/18 8/32/18 +f 40/31/18 6/30/18 8/32/18 +f 25/34/9 11/30/9 26/33/9 +f 26/33/9 11/30/9 29/35/9 +f 25/34/9 12/36/9 11/30/9 +f 29/35/9 11/30/9 16/32/9 +f 32/37/9 12/36/9 25/34/9 +f 14/26/9 29/35/9 16/32/9 +f 32/37/9 5/20/9 12/36/9 +f 14/26/9 31/38/9 29/35/9 +f 30/39/9 5/20/9 32/37/9 +f 5/20/9 30/39/9 7/17/9 +f 30/39/9 3/18/9 7/17/9 +f 3/18/9 30/39/9 28/40/9 +f 4/41/9 31/38/9 14/26/9 +f 3/18/9 28/40/9 4/41/9 +f 4/41/9 27/42/9 31/38/9 +f 4/41/9 28/40/9 27/42/9 + +usemtl brownLight + +f 43/45/19 42/44/20 41/43/19 +f 42/44/20 43/45/19 44/46/20 +f 46/49/8 35/48/5 45/47/5 +f 35/48/5 46/49/8 33/50/8 +f 44/45/20 47/44/21 42/43/20 +f 47/44/21 44/45/20 48/46/21 +f 49/43/22 43/46/19 41/44/19 +f 43/46/19 49/43/22 50/45/22 +f 38/50/6 50/47/3 51/49/6 +f 50/47/3 38/50/6 39/48/3 +f 52/49/7 33/48/8 46/47/8 +f 33/48/8 52/49/7 34/50/7 +f 53/44/23 46/45/24 45/46/23 +f 46/45/24 53/44/23 54/43/24 +f 37/48/1 43/49/4 40/50/4 +f 43/49/4 37/48/1 44/47/1 +f 35/50/5 51/47/6 45/49/5 +f 51/47/6 35/50/5 38/48/6 +f 36/50/2 52/47/7 48/49/2 +f 52/47/7 36/50/2 34/48/7 +f 52/46/25 47/43/21 48/45/21 +f 47/43/21 52/46/25 55/44/25 +f 40/48/4 50/49/3 39/50/3 +f 50/49/3 40/48/4 43/47/4 +f 37/50/1 48/47/2 44/49/1 +f 48/47/2 37/50/1 36/48/2 +f 46/46/24 55/43/25 52/45/25 +f 55/43/25 46/46/24 54/44/24 +f 56/43/26 50/46/22 49/44/22 +f 50/46/22 56/43/26 51/45/26 +f 56/44/26 45/45/23 51/46/26 +f 45/45/23 56/44/26 53/43/23 +f 42/53/1 58/52/2 57/51/1 +f 58/52/2 42/53/1 47/54/2 +f 61/57/28 60/56/27 59/55/27 +f 60/56/27 61/57/28 62/58/28 +f 47/53/2 63/52/7 58/51/2 +f 63/52/7 47/53/2 55/54/7 +f 66/55/29 65/58/30 64/56/29 +f 65/58/30 66/55/29 67/57/30 +f 70/55/31 69/58/32 68/56/31 +f 69/58/32 70/55/31 71/57/32 +f 62/61/18 69/60/18 60/59/18 +f 69/60/18 62/61/18 64/62/18 +f 69/60/18 64/62/18 68/63/18 +f 68/63/18 64/62/18 65/64/18 +f 68/63/18 65/64/18 72/65/18 +f 72/65/18 65/64/18 73/66/18 +f 75/69/1 59/68/4 74/67/4 +f 59/68/4 75/69/1 61/70/1 +f 75/67/1 66/70/2 61/68/1 +f 66/70/2 75/67/1 76/69/2 +f 78/67/5 70/70/6 77/68/5 +f 70/70/6 78/67/5 79/69/6 +f 67/68/7 81/69/8 80/70/8 +f 81/69/8 67/68/7 82/67/7 +f 56/53/6 84/52/3 83/51/6 +f 84/52/3 56/53/6 49/54/3 +f 41/54/4 84/51/3 49/53/3 +f 84/51/3 41/54/4 85/52/4 +f 74/69/4 71/68/3 86/67/3 +f 71/68/3 74/69/4 59/70/4 +f 79/67/6 71/70/3 70/68/6 +f 71/70/3 79/67/6 86/69/3 +f 77/55/33 68/58/31 72/56/33 +f 68/58/31 77/55/33 70/57/31 +f 88/51/8 53/54/5 87/52/5 +f 53/54/5 88/51/8 54/53/8 +f 61/55/28 64/58/29 62/56/28 +f 64/58/29 61/55/28 66/57/29 +f 59/57/27 69/56/32 71/55/32 +f 69/56/32 59/57/27 60/58/27 +f 73/58/34 67/55/30 80/57/34 +f 67/55/30 73/58/34 65/56/30 +f 80/68/8 78/69/5 77/70/5 +f 78/69/5 80/68/8 81/67/8 +f 76/67/2 67/70/7 66/68/2 +f 67/70/7 76/67/2 82/69/7 +f 42/54/1 85/51/4 41/53/4 +f 85/51/4 42/54/1 57/52/1 +f 53/53/5 83/52/6 87/51/5 +f 83/52/6 53/53/5 56/54/6 +f 63/51/7 54/54/8 88/52/8 +f 54/54/8 63/51/7 55/53/7 +f 72/58/33 80/55/34 77/57/33 +f 80/55/34 72/58/33 73/56/34 + +usemtl green + +f 57/52/1 74/67/4 85/51/4 +f 74/67/4 57/52/1 75/69/1 +f 83/51/6 86/69/3 79/67/6 +f 86/69/3 83/51/6 84/52/3 +f 58/51/2 82/69/7 76/67/2 +f 82/69/7 58/51/2 63/52/7 +f 85/52/4 86/67/3 84/51/3 +f 86/67/3 85/52/4 74/69/4 +f 87/51/5 79/69/6 78/67/5 +f 79/69/6 87/51/5 83/52/6 +f 82/67/7 88/52/8 81/69/8 +f 88/52/8 82/67/7 63/51/7 +f 81/67/8 87/52/5 78/69/5 +f 87/52/5 81/67/8 88/51/8 +f 57/51/1 76/69/2 75/67/1 +f 76/69/2 57/51/1 58/52/2 + diff --git a/PHILIPPON-CHAMPROUX/checklistProjet.md b/PHILIPPON-CHAMPROUX/checklistProjet.md new file mode 100644 index 0000000000000000000000000000000000000000..224626ee4df5e3f7b6d8328f3f960822b85a46bb --- /dev/null +++ b/PHILIPPON-CHAMPROUX/checklistProjet.md @@ -0,0 +1,20 @@ +- [x] Esthetisme +- [x] Mise en page de la page web +- [ ] Paragraphe(s) d'explications techniques +- [x] Légèreté du dossier (<2Mo) (pour l'instant + que push ce qui necesaire) +- [x] Géométrie +- [x] Couleur +- [x] Transparence +- [x] Eclairage +- [x] Ombres +- [x] Position de la caméra +- [ ] Brouillard +- [x] Effet miroir +- [x] Texture classique +- [x] Texture avec transparence +- [x] Sprites +- [x] Environment map +- [x] Skybox +- [x] Animations +- [x] normal maps +- [x] Interaction par GUI diff --git a/PHILIPPON-CHAMPROUX/crow.js b/PHILIPPON-CHAMPROUX/crow.js new file mode 100644 index 0000000000000000000000000000000000000000..0ad0233eaf56899977bee87ee72434f44fa96a99 --- /dev/null +++ b/PHILIPPON-CHAMPROUX/crow.js @@ -0,0 +1,60 @@ +import * as THREE from 'three'; + +/** Adds crows to the scene */ +export class Crow { + static async addCrows(scene, count = 100) { + const shape = new THREE.Shape(); + shape.moveTo(0, 0); + shape.lineTo(-1, 2); + shape.lineTo(0, 1.5); + shape.lineTo(1, 2); + shape.lineTo(0, 0); + + const extrudeSettings = { + depth: 0.2, + bevelEnabled: false + }; + + // body of the crow + const crowGeometry = new THREE.ExtrudeGeometry(shape, extrudeSettings); + const crowMaterial = new THREE.MeshLambertMaterial({ color: 0x000000 }); + + // wing of the crow + const wingGeometry = new THREE.BoxGeometry(1.0, 0.5, 0.1); + const wingMaterial = new THREE.MeshLambertMaterial({ color: 0x000000 }); + + for (let i = 0; i < count; i++) { + const crow = new THREE.Mesh(crowGeometry, crowMaterial); + + // Enable shadows for crow body + crow.castShadow = true; + crow.receiveShadow = true; + + //setup both wings for the crow + const leftWing = new THREE.Mesh(wingGeometry, wingMaterial); + leftWing.position.set(-0.9, 1.8, 0); + leftWing.rotation.z = 0.4; + // Enable shadows for wings + leftWing.castShadow = true; + leftWing.receiveShadow = true; + crow.add(leftWing); + + const rightWing = new THREE.Mesh(wingGeometry, wingMaterial); + rightWing.position.set(0.9, 1.8, 0); + rightWing.rotation.z = -0.4; + // Enable shadows for wings + rightWing.castShadow = true; + rightWing.receiveShadow = true; + crow.add(rightWing); + + // Random position in the sky + crow.position.set( + (Math.random() - Math.random()) * 500, + Math.random() * 200, + (Math.random() - Math.random()) * 500 + ); + + scene.add(crow); + } + } +} \ No newline at end of file diff --git a/PHILIPPON-CHAMPROUX/img.jpg b/PHILIPPON-CHAMPROUX/img.jpg index d642e136257de4fb317a18f7c422126216665b16..a140327d761eff04d1528b226af07f70b677d278 100644 Binary files a/PHILIPPON-CHAMPROUX/img.jpg and b/PHILIPPON-CHAMPROUX/img.jpg differ diff --git a/PHILIPPON-CHAMPROUX/img/height.jpg b/PHILIPPON-CHAMPROUX/img/height.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a023a9230274b39cfaf176e7ace38396a33e4b87 Binary files /dev/null and b/PHILIPPON-CHAMPROUX/img/height.jpg differ diff --git a/PHILIPPON-CHAMPROUX/img/normal.png b/PHILIPPON-CHAMPROUX/img/normal.png new file mode 100644 index 0000000000000000000000000000000000000000..122aa5aff41b1967d7abf02b0f1bc736ad334394 Binary files /dev/null and b/PHILIPPON-CHAMPROUX/img/normal.png differ diff --git a/PHILIPPON-CHAMPROUX/img/skybox/day_nx.png b/PHILIPPON-CHAMPROUX/img/skybox/day_nx.png new file mode 100644 index 0000000000000000000000000000000000000000..73887d913ac77b48be483204d570abc1a4ae4eb1 Binary files /dev/null and b/PHILIPPON-CHAMPROUX/img/skybox/day_nx.png differ diff --git a/PHILIPPON-CHAMPROUX/img/skybox/day_ny.png b/PHILIPPON-CHAMPROUX/img/skybox/day_ny.png new file mode 100644 index 0000000000000000000000000000000000000000..f84f3cd8f1728052c400dba6390d61105aa4eeaa Binary files /dev/null and b/PHILIPPON-CHAMPROUX/img/skybox/day_ny.png differ diff --git a/PHILIPPON-CHAMPROUX/img/skybox/day_nz.png b/PHILIPPON-CHAMPROUX/img/skybox/day_nz.png new file mode 100644 index 0000000000000000000000000000000000000000..821f070efbc6789b24ca5a162def7464a7754174 Binary files /dev/null and b/PHILIPPON-CHAMPROUX/img/skybox/day_nz.png differ diff --git a/PHILIPPON-CHAMPROUX/img/skybox/day_px.png b/PHILIPPON-CHAMPROUX/img/skybox/day_px.png new file mode 100644 index 0000000000000000000000000000000000000000..0f29b4aad053b804fc8b8ff56198b21b3c058831 Binary files /dev/null and b/PHILIPPON-CHAMPROUX/img/skybox/day_px.png differ diff --git a/PHILIPPON-CHAMPROUX/img/skybox/day_py.png b/PHILIPPON-CHAMPROUX/img/skybox/day_py.png new file mode 100644 index 0000000000000000000000000000000000000000..774afeb3e011ea7f0d8baa8e5f4f1b6873321d48 Binary files /dev/null and b/PHILIPPON-CHAMPROUX/img/skybox/day_py.png differ diff --git a/PHILIPPON-CHAMPROUX/img/skybox/day_pz.png b/PHILIPPON-CHAMPROUX/img/skybox/day_pz.png new file mode 100644 index 0000000000000000000000000000000000000000..b3a0a3d1b1ff7c860b9e6dd5918cc27ddb3f111e Binary files /dev/null and b/PHILIPPON-CHAMPROUX/img/skybox/day_pz.png differ diff --git a/PHILIPPON-CHAMPROUX/index.html b/PHILIPPON-CHAMPROUX/index.html index 76e27dc119783f47da855d49712c43bab0798e9a..f5c42e9024ed583059106759e8d3b94a1b708885 100644 --- a/PHILIPPON-CHAMPROUX/index.html +++ b/PHILIPPON-CHAMPROUX/index.html @@ -1 +1,44 @@ -Le travail n'a pas encore commencé!!! \ No newline at end of file +<!DOCTYPE html> +<html> + +<head> + <meta charset="UTF-8"> + <title>Champs de blé aux corbeaux</title> + <link rel="stylesheet" href="style.css"> +</head> + +<body> + <!-- API importe du site de Three.js --> + <script async src="https://unpkg.com/es-module-shims@1.3.6/dist/es-module-shims.js"></script> + <script type="importmap"> + { + "imports": + { + "three": "https://threejs.org/build/three.module.js", + "three/addons/": "https://threejs.org/examples/jsm/" + } + } +</script> + <!-- JQuery pour afficher les erreurs --> + <script type="text/javascript" src="https://code.jquery.com/jquery-3.5.1.min.js"></script> + <!-- Un titre centre --> + <h1 class="centre">Champs de blé aux corbeau (WIP)</h1> +<div class="render"> + <img class="background" src="img/Champs2BleOcorbeaux.jpg"> + <div id="webGL" class="centre"></div> + <!-- Mon script avec un chemin relatif --> + <script type="module" src="paint.js"></script> + </div> + + <div class="divider"></div> + + <div class="tableau"> + <img class="tableau-img" src="img/Champs2BleOcorbeaux.jpg" alt="tableau du champs"> + <div class="tableau-presentation"> + <p>Super stylé le tableau</p> + </div> + </div> + +</body> + +</html> \ No newline at end of file diff --git a/PHILIPPON-CHAMPROUX/new_wheat.js b/PHILIPPON-CHAMPROUX/new_wheat.js new file mode 100644 index 0000000000000000000000000000000000000000..47cfd11d78adb0af64de8b99623f358db30c49b9 --- /dev/null +++ b/PHILIPPON-CHAMPROUX/new_wheat.js @@ -0,0 +1,348 @@ +import * as THREE from "three"; + +class NewWheat { + // Create a wheat field with instanced meshes + static createDynamicWheatField(scene, camera, options = {}, isInRiver) { + // Default options + const config = { + chunkSize: 20, // Size of each terrain chunk + renderDistance: 3, // How many chunks to render in each direction + density: 0.3, // Plants per square unit + variations: 3, // Number of different wheat stalk models + windIntensity: 0.2, + windFrequency: 0.4, + ...options, + }; + + // Create container for all wheat-related objects + const fieldContainer = new THREE.Group(); + scene.add(fieldContainer); + + // Create ground plane with larger size to match render distance + // const groundSize = config.chunkSize * (config.renderDistance * 2 + 1); + // const groundGeometry = new THREE.PlaneGeometry(groundSize, groundSize); + // const groundMaterial = new THREE.MeshStandardMaterial({ + // color: 0x7c6b4c, + // roughness: 0.8, + // metalness: 0.1, + // }); + // const ground = new THREE.Mesh(groundGeometry, groundMaterial); + // ground.rotation.x = -Math.PI / 2; // Rotate to be horizontal + // ground.receiveShadow = true; + // fieldContainer.add(ground); + + // Create wheat stalk geometries (several variations) + const wheatGeometries = []; + for (let i = 0; i < config.variations; i++) { + wheatGeometries.push(NewWheat.createWheatStalkGeometry(i)); + } + + // Set up instanced meshes for wheat variations + const stalksPerChunk = Math.floor( + config.chunkSize * config.chunkSize * config.density, + ); + const totalChunks = Math.pow(config.renderDistance * 2 + 1, 2); + const totalStalks = stalksPerChunk * totalChunks; + const stalksPerVariation = Math.ceil(totalStalks / config.variations); + + const wheatMaterial = new THREE.MeshStandardMaterial({ + color: 0xdfd087, + roughness: 0.7, + metalness: 0.1, + }); + + const wheatInstances = []; + + // Create instanced meshes for each geometry variation + wheatGeometries.forEach((geometry, index) => { + const instancedMesh = new THREE.InstancedMesh( + geometry, + wheatMaterial, + stalksPerVariation, + ); + instancedMesh.castShadow = true; + + fieldContainer.add(instancedMesh); + wheatInstances.push(instancedMesh); + }); + + // Map to track which chunks have been generated + const generatedChunks = new Map(); + + // Helper to get chunk coordinates from world position + const getChunkCoords = (x, z) => { + const chunkX = Math.floor(x / config.chunkSize); + const chunkZ = Math.floor(z / config.chunkSize); + return { chunkX, chunkZ }; + }; + + // Generate a chunk of wheat at the specified chunk coordinates + const generateChunk = (chunkX, chunkZ) => { + const chunkKey = `${chunkX},${chunkZ}`; + + // Skip if chunk already exists + if (generatedChunks.has(chunkKey)) return; + + const dummy = new THREE.Object3D(); + const chunkInstances = []; + + // Calculate world space boundaries of this chunk + const startX = chunkX * config.chunkSize; + const startZ = chunkZ * config.chunkSize; + const endX = startX + config.chunkSize; + const endZ = startZ + config.chunkSize; + if (isInRiver(startX, startZ) || isInRiver(endX, endZ)) { + return; + } + + // Fill chunk with wheat stalks + let localIndex = 0; + + for (let x = startX; x < endX; x += 1 / config.density) { + for (let z = startZ; z < endZ; z += 1 / config.density) { + // Add some randomness to position + const posX = x + (Math.random() - 0.5) * 0.5; + const posZ = z + (Math.random() - 0.5) * 0.5; + + // Don't place wheat on every possible position (natural look) + if (Math.random() > 0.7) continue; + + // Position wheat stalk + dummy.position.set(posX, 0, posZ); + + // Random rotation around Y axis + dummy.rotation.y = Math.random() * Math.PI * 2; + + // Random scaling (height and width) + const scale = 0.8 + Math.random() * 0.4; + dummy.scale.set(scale, scale * (0.8 + Math.random() * 0.4), scale); + + dummy.updateMatrix(); + + // Store instance data to be added to mesh + chunkInstances.push({ + meshIndex: localIndex % config.variations, + matrix: dummy.matrix.clone(), + }); + + localIndex++; + } + } + + // Add chunk metadata to map + generatedChunks.set(chunkKey, { + instances: chunkInstances, + lastUpdated: Date.now(), + }); + + // Update instanced meshes + updateInstancedMeshes(); + }; + + // Remove a chunk at the specified chunk coordinates + const removeChunk = (chunkX, chunkZ) => { + const chunkKey = `${chunkX},${chunkZ}`; + if (generatedChunks.has(chunkKey)) { + generatedChunks.delete(chunkKey); + updateInstancedMeshes(); + } + }; + + // Update all instanced meshes based on currently generated chunks + const updateInstancedMeshes = () => { + // Reset all instance counters + const instanceCounters = Array(config.variations).fill(0); + + // Collect all instances + for (const chunk of generatedChunks.values()) { + for (const instance of chunk.instances) { + const meshIndex = instance.meshIndex; + const instanceIndex = instanceCounters[meshIndex]++; + + if (instanceIndex < stalksPerVariation) { + wheatInstances[meshIndex].setMatrixAt( + instanceIndex, + instance.matrix, + ); + } + } + } + + // Update matrices and visibility + wheatInstances.forEach((instances, index) => { + instances.count = Math.min(instanceCounters[index], stalksPerVariation); + instances.instanceMatrix.needsUpdate = true; + }); + }; + + // Update the visible chunks based on camera position + const updateVisibleChunks = () => { + // Get camera position + const camPos = new THREE.Vector3(); + camera.getWorldPosition(camPos); + + // Get chunk coordinates for camera position + const { chunkX: camChunkX, chunkZ: camChunkZ } = getChunkCoords( + camPos.x, + camPos.z, + ); + + // Calculate camera view direction on xz plane + const viewDirection = new THREE.Vector3(0, 0, -1); + viewDirection.applyQuaternion(camera.quaternion); + viewDirection.y = 0; + viewDirection.normalize(); + + // Track which chunks should be visible + const visibleChunks = new Set(); + + // Add chunks in render distance (with emphasis on view direction) + for (let dx = -config.renderDistance; dx <= config.renderDistance; dx++) { + for ( + let dz = -config.renderDistance; + dz <= config.renderDistance; + dz++ + ) { + // Calculate distance from camera chunk + const distance = Math.sqrt(dx * dx + dz * dz); + + // Skip if beyond render distance + if (distance > config.renderDistance) continue; + + // Calculate direction to this chunk + const dirX = dx === 0 ? 0 : dx / Math.abs(dx); + const dirZ = dz === 0 ? 0 : dz / Math.abs(dz); + const dirVec = new THREE.Vector3(dirX, 0, dirZ).normalize(); + + // Calculate dot product with view direction + const dotProduct = viewDirection.dot(dirVec); + + // Prioritize chunks in front of camera + if (distance <= 1 || dotProduct > -0.5) { + const chunkX = camChunkX + dx; + const chunkZ = camChunkZ + dz; + const chunkKey = `${chunkX},${chunkZ}`; + + visibleChunks.add(chunkKey); + + // Generate chunk if it doesn't exist + if (!generatedChunks.has(chunkKey)) { + generateChunk(chunkX, chunkZ); + } + } + } + } + + // Remove chunks that are no longer visible + for (const chunkKey of generatedChunks.keys()) { + if (!visibleChunks.has(chunkKey)) { + const [chunkX, chunkZ] = chunkKey.split(",").map(Number); + removeChunk(chunkX, chunkZ); + } + } + + // Update ground position to follow camera + }; + + // Wind animation function + const animateWind = (time, strength) => { + wheatInstances.forEach((instances) => { + const dummy = new THREE.Object3D(); + + for (let i = 0; i < instances.count; i++) { + // Get current matrix + instances.getMatrixAt(i, dummy.matrix); + dummy.matrix.decompose(dummy.position, dummy.quaternion, dummy.scale); + + // Apply wind effect - calculate wind based on position and time + const windX = Math.sin(dummy.position.x * strength + time) * strength; + const windZ = + Math.sin(dummy.position.z * strength + time * 0.7) * strength; + + // Get original rotation (store it in quaternion) + const originalRotation = new THREE.Euler().setFromQuaternion( + dummy.quaternion, + ); + + // Apply wind bending + dummy.rotation.set( + originalRotation.x + windX, + originalRotation.y, + originalRotation.z + windZ, + ); + + // Update matrix + dummy.updateMatrix(); + instances.setMatrixAt(i, dummy.matrix); + } + + instances.instanceMatrix.needsUpdate = true; + }); + }; + + // Generate initial chunks around starting position + updateVisibleChunks(); + + return { + fieldContainer, + animateWind, + updateVisibleChunks, + }; + } + // Helper function to create a wheat stalk geometry + static createWheatStalkGeometry(variation = 0) { + // Stem + const stemGeometry = new THREE.CylinderGeometry(0.02, 0.03, 1.5, 4, 3); + stemGeometry.translate(0, 0.75, 0); + + // Top grain part + let headGeometry; + + switch (variation % 3) { + case 0: + // Standard wheat head + headGeometry = new THREE.CylinderGeometry(0.04, 0.02, 0.3, 6, 1); + headGeometry.translate(0, 1.65, 0); + break; + case 1: + // Slightly bent wheat head + headGeometry = new THREE.CylinderGeometry(0.04, 0.02, 0.35, 6, 1); + headGeometry.translate(0, 1.65, 0); + headGeometry.rotateZ(Math.PI * 0.05); + break; + case 2: + // Different shape + headGeometry = new THREE.ConeGeometry(0.05, 0.4, 6, 1); + headGeometry.translate(0, 1.7, 0); + break; + } + + // Combine geometries + const mergedGeometry = new THREE.BufferGeometry(); + + // Merge stem and head + const stemPositions = stemGeometry.getAttribute("position").array; + const headPositions = headGeometry.getAttribute("position").array; + + const positions = new Float32Array( + stemPositions.length + headPositions.length, + ); + positions.set(stemPositions, 0); + positions.set(headPositions, stemPositions.length); + + mergedGeometry.setAttribute( + "position", + new THREE.BufferAttribute(positions, 3), + ); + + // Compute normals and UVs + mergedGeometry.computeVertexNormals(); + + return mergedGeometry; + } + + // Call init function when ready + // initWheatFieldDemo(); +} + +export { NewWheat }; diff --git a/PHILIPPON-CHAMPROUX/paint.js b/PHILIPPON-CHAMPROUX/paint.js new file mode 100644 index 0000000000000000000000000000000000000000..0a76d987e5c4cc6df712ebefadb9ea6ad619cdfb --- /dev/null +++ b/PHILIPPON-CHAMPROUX/paint.js @@ -0,0 +1,332 @@ +"use strict"; +import * as THREE from "three"; +import { OBJLoader } from "three/addons/loaders/OBJLoader.js"; +import { MTLLoader } from "three/addons/loaders/MTLLoader.js"; +import { OrbitControls } from "three/addons/controls/OrbitControls.js"; +import { Reflector } from 'three/addons/objects/Reflector.js'; + +import { dat } from "./lib/dat.gui.min.js"; +import { Coordinates } from "./lib/Coordinates.js"; +import { Wheat } from "./wheat.js"; +import { Sun } from "./sun.js"; +import { Skybox } from "./skybox.js"; +import { Crow } from "./crow.js"; +import { NewWheat } from "./new_wheat.js"; +import { River } from "./river.js"; + +Wheat.getModel(); + +var camera, renderer; +window.scene = new THREE.Scene(); + +var cameraControls, effectController; +var clock = new THREE.Clock(); +var gridX = false; +var gridY = false; +var gridZ = false; +var axes = false; +var ground = true; +var chunkSize = 40; +var renderDistance = 4; +var density = 1.25; +var windIntensity = 0.0025; +var displacementScale = 2; + +//TODO faudra faire en sorte de dupliquer pour avoir un vrai champ +function addWheatField() { + Wheat.render(10, scene); +} + +let _animateWind, _updateVisibleChunks; + +function addNewWheat(isInRiver) { + const { fieldContainer, animateWind, updateVisibleChunks } = + NewWheat.createDynamicWheatField( + scene, + camera, + { + chunkSize: chunkSize, + renderDistance: renderDistance, + density: density, + windIntensity: windIntensity, + }, + isInRiver, + ); + _updateVisibleChunks = updateVisibleChunks; + _animateWind = animateWind; + + fieldContainer.traverse(child => { + if (child.isInstancedMesh) { + child.castShadow = true; + child.receiveShadow = true; + } + }); +} + +function addElMordjene() { + var mtlLoader = new MTLLoader(); + mtlLoader.setPath("3Dmodel/Peanut Butter/"); + mtlLoader.load("peanutButter.mtl", function (materials) { + materials.preload(); + var objLoader = new OBJLoader(); + objLoader.setMaterials(materials); + objLoader.setPath("3Dmodel/Peanut Butter/"); + objLoader.load("peanutButter.obj", function (object) { + object.traverse(function (child) { + if (child instanceof THREE.Mesh) { + // usage de copilot + var geometry = new THREE.BufferGeometry(); + geometry.copy(child.geometry); + geometry.computeVertexNormals(); + geometry.castShadow = true; + geometry.recieveShadow = true; + geometry.scale(10, 10, 10); + child.geometry = geometry; + } + }); + object.position.y = 2; + scene.add(object); + }); + }); +} + +/** Ajoute la portion de mirroir qui reflette a la verticale */ +function addMirror() { + let geometry = new THREE.PlaneGeometry(160, 900); + var verticalMirror = new Reflector(geometry, { + clipBias: 0.003, + textureWidth: window.innerWidth * window.devicePixelRatio, + textureHeight: window.innerHeight * window.devicePixelRatio, + color: 0xc1cbcb, + }); + verticalMirror.rotation.x = - Math.PI /-1.4 ; + verticalMirror.position.y = -200; + verticalMirror.position.x = 30; + verticalMirror.position.z = 400; + scene.add(verticalMirror); + + + +} + +function init() { + var canvasWidth = 846; + var canvasHeight = 494; + var canvasRatio = canvasWidth / canvasHeight; + + // RENDERER + renderer = new THREE.WebGLRenderer({ antialias: true }); + renderer.gammaInput = true; + renderer.gammaOutput = true; + renderer.shadowMap.enabled = true; + renderer.shadowMap.type = THREE.PCFSoftShadowMap; + + renderer.setSize(canvasWidth, canvasHeight); + renderer.setClearColor(0xaaaaaa, 1.0); + + // CAMERA + camera = new THREE.PerspectiveCamera(45, canvasRatio, 1, 40000); + camera.position.set(-20, 12, -20); + // CONTROLS + cameraControls = new OrbitControls(camera, renderer.domElement); + cameraControls.target.set(0, 6, 0); + + setupGui(); + fillScene(); +} +function addToDOM() { + var container = document.getElementById("webGL"); + var canvas = container.getElementsByTagName("canvas"); + if (canvas.length > 0) { + container.removeChild(canvas[0]); + } + container.appendChild(renderer.domElement); +} +let riverAmplitude = 3; +let riverFrequency = 0.1; +let riverWidth = 10; +function fillScene() { + // SCENE + scene = new THREE.Scene(); + scene.fog = new THREE.Fog(0x808080, 8000, 12000); + // LIGHTS + var ambientLight = new THREE.AmbientLight(0xffffff); + + var spotlight = new THREE.SpotLight(0xffffff, 2); + spotlight.position.set(10, 80, 10); + spotlight.angle = Math.PI / 6; + spotlight.penumbra = 0.3; + + spotlight.shadow.mapSize.width = 1024; + spotlight.shadow.mapSize.height = 1024; + spotlight.shadow.camera.near = 10; + spotlight.shadow.camera.far = 200; + spotlight.shadow.bias = -0.001; + spotlight.shadow.normalBias = 0.02; + + spotlight.castShadow = true; + + scene.add(spotlight); + + scene.add(ambientLight); + + if (ground) { + var groundBase = new THREE.PlaneGeometry(500, 500, 128, 128); + + const textureLoader = new THREE.TextureLoader(); + + var groundMat = new THREE.MeshStandardMaterial({ + color: "#ad8a1f", + normalMap: textureLoader.load("img/normal.png"), + normalScale: new THREE.Vector2(1.0, 1.0), + displacementMap: textureLoader.load("img/height.jpg"), + displacementScale: displacementScale, + roughness: 0.6, + metalness: 0.2, + }); + var newGround = new THREE.Mesh(groundBase, groundMat); + newGround.receiveShadow = true; + newGround.rotation.x = (-90 * Math.PI) / 180; + newGround.material.needsUpdate = true; + + scene.add(newGround); + + scene.add(newGround); + } + if (gridX) { + Coordinates.drawGrid({ size: 1000, scale: 0.01 }); + } + if (gridY) { + Coordinates.drawGrid({ size: 1000, scale: 0.01, orientation: "y" }); + } + if (gridZ) { + Coordinates.drawGrid({ size: 1000, scale: 0.01, orientation: "z" }); + } + + let howMuch = 8; + + /*for (let i = 0; i < howMuch * howMuch; i++) { + Wheat.createDifferentWheat(i % 3); + Wheat.renderWheat( + ((i % howMuch) - howMuch / 2) * 8.5, + 0, + (i / howMuch - howMuch / 2) * 8.5, + scene, + ); + }*/ + let { obj, isInRiver } = River.createRiverMesh( + { + chunkSize: chunkSize, + renderDistance: renderDistance, + riverAmplitude: riverAmplitude, + riverFrequency: riverFrequency, + riverWidth: riverWidth, + }, + new THREE.MeshLambertMaterial({ color: 0x0000ff }), + ); + obj.position.y = 3; + scene.add(obj); + Sun.addSun(scene); + addElMordjene(); + let crowsGroup = new THREE.Group(); + crowsGroup.name = "crowsGroup"; + scene.add(crowsGroup); + updateCrowCrows(effectController.crowCount); + density: 0.3, riverWidth; + + addNewWheat((x) => false); + addMirror(); + Skybox.addSkybox(scene, "day"); + + let obje = new THREE.Mesh( + new THREE.SphereGeometry(1, 32, 16), + new THREE.MeshBasicMaterial({ + color: 0xff0000, + opacity: 0.2, + transparent: true, + }), + ); + obje.position.set(0, 10, 0); + scene.add(obje); +} + +function animate() { + window.requestAnimationFrame(animate); + + _updateVisibleChunks(); + + const time = clock.getElapsedTime(); + _animateWind(time, effectController.windIntensity); + + render(); +} + +function render() { + var delta = clock.getDelta(); + cameraControls.update(delta); + if ( + effectController.newGridX !== gridX || + effectController.newGridY !== gridY || + effectController.newGridZ !== gridZ || + effectController.newGround !== ground || + effectController.newAxes !== axes + ) { + gridX = effectController.newGridX; + gridY = effectController.newGridY; + gridZ = effectController.newGridZ; + ground = effectController.newGround; + axes = effectController.newAxes; + + fillScene(); + } + renderer.render(scene, camera); +} + +function setupGui() { + effectController = { + newGridX: gridX, + newGridY: gridY, + newGridZ: gridZ, + newGround: ground, + windIntensity: windIntensity, + crowCount: 100, // Initial crow count + }; + + var gui = new dat.GUI(); + gui.add(effectController, "newGridX").name("Show XZ grid"); + gui.add(effectController, "newGridY").name("Show YZ grid"); + gui.add(effectController, "newGridZ").name("Show XY grid"); + gui.add(effectController, "newGround").name("Show ground"); + gui.add(effectController, "windIntensity").name("Wind intensity"); + + // Add a slider to control the crow count + gui + .add(effectController, "crowCount", 0, 200, 1) + .name("Crow Count") + .onChange(function (value) { + updateCrowCrows(value); + }); +} + +function updateCrowCrows(count) { + let group = scene.getObjectByName("crowsGroup"); + if (group) { + group.clear(); + } else { + group = new THREE.Group(); + group.name = "crowsGroup"; + scene.add(group); + } + + Crow.addCrows(group, count); +} +try { + init(); + addToDOM(); + animate(); +} catch (e) { + var errorReport = + "Your program encountered an unrecoverable error, can not draw on canvas. Error was:<br/><br/>"; + $("#container").append(errorReport + e); + console.log(e); +} diff --git a/PHILIPPON-CHAMPROUX/river.js b/PHILIPPON-CHAMPROUX/river.js new file mode 100755 index 0000000000000000000000000000000000000000..416cdf4e1daa5da75263bfa1a7dd6ca4aef36781 --- /dev/null +++ b/PHILIPPON-CHAMPROUX/river.js @@ -0,0 +1,113 @@ +import * as THREE from "three"; + +class River { + static getRiverXPosition = (z, config) => { + return config.riverAmplitude * Math.sin(z * config.riverFrequency); + }; + + static createRiverMesh(config, material) { + // Define river bounds + // debugger; + const riverLength = + config.chunkSize * (config.renderDistance * 2 + 1) * 1.5; // Make river longer than visible area + const halfLength = riverLength / 2; + + // Create river path points + const points = []; + const segments = 40; + + for (let i = 0; i <= segments; i++) { + const z = -halfLength + i * (riverLength / segments); + const x = River.getRiverXPosition(z, config); + points.push(new THREE.Vector2(x, z)); + } + + // Create river shape + const shape = new THREE.Shape(); + + // Define river path + const path = new THREE.Path(points); + + // Create geometry from path with width + const geometry = new THREE.BufferGeometry(); + const positions = []; + const indices = []; + + // Create vertices on both sides of the path + for (let i = 0; i < points.length; i++) { + const point = points[i]; + + // Calculate tangent vector (perpendicular to path direction) + let tangentX, tangentZ; + + if (i === 0) { + // First point - use direction to next point + tangentX = points[i + 1].y - point.y; + tangentZ = -(points[i + 1].x - point.x); + } else if (i === points.length - 1) { + // Last point - use direction from previous point + tangentX = points[i].y - points[i - 1].y; + tangentZ = -(points[i].x - points[i - 1].x); + } else { + // Middle points - average of directions + tangentX = points[i + 1].y - points[i - 1].y; + tangentZ = -(points[i + 1].x - points[i - 1].x); + } + + // Normalize tangent + const len = Math.sqrt(tangentX * tangentX + tangentZ * tangentZ); + tangentX /= len; + tangentZ /= len; + + // Calculate points on both sides of the path + const halfWidth = config.riverWidth / 2; + + // Left bank + positions.push( + point.x - tangentX * halfWidth, + 0, + point.y - tangentZ * halfWidth, + ); + + // Right bank + positions.push( + point.x + tangentX * halfWidth, + 0, + point.y + tangentZ * halfWidth, + ); + } + + // Create indices for triangles + for (let i = 0; i < points.length - 1; i++) { + const topLeft = i * 2; + const topRight = i * 2 + 1; + const bottomLeft = (i + 1) * 2; + const bottomRight = (i + 1) * 2 + 1; + + // First triangle (top-left, bottom-left, bottom-right) + indices.push(topLeft, bottomLeft, bottomRight); + + // Second triangle (top-left, bottom-right, top-right) + indices.push(topLeft, bottomRight, topRight); + } + + // Set geometry attributes + geometry.setAttribute( + "position", + new THREE.Float32BufferAttribute(positions, 3), + ); + geometry.setIndex(indices); + geometry.computeVertexNormals(); + const isInRiver = (x, z) => { + const riverCenterX = this.getRiverXPosition(z, config); + const halfWidth = config.riverWidth / 2; + return Math.abs(x - riverCenterX) < halfWidth; + }; + // Create mesh + const riverMesh = new THREE.Mesh(geometry, material); + + return { obj: riverMesh, isInRiver: isInRiver }; + } +} + +export { River }; diff --git a/PHILIPPON-CHAMPROUX/skybox.js b/PHILIPPON-CHAMPROUX/skybox.js new file mode 100644 index 0000000000000000000000000000000000000000..296c3bf9905c5c223389888b54c9fce789a3bb7e --- /dev/null +++ b/PHILIPPON-CHAMPROUX/skybox.js @@ -0,0 +1,67 @@ +import * as THREE from "three"; + +class Skybox { + static async addSkybox(scene, nomFichier) { + let skyboxGeo, skybox; + let skyboxImage = nomFichier; + + function createPathStrings(filename) { + const basePath = `./img/skybox/`; + const baseFilename = basePath + filename; + const fileType = filename == nomFichier ? '.png' : '.jpg'; + // side 1,3,up,2,4,down + // en mode face a droite puis a gauche, celle du haut, face a en face, face derriere, face du bas + const sides = ['px', 'nx', 'py', 'ny', 'pz', 'nz']; + const pathStings = sides.map(side => { + return baseFilename + '_' + side + fileType; + }); + return pathStings; + } + + function createMaterialArray(filename) { + const skyboxImagepaths = createPathStrings(filename); + const materialArray = skyboxImagepaths.map(image => { + let texture = new THREE.TextureLoader().load(image); + + return new THREE.MeshBasicMaterial({ map: texture, side: THREE.BackSide }); + }); + return materialArray; + + } + const materialArray = createMaterialArray(skyboxImage); + + //on peut modif la taille pour avoir une skybox plus large ou moins large + skyboxGeo = new THREE.BoxGeometry(10000, 10000, 10000); + skybox = new THREE.Mesh(skyboxGeo, materialArray); + + scene.add(skybox); + + // add une env map pour la reflection + + const loader = new THREE.CubeTextureLoader(); + loader.setPath('./img/skybox/'); + + var textureCube = loader.load( + [ + skyboxImage + '_px.png', + skyboxImage + '_nx.png', + skyboxImage + '_py.png', + skyboxImage + '_ny.png', + skyboxImage + '_pz.png', + skyboxImage + '_nz.png']); + + scene.background = textureCube; + + var geometry = new THREE.IcosahedronGeometry(5, 15); + var sphereMaterial = new THREE.MeshBasicMaterial({ envMap: textureCube }); + var sphereMesh = new THREE.Mesh(geometry, sphereMaterial); + sphereMesh.position.y = 10; + sphereMesh.position.x = 30; + sphereMesh.position.z = 25; + scene.add(sphereMesh); + } +} + +export { Skybox }; + + diff --git a/PHILIPPON-CHAMPROUX/style.css b/PHILIPPON-CHAMPROUX/style.css new file mode 100644 index 0000000000000000000000000000000000000000..45ae8c78d6f0eeb2c7722cf6ddb85590a1134d48 --- /dev/null +++ b/PHILIPPON-CHAMPROUX/style.css @@ -0,0 +1,37 @@ +body { + margin: 0; +} + +canvas { + width: 80%; + height: 40%; + margin: auto; + border-radius: 20px; +} + +.render{ + display: flex; + +} + +.centre { + text-align: center; +} + +.divider{ + margin: 50px +} + +.tableau{ + flex-wrap: wrap; + flex-direction: column; + +} +.tableau-presentation{ + display: flex; +} +.tableau-img{ + display: flex; + width: 380px; + height: 242px; +} \ No newline at end of file diff --git a/PHILIPPON-CHAMPROUX/sun.js b/PHILIPPON-CHAMPROUX/sun.js new file mode 100644 index 0000000000000000000000000000000000000000..738570dbd0cb19a41d124c77414fa5c0927651de --- /dev/null +++ b/PHILIPPON-CHAMPROUX/sun.js @@ -0,0 +1,40 @@ +import * as THREE from "three"; + +class Sun { + static async addSun(scene) { + const geometry = new THREE.SphereGeometry(15, 32, 16); + const material = new THREE.MeshBasicMaterial({color: 0xd2efff}); + const sphere = new THREE.Mesh(geometry, material); + + sphere.position.set(-50, 200, -200); + + const light = new THREE.DirectionalLight(0xffffff, 1.5); + light.position.copy(sphere.position); + light.castShadow = true; + + light.shadow.mapSize.width = 4096; + light.shadow.mapSize.height = 4096; + + light.shadow.camera.left = -500; + light.shadow.camera.right = 500; + light.shadow.camera.top = 500; + light.shadow.camera.bottom = -500; + light.shadow.camera.near = 10; + light.shadow.camera.far = 1000; + + light.shadow.bias = -0.0001; + light.shadow.normalBias = 0.02; + + const target = new THREE.Object3D(); + target.position.set(0, 0, 0); + scene.add(target); + light.target = target; + + scene.add(sphere); + scene.add(light); + + return { sunSphere: sphere, sunLight: light }; + } +} + +export {Sun}; \ No newline at end of file diff --git a/PHILIPPON-CHAMPROUX/wheat.js b/PHILIPPON-CHAMPROUX/wheat.js new file mode 100644 index 0000000000000000000000000000000000000000..3c164c022501efb657289c00033a3a177c22f14a --- /dev/null +++ b/PHILIPPON-CHAMPROUX/wheat.js @@ -0,0 +1,112 @@ +import { OBJLoader } from "three/addons/loaders/OBJLoader.js"; +import { MTLLoader } from "three/addons/loaders/MTLLoader.js"; +import * as THREE from "three"; + +/** Manages the Wheat */ +class Wheat { + static texture; + static async getTexture() { + return; + if (Wheat.texture == null) { + Wheat.texture = await new Promise((res, rej) => { + var mtlLoader = new MTLLoader(); + mtlLoader.setPath("3Dmodel/Field of wheat/"); + mtlLoader.load("FieldOfWheat.mtl", res, () => {}, rej); + }); + Wheat.texture.preload(); + } + return Wheat.texture; + } + + static async createDifferentWheat(variation = 0) { + const stemGeometry = new THREE.CylinderGeometry(0.02, 0.03, 1.5, 4, 3); + stemGeometry.translate(0, 0.75, 0); + + // Top grain part + let headGeometry; + + switch (variation % 3) { + case 0: + // Standard wheat head + headGeometry = new THREE.CylinderGeometry(0.04, 0.02, 0.3, 6, 1); + headGeometry.translate(0, 1.65, 0); + break; + case 1: + // Slightly bent wheat head + headGeometry = new THREE.CylinderGeometry(0.04, 0.02, 0.35, 6, 1); + headGeometry.translate(0, 1.65, 0); + headGeometry.rotateZ(Math.PI * 0.05); + break; + case 2: + // Different shape + headGeometry = new THREE.ConeGeometry(0.05, 0.4, 6, 1); + headGeometry.translate(0, 1.7, 0); + break; + } + + // Combine geometries + const mergedGeometry = new THREE.BufferGeometry(); + + // Merge stem and head + const stemPositions = stemGeometry.getAttribute("position").array; + const headPositions = headGeometry.getAttribute("position").array; + + const positions = new Float32Array( + stemPositions.length + headPositions.length, + ); + positions.set(stemPositions, 0); + positions.set(headPositions, stemPositions.length); + + mergedGeometry.setAttribute( + "position", + new THREE.BufferAttribute(positions, 3), + ); + + // Compute normals and UVs + mergedGeometry.computeVertexNormals(); + + this.model = mergedGeometry; + + return mergedGeometry; + } + + static model; + + static async getModel() { + return; + if (Wheat.model == null) { + let objLoader = new OBJLoader(); + let txt = await Wheat.getTexture(); + // let txt = new THREE.MeshBasicMaterial({ color: 0xffffff }); + console.log(txt); + await objLoader.setMaterials(txt); + objLoader.setPath("3Dmodel/Field of wheat/"); + Wheat.model = await new Promise((res, rej) => + objLoader.load("FieldOfWheat.obj", res, function () {}, rej), + ); + Wheat.model.traverse(function (child) { + if (child instanceof THREE.Mesh) { + // usage de copilot + var geometry = new THREE.BufferGeometry(); + geometry.copy(child.geometry); + geometry.computeVertexNormals(); + geometry.castShadow = true; + geometry.recieveShadow = true; + geometry.scale(1, 1, 1); + child.geometry = geometry; + } + }); + } + return Wheat.model; + } + + static async renderWheat(x, y, z, scene) { + let model = await Wheat.getModel(); + model.position.x = x; + model.position.y = y; + model.position.z = z; + scene.add(model); + } +} + +export { Wheat }; diff --git a/RATTI/3Dmodel/Peanut Butter/peanutButter.mtl b/RATTI/3Dmodel/Peanut Butter/peanutButter.mtl new file mode 100644 index 0000000000000000000000000000000000000000..607d39ed60cb5b74dead9a18048a23cf748d3cee --- /dev/null +++ b/RATTI/3Dmodel/Peanut Butter/peanutButter.mtl @@ -0,0 +1,11 @@ +# Created by Kenney (www.kenney.nl) + +newmtl brownDark + Kd 0.60 0.22 0.11 + +newmtl brownLight + Kd 0.98 0.65 0.37 + +newmtl white + Kd 0.15 0.71 0.45 + diff --git a/RATTI/3Dmodel/Peanut Butter/peanutButter.obj b/RATTI/3Dmodel/Peanut Butter/peanutButter.obj new file mode 100644 index 0000000000000000000000000000000000000000..e340638ce97f87c3ab9a60ddd2d9b41c653f236b --- /dev/null +++ b/RATTI/3Dmodel/Peanut Butter/peanutButter.obj @@ -0,0 +1,382 @@ +# Created by Kenney (www.kenney.nl) + +mtllib peanutButter.mtl + +g peanutButter + +v 0.08019084 0.261 0.08019084 +v 1.082867E-15 0.261 0.113407 +v 0.08019084 0.2958 0.08019084 +v 1.082867E-15 0.2958 0.113407 +v 0.08019084 0.2958 -0.08019084 +v 0.08019084 0.261 -0.08019084 +v 0.113407 0.2958 0 +v 0.113407 0.261 0 +v -0.08019084 0.261 -0.08019084 +v 1.082867E-15 0.261 -0.113407 +v -0.08019084 0.2958 -0.08019084 +v 1.082867E-15 0.2958 -0.113407 +v -0.08019084 0.261 0.08019084 +v -0.08019084 0.2958 0.08019084 +v -0.113407 0.261 0 +v -0.113407 0.2958 0 +v 0.08444745 0.2784 7.219114E-16 +v 0.05971336 0.2784 0.05971336 +v 0.05971336 0.2784 -0.05971336 +v 1.443823E-15 0.2784 -0.08444745 +v 1.443823E-15 0.2784 0.08444745 +v -0.05971336 0.2784 -0.05971336 +v -0.05971336 0.2784 0.05971336 +v -0.08444745 0.2784 7.219114E-16 +v 1.082867E-15 0.2958 -0.09706604 +v -0.06863604 0.2958 -0.06863604 +v 1.082867E-15 0.2958 0.09706604 +v 0.06863604 0.2958 0.06863604 +v -0.09706604 0.2958 0 +v 0.09706604 0.2958 0 +v -0.06863604 0.2958 0.06863604 +v 0.06863604 0.2958 -0.06863604 +v -0.1002762 0.261 0 +v -0.07090598 0.261 0.07090598 +v -0.07090598 0.261 -0.07090598 +v 1.082867E-15 0.261 0.1002762 +v 0.07090598 0.261 0.07090598 +v 1.082867E-15 0.261 -0.1002762 +v 0.07090598 0.261 -0.07090598 +v 0.1002762 0.261 0 +v 0.117972 0.2262 0 +v 0.0834188 0.2262 0.0834188 +v 0.1002762 0.2436 0 +v 0.07090598 0.2436 0.07090598 +v -0.07090598 0.2436 -0.07090598 +v -0.1002762 0.2436 0 +v 7.219114E-16 0.2262 0.117972 +v 1.082867E-15 0.2436 0.1002762 +v 0.0834188 0.2262 -0.0834188 +v 0.07090598 0.2436 -0.07090598 +v 1.082867E-15 0.2436 -0.1002762 +v -0.07090598 0.2436 0.07090598 +v -0.0834188 0.2262 -0.0834188 +v -0.117972 0.2262 0 +v -0.0834188 0.2262 0.0834188 +v 7.219114E-16 0.2262 -0.117972 +v 0.0834188 0.202275 0.0834188 +v 7.219114E-16 0.202275 0.117972 +v 0.117972 0.0348 0 +v 0.1044 0 7.219114E-16 +v 0.0834188 0.0348 0.0834188 +v 0.07382195 0 0.07382195 +v -0.0834188 0.202275 0.0834188 +v -3.609557E-16 0 0.1044 +v -0.07382195 0 0.07382195 +v 7.219114E-16 0.0348 0.117972 +v -0.0834188 0.0348 0.0834188 +v -3.609557E-16 0 -0.1044 +v 0.07382195 0 -0.07382195 +v 7.219114E-16 0.0348 -0.117972 +v 0.0834188 0.0348 -0.0834188 +v -0.07382195 0 -0.07382195 +v -0.1044 0 7.219114E-16 +v 0.117972 0.058725 0 +v 0.0834188 0.058725 0.0834188 +v 7.219114E-16 0.058725 0.117972 +v -0.0834188 0.0348 -0.0834188 +v -0.0834188 0.058725 -0.0834188 +v 7.219114E-16 0.058725 -0.117972 +v -0.117972 0.0348 0 +v -0.117972 0.058725 0 +v -0.0834188 0.058725 0.0834188 +v 7.219114E-16 0.202275 -0.117972 +v 0.0834188 0.202275 -0.0834188 +v 0.117972 0.202275 0 +v 0.0834188 0.058725 -0.0834188 +v -0.0834188 0.202275 -0.0834188 +v -0.117972 0.202275 0 + +vn 0.7071068 0 0.7071068 +vn 0 0 1 +vn 0.7071068 0 -0.7071068 +vn 1 0 0 +vn -0.7071068 0 -0.7071068 +vn 0 0 -1 +vn -0.7071068 0 0.7071068 +vn -1 0 0 +vn 0 1 0 +vn 0 0.5870768 0.8095312 +vn 0.572425 0.5870768 0.572425 +vn 0 0.5870768 -0.8095312 +vn -0.572425 0.5870768 -0.572425 +vn 0.8095312 0.5870768 0 +vn -0.8095312 0.5870768 0 +vn 0.572425 0.5870768 -0.572425 +vn -0.572425 0.5870768 0.572425 +vn 0 -1 0 +vn 0.7011221 0.7130412 0 +vn 0.4957682 0.7130412 0.4957682 +vn 0 0.7130412 0.7011221 +vn 0.4957682 0.7130412 -0.4957682 +vn -0.4957682 0.7130412 -0.4957682 +vn -0.7011221 0.7130412 0 +vn -0.4957682 0.7130412 0.4957682 +vn 0 0.7130412 -0.7011221 +vn 0.9316545 -0.3633452 0 +vn 0.6587793 -0.3633452 0.6587793 +vn 0 -0.3633452 0.9316545 +vn -0.6587793 -0.3633452 0.6587793 +vn 0 -0.3633452 -0.9316545 +vn 0.6587793 -0.3633452 -0.6587793 +vn -0.6587793 -0.3633452 -0.6587793 +vn -0.9316545 -0.3633452 0 + +vt 1.708621 10.27559 +vt -1.708621 10.27559 +vt 1.708621 11.64567 +vt -1.708621 11.64567 +vt -3.324703 2.842171E-14 +vt -2.35092 2.35092 +vt -2.35092 -2.35092 +vt -5.684342E-14 -3.324703 +vt -5.684342E-14 3.324703 +vt 2.35092 -2.35092 +vt 2.35092 2.35092 +vt 3.324703 2.842171E-14 +vt 1.272309 10.81547 +vt -1.272309 10.81547 +vt 1.462424 11.64005 +vt -1.462424 11.64005 +vt -4.464842 0 +vt -3.15712 3.15712 +vt -3.947882 0 +vt -3.15712 -3.15712 +vt -2.791574 2.791574 +vt -2.791574 -2.791574 +vt 4.263256E-14 3.947882 +vt 4.263256E-14 4.464842 +vt 2.791574 2.791574 +vt 3.15712 3.15712 +vt 4.263256E-14 -4.464842 +vt 4.263256E-14 -3.947882 +vt 2.791574 -2.791574 +vt 3.15712 -3.15712 +vt 3.947882 0 +vt 4.464842 0 +vt 2.702207 -2.702207 +vt -4.263256E-14 -3.821497 +vt 3.821497 0 +vt -4.263256E-14 -4.464842 +vt -2.702207 -2.702207 +vt 2.702207 2.702207 +vt -3.821497 0 +vt -2.702207 2.702207 +vt -4.263256E-14 4.464842 +vt -4.263256E-14 3.821497 +vt 1.777399 3.55187 +vt -1.777399 3.55187 +vt 1.510789 4.491853 +vt -1.510789 4.491853 +vt -1.510789 9.590551 +vt -1.510789 10.27559 +vt 1.510789 9.590551 +vt 1.510789 10.27559 +vt 1.777399 7.963583 +vt -1.777399 7.963583 +vt 1.777399 8.905512 +vt -1.777399 8.905512 +vt 1.777399 2.743532 +vt 1.572919 1.287231 +vt -1.777399 2.743532 +vt -1.572919 1.287231 +vt 4.110236 2.842171E-14 +vt 2.906376 -2.906376 +vt 2.906376 2.906376 +vt -1.421085E-14 4.110236 +vt -1.421085E-14 -4.110236 +vt -2.906376 2.906376 +vt -2.906376 -2.906376 +vt -4.110236 2.842171E-14 +vt 1.777399 2.312008 +vt 1.777399 1.370079 +vt -1.777399 2.312008 +vt -1.777399 1.370079 + +usemtl brownDark + +f 3/3/1 2/2/2 1/1/1 +f 2/2/2 3/3/1 4/4/2 +f 7/4/4 6/1/3 5/3/3 +f 6/1/3 7/4/4 8/2/4 +f 11/3/5 10/2/6 9/1/5 +f 10/2/6 11/3/5 12/4/6 +f 4/3/2 13/2/7 2/1/2 +f 13/2/7 4/3/2 14/4/7 +f 12/3/6 6/2/3 10/1/6 +f 6/2/3 12/3/6 5/4/3 +f 3/4/1 8/1/4 7/3/4 +f 8/1/4 3/4/1 1/2/1 +f 15/1/8 11/4/5 9/2/5 +f 11/4/5 15/1/8 16/3/8 +f 19/7/9 18/6/9 17/5/9 +f 18/6/9 19/7/9 20/8/9 +f 18/6/9 20/8/9 21/9/9 +f 21/9/9 20/8/9 22/10/9 +f 21/9/9 22/10/9 23/11/9 +f 23/11/9 22/10/9 24/12/9 +f 25/15/10 22/14/11 20/13/10 +f 22/14/11 25/15/10 26/16/11 +f 27/15/12 18/14/13 21/13/12 +f 18/14/13 27/15/12 28/16/13 +f 29/16/14 22/13/11 26/15/11 +f 22/13/11 29/16/14 24/14/14 +f 17/14/15 28/15/13 30/16/15 +f 28/15/13 17/14/15 18/13/13 +f 31/16/16 24/13/14 29/15/14 +f 24/13/14 31/16/16 23/14/16 +f 32/15/17 20/14/10 19/13/17 +f 20/14/10 32/15/17 25/16/10 +f 13/1/7 16/4/8 15/2/8 +f 16/4/8 13/1/7 14/3/7 +f 19/14/17 30/15/15 32/16/17 +f 30/15/15 19/14/17 17/13/15 +f 31/15/16 21/14/12 23/13/16 +f 21/14/12 31/15/16 27/16/12 +f 33/19/18 13/18/18 15/17/18 +f 9/20/18 33/19/18 15/17/18 +f 34/21/18 13/18/18 33/19/18 +f 9/20/18 35/22/18 33/19/18 +f 36/23/18 13/18/18 34/21/18 +f 36/23/18 2/24/18 13/18/18 +f 37/25/18 2/24/18 36/23/18 +f 37/25/18 1/26/18 2/24/18 +f 10/27/18 35/22/18 9/20/18 +f 10/27/18 38/28/18 35/22/18 +f 10/27/18 39/29/18 38/28/18 +f 6/30/18 39/29/18 10/27/18 +f 40/31/18 1/26/18 37/25/18 +f 6/30/18 40/31/18 39/29/18 +f 1/26/18 40/31/18 8/32/18 +f 40/31/18 6/30/18 8/32/18 +f 25/34/9 11/30/9 26/33/9 +f 26/33/9 11/30/9 29/35/9 +f 25/34/9 12/36/9 11/30/9 +f 29/35/9 11/30/9 16/32/9 +f 32/37/9 12/36/9 25/34/9 +f 14/26/9 29/35/9 16/32/9 +f 32/37/9 5/20/9 12/36/9 +f 14/26/9 31/38/9 29/35/9 +f 30/39/9 5/20/9 32/37/9 +f 5/20/9 30/39/9 7/17/9 +f 30/39/9 3/18/9 7/17/9 +f 3/18/9 30/39/9 28/40/9 +f 4/41/9 31/38/9 14/26/9 +f 3/18/9 28/40/9 4/41/9 +f 4/41/9 27/42/9 31/38/9 +f 4/41/9 28/40/9 27/42/9 + +usemtl brownLight + +f 43/45/19 42/44/20 41/43/19 +f 42/44/20 43/45/19 44/46/20 +f 46/49/8 35/48/5 45/47/5 +f 35/48/5 46/49/8 33/50/8 +f 44/45/20 47/44/21 42/43/20 +f 47/44/21 44/45/20 48/46/21 +f 49/43/22 43/46/19 41/44/19 +f 43/46/19 49/43/22 50/45/22 +f 38/50/6 50/47/3 51/49/6 +f 50/47/3 38/50/6 39/48/3 +f 52/49/7 33/48/8 46/47/8 +f 33/48/8 52/49/7 34/50/7 +f 53/44/23 46/45/24 45/46/23 +f 46/45/24 53/44/23 54/43/24 +f 37/48/1 43/49/4 40/50/4 +f 43/49/4 37/48/1 44/47/1 +f 35/50/5 51/47/6 45/49/5 +f 51/47/6 35/50/5 38/48/6 +f 36/50/2 52/47/7 48/49/2 +f 52/47/7 36/50/2 34/48/7 +f 52/46/25 47/43/21 48/45/21 +f 47/43/21 52/46/25 55/44/25 +f 40/48/4 50/49/3 39/50/3 +f 50/49/3 40/48/4 43/47/4 +f 37/50/1 48/47/2 44/49/1 +f 48/47/2 37/50/1 36/48/2 +f 46/46/24 55/43/25 52/45/25 +f 55/43/25 46/46/24 54/44/24 +f 56/43/26 50/46/22 49/44/22 +f 50/46/22 56/43/26 51/45/26 +f 56/44/26 45/45/23 51/46/26 +f 45/45/23 56/44/26 53/43/23 +f 42/53/1 58/52/2 57/51/1 +f 58/52/2 42/53/1 47/54/2 +f 61/57/28 60/56/27 59/55/27 +f 60/56/27 61/57/28 62/58/28 +f 47/53/2 63/52/7 58/51/2 +f 63/52/7 47/53/2 55/54/7 +f 66/55/29 65/58/30 64/56/29 +f 65/58/30 66/55/29 67/57/30 +f 70/55/31 69/58/32 68/56/31 +f 69/58/32 70/55/31 71/57/32 +f 62/61/18 69/60/18 60/59/18 +f 69/60/18 62/61/18 64/62/18 +f 69/60/18 64/62/18 68/63/18 +f 68/63/18 64/62/18 65/64/18 +f 68/63/18 65/64/18 72/65/18 +f 72/65/18 65/64/18 73/66/18 +f 75/69/1 59/68/4 74/67/4 +f 59/68/4 75/69/1 61/70/1 +f 75/67/1 66/70/2 61/68/1 +f 66/70/2 75/67/1 76/69/2 +f 78/67/5 70/70/6 77/68/5 +f 70/70/6 78/67/5 79/69/6 +f 67/68/7 81/69/8 80/70/8 +f 81/69/8 67/68/7 82/67/7 +f 56/53/6 84/52/3 83/51/6 +f 84/52/3 56/53/6 49/54/3 +f 41/54/4 84/51/3 49/53/3 +f 84/51/3 41/54/4 85/52/4 +f 74/69/4 71/68/3 86/67/3 +f 71/68/3 74/69/4 59/70/4 +f 79/67/6 71/70/3 70/68/6 +f 71/70/3 79/67/6 86/69/3 +f 77/55/33 68/58/31 72/56/33 +f 68/58/31 77/55/33 70/57/31 +f 88/51/8 53/54/5 87/52/5 +f 53/54/5 88/51/8 54/53/8 +f 61/55/28 64/58/29 62/56/28 +f 64/58/29 61/55/28 66/57/29 +f 59/57/27 69/56/32 71/55/32 +f 69/56/32 59/57/27 60/58/27 +f 73/58/34 67/55/30 80/57/34 +f 67/55/30 73/58/34 65/56/30 +f 80/68/8 78/69/5 77/70/5 +f 78/69/5 80/68/8 81/67/8 +f 76/67/2 67/70/7 66/68/2 +f 67/70/7 76/67/2 82/69/7 +f 42/54/1 85/51/4 41/53/4 +f 85/51/4 42/54/1 57/52/1 +f 53/53/5 83/52/6 87/51/5 +f 83/52/6 53/53/5 56/54/6 +f 63/51/7 54/54/8 88/52/8 +f 54/54/8 63/51/7 55/53/7 +f 72/58/33 80/55/34 77/57/33 +f 80/55/34 72/58/33 73/56/34 + +usemtl green + +f 57/52/1 74/67/4 85/51/4 +f 74/67/4 57/52/1 75/69/1 +f 83/51/6 86/69/3 79/67/6 +f 86/69/3 83/51/6 84/52/3 +f 58/51/2 82/69/7 76/67/2 +f 82/69/7 58/51/2 63/52/7 +f 85/52/4 86/67/3 84/51/3 +f 86/67/3 85/52/4 74/69/4 +f 87/51/5 79/69/6 78/67/5 +f 79/69/6 87/51/5 83/52/6 +f 82/67/7 88/52/8 81/69/8 +f 88/52/8 82/67/7 63/51/7 +f 81/67/8 87/52/5 78/69/5 +f 87/52/5 81/67/8 88/51/8 +f 57/51/1 76/69/2 75/67/1 +f 76/69/2 57/51/1 58/52/2 + diff --git a/RATTI/checklistProjet.md b/RATTI/checklistProjet.md new file mode 100644 index 0000000000000000000000000000000000000000..224626ee4df5e3f7b6d8328f3f960822b85a46bb --- /dev/null +++ b/RATTI/checklistProjet.md @@ -0,0 +1,20 @@ +- [x] Esthetisme +- [x] Mise en page de la page web +- [ ] Paragraphe(s) d'explications techniques +- [x] Légèreté du dossier (<2Mo) (pour l'instant + que push ce qui necesaire) +- [x] Géométrie +- [x] Couleur +- [x] Transparence +- [x] Eclairage +- [x] Ombres +- [x] Position de la caméra +- [ ] Brouillard +- [x] Effet miroir +- [x] Texture classique +- [x] Texture avec transparence +- [x] Sprites +- [x] Environment map +- [x] Skybox +- [x] Animations +- [x] normal maps +- [x] Interaction par GUI diff --git a/RATTI/crow.js b/RATTI/crow.js new file mode 100644 index 0000000000000000000000000000000000000000..0ad0233eaf56899977bee87ee72434f44fa96a99 --- /dev/null +++ b/RATTI/crow.js @@ -0,0 +1,60 @@ +import * as THREE from 'three'; + +/** Adds crows to the scene */ +export class Crow { + static async addCrows(scene, count = 100) { + const shape = new THREE.Shape(); + shape.moveTo(0, 0); + shape.lineTo(-1, 2); + shape.lineTo(0, 1.5); + shape.lineTo(1, 2); + shape.lineTo(0, 0); + + const extrudeSettings = { + depth: 0.2, + bevelEnabled: false + }; + + // body of the crow + const crowGeometry = new THREE.ExtrudeGeometry(shape, extrudeSettings); + const crowMaterial = new THREE.MeshLambertMaterial({ color: 0x000000 }); + + // wing of the crow + const wingGeometry = new THREE.BoxGeometry(1.0, 0.5, 0.1); + const wingMaterial = new THREE.MeshLambertMaterial({ color: 0x000000 }); + + for (let i = 0; i < count; i++) { + const crow = new THREE.Mesh(crowGeometry, crowMaterial); + + // Enable shadows for crow body + crow.castShadow = true; + crow.receiveShadow = true; + + //setup both wings for the crow + const leftWing = new THREE.Mesh(wingGeometry, wingMaterial); + leftWing.position.set(-0.9, 1.8, 0); + leftWing.rotation.z = 0.4; + // Enable shadows for wings + leftWing.castShadow = true; + leftWing.receiveShadow = true; + crow.add(leftWing); + + const rightWing = new THREE.Mesh(wingGeometry, wingMaterial); + rightWing.position.set(0.9, 1.8, 0); + rightWing.rotation.z = -0.4; + // Enable shadows for wings + rightWing.castShadow = true; + rightWing.receiveShadow = true; + crow.add(rightWing); + + // Random position in the sky + crow.position.set( + (Math.random() - Math.random()) * 500, + Math.random() * 200, + (Math.random() - Math.random()) * 500 + ); + + scene.add(crow); + } + } +} \ No newline at end of file diff --git a/RATTI/img.jpg b/RATTI/img.jpg index d642e136257de4fb317a18f7c422126216665b16..a140327d761eff04d1528b226af07f70b677d278 100644 Binary files a/RATTI/img.jpg and b/RATTI/img.jpg differ diff --git a/RATTI/img/height.jpg b/RATTI/img/height.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a023a9230274b39cfaf176e7ace38396a33e4b87 Binary files /dev/null and b/RATTI/img/height.jpg differ diff --git a/RATTI/img/normal.png b/RATTI/img/normal.png new file mode 100644 index 0000000000000000000000000000000000000000..122aa5aff41b1967d7abf02b0f1bc736ad334394 Binary files /dev/null and b/RATTI/img/normal.png differ diff --git a/RATTI/img/skybox/day_nx.png b/RATTI/img/skybox/day_nx.png new file mode 100644 index 0000000000000000000000000000000000000000..73887d913ac77b48be483204d570abc1a4ae4eb1 Binary files /dev/null and b/RATTI/img/skybox/day_nx.png differ diff --git a/RATTI/img/skybox/day_ny.png b/RATTI/img/skybox/day_ny.png new file mode 100644 index 0000000000000000000000000000000000000000..f84f3cd8f1728052c400dba6390d61105aa4eeaa Binary files /dev/null and b/RATTI/img/skybox/day_ny.png differ diff --git a/RATTI/img/skybox/day_nz.png b/RATTI/img/skybox/day_nz.png new file mode 100644 index 0000000000000000000000000000000000000000..821f070efbc6789b24ca5a162def7464a7754174 Binary files /dev/null and b/RATTI/img/skybox/day_nz.png differ diff --git a/RATTI/img/skybox/day_px.png b/RATTI/img/skybox/day_px.png new file mode 100644 index 0000000000000000000000000000000000000000..0f29b4aad053b804fc8b8ff56198b21b3c058831 Binary files /dev/null and b/RATTI/img/skybox/day_px.png differ diff --git a/RATTI/img/skybox/day_py.png b/RATTI/img/skybox/day_py.png new file mode 100644 index 0000000000000000000000000000000000000000..774afeb3e011ea7f0d8baa8e5f4f1b6873321d48 Binary files /dev/null and b/RATTI/img/skybox/day_py.png differ diff --git a/RATTI/img/skybox/day_pz.png b/RATTI/img/skybox/day_pz.png new file mode 100644 index 0000000000000000000000000000000000000000..b3a0a3d1b1ff7c860b9e6dd5918cc27ddb3f111e Binary files /dev/null and b/RATTI/img/skybox/day_pz.png differ diff --git a/RATTI/index.html b/RATTI/index.html index 76e27dc119783f47da855d49712c43bab0798e9a..f5c42e9024ed583059106759e8d3b94a1b708885 100644 --- a/RATTI/index.html +++ b/RATTI/index.html @@ -1 +1,44 @@ -Le travail n'a pas encore commencé!!! \ No newline at end of file +<!DOCTYPE html> +<html> + +<head> + <meta charset="UTF-8"> + <title>Champs de blé aux corbeaux</title> + <link rel="stylesheet" href="style.css"> +</head> + +<body> + <!-- API importe du site de Three.js --> + <script async src="https://unpkg.com/es-module-shims@1.3.6/dist/es-module-shims.js"></script> + <script type="importmap"> + { + "imports": + { + "three": "https://threejs.org/build/three.module.js", + "three/addons/": "https://threejs.org/examples/jsm/" + } + } +</script> + <!-- JQuery pour afficher les erreurs --> + <script type="text/javascript" src="https://code.jquery.com/jquery-3.5.1.min.js"></script> + <!-- Un titre centre --> + <h1 class="centre">Champs de blé aux corbeau (WIP)</h1> +<div class="render"> + <img class="background" src="img/Champs2BleOcorbeaux.jpg"> + <div id="webGL" class="centre"></div> + <!-- Mon script avec un chemin relatif --> + <script type="module" src="paint.js"></script> + </div> + + <div class="divider"></div> + + <div class="tableau"> + <img class="tableau-img" src="img/Champs2BleOcorbeaux.jpg" alt="tableau du champs"> + <div class="tableau-presentation"> + <p>Super stylé le tableau</p> + </div> + </div> + +</body> + +</html> \ No newline at end of file diff --git a/RATTI/new_wheat.js b/RATTI/new_wheat.js new file mode 100644 index 0000000000000000000000000000000000000000..47cfd11d78adb0af64de8b99623f358db30c49b9 --- /dev/null +++ b/RATTI/new_wheat.js @@ -0,0 +1,348 @@ +import * as THREE from "three"; + +class NewWheat { + // Create a wheat field with instanced meshes + static createDynamicWheatField(scene, camera, options = {}, isInRiver) { + // Default options + const config = { + chunkSize: 20, // Size of each terrain chunk + renderDistance: 3, // How many chunks to render in each direction + density: 0.3, // Plants per square unit + variations: 3, // Number of different wheat stalk models + windIntensity: 0.2, + windFrequency: 0.4, + ...options, + }; + + // Create container for all wheat-related objects + const fieldContainer = new THREE.Group(); + scene.add(fieldContainer); + + // Create ground plane with larger size to match render distance + // const groundSize = config.chunkSize * (config.renderDistance * 2 + 1); + // const groundGeometry = new THREE.PlaneGeometry(groundSize, groundSize); + // const groundMaterial = new THREE.MeshStandardMaterial({ + // color: 0x7c6b4c, + // roughness: 0.8, + // metalness: 0.1, + // }); + // const ground = new THREE.Mesh(groundGeometry, groundMaterial); + // ground.rotation.x = -Math.PI / 2; // Rotate to be horizontal + // ground.receiveShadow = true; + // fieldContainer.add(ground); + + // Create wheat stalk geometries (several variations) + const wheatGeometries = []; + for (let i = 0; i < config.variations; i++) { + wheatGeometries.push(NewWheat.createWheatStalkGeometry(i)); + } + + // Set up instanced meshes for wheat variations + const stalksPerChunk = Math.floor( + config.chunkSize * config.chunkSize * config.density, + ); + const totalChunks = Math.pow(config.renderDistance * 2 + 1, 2); + const totalStalks = stalksPerChunk * totalChunks; + const stalksPerVariation = Math.ceil(totalStalks / config.variations); + + const wheatMaterial = new THREE.MeshStandardMaterial({ + color: 0xdfd087, + roughness: 0.7, + metalness: 0.1, + }); + + const wheatInstances = []; + + // Create instanced meshes for each geometry variation + wheatGeometries.forEach((geometry, index) => { + const instancedMesh = new THREE.InstancedMesh( + geometry, + wheatMaterial, + stalksPerVariation, + ); + instancedMesh.castShadow = true; + + fieldContainer.add(instancedMesh); + wheatInstances.push(instancedMesh); + }); + + // Map to track which chunks have been generated + const generatedChunks = new Map(); + + // Helper to get chunk coordinates from world position + const getChunkCoords = (x, z) => { + const chunkX = Math.floor(x / config.chunkSize); + const chunkZ = Math.floor(z / config.chunkSize); + return { chunkX, chunkZ }; + }; + + // Generate a chunk of wheat at the specified chunk coordinates + const generateChunk = (chunkX, chunkZ) => { + const chunkKey = `${chunkX},${chunkZ}`; + + // Skip if chunk already exists + if (generatedChunks.has(chunkKey)) return; + + const dummy = new THREE.Object3D(); + const chunkInstances = []; + + // Calculate world space boundaries of this chunk + const startX = chunkX * config.chunkSize; + const startZ = chunkZ * config.chunkSize; + const endX = startX + config.chunkSize; + const endZ = startZ + config.chunkSize; + if (isInRiver(startX, startZ) || isInRiver(endX, endZ)) { + return; + } + + // Fill chunk with wheat stalks + let localIndex = 0; + + for (let x = startX; x < endX; x += 1 / config.density) { + for (let z = startZ; z < endZ; z += 1 / config.density) { + // Add some randomness to position + const posX = x + (Math.random() - 0.5) * 0.5; + const posZ = z + (Math.random() - 0.5) * 0.5; + + // Don't place wheat on every possible position (natural look) + if (Math.random() > 0.7) continue; + + // Position wheat stalk + dummy.position.set(posX, 0, posZ); + + // Random rotation around Y axis + dummy.rotation.y = Math.random() * Math.PI * 2; + + // Random scaling (height and width) + const scale = 0.8 + Math.random() * 0.4; + dummy.scale.set(scale, scale * (0.8 + Math.random() * 0.4), scale); + + dummy.updateMatrix(); + + // Store instance data to be added to mesh + chunkInstances.push({ + meshIndex: localIndex % config.variations, + matrix: dummy.matrix.clone(), + }); + + localIndex++; + } + } + + // Add chunk metadata to map + generatedChunks.set(chunkKey, { + instances: chunkInstances, + lastUpdated: Date.now(), + }); + + // Update instanced meshes + updateInstancedMeshes(); + }; + + // Remove a chunk at the specified chunk coordinates + const removeChunk = (chunkX, chunkZ) => { + const chunkKey = `${chunkX},${chunkZ}`; + if (generatedChunks.has(chunkKey)) { + generatedChunks.delete(chunkKey); + updateInstancedMeshes(); + } + }; + + // Update all instanced meshes based on currently generated chunks + const updateInstancedMeshes = () => { + // Reset all instance counters + const instanceCounters = Array(config.variations).fill(0); + + // Collect all instances + for (const chunk of generatedChunks.values()) { + for (const instance of chunk.instances) { + const meshIndex = instance.meshIndex; + const instanceIndex = instanceCounters[meshIndex]++; + + if (instanceIndex < stalksPerVariation) { + wheatInstances[meshIndex].setMatrixAt( + instanceIndex, + instance.matrix, + ); + } + } + } + + // Update matrices and visibility + wheatInstances.forEach((instances, index) => { + instances.count = Math.min(instanceCounters[index], stalksPerVariation); + instances.instanceMatrix.needsUpdate = true; + }); + }; + + // Update the visible chunks based on camera position + const updateVisibleChunks = () => { + // Get camera position + const camPos = new THREE.Vector3(); + camera.getWorldPosition(camPos); + + // Get chunk coordinates for camera position + const { chunkX: camChunkX, chunkZ: camChunkZ } = getChunkCoords( + camPos.x, + camPos.z, + ); + + // Calculate camera view direction on xz plane + const viewDirection = new THREE.Vector3(0, 0, -1); + viewDirection.applyQuaternion(camera.quaternion); + viewDirection.y = 0; + viewDirection.normalize(); + + // Track which chunks should be visible + const visibleChunks = new Set(); + + // Add chunks in render distance (with emphasis on view direction) + for (let dx = -config.renderDistance; dx <= config.renderDistance; dx++) { + for ( + let dz = -config.renderDistance; + dz <= config.renderDistance; + dz++ + ) { + // Calculate distance from camera chunk + const distance = Math.sqrt(dx * dx + dz * dz); + + // Skip if beyond render distance + if (distance > config.renderDistance) continue; + + // Calculate direction to this chunk + const dirX = dx === 0 ? 0 : dx / Math.abs(dx); + const dirZ = dz === 0 ? 0 : dz / Math.abs(dz); + const dirVec = new THREE.Vector3(dirX, 0, dirZ).normalize(); + + // Calculate dot product with view direction + const dotProduct = viewDirection.dot(dirVec); + + // Prioritize chunks in front of camera + if (distance <= 1 || dotProduct > -0.5) { + const chunkX = camChunkX + dx; + const chunkZ = camChunkZ + dz; + const chunkKey = `${chunkX},${chunkZ}`; + + visibleChunks.add(chunkKey); + + // Generate chunk if it doesn't exist + if (!generatedChunks.has(chunkKey)) { + generateChunk(chunkX, chunkZ); + } + } + } + } + + // Remove chunks that are no longer visible + for (const chunkKey of generatedChunks.keys()) { + if (!visibleChunks.has(chunkKey)) { + const [chunkX, chunkZ] = chunkKey.split(",").map(Number); + removeChunk(chunkX, chunkZ); + } + } + + // Update ground position to follow camera + }; + + // Wind animation function + const animateWind = (time, strength) => { + wheatInstances.forEach((instances) => { + const dummy = new THREE.Object3D(); + + for (let i = 0; i < instances.count; i++) { + // Get current matrix + instances.getMatrixAt(i, dummy.matrix); + dummy.matrix.decompose(dummy.position, dummy.quaternion, dummy.scale); + + // Apply wind effect - calculate wind based on position and time + const windX = Math.sin(dummy.position.x * strength + time) * strength; + const windZ = + Math.sin(dummy.position.z * strength + time * 0.7) * strength; + + // Get original rotation (store it in quaternion) + const originalRotation = new THREE.Euler().setFromQuaternion( + dummy.quaternion, + ); + + // Apply wind bending + dummy.rotation.set( + originalRotation.x + windX, + originalRotation.y, + originalRotation.z + windZ, + ); + + // Update matrix + dummy.updateMatrix(); + instances.setMatrixAt(i, dummy.matrix); + } + + instances.instanceMatrix.needsUpdate = true; + }); + }; + + // Generate initial chunks around starting position + updateVisibleChunks(); + + return { + fieldContainer, + animateWind, + updateVisibleChunks, + }; + } + // Helper function to create a wheat stalk geometry + static createWheatStalkGeometry(variation = 0) { + // Stem + const stemGeometry = new THREE.CylinderGeometry(0.02, 0.03, 1.5, 4, 3); + stemGeometry.translate(0, 0.75, 0); + + // Top grain part + let headGeometry; + + switch (variation % 3) { + case 0: + // Standard wheat head + headGeometry = new THREE.CylinderGeometry(0.04, 0.02, 0.3, 6, 1); + headGeometry.translate(0, 1.65, 0); + break; + case 1: + // Slightly bent wheat head + headGeometry = new THREE.CylinderGeometry(0.04, 0.02, 0.35, 6, 1); + headGeometry.translate(0, 1.65, 0); + headGeometry.rotateZ(Math.PI * 0.05); + break; + case 2: + // Different shape + headGeometry = new THREE.ConeGeometry(0.05, 0.4, 6, 1); + headGeometry.translate(0, 1.7, 0); + break; + } + + // Combine geometries + const mergedGeometry = new THREE.BufferGeometry(); + + // Merge stem and head + const stemPositions = stemGeometry.getAttribute("position").array; + const headPositions = headGeometry.getAttribute("position").array; + + const positions = new Float32Array( + stemPositions.length + headPositions.length, + ); + positions.set(stemPositions, 0); + positions.set(headPositions, stemPositions.length); + + mergedGeometry.setAttribute( + "position", + new THREE.BufferAttribute(positions, 3), + ); + + // Compute normals and UVs + mergedGeometry.computeVertexNormals(); + + return mergedGeometry; + } + + // Call init function when ready + // initWheatFieldDemo(); +} + +export { NewWheat }; diff --git a/RATTI/paint.js b/RATTI/paint.js new file mode 100644 index 0000000000000000000000000000000000000000..0a76d987e5c4cc6df712ebefadb9ea6ad619cdfb --- /dev/null +++ b/RATTI/paint.js @@ -0,0 +1,332 @@ +"use strict"; +import * as THREE from "three"; +import { OBJLoader } from "three/addons/loaders/OBJLoader.js"; +import { MTLLoader } from "three/addons/loaders/MTLLoader.js"; +import { OrbitControls } from "three/addons/controls/OrbitControls.js"; +import { Reflector } from 'three/addons/objects/Reflector.js'; + +import { dat } from "./lib/dat.gui.min.js"; +import { Coordinates } from "./lib/Coordinates.js"; +import { Wheat } from "./wheat.js"; +import { Sun } from "./sun.js"; +import { Skybox } from "./skybox.js"; +import { Crow } from "./crow.js"; +import { NewWheat } from "./new_wheat.js"; +import { River } from "./river.js"; + +Wheat.getModel(); + +var camera, renderer; +window.scene = new THREE.Scene(); + +var cameraControls, effectController; +var clock = new THREE.Clock(); +var gridX = false; +var gridY = false; +var gridZ = false; +var axes = false; +var ground = true; +var chunkSize = 40; +var renderDistance = 4; +var density = 1.25; +var windIntensity = 0.0025; +var displacementScale = 2; + +//TODO faudra faire en sorte de dupliquer pour avoir un vrai champ +function addWheatField() { + Wheat.render(10, scene); +} + +let _animateWind, _updateVisibleChunks; + +function addNewWheat(isInRiver) { + const { fieldContainer, animateWind, updateVisibleChunks } = + NewWheat.createDynamicWheatField( + scene, + camera, + { + chunkSize: chunkSize, + renderDistance: renderDistance, + density: density, + windIntensity: windIntensity, + }, + isInRiver, + ); + _updateVisibleChunks = updateVisibleChunks; + _animateWind = animateWind; + + fieldContainer.traverse(child => { + if (child.isInstancedMesh) { + child.castShadow = true; + child.receiveShadow = true; + } + }); +} + +function addElMordjene() { + var mtlLoader = new MTLLoader(); + mtlLoader.setPath("3Dmodel/Peanut Butter/"); + mtlLoader.load("peanutButter.mtl", function (materials) { + materials.preload(); + var objLoader = new OBJLoader(); + objLoader.setMaterials(materials); + objLoader.setPath("3Dmodel/Peanut Butter/"); + objLoader.load("peanutButter.obj", function (object) { + object.traverse(function (child) { + if (child instanceof THREE.Mesh) { + // usage de copilot + var geometry = new THREE.BufferGeometry(); + geometry.copy(child.geometry); + geometry.computeVertexNormals(); + geometry.castShadow = true; + geometry.recieveShadow = true; + geometry.scale(10, 10, 10); + child.geometry = geometry; + } + }); + object.position.y = 2; + scene.add(object); + }); + }); +} + +/** Ajoute la portion de mirroir qui reflette a la verticale */ +function addMirror() { + let geometry = new THREE.PlaneGeometry(160, 900); + var verticalMirror = new Reflector(geometry, { + clipBias: 0.003, + textureWidth: window.innerWidth * window.devicePixelRatio, + textureHeight: window.innerHeight * window.devicePixelRatio, + color: 0xc1cbcb, + }); + verticalMirror.rotation.x = - Math.PI /-1.4 ; + verticalMirror.position.y = -200; + verticalMirror.position.x = 30; + verticalMirror.position.z = 400; + scene.add(verticalMirror); + + + +} + +function init() { + var canvasWidth = 846; + var canvasHeight = 494; + var canvasRatio = canvasWidth / canvasHeight; + + // RENDERER + renderer = new THREE.WebGLRenderer({ antialias: true }); + renderer.gammaInput = true; + renderer.gammaOutput = true; + renderer.shadowMap.enabled = true; + renderer.shadowMap.type = THREE.PCFSoftShadowMap; + + renderer.setSize(canvasWidth, canvasHeight); + renderer.setClearColor(0xaaaaaa, 1.0); + + // CAMERA + camera = new THREE.PerspectiveCamera(45, canvasRatio, 1, 40000); + camera.position.set(-20, 12, -20); + // CONTROLS + cameraControls = new OrbitControls(camera, renderer.domElement); + cameraControls.target.set(0, 6, 0); + + setupGui(); + fillScene(); +} +function addToDOM() { + var container = document.getElementById("webGL"); + var canvas = container.getElementsByTagName("canvas"); + if (canvas.length > 0) { + container.removeChild(canvas[0]); + } + container.appendChild(renderer.domElement); +} +let riverAmplitude = 3; +let riverFrequency = 0.1; +let riverWidth = 10; +function fillScene() { + // SCENE + scene = new THREE.Scene(); + scene.fog = new THREE.Fog(0x808080, 8000, 12000); + // LIGHTS + var ambientLight = new THREE.AmbientLight(0xffffff); + + var spotlight = new THREE.SpotLight(0xffffff, 2); + spotlight.position.set(10, 80, 10); + spotlight.angle = Math.PI / 6; + spotlight.penumbra = 0.3; + + spotlight.shadow.mapSize.width = 1024; + spotlight.shadow.mapSize.height = 1024; + spotlight.shadow.camera.near = 10; + spotlight.shadow.camera.far = 200; + spotlight.shadow.bias = -0.001; + spotlight.shadow.normalBias = 0.02; + + spotlight.castShadow = true; + + scene.add(spotlight); + + scene.add(ambientLight); + + if (ground) { + var groundBase = new THREE.PlaneGeometry(500, 500, 128, 128); + + const textureLoader = new THREE.TextureLoader(); + + var groundMat = new THREE.MeshStandardMaterial({ + color: "#ad8a1f", + normalMap: textureLoader.load("img/normal.png"), + normalScale: new THREE.Vector2(1.0, 1.0), + displacementMap: textureLoader.load("img/height.jpg"), + displacementScale: displacementScale, + roughness: 0.6, + metalness: 0.2, + }); + var newGround = new THREE.Mesh(groundBase, groundMat); + newGround.receiveShadow = true; + newGround.rotation.x = (-90 * Math.PI) / 180; + newGround.material.needsUpdate = true; + + scene.add(newGround); + + scene.add(newGround); + } + if (gridX) { + Coordinates.drawGrid({ size: 1000, scale: 0.01 }); + } + if (gridY) { + Coordinates.drawGrid({ size: 1000, scale: 0.01, orientation: "y" }); + } + if (gridZ) { + Coordinates.drawGrid({ size: 1000, scale: 0.01, orientation: "z" }); + } + + let howMuch = 8; + + /*for (let i = 0; i < howMuch * howMuch; i++) { + Wheat.createDifferentWheat(i % 3); + Wheat.renderWheat( + ((i % howMuch) - howMuch / 2) * 8.5, + 0, + (i / howMuch - howMuch / 2) * 8.5, + scene, + ); + }*/ + let { obj, isInRiver } = River.createRiverMesh( + { + chunkSize: chunkSize, + renderDistance: renderDistance, + riverAmplitude: riverAmplitude, + riverFrequency: riverFrequency, + riverWidth: riverWidth, + }, + new THREE.MeshLambertMaterial({ color: 0x0000ff }), + ); + obj.position.y = 3; + scene.add(obj); + Sun.addSun(scene); + addElMordjene(); + let crowsGroup = new THREE.Group(); + crowsGroup.name = "crowsGroup"; + scene.add(crowsGroup); + updateCrowCrows(effectController.crowCount); + density: 0.3, riverWidth; + + addNewWheat((x) => false); + addMirror(); + Skybox.addSkybox(scene, "day"); + + let obje = new THREE.Mesh( + new THREE.SphereGeometry(1, 32, 16), + new THREE.MeshBasicMaterial({ + color: 0xff0000, + opacity: 0.2, + transparent: true, + }), + ); + obje.position.set(0, 10, 0); + scene.add(obje); +} + +function animate() { + window.requestAnimationFrame(animate); + + _updateVisibleChunks(); + + const time = clock.getElapsedTime(); + _animateWind(time, effectController.windIntensity); + + render(); +} + +function render() { + var delta = clock.getDelta(); + cameraControls.update(delta); + if ( + effectController.newGridX !== gridX || + effectController.newGridY !== gridY || + effectController.newGridZ !== gridZ || + effectController.newGround !== ground || + effectController.newAxes !== axes + ) { + gridX = effectController.newGridX; + gridY = effectController.newGridY; + gridZ = effectController.newGridZ; + ground = effectController.newGround; + axes = effectController.newAxes; + + fillScene(); + } + renderer.render(scene, camera); +} + +function setupGui() { + effectController = { + newGridX: gridX, + newGridY: gridY, + newGridZ: gridZ, + newGround: ground, + windIntensity: windIntensity, + crowCount: 100, // Initial crow count + }; + + var gui = new dat.GUI(); + gui.add(effectController, "newGridX").name("Show XZ grid"); + gui.add(effectController, "newGridY").name("Show YZ grid"); + gui.add(effectController, "newGridZ").name("Show XY grid"); + gui.add(effectController, "newGround").name("Show ground"); + gui.add(effectController, "windIntensity").name("Wind intensity"); + + // Add a slider to control the crow count + gui + .add(effectController, "crowCount", 0, 200, 1) + .name("Crow Count") + .onChange(function (value) { + updateCrowCrows(value); + }); +} + +function updateCrowCrows(count) { + let group = scene.getObjectByName("crowsGroup"); + if (group) { + group.clear(); + } else { + group = new THREE.Group(); + group.name = "crowsGroup"; + scene.add(group); + } + + Crow.addCrows(group, count); +} +try { + init(); + addToDOM(); + animate(); +} catch (e) { + var errorReport = + "Your program encountered an unrecoverable error, can not draw on canvas. Error was:<br/><br/>"; + $("#container").append(errorReport + e); + console.log(e); +} diff --git a/RATTI/river.js b/RATTI/river.js new file mode 100755 index 0000000000000000000000000000000000000000..416cdf4e1daa5da75263bfa1a7dd6ca4aef36781 --- /dev/null +++ b/RATTI/river.js @@ -0,0 +1,113 @@ +import * as THREE from "three"; + +class River { + static getRiverXPosition = (z, config) => { + return config.riverAmplitude * Math.sin(z * config.riverFrequency); + }; + + static createRiverMesh(config, material) { + // Define river bounds + // debugger; + const riverLength = + config.chunkSize * (config.renderDistance * 2 + 1) * 1.5; // Make river longer than visible area + const halfLength = riverLength / 2; + + // Create river path points + const points = []; + const segments = 40; + + for (let i = 0; i <= segments; i++) { + const z = -halfLength + i * (riverLength / segments); + const x = River.getRiverXPosition(z, config); + points.push(new THREE.Vector2(x, z)); + } + + // Create river shape + const shape = new THREE.Shape(); + + // Define river path + const path = new THREE.Path(points); + + // Create geometry from path with width + const geometry = new THREE.BufferGeometry(); + const positions = []; + const indices = []; + + // Create vertices on both sides of the path + for (let i = 0; i < points.length; i++) { + const point = points[i]; + + // Calculate tangent vector (perpendicular to path direction) + let tangentX, tangentZ; + + if (i === 0) { + // First point - use direction to next point + tangentX = points[i + 1].y - point.y; + tangentZ = -(points[i + 1].x - point.x); + } else if (i === points.length - 1) { + // Last point - use direction from previous point + tangentX = points[i].y - points[i - 1].y; + tangentZ = -(points[i].x - points[i - 1].x); + } else { + // Middle points - average of directions + tangentX = points[i + 1].y - points[i - 1].y; + tangentZ = -(points[i + 1].x - points[i - 1].x); + } + + // Normalize tangent + const len = Math.sqrt(tangentX * tangentX + tangentZ * tangentZ); + tangentX /= len; + tangentZ /= len; + + // Calculate points on both sides of the path + const halfWidth = config.riverWidth / 2; + + // Left bank + positions.push( + point.x - tangentX * halfWidth, + 0, + point.y - tangentZ * halfWidth, + ); + + // Right bank + positions.push( + point.x + tangentX * halfWidth, + 0, + point.y + tangentZ * halfWidth, + ); + } + + // Create indices for triangles + for (let i = 0; i < points.length - 1; i++) { + const topLeft = i * 2; + const topRight = i * 2 + 1; + const bottomLeft = (i + 1) * 2; + const bottomRight = (i + 1) * 2 + 1; + + // First triangle (top-left, bottom-left, bottom-right) + indices.push(topLeft, bottomLeft, bottomRight); + + // Second triangle (top-left, bottom-right, top-right) + indices.push(topLeft, bottomRight, topRight); + } + + // Set geometry attributes + geometry.setAttribute( + "position", + new THREE.Float32BufferAttribute(positions, 3), + ); + geometry.setIndex(indices); + geometry.computeVertexNormals(); + const isInRiver = (x, z) => { + const riverCenterX = this.getRiverXPosition(z, config); + const halfWidth = config.riverWidth / 2; + return Math.abs(x - riverCenterX) < halfWidth; + }; + // Create mesh + const riverMesh = new THREE.Mesh(geometry, material); + + return { obj: riverMesh, isInRiver: isInRiver }; + } +} + +export { River }; diff --git a/RATTI/skybox.js b/RATTI/skybox.js new file mode 100644 index 0000000000000000000000000000000000000000..296c3bf9905c5c223389888b54c9fce789a3bb7e --- /dev/null +++ b/RATTI/skybox.js @@ -0,0 +1,67 @@ +import * as THREE from "three"; + +class Skybox { + static async addSkybox(scene, nomFichier) { + let skyboxGeo, skybox; + let skyboxImage = nomFichier; + + function createPathStrings(filename) { + const basePath = `./img/skybox/`; + const baseFilename = basePath + filename; + const fileType = filename == nomFichier ? '.png' : '.jpg'; + // side 1,3,up,2,4,down + // en mode face a droite puis a gauche, celle du haut, face a en face, face derriere, face du bas + const sides = ['px', 'nx', 'py', 'ny', 'pz', 'nz']; + const pathStings = sides.map(side => { + return baseFilename + '_' + side + fileType; + }); + return pathStings; + } + + function createMaterialArray(filename) { + const skyboxImagepaths = createPathStrings(filename); + const materialArray = skyboxImagepaths.map(image => { + let texture = new THREE.TextureLoader().load(image); + + return new THREE.MeshBasicMaterial({ map: texture, side: THREE.BackSide }); + }); + return materialArray; + + } + const materialArray = createMaterialArray(skyboxImage); + + //on peut modif la taille pour avoir une skybox plus large ou moins large + skyboxGeo = new THREE.BoxGeometry(10000, 10000, 10000); + skybox = new THREE.Mesh(skyboxGeo, materialArray); + + scene.add(skybox); + + // add une env map pour la reflection + + const loader = new THREE.CubeTextureLoader(); + loader.setPath('./img/skybox/'); + + var textureCube = loader.load( + [ + skyboxImage + '_px.png', + skyboxImage + '_nx.png', + skyboxImage + '_py.png', + skyboxImage + '_ny.png', + skyboxImage + '_pz.png', + skyboxImage + '_nz.png']); + + scene.background = textureCube; + + var geometry = new THREE.IcosahedronGeometry(5, 15); + var sphereMaterial = new THREE.MeshBasicMaterial({ envMap: textureCube }); + var sphereMesh = new THREE.Mesh(geometry, sphereMaterial); + sphereMesh.position.y = 10; + sphereMesh.position.x = 30; + sphereMesh.position.z = 25; + scene.add(sphereMesh); + } +} + +export { Skybox }; + + diff --git a/RATTI/style.css b/RATTI/style.css new file mode 100644 index 0000000000000000000000000000000000000000..45ae8c78d6f0eeb2c7722cf6ddb85590a1134d48 --- /dev/null +++ b/RATTI/style.css @@ -0,0 +1,37 @@ +body { + margin: 0; +} + +canvas { + width: 80%; + height: 40%; + margin: auto; + border-radius: 20px; +} + +.render{ + display: flex; + +} + +.centre { + text-align: center; +} + +.divider{ + margin: 50px +} + +.tableau{ + flex-wrap: wrap; + flex-direction: column; + +} +.tableau-presentation{ + display: flex; +} +.tableau-img{ + display: flex; + width: 380px; + height: 242px; +} \ No newline at end of file diff --git a/RATTI/sun.js b/RATTI/sun.js new file mode 100644 index 0000000000000000000000000000000000000000..738570dbd0cb19a41d124c77414fa5c0927651de --- /dev/null +++ b/RATTI/sun.js @@ -0,0 +1,40 @@ +import * as THREE from "three"; + +class Sun { + static async addSun(scene) { + const geometry = new THREE.SphereGeometry(15, 32, 16); + const material = new THREE.MeshBasicMaterial({color: 0xd2efff}); + const sphere = new THREE.Mesh(geometry, material); + + sphere.position.set(-50, 200, -200); + + const light = new THREE.DirectionalLight(0xffffff, 1.5); + light.position.copy(sphere.position); + light.castShadow = true; + + light.shadow.mapSize.width = 4096; + light.shadow.mapSize.height = 4096; + + light.shadow.camera.left = -500; + light.shadow.camera.right = 500; + light.shadow.camera.top = 500; + light.shadow.camera.bottom = -500; + light.shadow.camera.near = 10; + light.shadow.camera.far = 1000; + + light.shadow.bias = -0.0001; + light.shadow.normalBias = 0.02; + + const target = new THREE.Object3D(); + target.position.set(0, 0, 0); + scene.add(target); + light.target = target; + + scene.add(sphere); + scene.add(light); + + return { sunSphere: sphere, sunLight: light }; + } +} + +export {Sun}; \ No newline at end of file diff --git a/RATTI/wheat.js b/RATTI/wheat.js new file mode 100644 index 0000000000000000000000000000000000000000..3c164c022501efb657289c00033a3a177c22f14a --- /dev/null +++ b/RATTI/wheat.js @@ -0,0 +1,112 @@ +import { OBJLoader } from "three/addons/loaders/OBJLoader.js"; +import { MTLLoader } from "three/addons/loaders/MTLLoader.js"; +import * as THREE from "three"; + +/** Manages the Wheat */ +class Wheat { + static texture; + static async getTexture() { + return; + if (Wheat.texture == null) { + Wheat.texture = await new Promise((res, rej) => { + var mtlLoader = new MTLLoader(); + mtlLoader.setPath("3Dmodel/Field of wheat/"); + mtlLoader.load("FieldOfWheat.mtl", res, () => {}, rej); + }); + Wheat.texture.preload(); + } + return Wheat.texture; + } + + static async createDifferentWheat(variation = 0) { + const stemGeometry = new THREE.CylinderGeometry(0.02, 0.03, 1.5, 4, 3); + stemGeometry.translate(0, 0.75, 0); + + // Top grain part + let headGeometry; + + switch (variation % 3) { + case 0: + // Standard wheat head + headGeometry = new THREE.CylinderGeometry(0.04, 0.02, 0.3, 6, 1); + headGeometry.translate(0, 1.65, 0); + break; + case 1: + // Slightly bent wheat head + headGeometry = new THREE.CylinderGeometry(0.04, 0.02, 0.35, 6, 1); + headGeometry.translate(0, 1.65, 0); + headGeometry.rotateZ(Math.PI * 0.05); + break; + case 2: + // Different shape + headGeometry = new THREE.ConeGeometry(0.05, 0.4, 6, 1); + headGeometry.translate(0, 1.7, 0); + break; + } + + // Combine geometries + const mergedGeometry = new THREE.BufferGeometry(); + + // Merge stem and head + const stemPositions = stemGeometry.getAttribute("position").array; + const headPositions = headGeometry.getAttribute("position").array; + + const positions = new Float32Array( + stemPositions.length + headPositions.length, + ); + positions.set(stemPositions, 0); + positions.set(headPositions, stemPositions.length); + + mergedGeometry.setAttribute( + "position", + new THREE.BufferAttribute(positions, 3), + ); + + // Compute normals and UVs + mergedGeometry.computeVertexNormals(); + + this.model = mergedGeometry; + + return mergedGeometry; + } + + static model; + + static async getModel() { + return; + if (Wheat.model == null) { + let objLoader = new OBJLoader(); + let txt = await Wheat.getTexture(); + // let txt = new THREE.MeshBasicMaterial({ color: 0xffffff }); + console.log(txt); + await objLoader.setMaterials(txt); + objLoader.setPath("3Dmodel/Field of wheat/"); + Wheat.model = await new Promise((res, rej) => + objLoader.load("FieldOfWheat.obj", res, function () {}, rej), + ); + Wheat.model.traverse(function (child) { + if (child instanceof THREE.Mesh) { + // usage de copilot + var geometry = new THREE.BufferGeometry(); + geometry.copy(child.geometry); + geometry.computeVertexNormals(); + geometry.castShadow = true; + geometry.recieveShadow = true; + geometry.scale(1, 1, 1); + child.geometry = geometry; + } + }); + } + return Wheat.model; + } + + static async renderWheat(x, y, z, scene) { + let model = await Wheat.getModel(); + model.position.x = x; + model.position.y = y; + model.position.z = z; + scene.add(model); + } +} + +export { Wheat }; diff --git a/nirrengarten ratti phillipon-champroux/3Dmodel/Peanut Butter/peanutButter.mtl b/nirrengarten ratti phillipon-champroux/3Dmodel/Peanut Butter/peanutButter.mtl new file mode 100644 index 0000000000000000000000000000000000000000..607d39ed60cb5b74dead9a18048a23cf748d3cee --- /dev/null +++ b/nirrengarten ratti phillipon-champroux/3Dmodel/Peanut Butter/peanutButter.mtl @@ -0,0 +1,11 @@ +# Created by Kenney (www.kenney.nl) + +newmtl brownDark + Kd 0.60 0.22 0.11 + +newmtl brownLight + Kd 0.98 0.65 0.37 + +newmtl white + Kd 0.15 0.71 0.45 + diff --git a/nirrengarten ratti phillipon-champroux/3Dmodel/Peanut Butter/peanutButter.obj b/nirrengarten ratti phillipon-champroux/3Dmodel/Peanut Butter/peanutButter.obj new file mode 100644 index 0000000000000000000000000000000000000000..e340638ce97f87c3ab9a60ddd2d9b41c653f236b --- /dev/null +++ b/nirrengarten ratti phillipon-champroux/3Dmodel/Peanut Butter/peanutButter.obj @@ -0,0 +1,382 @@ +# Created by Kenney (www.kenney.nl) + +mtllib peanutButter.mtl + +g peanutButter + +v 0.08019084 0.261 0.08019084 +v 1.082867E-15 0.261 0.113407 +v 0.08019084 0.2958 0.08019084 +v 1.082867E-15 0.2958 0.113407 +v 0.08019084 0.2958 -0.08019084 +v 0.08019084 0.261 -0.08019084 +v 0.113407 0.2958 0 +v 0.113407 0.261 0 +v -0.08019084 0.261 -0.08019084 +v 1.082867E-15 0.261 -0.113407 +v -0.08019084 0.2958 -0.08019084 +v 1.082867E-15 0.2958 -0.113407 +v -0.08019084 0.261 0.08019084 +v -0.08019084 0.2958 0.08019084 +v -0.113407 0.261 0 +v -0.113407 0.2958 0 +v 0.08444745 0.2784 7.219114E-16 +v 0.05971336 0.2784 0.05971336 +v 0.05971336 0.2784 -0.05971336 +v 1.443823E-15 0.2784 -0.08444745 +v 1.443823E-15 0.2784 0.08444745 +v -0.05971336 0.2784 -0.05971336 +v -0.05971336 0.2784 0.05971336 +v -0.08444745 0.2784 7.219114E-16 +v 1.082867E-15 0.2958 -0.09706604 +v -0.06863604 0.2958 -0.06863604 +v 1.082867E-15 0.2958 0.09706604 +v 0.06863604 0.2958 0.06863604 +v -0.09706604 0.2958 0 +v 0.09706604 0.2958 0 +v -0.06863604 0.2958 0.06863604 +v 0.06863604 0.2958 -0.06863604 +v -0.1002762 0.261 0 +v -0.07090598 0.261 0.07090598 +v -0.07090598 0.261 -0.07090598 +v 1.082867E-15 0.261 0.1002762 +v 0.07090598 0.261 0.07090598 +v 1.082867E-15 0.261 -0.1002762 +v 0.07090598 0.261 -0.07090598 +v 0.1002762 0.261 0 +v 0.117972 0.2262 0 +v 0.0834188 0.2262 0.0834188 +v 0.1002762 0.2436 0 +v 0.07090598 0.2436 0.07090598 +v -0.07090598 0.2436 -0.07090598 +v -0.1002762 0.2436 0 +v 7.219114E-16 0.2262 0.117972 +v 1.082867E-15 0.2436 0.1002762 +v 0.0834188 0.2262 -0.0834188 +v 0.07090598 0.2436 -0.07090598 +v 1.082867E-15 0.2436 -0.1002762 +v -0.07090598 0.2436 0.07090598 +v -0.0834188 0.2262 -0.0834188 +v -0.117972 0.2262 0 +v -0.0834188 0.2262 0.0834188 +v 7.219114E-16 0.2262 -0.117972 +v 0.0834188 0.202275 0.0834188 +v 7.219114E-16 0.202275 0.117972 +v 0.117972 0.0348 0 +v 0.1044 0 7.219114E-16 +v 0.0834188 0.0348 0.0834188 +v 0.07382195 0 0.07382195 +v -0.0834188 0.202275 0.0834188 +v -3.609557E-16 0 0.1044 +v -0.07382195 0 0.07382195 +v 7.219114E-16 0.0348 0.117972 +v -0.0834188 0.0348 0.0834188 +v -3.609557E-16 0 -0.1044 +v 0.07382195 0 -0.07382195 +v 7.219114E-16 0.0348 -0.117972 +v 0.0834188 0.0348 -0.0834188 +v -0.07382195 0 -0.07382195 +v -0.1044 0 7.219114E-16 +v 0.117972 0.058725 0 +v 0.0834188 0.058725 0.0834188 +v 7.219114E-16 0.058725 0.117972 +v -0.0834188 0.0348 -0.0834188 +v -0.0834188 0.058725 -0.0834188 +v 7.219114E-16 0.058725 -0.117972 +v -0.117972 0.0348 0 +v -0.117972 0.058725 0 +v -0.0834188 0.058725 0.0834188 +v 7.219114E-16 0.202275 -0.117972 +v 0.0834188 0.202275 -0.0834188 +v 0.117972 0.202275 0 +v 0.0834188 0.058725 -0.0834188 +v -0.0834188 0.202275 -0.0834188 +v -0.117972 0.202275 0 + +vn 0.7071068 0 0.7071068 +vn 0 0 1 +vn 0.7071068 0 -0.7071068 +vn 1 0 0 +vn -0.7071068 0 -0.7071068 +vn 0 0 -1 +vn -0.7071068 0 0.7071068 +vn -1 0 0 +vn 0 1 0 +vn 0 0.5870768 0.8095312 +vn 0.572425 0.5870768 0.572425 +vn 0 0.5870768 -0.8095312 +vn -0.572425 0.5870768 -0.572425 +vn 0.8095312 0.5870768 0 +vn -0.8095312 0.5870768 0 +vn 0.572425 0.5870768 -0.572425 +vn -0.572425 0.5870768 0.572425 +vn 0 -1 0 +vn 0.7011221 0.7130412 0 +vn 0.4957682 0.7130412 0.4957682 +vn 0 0.7130412 0.7011221 +vn 0.4957682 0.7130412 -0.4957682 +vn -0.4957682 0.7130412 -0.4957682 +vn -0.7011221 0.7130412 0 +vn -0.4957682 0.7130412 0.4957682 +vn 0 0.7130412 -0.7011221 +vn 0.9316545 -0.3633452 0 +vn 0.6587793 -0.3633452 0.6587793 +vn 0 -0.3633452 0.9316545 +vn -0.6587793 -0.3633452 0.6587793 +vn 0 -0.3633452 -0.9316545 +vn 0.6587793 -0.3633452 -0.6587793 +vn -0.6587793 -0.3633452 -0.6587793 +vn -0.9316545 -0.3633452 0 + +vt 1.708621 10.27559 +vt -1.708621 10.27559 +vt 1.708621 11.64567 +vt -1.708621 11.64567 +vt -3.324703 2.842171E-14 +vt -2.35092 2.35092 +vt -2.35092 -2.35092 +vt -5.684342E-14 -3.324703 +vt -5.684342E-14 3.324703 +vt 2.35092 -2.35092 +vt 2.35092 2.35092 +vt 3.324703 2.842171E-14 +vt 1.272309 10.81547 +vt -1.272309 10.81547 +vt 1.462424 11.64005 +vt -1.462424 11.64005 +vt -4.464842 0 +vt -3.15712 3.15712 +vt -3.947882 0 +vt -3.15712 -3.15712 +vt -2.791574 2.791574 +vt -2.791574 -2.791574 +vt 4.263256E-14 3.947882 +vt 4.263256E-14 4.464842 +vt 2.791574 2.791574 +vt 3.15712 3.15712 +vt 4.263256E-14 -4.464842 +vt 4.263256E-14 -3.947882 +vt 2.791574 -2.791574 +vt 3.15712 -3.15712 +vt 3.947882 0 +vt 4.464842 0 +vt 2.702207 -2.702207 +vt -4.263256E-14 -3.821497 +vt 3.821497 0 +vt -4.263256E-14 -4.464842 +vt -2.702207 -2.702207 +vt 2.702207 2.702207 +vt -3.821497 0 +vt -2.702207 2.702207 +vt -4.263256E-14 4.464842 +vt -4.263256E-14 3.821497 +vt 1.777399 3.55187 +vt -1.777399 3.55187 +vt 1.510789 4.491853 +vt -1.510789 4.491853 +vt -1.510789 9.590551 +vt -1.510789 10.27559 +vt 1.510789 9.590551 +vt 1.510789 10.27559 +vt 1.777399 7.963583 +vt -1.777399 7.963583 +vt 1.777399 8.905512 +vt -1.777399 8.905512 +vt 1.777399 2.743532 +vt 1.572919 1.287231 +vt -1.777399 2.743532 +vt -1.572919 1.287231 +vt 4.110236 2.842171E-14 +vt 2.906376 -2.906376 +vt 2.906376 2.906376 +vt -1.421085E-14 4.110236 +vt -1.421085E-14 -4.110236 +vt -2.906376 2.906376 +vt -2.906376 -2.906376 +vt -4.110236 2.842171E-14 +vt 1.777399 2.312008 +vt 1.777399 1.370079 +vt -1.777399 2.312008 +vt -1.777399 1.370079 + +usemtl brownDark + +f 3/3/1 2/2/2 1/1/1 +f 2/2/2 3/3/1 4/4/2 +f 7/4/4 6/1/3 5/3/3 +f 6/1/3 7/4/4 8/2/4 +f 11/3/5 10/2/6 9/1/5 +f 10/2/6 11/3/5 12/4/6 +f 4/3/2 13/2/7 2/1/2 +f 13/2/7 4/3/2 14/4/7 +f 12/3/6 6/2/3 10/1/6 +f 6/2/3 12/3/6 5/4/3 +f 3/4/1 8/1/4 7/3/4 +f 8/1/4 3/4/1 1/2/1 +f 15/1/8 11/4/5 9/2/5 +f 11/4/5 15/1/8 16/3/8 +f 19/7/9 18/6/9 17/5/9 +f 18/6/9 19/7/9 20/8/9 +f 18/6/9 20/8/9 21/9/9 +f 21/9/9 20/8/9 22/10/9 +f 21/9/9 22/10/9 23/11/9 +f 23/11/9 22/10/9 24/12/9 +f 25/15/10 22/14/11 20/13/10 +f 22/14/11 25/15/10 26/16/11 +f 27/15/12 18/14/13 21/13/12 +f 18/14/13 27/15/12 28/16/13 +f 29/16/14 22/13/11 26/15/11 +f 22/13/11 29/16/14 24/14/14 +f 17/14/15 28/15/13 30/16/15 +f 28/15/13 17/14/15 18/13/13 +f 31/16/16 24/13/14 29/15/14 +f 24/13/14 31/16/16 23/14/16 +f 32/15/17 20/14/10 19/13/17 +f 20/14/10 32/15/17 25/16/10 +f 13/1/7 16/4/8 15/2/8 +f 16/4/8 13/1/7 14/3/7 +f 19/14/17 30/15/15 32/16/17 +f 30/15/15 19/14/17 17/13/15 +f 31/15/16 21/14/12 23/13/16 +f 21/14/12 31/15/16 27/16/12 +f 33/19/18 13/18/18 15/17/18 +f 9/20/18 33/19/18 15/17/18 +f 34/21/18 13/18/18 33/19/18 +f 9/20/18 35/22/18 33/19/18 +f 36/23/18 13/18/18 34/21/18 +f 36/23/18 2/24/18 13/18/18 +f 37/25/18 2/24/18 36/23/18 +f 37/25/18 1/26/18 2/24/18 +f 10/27/18 35/22/18 9/20/18 +f 10/27/18 38/28/18 35/22/18 +f 10/27/18 39/29/18 38/28/18 +f 6/30/18 39/29/18 10/27/18 +f 40/31/18 1/26/18 37/25/18 +f 6/30/18 40/31/18 39/29/18 +f 1/26/18 40/31/18 8/32/18 +f 40/31/18 6/30/18 8/32/18 +f 25/34/9 11/30/9 26/33/9 +f 26/33/9 11/30/9 29/35/9 +f 25/34/9 12/36/9 11/30/9 +f 29/35/9 11/30/9 16/32/9 +f 32/37/9 12/36/9 25/34/9 +f 14/26/9 29/35/9 16/32/9 +f 32/37/9 5/20/9 12/36/9 +f 14/26/9 31/38/9 29/35/9 +f 30/39/9 5/20/9 32/37/9 +f 5/20/9 30/39/9 7/17/9 +f 30/39/9 3/18/9 7/17/9 +f 3/18/9 30/39/9 28/40/9 +f 4/41/9 31/38/9 14/26/9 +f 3/18/9 28/40/9 4/41/9 +f 4/41/9 27/42/9 31/38/9 +f 4/41/9 28/40/9 27/42/9 + +usemtl brownLight + +f 43/45/19 42/44/20 41/43/19 +f 42/44/20 43/45/19 44/46/20 +f 46/49/8 35/48/5 45/47/5 +f 35/48/5 46/49/8 33/50/8 +f 44/45/20 47/44/21 42/43/20 +f 47/44/21 44/45/20 48/46/21 +f 49/43/22 43/46/19 41/44/19 +f 43/46/19 49/43/22 50/45/22 +f 38/50/6 50/47/3 51/49/6 +f 50/47/3 38/50/6 39/48/3 +f 52/49/7 33/48/8 46/47/8 +f 33/48/8 52/49/7 34/50/7 +f 53/44/23 46/45/24 45/46/23 +f 46/45/24 53/44/23 54/43/24 +f 37/48/1 43/49/4 40/50/4 +f 43/49/4 37/48/1 44/47/1 +f 35/50/5 51/47/6 45/49/5 +f 51/47/6 35/50/5 38/48/6 +f 36/50/2 52/47/7 48/49/2 +f 52/47/7 36/50/2 34/48/7 +f 52/46/25 47/43/21 48/45/21 +f 47/43/21 52/46/25 55/44/25 +f 40/48/4 50/49/3 39/50/3 +f 50/49/3 40/48/4 43/47/4 +f 37/50/1 48/47/2 44/49/1 +f 48/47/2 37/50/1 36/48/2 +f 46/46/24 55/43/25 52/45/25 +f 55/43/25 46/46/24 54/44/24 +f 56/43/26 50/46/22 49/44/22 +f 50/46/22 56/43/26 51/45/26 +f 56/44/26 45/45/23 51/46/26 +f 45/45/23 56/44/26 53/43/23 +f 42/53/1 58/52/2 57/51/1 +f 58/52/2 42/53/1 47/54/2 +f 61/57/28 60/56/27 59/55/27 +f 60/56/27 61/57/28 62/58/28 +f 47/53/2 63/52/7 58/51/2 +f 63/52/7 47/53/2 55/54/7 +f 66/55/29 65/58/30 64/56/29 +f 65/58/30 66/55/29 67/57/30 +f 70/55/31 69/58/32 68/56/31 +f 69/58/32 70/55/31 71/57/32 +f 62/61/18 69/60/18 60/59/18 +f 69/60/18 62/61/18 64/62/18 +f 69/60/18 64/62/18 68/63/18 +f 68/63/18 64/62/18 65/64/18 +f 68/63/18 65/64/18 72/65/18 +f 72/65/18 65/64/18 73/66/18 +f 75/69/1 59/68/4 74/67/4 +f 59/68/4 75/69/1 61/70/1 +f 75/67/1 66/70/2 61/68/1 +f 66/70/2 75/67/1 76/69/2 +f 78/67/5 70/70/6 77/68/5 +f 70/70/6 78/67/5 79/69/6 +f 67/68/7 81/69/8 80/70/8 +f 81/69/8 67/68/7 82/67/7 +f 56/53/6 84/52/3 83/51/6 +f 84/52/3 56/53/6 49/54/3 +f 41/54/4 84/51/3 49/53/3 +f 84/51/3 41/54/4 85/52/4 +f 74/69/4 71/68/3 86/67/3 +f 71/68/3 74/69/4 59/70/4 +f 79/67/6 71/70/3 70/68/6 +f 71/70/3 79/67/6 86/69/3 +f 77/55/33 68/58/31 72/56/33 +f 68/58/31 77/55/33 70/57/31 +f 88/51/8 53/54/5 87/52/5 +f 53/54/5 88/51/8 54/53/8 +f 61/55/28 64/58/29 62/56/28 +f 64/58/29 61/55/28 66/57/29 +f 59/57/27 69/56/32 71/55/32 +f 69/56/32 59/57/27 60/58/27 +f 73/58/34 67/55/30 80/57/34 +f 67/55/30 73/58/34 65/56/30 +f 80/68/8 78/69/5 77/70/5 +f 78/69/5 80/68/8 81/67/8 +f 76/67/2 67/70/7 66/68/2 +f 67/70/7 76/67/2 82/69/7 +f 42/54/1 85/51/4 41/53/4 +f 85/51/4 42/54/1 57/52/1 +f 53/53/5 83/52/6 87/51/5 +f 83/52/6 53/53/5 56/54/6 +f 63/51/7 54/54/8 88/52/8 +f 54/54/8 63/51/7 55/53/7 +f 72/58/33 80/55/34 77/57/33 +f 80/55/34 72/58/33 73/56/34 + +usemtl green + +f 57/52/1 74/67/4 85/51/4 +f 74/67/4 57/52/1 75/69/1 +f 83/51/6 86/69/3 79/67/6 +f 86/69/3 83/51/6 84/52/3 +f 58/51/2 82/69/7 76/67/2 +f 82/69/7 58/51/2 63/52/7 +f 85/52/4 86/67/3 84/51/3 +f 86/67/3 85/52/4 74/69/4 +f 87/51/5 79/69/6 78/67/5 +f 79/69/6 87/51/5 83/52/6 +f 82/67/7 88/52/8 81/69/8 +f 88/52/8 82/67/7 63/51/7 +f 81/67/8 87/52/5 78/69/5 +f 87/52/5 81/67/8 88/51/8 +f 57/51/1 76/69/2 75/67/1 +f 76/69/2 57/51/1 58/52/2 + diff --git a/nirrengarten ratti phillipon-champroux/checklistProjet.md b/nirrengarten ratti phillipon-champroux/checklistProjet.md new file mode 100644 index 0000000000000000000000000000000000000000..224626ee4df5e3f7b6d8328f3f960822b85a46bb --- /dev/null +++ b/nirrengarten ratti phillipon-champroux/checklistProjet.md @@ -0,0 +1,20 @@ +- [x] Esthetisme +- [x] Mise en page de la page web +- [ ] Paragraphe(s) d'explications techniques +- [x] Légèreté du dossier (<2Mo) (pour l'instant + que push ce qui necesaire) +- [x] Géométrie +- [x] Couleur +- [x] Transparence +- [x] Eclairage +- [x] Ombres +- [x] Position de la caméra +- [ ] Brouillard +- [x] Effet miroir +- [x] Texture classique +- [x] Texture avec transparence +- [x] Sprites +- [x] Environment map +- [x] Skybox +- [x] Animations +- [x] normal maps +- [x] Interaction par GUI diff --git a/nirrengarten ratti phillipon-champroux/crow.js b/nirrengarten ratti phillipon-champroux/crow.js new file mode 100644 index 0000000000000000000000000000000000000000..0ad0233eaf56899977bee87ee72434f44fa96a99 --- /dev/null +++ b/nirrengarten ratti phillipon-champroux/crow.js @@ -0,0 +1,60 @@ +import * as THREE from 'three'; + +/** Adds crows to the scene */ +export class Crow { + static async addCrows(scene, count = 100) { + const shape = new THREE.Shape(); + shape.moveTo(0, 0); + shape.lineTo(-1, 2); + shape.lineTo(0, 1.5); + shape.lineTo(1, 2); + shape.lineTo(0, 0); + + const extrudeSettings = { + depth: 0.2, + bevelEnabled: false + }; + + // body of the crow + const crowGeometry = new THREE.ExtrudeGeometry(shape, extrudeSettings); + const crowMaterial = new THREE.MeshLambertMaterial({ color: 0x000000 }); + + // wing of the crow + const wingGeometry = new THREE.BoxGeometry(1.0, 0.5, 0.1); + const wingMaterial = new THREE.MeshLambertMaterial({ color: 0x000000 }); + + for (let i = 0; i < count; i++) { + const crow = new THREE.Mesh(crowGeometry, crowMaterial); + + // Enable shadows for crow body + crow.castShadow = true; + crow.receiveShadow = true; + + //setup both wings for the crow + const leftWing = new THREE.Mesh(wingGeometry, wingMaterial); + leftWing.position.set(-0.9, 1.8, 0); + leftWing.rotation.z = 0.4; + // Enable shadows for wings + leftWing.castShadow = true; + leftWing.receiveShadow = true; + crow.add(leftWing); + + const rightWing = new THREE.Mesh(wingGeometry, wingMaterial); + rightWing.position.set(0.9, 1.8, 0); + rightWing.rotation.z = -0.4; + // Enable shadows for wings + rightWing.castShadow = true; + rightWing.receiveShadow = true; + crow.add(rightWing); + + // Random position in the sky + crow.position.set( + (Math.random() - Math.random()) * 500, + Math.random() * 200, + (Math.random() - Math.random()) * 500 + ); + + scene.add(crow); + } + } +} \ No newline at end of file diff --git a/nirrengarten ratti phillipon-champroux/img.jpg b/nirrengarten ratti phillipon-champroux/img.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a140327d761eff04d1528b226af07f70b677d278 Binary files /dev/null and b/nirrengarten ratti phillipon-champroux/img.jpg differ diff --git a/nirrengarten ratti phillipon-champroux/img/height.jpg b/nirrengarten ratti phillipon-champroux/img/height.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a023a9230274b39cfaf176e7ace38396a33e4b87 Binary files /dev/null and b/nirrengarten ratti phillipon-champroux/img/height.jpg differ diff --git a/nirrengarten ratti phillipon-champroux/img/normal.png b/nirrengarten ratti phillipon-champroux/img/normal.png new file mode 100644 index 0000000000000000000000000000000000000000..122aa5aff41b1967d7abf02b0f1bc736ad334394 Binary files /dev/null and b/nirrengarten ratti phillipon-champroux/img/normal.png differ diff --git a/nirrengarten ratti phillipon-champroux/img/skybox/day_nx.png b/nirrengarten ratti phillipon-champroux/img/skybox/day_nx.png new file mode 100644 index 0000000000000000000000000000000000000000..73887d913ac77b48be483204d570abc1a4ae4eb1 Binary files /dev/null and b/nirrengarten ratti phillipon-champroux/img/skybox/day_nx.png differ diff --git a/nirrengarten ratti phillipon-champroux/img/skybox/day_ny.png b/nirrengarten ratti phillipon-champroux/img/skybox/day_ny.png new file mode 100644 index 0000000000000000000000000000000000000000..f84f3cd8f1728052c400dba6390d61105aa4eeaa Binary files /dev/null and b/nirrengarten ratti phillipon-champroux/img/skybox/day_ny.png differ diff --git a/nirrengarten ratti phillipon-champroux/img/skybox/day_nz.png b/nirrengarten ratti phillipon-champroux/img/skybox/day_nz.png new file mode 100644 index 0000000000000000000000000000000000000000..821f070efbc6789b24ca5a162def7464a7754174 Binary files /dev/null and b/nirrengarten ratti phillipon-champroux/img/skybox/day_nz.png differ diff --git a/nirrengarten ratti phillipon-champroux/img/skybox/day_px.png b/nirrengarten ratti phillipon-champroux/img/skybox/day_px.png new file mode 100644 index 0000000000000000000000000000000000000000..0f29b4aad053b804fc8b8ff56198b21b3c058831 Binary files /dev/null and b/nirrengarten ratti phillipon-champroux/img/skybox/day_px.png differ diff --git a/nirrengarten ratti phillipon-champroux/img/skybox/day_py.png b/nirrengarten ratti phillipon-champroux/img/skybox/day_py.png new file mode 100644 index 0000000000000000000000000000000000000000..774afeb3e011ea7f0d8baa8e5f4f1b6873321d48 Binary files /dev/null and b/nirrengarten ratti phillipon-champroux/img/skybox/day_py.png differ diff --git a/nirrengarten ratti phillipon-champroux/img/skybox/day_pz.png b/nirrengarten ratti phillipon-champroux/img/skybox/day_pz.png new file mode 100644 index 0000000000000000000000000000000000000000..b3a0a3d1b1ff7c860b9e6dd5918cc27ddb3f111e Binary files /dev/null and b/nirrengarten ratti phillipon-champroux/img/skybox/day_pz.png differ diff --git a/nirrengarten ratti phillipon-champroux/index.html b/nirrengarten ratti phillipon-champroux/index.html new file mode 100644 index 0000000000000000000000000000000000000000..f5c42e9024ed583059106759e8d3b94a1b708885 --- /dev/null +++ b/nirrengarten ratti phillipon-champroux/index.html @@ -0,0 +1,44 @@ +<!DOCTYPE html> +<html> + +<head> + <meta charset="UTF-8"> + <title>Champs de blé aux corbeaux</title> + <link rel="stylesheet" href="style.css"> +</head> + +<body> + <!-- API importe du site de Three.js --> + <script async src="https://unpkg.com/es-module-shims@1.3.6/dist/es-module-shims.js"></script> + <script type="importmap"> + { + "imports": + { + "three": "https://threejs.org/build/three.module.js", + "three/addons/": "https://threejs.org/examples/jsm/" + } + } +</script> + <!-- JQuery pour afficher les erreurs --> + <script type="text/javascript" src="https://code.jquery.com/jquery-3.5.1.min.js"></script> + <!-- Un titre centre --> + <h1 class="centre">Champs de blé aux corbeau (WIP)</h1> +<div class="render"> + <img class="background" src="img/Champs2BleOcorbeaux.jpg"> + <div id="webGL" class="centre"></div> + <!-- Mon script avec un chemin relatif --> + <script type="module" src="paint.js"></script> + </div> + + <div class="divider"></div> + + <div class="tableau"> + <img class="tableau-img" src="img/Champs2BleOcorbeaux.jpg" alt="tableau du champs"> + <div class="tableau-presentation"> + <p>Super stylé le tableau</p> + </div> + </div> + +</body> + +</html> \ No newline at end of file diff --git a/nirrengarten ratti phillipon-champroux/new_wheat.js b/nirrengarten ratti phillipon-champroux/new_wheat.js new file mode 100644 index 0000000000000000000000000000000000000000..47cfd11d78adb0af64de8b99623f358db30c49b9 --- /dev/null +++ b/nirrengarten ratti phillipon-champroux/new_wheat.js @@ -0,0 +1,348 @@ +import * as THREE from "three"; + +class NewWheat { + // Create a wheat field with instanced meshes + static createDynamicWheatField(scene, camera, options = {}, isInRiver) { + // Default options + const config = { + chunkSize: 20, // Size of each terrain chunk + renderDistance: 3, // How many chunks to render in each direction + density: 0.3, // Plants per square unit + variations: 3, // Number of different wheat stalk models + windIntensity: 0.2, + windFrequency: 0.4, + ...options, + }; + + // Create container for all wheat-related objects + const fieldContainer = new THREE.Group(); + scene.add(fieldContainer); + + // Create ground plane with larger size to match render distance + // const groundSize = config.chunkSize * (config.renderDistance * 2 + 1); + // const groundGeometry = new THREE.PlaneGeometry(groundSize, groundSize); + // const groundMaterial = new THREE.MeshStandardMaterial({ + // color: 0x7c6b4c, + // roughness: 0.8, + // metalness: 0.1, + // }); + // const ground = new THREE.Mesh(groundGeometry, groundMaterial); + // ground.rotation.x = -Math.PI / 2; // Rotate to be horizontal + // ground.receiveShadow = true; + // fieldContainer.add(ground); + + // Create wheat stalk geometries (several variations) + const wheatGeometries = []; + for (let i = 0; i < config.variations; i++) { + wheatGeometries.push(NewWheat.createWheatStalkGeometry(i)); + } + + // Set up instanced meshes for wheat variations + const stalksPerChunk = Math.floor( + config.chunkSize * config.chunkSize * config.density, + ); + const totalChunks = Math.pow(config.renderDistance * 2 + 1, 2); + const totalStalks = stalksPerChunk * totalChunks; + const stalksPerVariation = Math.ceil(totalStalks / config.variations); + + const wheatMaterial = new THREE.MeshStandardMaterial({ + color: 0xdfd087, + roughness: 0.7, + metalness: 0.1, + }); + + const wheatInstances = []; + + // Create instanced meshes for each geometry variation + wheatGeometries.forEach((geometry, index) => { + const instancedMesh = new THREE.InstancedMesh( + geometry, + wheatMaterial, + stalksPerVariation, + ); + instancedMesh.castShadow = true; + + fieldContainer.add(instancedMesh); + wheatInstances.push(instancedMesh); + }); + + // Map to track which chunks have been generated + const generatedChunks = new Map(); + + // Helper to get chunk coordinates from world position + const getChunkCoords = (x, z) => { + const chunkX = Math.floor(x / config.chunkSize); + const chunkZ = Math.floor(z / config.chunkSize); + return { chunkX, chunkZ }; + }; + + // Generate a chunk of wheat at the specified chunk coordinates + const generateChunk = (chunkX, chunkZ) => { + const chunkKey = `${chunkX},${chunkZ}`; + + // Skip if chunk already exists + if (generatedChunks.has(chunkKey)) return; + + const dummy = new THREE.Object3D(); + const chunkInstances = []; + + // Calculate world space boundaries of this chunk + const startX = chunkX * config.chunkSize; + const startZ = chunkZ * config.chunkSize; + const endX = startX + config.chunkSize; + const endZ = startZ + config.chunkSize; + if (isInRiver(startX, startZ) || isInRiver(endX, endZ)) { + return; + } + + // Fill chunk with wheat stalks + let localIndex = 0; + + for (let x = startX; x < endX; x += 1 / config.density) { + for (let z = startZ; z < endZ; z += 1 / config.density) { + // Add some randomness to position + const posX = x + (Math.random() - 0.5) * 0.5; + const posZ = z + (Math.random() - 0.5) * 0.5; + + // Don't place wheat on every possible position (natural look) + if (Math.random() > 0.7) continue; + + // Position wheat stalk + dummy.position.set(posX, 0, posZ); + + // Random rotation around Y axis + dummy.rotation.y = Math.random() * Math.PI * 2; + + // Random scaling (height and width) + const scale = 0.8 + Math.random() * 0.4; + dummy.scale.set(scale, scale * (0.8 + Math.random() * 0.4), scale); + + dummy.updateMatrix(); + + // Store instance data to be added to mesh + chunkInstances.push({ + meshIndex: localIndex % config.variations, + matrix: dummy.matrix.clone(), + }); + + localIndex++; + } + } + + // Add chunk metadata to map + generatedChunks.set(chunkKey, { + instances: chunkInstances, + lastUpdated: Date.now(), + }); + + // Update instanced meshes + updateInstancedMeshes(); + }; + + // Remove a chunk at the specified chunk coordinates + const removeChunk = (chunkX, chunkZ) => { + const chunkKey = `${chunkX},${chunkZ}`; + if (generatedChunks.has(chunkKey)) { + generatedChunks.delete(chunkKey); + updateInstancedMeshes(); + } + }; + + // Update all instanced meshes based on currently generated chunks + const updateInstancedMeshes = () => { + // Reset all instance counters + const instanceCounters = Array(config.variations).fill(0); + + // Collect all instances + for (const chunk of generatedChunks.values()) { + for (const instance of chunk.instances) { + const meshIndex = instance.meshIndex; + const instanceIndex = instanceCounters[meshIndex]++; + + if (instanceIndex < stalksPerVariation) { + wheatInstances[meshIndex].setMatrixAt( + instanceIndex, + instance.matrix, + ); + } + } + } + + // Update matrices and visibility + wheatInstances.forEach((instances, index) => { + instances.count = Math.min(instanceCounters[index], stalksPerVariation); + instances.instanceMatrix.needsUpdate = true; + }); + }; + + // Update the visible chunks based on camera position + const updateVisibleChunks = () => { + // Get camera position + const camPos = new THREE.Vector3(); + camera.getWorldPosition(camPos); + + // Get chunk coordinates for camera position + const { chunkX: camChunkX, chunkZ: camChunkZ } = getChunkCoords( + camPos.x, + camPos.z, + ); + + // Calculate camera view direction on xz plane + const viewDirection = new THREE.Vector3(0, 0, -1); + viewDirection.applyQuaternion(camera.quaternion); + viewDirection.y = 0; + viewDirection.normalize(); + + // Track which chunks should be visible + const visibleChunks = new Set(); + + // Add chunks in render distance (with emphasis on view direction) + for (let dx = -config.renderDistance; dx <= config.renderDistance; dx++) { + for ( + let dz = -config.renderDistance; + dz <= config.renderDistance; + dz++ + ) { + // Calculate distance from camera chunk + const distance = Math.sqrt(dx * dx + dz * dz); + + // Skip if beyond render distance + if (distance > config.renderDistance) continue; + + // Calculate direction to this chunk + const dirX = dx === 0 ? 0 : dx / Math.abs(dx); + const dirZ = dz === 0 ? 0 : dz / Math.abs(dz); + const dirVec = new THREE.Vector3(dirX, 0, dirZ).normalize(); + + // Calculate dot product with view direction + const dotProduct = viewDirection.dot(dirVec); + + // Prioritize chunks in front of camera + if (distance <= 1 || dotProduct > -0.5) { + const chunkX = camChunkX + dx; + const chunkZ = camChunkZ + dz; + const chunkKey = `${chunkX},${chunkZ}`; + + visibleChunks.add(chunkKey); + + // Generate chunk if it doesn't exist + if (!generatedChunks.has(chunkKey)) { + generateChunk(chunkX, chunkZ); + } + } + } + } + + // Remove chunks that are no longer visible + for (const chunkKey of generatedChunks.keys()) { + if (!visibleChunks.has(chunkKey)) { + const [chunkX, chunkZ] = chunkKey.split(",").map(Number); + removeChunk(chunkX, chunkZ); + } + } + + // Update ground position to follow camera + }; + + // Wind animation function + const animateWind = (time, strength) => { + wheatInstances.forEach((instances) => { + const dummy = new THREE.Object3D(); + + for (let i = 0; i < instances.count; i++) { + // Get current matrix + instances.getMatrixAt(i, dummy.matrix); + dummy.matrix.decompose(dummy.position, dummy.quaternion, dummy.scale); + + // Apply wind effect - calculate wind based on position and time + const windX = Math.sin(dummy.position.x * strength + time) * strength; + const windZ = + Math.sin(dummy.position.z * strength + time * 0.7) * strength; + + // Get original rotation (store it in quaternion) + const originalRotation = new THREE.Euler().setFromQuaternion( + dummy.quaternion, + ); + + // Apply wind bending + dummy.rotation.set( + originalRotation.x + windX, + originalRotation.y, + originalRotation.z + windZ, + ); + + // Update matrix + dummy.updateMatrix(); + instances.setMatrixAt(i, dummy.matrix); + } + + instances.instanceMatrix.needsUpdate = true; + }); + }; + + // Generate initial chunks around starting position + updateVisibleChunks(); + + return { + fieldContainer, + animateWind, + updateVisibleChunks, + }; + } + // Helper function to create a wheat stalk geometry + static createWheatStalkGeometry(variation = 0) { + // Stem + const stemGeometry = new THREE.CylinderGeometry(0.02, 0.03, 1.5, 4, 3); + stemGeometry.translate(0, 0.75, 0); + + // Top grain part + let headGeometry; + + switch (variation % 3) { + case 0: + // Standard wheat head + headGeometry = new THREE.CylinderGeometry(0.04, 0.02, 0.3, 6, 1); + headGeometry.translate(0, 1.65, 0); + break; + case 1: + // Slightly bent wheat head + headGeometry = new THREE.CylinderGeometry(0.04, 0.02, 0.35, 6, 1); + headGeometry.translate(0, 1.65, 0); + headGeometry.rotateZ(Math.PI * 0.05); + break; + case 2: + // Different shape + headGeometry = new THREE.ConeGeometry(0.05, 0.4, 6, 1); + headGeometry.translate(0, 1.7, 0); + break; + } + + // Combine geometries + const mergedGeometry = new THREE.BufferGeometry(); + + // Merge stem and head + const stemPositions = stemGeometry.getAttribute("position").array; + const headPositions = headGeometry.getAttribute("position").array; + + const positions = new Float32Array( + stemPositions.length + headPositions.length, + ); + positions.set(stemPositions, 0); + positions.set(headPositions, stemPositions.length); + + mergedGeometry.setAttribute( + "position", + new THREE.BufferAttribute(positions, 3), + ); + + // Compute normals and UVs + mergedGeometry.computeVertexNormals(); + + return mergedGeometry; + } + + // Call init function when ready + // initWheatFieldDemo(); +} + +export { NewWheat }; diff --git a/nirrengarten ratti phillipon-champroux/paint.js b/nirrengarten ratti phillipon-champroux/paint.js new file mode 100644 index 0000000000000000000000000000000000000000..0a76d987e5c4cc6df712ebefadb9ea6ad619cdfb --- /dev/null +++ b/nirrengarten ratti phillipon-champroux/paint.js @@ -0,0 +1,332 @@ +"use strict"; +import * as THREE from "three"; +import { OBJLoader } from "three/addons/loaders/OBJLoader.js"; +import { MTLLoader } from "three/addons/loaders/MTLLoader.js"; +import { OrbitControls } from "three/addons/controls/OrbitControls.js"; +import { Reflector } from 'three/addons/objects/Reflector.js'; + +import { dat } from "./lib/dat.gui.min.js"; +import { Coordinates } from "./lib/Coordinates.js"; +import { Wheat } from "./wheat.js"; +import { Sun } from "./sun.js"; +import { Skybox } from "./skybox.js"; +import { Crow } from "./crow.js"; +import { NewWheat } from "./new_wheat.js"; +import { River } from "./river.js"; + +Wheat.getModel(); + +var camera, renderer; +window.scene = new THREE.Scene(); + +var cameraControls, effectController; +var clock = new THREE.Clock(); +var gridX = false; +var gridY = false; +var gridZ = false; +var axes = false; +var ground = true; +var chunkSize = 40; +var renderDistance = 4; +var density = 1.25; +var windIntensity = 0.0025; +var displacementScale = 2; + +//TODO faudra faire en sorte de dupliquer pour avoir un vrai champ +function addWheatField() { + Wheat.render(10, scene); +} + +let _animateWind, _updateVisibleChunks; + +function addNewWheat(isInRiver) { + const { fieldContainer, animateWind, updateVisibleChunks } = + NewWheat.createDynamicWheatField( + scene, + camera, + { + chunkSize: chunkSize, + renderDistance: renderDistance, + density: density, + windIntensity: windIntensity, + }, + isInRiver, + ); + _updateVisibleChunks = updateVisibleChunks; + _animateWind = animateWind; + + fieldContainer.traverse(child => { + if (child.isInstancedMesh) { + child.castShadow = true; + child.receiveShadow = true; + } + }); +} + +function addElMordjene() { + var mtlLoader = new MTLLoader(); + mtlLoader.setPath("3Dmodel/Peanut Butter/"); + mtlLoader.load("peanutButter.mtl", function (materials) { + materials.preload(); + var objLoader = new OBJLoader(); + objLoader.setMaterials(materials); + objLoader.setPath("3Dmodel/Peanut Butter/"); + objLoader.load("peanutButter.obj", function (object) { + object.traverse(function (child) { + if (child instanceof THREE.Mesh) { + // usage de copilot + var geometry = new THREE.BufferGeometry(); + geometry.copy(child.geometry); + geometry.computeVertexNormals(); + geometry.castShadow = true; + geometry.recieveShadow = true; + geometry.scale(10, 10, 10); + child.geometry = geometry; + } + }); + object.position.y = 2; + scene.add(object); + }); + }); +} + +/** Ajoute la portion de mirroir qui reflette a la verticale */ +function addMirror() { + let geometry = new THREE.PlaneGeometry(160, 900); + var verticalMirror = new Reflector(geometry, { + clipBias: 0.003, + textureWidth: window.innerWidth * window.devicePixelRatio, + textureHeight: window.innerHeight * window.devicePixelRatio, + color: 0xc1cbcb, + }); + verticalMirror.rotation.x = - Math.PI /-1.4 ; + verticalMirror.position.y = -200; + verticalMirror.position.x = 30; + verticalMirror.position.z = 400; + scene.add(verticalMirror); + + + +} + +function init() { + var canvasWidth = 846; + var canvasHeight = 494; + var canvasRatio = canvasWidth / canvasHeight; + + // RENDERER + renderer = new THREE.WebGLRenderer({ antialias: true }); + renderer.gammaInput = true; + renderer.gammaOutput = true; + renderer.shadowMap.enabled = true; + renderer.shadowMap.type = THREE.PCFSoftShadowMap; + + renderer.setSize(canvasWidth, canvasHeight); + renderer.setClearColor(0xaaaaaa, 1.0); + + // CAMERA + camera = new THREE.PerspectiveCamera(45, canvasRatio, 1, 40000); + camera.position.set(-20, 12, -20); + // CONTROLS + cameraControls = new OrbitControls(camera, renderer.domElement); + cameraControls.target.set(0, 6, 0); + + setupGui(); + fillScene(); +} +function addToDOM() { + var container = document.getElementById("webGL"); + var canvas = container.getElementsByTagName("canvas"); + if (canvas.length > 0) { + container.removeChild(canvas[0]); + } + container.appendChild(renderer.domElement); +} +let riverAmplitude = 3; +let riverFrequency = 0.1; +let riverWidth = 10; +function fillScene() { + // SCENE + scene = new THREE.Scene(); + scene.fog = new THREE.Fog(0x808080, 8000, 12000); + // LIGHTS + var ambientLight = new THREE.AmbientLight(0xffffff); + + var spotlight = new THREE.SpotLight(0xffffff, 2); + spotlight.position.set(10, 80, 10); + spotlight.angle = Math.PI / 6; + spotlight.penumbra = 0.3; + + spotlight.shadow.mapSize.width = 1024; + spotlight.shadow.mapSize.height = 1024; + spotlight.shadow.camera.near = 10; + spotlight.shadow.camera.far = 200; + spotlight.shadow.bias = -0.001; + spotlight.shadow.normalBias = 0.02; + + spotlight.castShadow = true; + + scene.add(spotlight); + + scene.add(ambientLight); + + if (ground) { + var groundBase = new THREE.PlaneGeometry(500, 500, 128, 128); + + const textureLoader = new THREE.TextureLoader(); + + var groundMat = new THREE.MeshStandardMaterial({ + color: "#ad8a1f", + normalMap: textureLoader.load("img/normal.png"), + normalScale: new THREE.Vector2(1.0, 1.0), + displacementMap: textureLoader.load("img/height.jpg"), + displacementScale: displacementScale, + roughness: 0.6, + metalness: 0.2, + }); + var newGround = new THREE.Mesh(groundBase, groundMat); + newGround.receiveShadow = true; + newGround.rotation.x = (-90 * Math.PI) / 180; + newGround.material.needsUpdate = true; + + scene.add(newGround); + + scene.add(newGround); + } + if (gridX) { + Coordinates.drawGrid({ size: 1000, scale: 0.01 }); + } + if (gridY) { + Coordinates.drawGrid({ size: 1000, scale: 0.01, orientation: "y" }); + } + if (gridZ) { + Coordinates.drawGrid({ size: 1000, scale: 0.01, orientation: "z" }); + } + + let howMuch = 8; + + /*for (let i = 0; i < howMuch * howMuch; i++) { + Wheat.createDifferentWheat(i % 3); + Wheat.renderWheat( + ((i % howMuch) - howMuch / 2) * 8.5, + 0, + (i / howMuch - howMuch / 2) * 8.5, + scene, + ); + }*/ + let { obj, isInRiver } = River.createRiverMesh( + { + chunkSize: chunkSize, + renderDistance: renderDistance, + riverAmplitude: riverAmplitude, + riverFrequency: riverFrequency, + riverWidth: riverWidth, + }, + new THREE.MeshLambertMaterial({ color: 0x0000ff }), + ); + obj.position.y = 3; + scene.add(obj); + Sun.addSun(scene); + addElMordjene(); + let crowsGroup = new THREE.Group(); + crowsGroup.name = "crowsGroup"; + scene.add(crowsGroup); + updateCrowCrows(effectController.crowCount); + density: 0.3, riverWidth; + + addNewWheat((x) => false); + addMirror(); + Skybox.addSkybox(scene, "day"); + + let obje = new THREE.Mesh( + new THREE.SphereGeometry(1, 32, 16), + new THREE.MeshBasicMaterial({ + color: 0xff0000, + opacity: 0.2, + transparent: true, + }), + ); + obje.position.set(0, 10, 0); + scene.add(obje); +} + +function animate() { + window.requestAnimationFrame(animate); + + _updateVisibleChunks(); + + const time = clock.getElapsedTime(); + _animateWind(time, effectController.windIntensity); + + render(); +} + +function render() { + var delta = clock.getDelta(); + cameraControls.update(delta); + if ( + effectController.newGridX !== gridX || + effectController.newGridY !== gridY || + effectController.newGridZ !== gridZ || + effectController.newGround !== ground || + effectController.newAxes !== axes + ) { + gridX = effectController.newGridX; + gridY = effectController.newGridY; + gridZ = effectController.newGridZ; + ground = effectController.newGround; + axes = effectController.newAxes; + + fillScene(); + } + renderer.render(scene, camera); +} + +function setupGui() { + effectController = { + newGridX: gridX, + newGridY: gridY, + newGridZ: gridZ, + newGround: ground, + windIntensity: windIntensity, + crowCount: 100, // Initial crow count + }; + + var gui = new dat.GUI(); + gui.add(effectController, "newGridX").name("Show XZ grid"); + gui.add(effectController, "newGridY").name("Show YZ grid"); + gui.add(effectController, "newGridZ").name("Show XY grid"); + gui.add(effectController, "newGround").name("Show ground"); + gui.add(effectController, "windIntensity").name("Wind intensity"); + + // Add a slider to control the crow count + gui + .add(effectController, "crowCount", 0, 200, 1) + .name("Crow Count") + .onChange(function (value) { + updateCrowCrows(value); + }); +} + +function updateCrowCrows(count) { + let group = scene.getObjectByName("crowsGroup"); + if (group) { + group.clear(); + } else { + group = new THREE.Group(); + group.name = "crowsGroup"; + scene.add(group); + } + + Crow.addCrows(group, count); +} +try { + init(); + addToDOM(); + animate(); +} catch (e) { + var errorReport = + "Your program encountered an unrecoverable error, can not draw on canvas. Error was:<br/><br/>"; + $("#container").append(errorReport + e); + console.log(e); +} diff --git a/nirrengarten ratti phillipon-champroux/river.js b/nirrengarten ratti phillipon-champroux/river.js new file mode 100755 index 0000000000000000000000000000000000000000..416cdf4e1daa5da75263bfa1a7dd6ca4aef36781 --- /dev/null +++ b/nirrengarten ratti phillipon-champroux/river.js @@ -0,0 +1,113 @@ +import * as THREE from "three"; + +class River { + static getRiverXPosition = (z, config) => { + return config.riverAmplitude * Math.sin(z * config.riverFrequency); + }; + + static createRiverMesh(config, material) { + // Define river bounds + // debugger; + const riverLength = + config.chunkSize * (config.renderDistance * 2 + 1) * 1.5; // Make river longer than visible area + const halfLength = riverLength / 2; + + // Create river path points + const points = []; + const segments = 40; + + for (let i = 0; i <= segments; i++) { + const z = -halfLength + i * (riverLength / segments); + const x = River.getRiverXPosition(z, config); + points.push(new THREE.Vector2(x, z)); + } + + // Create river shape + const shape = new THREE.Shape(); + + // Define river path + const path = new THREE.Path(points); + + // Create geometry from path with width + const geometry = new THREE.BufferGeometry(); + const positions = []; + const indices = []; + + // Create vertices on both sides of the path + for (let i = 0; i < points.length; i++) { + const point = points[i]; + + // Calculate tangent vector (perpendicular to path direction) + let tangentX, tangentZ; + + if (i === 0) { + // First point - use direction to next point + tangentX = points[i + 1].y - point.y; + tangentZ = -(points[i + 1].x - point.x); + } else if (i === points.length - 1) { + // Last point - use direction from previous point + tangentX = points[i].y - points[i - 1].y; + tangentZ = -(points[i].x - points[i - 1].x); + } else { + // Middle points - average of directions + tangentX = points[i + 1].y - points[i - 1].y; + tangentZ = -(points[i + 1].x - points[i - 1].x); + } + + // Normalize tangent + const len = Math.sqrt(tangentX * tangentX + tangentZ * tangentZ); + tangentX /= len; + tangentZ /= len; + + // Calculate points on both sides of the path + const halfWidth = config.riverWidth / 2; + + // Left bank + positions.push( + point.x - tangentX * halfWidth, + 0, + point.y - tangentZ * halfWidth, + ); + + // Right bank + positions.push( + point.x + tangentX * halfWidth, + 0, + point.y + tangentZ * halfWidth, + ); + } + + // Create indices for triangles + for (let i = 0; i < points.length - 1; i++) { + const topLeft = i * 2; + const topRight = i * 2 + 1; + const bottomLeft = (i + 1) * 2; + const bottomRight = (i + 1) * 2 + 1; + + // First triangle (top-left, bottom-left, bottom-right) + indices.push(topLeft, bottomLeft, bottomRight); + + // Second triangle (top-left, bottom-right, top-right) + indices.push(topLeft, bottomRight, topRight); + } + + // Set geometry attributes + geometry.setAttribute( + "position", + new THREE.Float32BufferAttribute(positions, 3), + ); + geometry.setIndex(indices); + geometry.computeVertexNormals(); + const isInRiver = (x, z) => { + const riverCenterX = this.getRiverXPosition(z, config); + const halfWidth = config.riverWidth / 2; + return Math.abs(x - riverCenterX) < halfWidth; + }; + // Create mesh + const riverMesh = new THREE.Mesh(geometry, material); + + return { obj: riverMesh, isInRiver: isInRiver }; + } +} + +export { River }; diff --git a/nirrengarten ratti phillipon-champroux/skybox.js b/nirrengarten ratti phillipon-champroux/skybox.js new file mode 100644 index 0000000000000000000000000000000000000000..296c3bf9905c5c223389888b54c9fce789a3bb7e --- /dev/null +++ b/nirrengarten ratti phillipon-champroux/skybox.js @@ -0,0 +1,67 @@ +import * as THREE from "three"; + +class Skybox { + static async addSkybox(scene, nomFichier) { + let skyboxGeo, skybox; + let skyboxImage = nomFichier; + + function createPathStrings(filename) { + const basePath = `./img/skybox/`; + const baseFilename = basePath + filename; + const fileType = filename == nomFichier ? '.png' : '.jpg'; + // side 1,3,up,2,4,down + // en mode face a droite puis a gauche, celle du haut, face a en face, face derriere, face du bas + const sides = ['px', 'nx', 'py', 'ny', 'pz', 'nz']; + const pathStings = sides.map(side => { + return baseFilename + '_' + side + fileType; + }); + return pathStings; + } + + function createMaterialArray(filename) { + const skyboxImagepaths = createPathStrings(filename); + const materialArray = skyboxImagepaths.map(image => { + let texture = new THREE.TextureLoader().load(image); + + return new THREE.MeshBasicMaterial({ map: texture, side: THREE.BackSide }); + }); + return materialArray; + + } + const materialArray = createMaterialArray(skyboxImage); + + //on peut modif la taille pour avoir une skybox plus large ou moins large + skyboxGeo = new THREE.BoxGeometry(10000, 10000, 10000); + skybox = new THREE.Mesh(skyboxGeo, materialArray); + + scene.add(skybox); + + // add une env map pour la reflection + + const loader = new THREE.CubeTextureLoader(); + loader.setPath('./img/skybox/'); + + var textureCube = loader.load( + [ + skyboxImage + '_px.png', + skyboxImage + '_nx.png', + skyboxImage + '_py.png', + skyboxImage + '_ny.png', + skyboxImage + '_pz.png', + skyboxImage + '_nz.png']); + + scene.background = textureCube; + + var geometry = new THREE.IcosahedronGeometry(5, 15); + var sphereMaterial = new THREE.MeshBasicMaterial({ envMap: textureCube }); + var sphereMesh = new THREE.Mesh(geometry, sphereMaterial); + sphereMesh.position.y = 10; + sphereMesh.position.x = 30; + sphereMesh.position.z = 25; + scene.add(sphereMesh); + } +} + +export { Skybox }; + + diff --git a/nirrengarten ratti phillipon-champroux/style.css b/nirrengarten ratti phillipon-champroux/style.css new file mode 100644 index 0000000000000000000000000000000000000000..45ae8c78d6f0eeb2c7722cf6ddb85590a1134d48 --- /dev/null +++ b/nirrengarten ratti phillipon-champroux/style.css @@ -0,0 +1,37 @@ +body { + margin: 0; +} + +canvas { + width: 80%; + height: 40%; + margin: auto; + border-radius: 20px; +} + +.render{ + display: flex; + +} + +.centre { + text-align: center; +} + +.divider{ + margin: 50px +} + +.tableau{ + flex-wrap: wrap; + flex-direction: column; + +} +.tableau-presentation{ + display: flex; +} +.tableau-img{ + display: flex; + width: 380px; + height: 242px; +} \ No newline at end of file diff --git a/nirrengarten ratti phillipon-champroux/sun.js b/nirrengarten ratti phillipon-champroux/sun.js new file mode 100644 index 0000000000000000000000000000000000000000..738570dbd0cb19a41d124c77414fa5c0927651de --- /dev/null +++ b/nirrengarten ratti phillipon-champroux/sun.js @@ -0,0 +1,40 @@ +import * as THREE from "three"; + +class Sun { + static async addSun(scene) { + const geometry = new THREE.SphereGeometry(15, 32, 16); + const material = new THREE.MeshBasicMaterial({color: 0xd2efff}); + const sphere = new THREE.Mesh(geometry, material); + + sphere.position.set(-50, 200, -200); + + const light = new THREE.DirectionalLight(0xffffff, 1.5); + light.position.copy(sphere.position); + light.castShadow = true; + + light.shadow.mapSize.width = 4096; + light.shadow.mapSize.height = 4096; + + light.shadow.camera.left = -500; + light.shadow.camera.right = 500; + light.shadow.camera.top = 500; + light.shadow.camera.bottom = -500; + light.shadow.camera.near = 10; + light.shadow.camera.far = 1000; + + light.shadow.bias = -0.0001; + light.shadow.normalBias = 0.02; + + const target = new THREE.Object3D(); + target.position.set(0, 0, 0); + scene.add(target); + light.target = target; + + scene.add(sphere); + scene.add(light); + + return { sunSphere: sphere, sunLight: light }; + } +} + +export {Sun}; \ No newline at end of file diff --git a/nirrengarten ratti phillipon-champroux/wheat.js b/nirrengarten ratti phillipon-champroux/wheat.js new file mode 100644 index 0000000000000000000000000000000000000000..3c164c022501efb657289c00033a3a177c22f14a --- /dev/null +++ b/nirrengarten ratti phillipon-champroux/wheat.js @@ -0,0 +1,112 @@ +import { OBJLoader } from "three/addons/loaders/OBJLoader.js"; +import { MTLLoader } from "three/addons/loaders/MTLLoader.js"; +import * as THREE from "three"; + +/** Manages the Wheat */ +class Wheat { + static texture; + static async getTexture() { + return; + if (Wheat.texture == null) { + Wheat.texture = await new Promise((res, rej) => { + var mtlLoader = new MTLLoader(); + mtlLoader.setPath("3Dmodel/Field of wheat/"); + mtlLoader.load("FieldOfWheat.mtl", res, () => {}, rej); + }); + Wheat.texture.preload(); + } + return Wheat.texture; + } + + static async createDifferentWheat(variation = 0) { + const stemGeometry = new THREE.CylinderGeometry(0.02, 0.03, 1.5, 4, 3); + stemGeometry.translate(0, 0.75, 0); + + // Top grain part + let headGeometry; + + switch (variation % 3) { + case 0: + // Standard wheat head + headGeometry = new THREE.CylinderGeometry(0.04, 0.02, 0.3, 6, 1); + headGeometry.translate(0, 1.65, 0); + break; + case 1: + // Slightly bent wheat head + headGeometry = new THREE.CylinderGeometry(0.04, 0.02, 0.35, 6, 1); + headGeometry.translate(0, 1.65, 0); + headGeometry.rotateZ(Math.PI * 0.05); + break; + case 2: + // Different shape + headGeometry = new THREE.ConeGeometry(0.05, 0.4, 6, 1); + headGeometry.translate(0, 1.7, 0); + break; + } + + // Combine geometries + const mergedGeometry = new THREE.BufferGeometry(); + + // Merge stem and head + const stemPositions = stemGeometry.getAttribute("position").array; + const headPositions = headGeometry.getAttribute("position").array; + + const positions = new Float32Array( + stemPositions.length + headPositions.length, + ); + positions.set(stemPositions, 0); + positions.set(headPositions, stemPositions.length); + + mergedGeometry.setAttribute( + "position", + new THREE.BufferAttribute(positions, 3), + ); + + // Compute normals and UVs + mergedGeometry.computeVertexNormals(); + + this.model = mergedGeometry; + + return mergedGeometry; + } + + static model; + + static async getModel() { + return; + if (Wheat.model == null) { + let objLoader = new OBJLoader(); + let txt = await Wheat.getTexture(); + // let txt = new THREE.MeshBasicMaterial({ color: 0xffffff }); + console.log(txt); + await objLoader.setMaterials(txt); + objLoader.setPath("3Dmodel/Field of wheat/"); + Wheat.model = await new Promise((res, rej) => + objLoader.load("FieldOfWheat.obj", res, function () {}, rej), + ); + Wheat.model.traverse(function (child) { + if (child instanceof THREE.Mesh) { + // usage de copilot + var geometry = new THREE.BufferGeometry(); + geometry.copy(child.geometry); + geometry.computeVertexNormals(); + geometry.castShadow = true; + geometry.recieveShadow = true; + geometry.scale(1, 1, 1); + child.geometry = geometry; + } + }); + } + return Wheat.model; + } + + static async renderWheat(x, y, z, scene) { + let model = await Wheat.getModel(); + model.position.x = x; + model.position.y = y; + model.position.z = z; + scene.add(model); + } +} + +export { Wheat };