diff --git a/public/index.html b/public/index.html
index b0235a9..3b11361 100644
--- a/public/index.html
+++ b/public/index.html
@@ -1,16 +1,16 @@
-
-
-
-
- <%= htmlWebpackPlugin.options.title %>
+
+
+
+
+ <%= htmlWebpackPlugin.options.title %>
@@ -18,6 +18,8 @@
diff --git a/src/animation/Config.ts b/src/animation/Config.ts
new file mode 100644
index 0000000..269b30f
--- /dev/null
+++ b/src/animation/Config.ts
@@ -0,0 +1,30 @@
+import {Color} from "three";
+
+/**
+ * Configurations
+ */
+export const config = {
+
+ background: '#333',
+
+ // Field of vision and cutoff frustum for near and far
+ cam: {fov: 50, near: 1, far: 5000},
+
+ // Mouse movement factor
+ mouseFactor: 20,
+
+ // Smooth movements (speeds are in terms of pixels per ms)
+ smooth: {mouseSpeed: 10 * window.devicePixelRatio},
+
+ // Debug mode
+ debug: true
+}
+
+export const colors = {
+ sky: {
+ top: new Color('#3284ff'),
+ bottom: new Color('#ffffff'),
+ ground: new Color('#ffc87f'),
+ dirLight: new Color('#fff4e5')
+ },
+}
diff --git a/src/animation/Helpers.ts b/src/animation/Helpers.ts
index 72007c1..aefaf27 100644
--- a/src/animation/Helpers.ts
+++ b/src/animation/Helpers.ts
@@ -37,12 +37,13 @@ export function box(width: number, height: number, depth: number): THREE.BufferG
* @param color
* @param z
* @param r
+ * @param hollow
*/
-export function circle(color: number, z: number, r: number): THREE.Mesh
+export function circle(color: number, z: number, r: number, hollow = false): THREE.Object3D
{
const geometry = new THREE.CircleGeometry(r, 32)
const material = new THREE.MeshBasicMaterial({color})
- const circle = new THREE.Mesh(geometry, material)
+ const circle = hollow ? new THREE.Line(geometry, material) : new THREE.Mesh(geometry, material)
circle.position.z = z
return circle
}
diff --git a/src/animation/Home.ts b/src/animation/Home.ts
index 9598868..ff2b0dd 100644
--- a/src/animation/Home.ts
+++ b/src/animation/Home.ts
@@ -1,40 +1,33 @@
import * as THREE from 'three'
-import * as helper from "@/animation/Helpers";
-import {initMouseTracker, moused} from "@/animation/Trackers";
-import {circle} from "@/animation/Helpers";
+import * as helper from "@/animation/Helpers"
+import {circle} from "@/animation/Helpers"
+import {initMouseTracker, moused} from "@/animation/Trackers"
+import {addDirLight, addGround, addHemiLight, addSky} from "@/animation/Shaders"
+import {colors, config} from "@/animation/Config"
let renderer: THREE.WebGLRenderer, scene: THREE.Scene, camera: THREE.PerspectiveCamera
const clock = new THREE.Clock()
-const objects = []
-
-const config = {
- background: '#333',
-
- // Field of vision and cutoff frustum for near and far
- cam: {fov: 50, near: 1, far: 2000},
-
- // Mouse movement factor
- mouseFactor: 20,
-
- // Smooth movements (speeds are in terms of pixels per ms)
- smooth: {mouseSpeed: 10 * window.devicePixelRatio},
-}
+const objects: { [id: string]: THREE.Object3D } = {}
// ////////////////////
// Three.js scene code
function init(): void
{
- const geometryBox = helper.box(50, 50, 50);
+ const geometryBox = helper.box(50, 50, 50)
const lineSegments = new THREE.LineSegments(geometryBox, new THREE.LineDashedMaterial({
color: 0xffaa00,
dashSize: 3,
gapSize: 1
- }));
+ }))
lineSegments.computeLineDistances()
- objects.push(lineSegments)
+ const cursor = circle(0xffaa00, 100, 1)
+ objects.cursor = cursor
+ scene.add(cursor)
+
+ objects.box = lineSegments
scene.add(lineSegments)
scene.add(circle(0xffff00, 0, 5))
@@ -59,16 +52,25 @@ function pn(b: boolean): number
*/
function update(dt: number): void
{
- smoothBuffer.cam.x = moused.x * config.mouseFactor
- smoothBuffer.cam.y = moused.y * config.mouseFactor
+ // objects['cursor'].position.set(moused.x, moused.y, 150)
+
+ const vector = new THREE.Vector3(moused.x, moused.y, 0.5)
+ vector.unproject(camera)
+ const dir = vector.sub(camera.position).normalize()
+ const distance = -camera.position.z / dir.z
+ const pos = camera.position.clone().add(dir.multiplyScalar(distance))
+ objects.cursor.position.copy(pos)
+
+ // smoothBuffer.cam.x = moused.x * config.mouseFactor
+ // smoothBuffer.cam.y = moused.y * config.mouseFactor
smoothUpdate()
// const time = Date.now() * 0.001
// scene.traverse((object) =>
// {
- // object.rotation.x = 0.25 * time;
- // object.rotation.y = 0.25 * time;
- // });
+ // object.rotation.x = 0.25 * time
+ // object.rotation.y = 0.25 * time
+ // })
function smoothUpdate(): void
{
@@ -79,11 +81,21 @@ function update(dt: number): void
// Target position
const tp = smoothBuffer.cam
- if (Math.abs(cp.x - tp.x) > delta) { cp.x = cp.x + delta * pn(cp.x < tp.x) }
- else { cp.x = tp.x }
+ if (Math.abs(cp.x - tp.x) > delta)
+ {
+ cp.x = cp.x + delta * pn(cp.x < tp.x)
+ } else
+ {
+ cp.x = tp.x
+ }
- if (Math.abs(cp.y - tp.y) > delta) { cp.y = cp.y + delta * pn(cp.y < tp.y) }
- else { cp.y = tp.y }
+ if (Math.abs(cp.y - tp.y) > delta)
+ {
+ cp.y = cp.y + delta * pn(cp.y < tp.y)
+ } else
+ {
+ cp.y = tp.y
+ }
}
}
@@ -99,7 +111,6 @@ export function start(id: string): void
{
scene = new THREE.Scene()
scene.background = new THREE.Color(config.background)
-
// Create camera
camera = new THREE.PerspectiveCamera(config.cam.fov, window.innerWidth / window.innerHeight,
config.cam.near, config.cam.far)
@@ -111,11 +122,24 @@ export function start(id: string): void
onWindowResize()
window.addEventListener('resize', onWindowResize)
+ addLights()
+
init()
initMouseTracker()
animate()
}
+function addLights(): void
+{
+ objects.hemiLight = addHemiLight(scene)
+ objects.dirLight = addDirLight(scene)
+ objects.ground = addGround(scene)
+ objects.sky = addSky(scene)
+
+ renderer.outputEncoding = THREE.sRGBEncoding
+ renderer.shadowMap.enabled = true
+}
+
function onWindowResize()
{
camera.aspect = window.innerWidth / window.innerHeight
diff --git a/src/animation/Shaders.ts b/src/animation/Shaders.ts
new file mode 100644
index 0000000..1562486
--- /dev/null
+++ b/src/animation/Shaders.ts
@@ -0,0 +1,118 @@
+import * as THREE from 'three'
+import {colors, config} from "@/animation/Config";
+import {DirectionalLight, HemisphereLight, Mesh} from "three";
+
+export const vertexShader = `
+ varying vec3 vWorldPosition;
+
+ void main() {
+ vec4 worldPosition = modelMatrix * vec4( position, 1.0 );
+ vWorldPosition = worldPosition.xyz;
+
+ gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
+ }`;
+
+export const fragmentShader = `
+ uniform vec3 topColor;
+ uniform vec3 bottomColor;
+ uniform float offset;
+ uniform float exponent;
+
+ varying vec3 vWorldPosition;
+
+ void main() {
+ float h = normalize( vWorldPosition + offset ).y;
+ gl_FragColor = vec4( mix( bottomColor, topColor, max( pow( max( h , 0.0), exponent ), 0.0 ) ), 1.0 );
+ }`;
+
+/**
+ * Create sky dome
+ * @param scene
+ */
+export function addSky(scene: THREE.Scene): Mesh
+{
+ const uniforms = {
+ "topColor": { value: colors.sky.top },
+ "bottomColor": { value: colors.sky.bottom },
+ "offset": { value: 33 },
+ "exponent": { value: 0.6 }
+ }
+
+ const skyGeo = new THREE.SphereGeometry( 4000, 32, 15 );
+ const skyMat = new THREE.ShaderMaterial({
+ uniforms: uniforms,
+ vertexShader: vertexShader,
+ fragmentShader: fragmentShader,
+ side: THREE.BackSide
+ });
+
+ const sky = new THREE.Mesh(skyGeo, skyMat)
+ scene.add(sky)
+ scene.fog = new THREE.Fog(colors.sky.bottom, 1, 5000)
+
+ return sky
+}
+
+/**
+ * Create ground
+ * @param scene
+ */
+export function addGround(scene: THREE.Scene): Mesh
+{
+ const groundGeo = new THREE.PlaneGeometry(10000, 10000)
+ const groundMat = new THREE.MeshLambertMaterial({color: colors.sky.ground})
+ const ground = new THREE.Mesh(groundGeo, groundMat)
+ ground.position.y = -33
+ ground.rotation.x = -Math.PI / 2
+ ground.receiveShadow = true
+ scene.add(ground)
+
+ return ground
+}
+
+/**
+ * Add hemisphere light
+ * @param scene
+ */
+export function addHemiLight(scene: THREE.Scene): HemisphereLight
+{
+ const hemiLight = new THREE.HemisphereLight(colors.sky.top, colors.sky.ground, 0.6)
+ hemiLight.position.set(0, 50, 0)
+ scene.add(hemiLight)
+
+ if (config.debug) scene.add(new THREE.HemisphereLightHelper(hemiLight, 10))
+
+ return hemiLight
+}
+
+/**
+ * Add directional light
+ * @param scene
+ */
+export function addDirLight(scene: THREE.Scene): DirectionalLight
+{
+ // Directional light
+ const dirLight = new THREE.DirectionalLight(colors.sky.dirLight, 1)
+ dirLight.position.set(-1, 1.75, 1)
+ dirLight.position.multiplyScalar(30)
+ scene.add(dirLight)
+
+ dirLight.castShadow = true
+
+ dirLight.shadow.mapSize.width = 2048
+ dirLight.shadow.mapSize.height = 2048
+
+ const d = 50
+
+ dirLight.shadow.camera.left = -d
+ dirLight.shadow.camera.right = d
+ dirLight.shadow.camera.top = d
+ dirLight.shadow.camera.bottom = -d
+
+ dirLight.shadow.camera.far = 3500
+ dirLight.shadow.bias = -0.0001
+
+ if (config.debug) scene.add(new THREE.DirectionalLightHelper(dirLight, 10))
+
+ return dirLight
+}