Core.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375
  1. import * as THREE from './threejs/build/three.module.js';
  2. import { GLTFLoader } from './threejs/examples/jsm/loaders/GLTFLoader.js';
  3. import { OrbitControls } from './threejs/examples/jsm/controls/OrbitControls.js';
  4. import { Water } from './threejs/examples/jsm/objects/Water.js';
  5. import { Sky } from './threejs/examples/jsm/objects/Sky.js';
  6. import { Ship } from './Ship.js';
  7. // scene size
  8. var WIDTH = window.innerWidth;
  9. var HEIGHT = window.innerHeight;
  10. // camera
  11. var VIEW_ANGLE = 45;
  12. var ASPECT = WIDTH / HEIGHT;
  13. var NEAR = 1;
  14. var FAR = 5000;
  15. var camera, scene, renderer, raycaster;
  16. var clock;
  17. var intersects;
  18. export var keys = [];
  19. var mouse;
  20. var controls;
  21. var ship, water, sun, sky;
  22. var parameters;
  23. var simpleWater, wireframe;
  24. function init() {
  25. raycaster = new THREE.Raycaster();
  26. mouse = new THREE.Vector2(-1, -1);
  27. intersects = [];
  28. // renderer
  29. renderer = new THREE.WebGLRenderer();
  30. renderer.setPixelRatio(window.devicePixelRatio);
  31. renderer.setSize(WIDTH, HEIGHT);
  32. renderer.shadowMap.enabled = true;
  33. renderer.shadowMap.type = THREE.PCFSoftShadowMap;
  34. // renderer.outputEncoding = THREE.sRGBEncoding;
  35. // scene
  36. scene = new THREE.Scene();
  37. scene.fog = new THREE.Fog(0xFFFFFF, 50, 500);
  38. // camera
  39. camera = new THREE.PerspectiveCamera(VIEW_ANGLE, ASPECT, NEAR, FAR);
  40. camera.position.set(16, 22, 16);
  41. camera.lookAt(0, 0, 0);
  42. let container = document.getElementById('container');
  43. container.appendChild(renderer.domElement);
  44. controls = new OrbitControls(camera, renderer.domElement);
  45. controls.maxPolarAngle = Math.PI * 0.495;
  46. controls.target.set(0, 0, 0);
  47. controls.minDistance = 10.0;
  48. controls.maxDistance = 100.0;
  49. controls.update();
  50. clock = new THREE.Clock();
  51. }
  52. function fillScene() {
  53. //sky
  54. let cubeloader = new THREE.CubeTextureLoader();
  55. let texture = cubeloader.load([
  56. './textures/cubemap/posx.png',
  57. './textures/cubemap/negx.png',
  58. './textures/cubemap/posy.png',
  59. './textures/cubemap/negy.png',
  60. './textures/cubemap/posz.png',
  61. './textures/cubemap/negz.png',
  62. ]);
  63. scene.background = texture;
  64. //ground
  65. // let textureLoader = new THREE.TextureLoader();
  66. // let lawnTex = textureLoader.load("textures/lawn.jpg");
  67. // var planeGeo = new THREE.PlaneBufferGeometry(1000, 1000, 32, 32);
  68. // let floorMat = new THREE.MeshPhongMaterial({ map: lawnTex });
  69. // floorMat.flatShading = true;
  70. // floorMat.shininess = 0;
  71. // lawnTex.wrapS = lawnTex.wrapT = THREE.RepeatWrapping;
  72. // lawnTex.repeat.set(5, 5);
  73. // ground = new THREE.Mesh(planeGeo, floorMat);
  74. // ground.rotateX(- Math.PI / 2);
  75. // ground.receiveShadow = true;
  76. // scene.add(ground);
  77. // lights
  78. var sunlight = new THREE.PointLight(0xffffff, 1, 0, 2);
  79. sunlight.position.x = 400;
  80. sunlight.position.y = 400;
  81. sunlight.position.z = 100;
  82. sunlight.castShadow = true;
  83. sunlight.shadow.camera.far = 1600;
  84. scene.add(sunlight);
  85. // var mainLight = new THREE.HemisphereLight(0xB1E1FF, 0xB97A20, 0.8);
  86. // mainLight.position.x = 1;
  87. // mainLight.position.y = 1;
  88. // mainLight.position.z = 1;
  89. // mainLight.lookAt(0, 0, 0);
  90. // scene.add(mainLight);
  91. //ground
  92. // let textureLoader = new THREE.TextureLoader();
  93. // let lawnTex = textureLoader.load("textures/lawn.jpg");
  94. var planeGeo = new THREE.PlaneBufferGeometry(5000, 5000, 32, 32);
  95. water = new Water(
  96. planeGeo,
  97. {
  98. textureWidth: 512,
  99. textureHeight: 512,
  100. waterNormals: new THREE.TextureLoader().load('./js/threejs/examples/textures/waternormals.jpg', function (texture) {
  101. texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
  102. //texture.repeat.set(5,5);
  103. }),
  104. alpha: 1.0,
  105. sunDirection: new THREE.Vector3(),
  106. sunColor: 0xffffff,
  107. waterColor: 0x001e0f,
  108. distortionScale: 3.7,
  109. fog: scene.fog !== undefined
  110. }
  111. );
  112. water.rotation.x = - Math.PI / 2;
  113. water.material.uniforms['size'].value = 20;
  114. water.material.uniforms['eye'].value = new THREE.Vector3(16, 22, 16);
  115. // scene.add(water);
  116. //simple water
  117. // https://csantosbh.wordpress.com/2014/01/09/custom-shaders-with-three-js-uniforms-textures-and-lighting/
  118. let simplePlane = new THREE.PlaneBufferGeometry(500, 500, 100, 100);
  119. let simpleMaterial = new THREE.MeshPhongMaterial({ color: 0x4080EE });
  120. let simpleUniforms = new THREE.UniformsUtils.merge([
  121. THREE.UniformsLib.lights,
  122. THREE.UniformsLib.fog,
  123. {
  124. waterColor: { value: new THREE.Color(0x0880AA) },
  125. u_time: { value: 0 },
  126. lightIntensity: { value: 1 },
  127. }
  128. ]
  129. );
  130. let shaderMaterial = new THREE.ShaderMaterial({
  131. wireframe: false,
  132. lights: true,
  133. vertexShader: `
  134. varying vec3 vecPos;
  135. varying vec3 vecNormal;
  136. uniform float u_time;
  137. void main() {
  138. vec3 p = position;
  139. p.z = p.z + 0.3 * (sin(2.5 * (u_time + (p.y * 0.1)))) + 0.5;
  140. p.z = p.z + 0.3 * (sin(3.5 * (u_time + (p.x * 0.1)))) + 0.5;
  141. // Since the light is in camera coordinates,
  142. // I'll need the vertex position in camera coords too
  143. vecPos = (modelViewMatrix * vec4(p, 1.0)).xyz;
  144. // That's NOT exacly how you should transform your
  145. // normals but this will work fine, since my model
  146. // matrix is pretty basic
  147. vecNormal = (modelViewMatrix * vec4(normal, 0.0)).xyz;
  148. gl_Position = projectionMatrix *
  149. vec4(vecPos, 1.0);
  150. }`,
  151. fragmentShader: `
  152. precision highp float;
  153. varying vec3 vecPos;
  154. varying vec3 vecNormal;
  155. uniform float lightIntensity;
  156. uniform sampler2D textureSampler;
  157. uniform vec3 waterColor;
  158. struct PointLight {
  159. vec3 color;
  160. vec3 position; // light position, in camera coordinates
  161. float distance; // used for attenuation purposes. Since
  162. // we're writing our own shader, it can
  163. // really be anything we want (as long as
  164. // we assign it to our light in its
  165. // "distance" field
  166. };
  167. uniform PointLight pointLights[NUM_POINT_LIGHTS];
  168. void main(void) {
  169. // Pretty basic lambertian lighting...
  170. vec4 addedLights = vec4(0.0,
  171. 0.0,
  172. 0.0,
  173. 1.0);
  174. for(int l = 0; l < NUM_POINT_LIGHTS; l++) {
  175. vec3 lightDirection = normalize(vecPos
  176. - pointLights[l].position);
  177. addedLights.rgb += clamp(dot(-lightDirection,
  178. vecNormal), 0.0, 1.0)
  179. * pointLights[l].color
  180. * lightIntensity;
  181. }
  182. gl_FragColor = vec4(waterColor, 1.0) * addedLights;
  183. }`,
  184. uniforms: simpleUniforms,
  185. });
  186. simpleWater = new THREE.Mesh(simplePlane, shaderMaterial);
  187. simpleWater.receiveShadow = true;
  188. simpleWater.rotation.x = -Math.PI / 2;
  189. wireframe = simpleWater.clone();
  190. wireframe.position.y += 0.01;
  191. wireframe.material = wireframe.material.clone();
  192. wireframe.material.wireframe = true;
  193. wireframe.material.uniforms['waterColor'].value = new THREE.Color(0x28A0CA);
  194. scene.add(simpleWater);
  195. scene.add(wireframe);
  196. Ship.loadShip().then(gltf => {
  197. ship = new Ship(gltf.scene);
  198. ship.init();
  199. scene.add(gltf.scene);
  200. });
  201. // sun = new THREE.Vector3();
  202. // sky = new Sky();
  203. // sky.scale.setScalar(10000);
  204. // scene.add(sky);
  205. // var uniforms = sky.material.uniforms;
  206. // uniforms['turbidity'].value = 1;
  207. // uniforms['rayleigh'].value = 2;
  208. // uniforms['mieCoefficient'].value = 0.005;
  209. // uniforms['mieDirectionalG'].value = 0.8;
  210. // parameters = {
  211. // inclination: -0.5,
  212. // azimuth: 0.205
  213. // };
  214. // updateSun();
  215. update();
  216. }
  217. function updateSun() {
  218. var pmremGenerator = new THREE.PMREMGenerator(renderer);
  219. var theta = Math.PI * (parameters.inclination - 0.5);
  220. var phi = 2 * Math.PI * (parameters.azimuth - 0.5);
  221. sun.x = Math.cos(phi);
  222. sun.y = Math.sin(phi) * Math.sin(theta);
  223. sun.z = Math.sin(phi) * Math.cos(theta);
  224. sky.material.uniforms['sunPosition'].value.copy(sun);
  225. water.material.uniforms['sunDirection'].value.copy(sun).normalize();
  226. scene.environment = pmremGenerator.fromScene(sky).texture;
  227. }
  228. function update() {
  229. requestAnimationFrame(update);
  230. water.material.uniforms['time'].value += 1.0 / 60.0;
  231. if (simpleWater.material) {
  232. simpleWater.material.uniforms['u_time'].value = clock.getElapsedTime();
  233. wireframe.material.uniforms['u_time'].value = clock.getElapsedTime();
  234. // simpleWater.material.uniforms['eye'].value = camera.position;
  235. // simpleWater.material.uniforms['sunDirection'].value.copy(sun).normalize();
  236. }
  237. // water.material.uniforms['eye'].value = new THREE.Vector3(scene.position.x, scene.position.y, scene.position.z);
  238. let cameraMoveSpeed = 1;
  239. //camera controls
  240. if (keys["ArrowLeft"]) { //left
  241. scene.translateX(cameraMoveSpeed);
  242. }
  243. if (keys["ArrowRight"]) { //right
  244. scene.translateX(-cameraMoveSpeed);
  245. }
  246. if (keys["ArrowUp"]) { //up
  247. scene.translateZ(cameraMoveSpeed);
  248. }
  249. if (keys["ArrowDown"]) { //down
  250. scene.translateZ(-cameraMoveSpeed);
  251. }
  252. ship.handleInput();
  253. // if (keys["KeyF"]) {
  254. // scene.position.set(ship.position.x + 16, ship.position.y + 22, ship.position.z + 16);
  255. // }
  256. ship.updateModel();
  257. // camera.lookAt(ship.scene.position);
  258. // parameters.inclination += 0.0005;
  259. // parameters.inclination %= 2 * Math.PI;
  260. // updateSun();
  261. scene.position.set(-ship.position.x, 0, -ship.position.z);
  262. renderer.render(scene, camera);
  263. }
  264. document.addEventListener("DOMContentLoaded", () => {
  265. init();
  266. fillScene();
  267. });
  268. window.addEventListener("keydown", e => keys[e.code] = true);
  269. window.addEventListener("keyup", e => keys[e.code] = false);
  270. window.addEventListener("mousemove", event => {
  271. mouse.x = normalize(event.clientX / window.innerWidth);
  272. mouse.y = -normalize(event.clientY / window.innerHeight);
  273. });
  274. window.addEventListener("mousedown", event => {
  275. mouse.x = normalize(event.clientX / window.innerWidth);
  276. mouse.y = -normalize(event.clientY / window.innerHeight);
  277. });
  278. window.addEventListener("contextmenu", event => {
  279. event.preventDefault();
  280. });
  281. window.addEventListener("mouseup", event => {
  282. });
  283. window.addEventListener("wheel", event => {
  284. });
  285. window.addEventListener("touchmove", event => {
  286. mouse.x = normalize(event.touches[0].clientX / window.innerWidth);
  287. mouse.y = -normalize(event.touches[0].clientY / window.innerHeight);
  288. });
  289. window.addEventListener("resize", () => {
  290. WIDTH = window.innerWidth;
  291. HEIGHT = window.innerHeight;
  292. ASPECT = WIDTH / HEIGHT;
  293. camera.aspect = ASPECT;
  294. renderer.setSize(WIDTH, HEIGHT);
  295. camera.updateProjectionMatrix();
  296. });
  297. function normalize(value) {
  298. return (2 * value) - 1;
  299. }