Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Environment asset population #2

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added public/assets/houses/house_type01.backup
Binary file not shown.
Binary file modified public/assets/houses/house_type01.glb
Binary file not shown.
Binary file added public/assets/nature/bush2.glb
Binary file not shown.
Binary file added public/assets/textures/window_blinds.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/assets/textures/window_blinds_emissive.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
34 changes: 32 additions & 2 deletions src/state/SceneState.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import * as THREE from 'three';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';
import { Sky } from 'three/examples/jsm/objects/Sky.js';

import { CanvasListener } from '../utils/CanvasListener';
import { HouseName, ModelLoader, ModelNames, RoadName, VehicleName } from '../utils/ModelLoader';
import { HouseName, ModelLoader, ModelNames, RoadName, VehicleName, FoliageName } from '../utils/ModelLoader';
import { MouseListener } from '../utils/MouseListener';
import { Prop } from '../model/Prop';
import { Road } from '../model/Road';
Expand Down Expand Up @@ -38,6 +39,7 @@ export class SceneState {
modelNames.roads = Object.values(RoadName);
modelNames.vehicles = Object.values(VehicleName);
modelNames.houses = Object.values(HouseName);
modelNames.foliage = Object.values(FoliageName);

this.modelLoader.loadModels(modelNames, () => this.buildScene());
}
Expand Down Expand Up @@ -89,7 +91,7 @@ export class SceneState {

private setupLights() {
// Ambient
const ambientLight = new THREE.HemisphereLight(0xebf6ff, 0x5fa36b, 0.25);
const ambientLight = new THREE.HemisphereLight(0xebf6ff, 0x5fa36b, 0.05);
this.scene.add(ambientLight);

// Directional
Expand Down Expand Up @@ -117,7 +119,35 @@ export class SceneState {
sunGroup.add(helper);
sunGroup.add(directionalLight);
sunGroup.add(directionalLight.target);

const moon = directionalLight.clone(true);
moon.color = new THREE.Color(0x2d7fa8);
moon.intensity = 0.1;
const moonGroup = new THREE.Group();
moonGroup.name = 'MoonGroup';
moonGroup.add(moon);
moonGroup.add(moon.target);

this.scene.add(sunGroup);
//this.scene.add(moonGroup);

// Sky
const sky = new Sky();
sky.scale.setScalar( 450000 );
this.scene.add(sky);
const sunPosition = new THREE.Vector3();
const uniforms = sky.material.uniforms;

// elevation
const phi = THREE.MathUtils.degToRad( 90 - 5 );
// azimuth
const theta = THREE.MathUtils.degToRad( 15 );

sunPosition.setFromSphericalCoords( 1, phi, theta );
const dirLightPos = sunPosition.clone().multiplyScalar(15);
directionalLight.position.copy(dirLightPos);
directionalLight.target.position.set(0,0,0);
uniforms[ 'sunPosition' ].value.copy( sunPosition );
}

private setupCamera() {
Expand Down
Binary file added src/textures/windowBlinds.psd
Binary file not shown.
Binary file added src/textures/window_blinds.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/textures/window_blinds_emissive.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
101 changes: 99 additions & 2 deletions src/utils/ModelLoader.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
import * as THREE from 'three';
import { GLTF, GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
import { NumberUtils } from './NumberUtils';

export class ModelNames {
vehicles: VehicleName[] = [];
roads: RoadName[] = [];
houses: HouseName[] = [];
foliage: FoliageName[] = [];

get modelCount() {
return this.vehicles.length + this.roads.length + this.houses.length;
return this.vehicles.length + this.roads.length + this.houses.length + this.foliage.length;
}
}

type ModelName = VehicleName | RoadName | HouseName;
type ModelName = VehicleName | RoadName | HouseName | FoliageName;

export enum VehicleName {
DELIVERY = 'delivery',
Expand Down Expand Up @@ -56,13 +58,18 @@ export enum HouseName {
TYPE_21 = 'house_type21',
}

export enum FoliageName {
BUSH = 'bush2',
}

/**
* Responsible for loading models and storing them during runtime.
*/
export class ModelLoader {
private readonly vehicleScaleModifer = 0.3;
private readonly roadScaleModifier = 2;
private readonly houseScaleModifier = 1.5;
private readonly foliageScaleModifier = 0.25;
private modelMap = new Map<ModelName, THREE.Group>();
private loadedModels = 0;
private modelsToLoad = 0;
Expand Down Expand Up @@ -97,6 +104,9 @@ export class ModelLoader {

// Load houses
modelNames.houses.forEach((hName) => this.loadHouse(hName, loader));

// Load foliage
modelNames.foliage.forEach((fName) => this.loadFoliage(fName, loader));
}

public getModel(name: ModelName): THREE.Group {
Expand Down Expand Up @@ -198,6 +208,10 @@ export class ModelLoader {
}

private loadHouse(hName: HouseName, loader: GLTFLoader) {
const glassDiffuse = new THREE.TextureLoader().load('assets/textures/window_blinds_diffuse.png'); // should move this out of here
const glassEmissive = new THREE.TextureLoader().load('assets/textures/window_blinds_emissive.png'); // should move this out of here
const glassMat = new THREE.MeshStandardMaterial({roughness: 1, emissive: 0xffb73b, emissiveIntensity: 1});

loader.load(
this.baseAssetPath + `houses/${hName}.glb`,
(model: GLTF) => {
Expand All @@ -209,6 +223,10 @@ export class ModelLoader {
((node as THREE.Mesh).material as THREE.MeshStandardMaterial).metalness = 0;
node.castShadow = true;
node.receiveShadow = true;

if (((node as THREE.Mesh).material as THREE.MeshStandardMaterial).name === 'window') {
(node as THREE.Mesh).material = glassMat;
}
}
});

Expand Down Expand Up @@ -237,4 +255,83 @@ export class ModelLoader {

return parent;
}

private loadFoliage(fName: FoliageName, loader: GLTFLoader) {
loader.load(
this.baseAssetPath + `nature/${fName}.glb`,
(model: GLTF) => {
// Traverse model nodes
model.scene.traverse((node) => {
// If it's a mesh
if ((node as THREE.Mesh).isMesh) {
// Adjust metalness
((node as THREE.Mesh).material as THREE.MeshStandardMaterial).metalness = 0;

if (node.name === 'Leaves') {
const alpha = new THREE.TextureLoader().load('assets/textures/bushUpper_alpha.png'); // should move this out of here
const diffuse = new THREE.TextureLoader().load('assets/textures/bushUpper_diffuse.png'); // should move this out of here
(node as THREE.Mesh).material = new THREE.MeshStandardMaterial({alphaMap: alpha, map: diffuse, transparent: true, alphaTest: 0.9, roughness: 0.66});
} else {
(node as THREE.Mesh).geometry.computeBoundingSphere();
const bSphere = (node as THREE.Mesh).geometry.boundingSphere;
const vec = new THREE.Vector3();
const vertArr = (node as THREE.Mesh).geometry.attributes.position.array;
const vertColors = new Float32Array(vertArr.length * 3);
const baseColor = [46, 38, 28];
const tipColor = [76, 84, 47];
const weightStrength = 1;
//const baseColor = [255, 0, 0];
for (let i = 0; i < vertArr.length; i+=3) {
vec.set(
vertArr[i],
vertArr[i+1],
vertArr[i+2],
);

const length = vec.length() / bSphere.radius;
const alpha = length * weightStrength;
// vertColors[i] = (baseColor[0] / 255) * (1 - length * weightStrength);
// vertColors[i+1] = (baseColor[1] / 255) * (1 - length * weightStrength);
// vertColors[i+2] = (baseColor[2] / 255) * (1 - length * weightStrength);

vertColors[i] = NumberUtils.lerp((baseColor[0] / 255), (tipColor[0] / 255), alpha);
vertColors[i+1] = NumberUtils.lerp((baseColor[1] / 255), (tipColor[1] / 255), alpha);
vertColors[i+2] = NumberUtils.lerp((baseColor[2] / 255), (tipColor[2] / 255), alpha);
}
(node as THREE.Mesh).geometry.setAttribute('color', new THREE.BufferAttribute(vertColors, 3));
(node as THREE.Mesh).material = new THREE.MeshStandardMaterial({vertexColors: true});
//((node as THREE.Mesh).material as THREE.MeshStandardMaterial).vertexColors = true;
}

//node.castShadow = true;
//node.receiveShadow = true;
}
});

const foliage = this.setupFoliage(model.scene);
this.onLoadModel(fName, foliage);
},
undefined,
this.onLoadError
);
}

private setupFoliage(foliage: THREE.Group) {
// Adjust scale of houses
//house.scale.set(this.houseScaleModifier, this.houseScaleModifier, this.houseScaleModifier);
foliage.scale.set(this.foliageScaleModifier, this.foliageScaleModifier, this.foliageScaleModifier);

// Set transform origin to center of the model
const box = new THREE.Box3().setFromObject(foliage);
box.getCenter(foliage.position).multiplyScalar(-1);

// Models are centered, move to sit at ground level
foliage.position.y = 0;

// Wrap in parent to avoid losing above transforms
const parent = new THREE.Group();
parent.add(foliage);

return parent;
}
}
4 changes: 4 additions & 0 deletions src/utils/NumberUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,4 +68,8 @@ export class NumberUtils {

return closest;
}

public static lerp (a: number, b: number, t: number) {
return (1 - t) * a + t * b;
}
}
28 changes: 21 additions & 7 deletions src/utils/SceneBuilder.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import * as THREE from 'three';

import { HouseName, ModelLoader, RoadName, VehicleName } from './ModelLoader';
import { HouseName, ModelLoader, RoadName, VehicleName, FoliageName } from './ModelLoader';
import { Prop } from '../model/Prop';
import { Road } from '../model/Road';
import { RoadFactory } from './RoadFactory';
import { RoadUtils } from './RoadUtils';
import { Vehicle } from '../model/Vehicle';
import { VehicleFactory } from './VehicleFactory';
import { BufferAttribute } from 'three';

enum GroundType {
GRASS = 'grass',
Expand Down Expand Up @@ -550,6 +549,8 @@ export class SceneBuilder {
new THREE.Vector2(1, 1),
new THREE.Vector3(8, 0, -4)
);
const f1 = this.addFoliage(FoliageName.BUSH, new THREE.Vector3(8, 0, -4));
const r1 = [g16, f1];

return [
...block1,
Expand All @@ -565,7 +566,7 @@ export class SceneBuilder {
...block11,
...block12,
...block13,
g16,
...r1,
];
}

Expand Down Expand Up @@ -634,16 +635,29 @@ export class SceneBuilder {

if (type === GroundType.GRASS) {
const grass = this.addGrass(size, pos, 1000);
const bushes = this.addBushes(size, pos, 2);
//const bushes = this.addBushes(size, pos, 2);
group.add(grass);
group.add(bushes);
//group.add(bushes);
}

const prop = new Prop(group);

return prop;
}

private addFoliage(name: FoliageName, pos: THREE.Vector3) {
const foliageModel = this.modelLoader.getModel(name);
const foliage = new Prop(foliageModel);

foliage.position.x = pos.x;
foliage.position.y = pos.y;
foliage.position.z = pos.z;

foliage.rotation.y = Math.random() * Math.PI * 2;

return foliage;
}

private addGrass(size: THREE.Vector2, pos: THREE.Vector3, density: number): THREE.Group {
const totalCount = size.x * size.y * density;

Expand Down Expand Up @@ -700,7 +714,7 @@ export class SceneBuilder {
grassGeo.setAttribute( 'position', new THREE.Float32BufferAttribute( square, 3 ) );
grassGeo.setAttribute( 'normal', new THREE.Float32BufferAttribute( normals, 3 ) );
grassGeo.setAttribute( 'uv', new THREE.Float32BufferAttribute( uv, 2 ) );
grassGeo.setAttribute('color', new BufferAttribute(vertColors, 3));
grassGeo.setAttribute('color', new THREE.BufferAttribute(vertColors, 3));
//const grass = new THREE.Mesh( grassGeo, grassMat );

const mesh = new THREE.InstancedMesh(grassGeo, grassMat, totalCount);
Expand Down Expand Up @@ -804,7 +818,7 @@ export class SceneBuilder {
bushGeo.setAttribute( 'position', new THREE.Float32BufferAttribute( square, 3 ) );
bushGeo.setAttribute( 'normal', new THREE.Float32BufferAttribute( normals, 3 ) );
bushGeo.setAttribute( 'uv', new THREE.Float32BufferAttribute( uv, 2 ) );
bushGeo.setAttribute('color', new BufferAttribute(vertColors, 3));
bushGeo.setAttribute('color', new THREE.BufferAttribute(vertColors, 3));

const mesh = new THREE.InstancedMesh(bushGeo, bushMat, totalCount);

Expand Down