From 89f656f2f30d79d2d5401bbd37eb1f1a0119a2e3 Mon Sep 17 00:00:00 2001 From: Florian Sylvain Date: Mon, 10 Jun 2024 13:35:21 +0200 Subject: [PATCH] feat: basic chunk system --- public/stone.png | Bin 0 -> 322 bytes src/chunk.ts | 119 +++++++++++++++++++++++++++++++++++++++++++++ src/main.ts | 123 +++++++---------------------------------------- 3 files changed, 136 insertions(+), 106 deletions(-) create mode 100644 public/stone.png create mode 100644 src/chunk.ts diff --git a/public/stone.png b/public/stone.png new file mode 100644 index 0000000000000000000000000000000000000000..ffb3b731a77475ba403e1b073268c2abb3f42f2e GIT binary patch literal 322 zcmeAS@N?(olHy`uVBq!ia0vp^0zjO=!VDyz{eM3hNHG=%xjQkeJ16rJ$YDu$^mSxl z*x1kgCy^D%*A4IqaZOH6j*X3ti;GK0NJvUbN=!_QkB?7DNr{PxiH?qrii(PijEsng z2oDbr3kzEikoO9xk+Z-fvY3H^?+^$xifVW@00rlHx;TbdoPK+5qhOPPMBBsjf=RC0 z_bPc7ToE&B3z>NI9GZlmq%+rO6qS;G}HXl~K z_|wW;St9$+iRKll?`CeaU-{zWJ7%HWSPQ%w0W?mR5L8d&;IiH|9?DwGJ52l{p1`uD+=gR N22WQ%mvv4FO#pU;d4vD} literal 0 HcmV?d00001 diff --git a/src/chunk.ts b/src/chunk.ts new file mode 100644 index 0000000..24ed2f5 --- /dev/null +++ b/src/chunk.ts @@ -0,0 +1,119 @@ +import { InstancedMesh, Texture, Vector3 } from "three" +import Face, { Orientation } from "./face" + +const FACES_OFFSETS: { [key: string]: Vector3 } = { + Up: new Vector3(0, 1, 0), + North: new Vector3(0, 0, 1), + South: new Vector3(0, 0, -1), + East: new Vector3(-1, 0, 0), + West: new Vector3(1, 0, 0), + Down: new Vector3(0, -1, 0) +} + +interface BlockData { + position: Vector3 + textureName: string +} + +export default class Chunk { + chunk: BlockData[] + chunkSet: Set + radius: number + textures: { [name: string]: Texture[] } + faces: { [key: string]: Face[] } + + constructor(radius: number, textures: { [name: string]: Texture[] }) { + this.chunk = [] + this.chunkSet = new Set() + this.radius = radius + this.textures = textures + this.faces = {} + this.generateChunk() + this.initializeFaces() + } + + generateChunk() { + for (let i = 0; i < this.radius; i++) { + for (let j = 0; j < this.radius; j++) { + const max = Math.ceil(Math.sin(i / 30) * 10 + Math.cos(j / 30) * 10) + for (let k = -16; k <= max; k++) { + const position = new Vector3(i, k, j) + let textureName = "stone" + if (k === max) textureName = "grass" + else if (k > max - 6) textureName = "dirt" + this.chunk.push({ position, textureName }) + this.chunkSet.add(position.toArray().toString()) + } + } + } + } + + initializeFaces() { + for (const textureName in this.textures) { + const textureFaces = this.textures[textureName].map((texture, index) => { + const orientation = ["Up", "North", "South", "East", "West", "Down"][ + index + ] as Orientation + return new Face(orientation, 0, texture) + }) + this.faces[textureName] = textureFaces + } + } + + filterFaces(block: Vector3, textureName: string): Face[] { + return this.faces[textureName].filter((face) => { + const offset = FACES_OFFSETS[face.orientation] + const adjacentBlock = new Vector3( + block.x + offset.x, + block.y + offset.y, + block.z + offset.z + ) + return !this.chunkSet.has(adjacentBlock.toArray().toString()) + }) + } + + countVisibleFaces() { + const faceCounts: { [key: string]: { [key: string]: number } } = {} + + this.chunk.forEach(({ position, textureName }) => { + if (!faceCounts[textureName]) { + faceCounts[textureName] = { + Up: 0, + North: 0, + South: 0, + East: 0, + West: 0, + Down: 0 + } + } + Object.keys(FACES_OFFSETS).forEach((orientation) => { + const offset = FACES_OFFSETS[orientation] + const adjacentBlock = new Vector3( + position.x + offset.x, + position.y + offset.y, + position.z + offset.z + ) + if (!this.chunkSet.has(adjacentBlock.toArray().toString())) { + faceCounts[textureName][orientation]++ + } + }) + }) + + for (const textureName in faceCounts) { + for (const orientation in faceCounts[textureName]) { + const face = this.faces[textureName].find( + (f) => f.orientation === orientation + ) + if (!face?.instancedMesh) return + face.instancedMesh.count = faceCounts[textureName][orientation] + face.instancedMesh = new InstancedMesh( + face?.geometry, + face?.material, + faceCounts[textureName][orientation] + ) // TODO dégueulasse + } + } + + return faceCounts + } +} diff --git a/src/main.ts b/src/main.ts index 602ed0f..6a3f575 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,10 +1,9 @@ import "./style.css" import * as THREE from "three" import { OrbitControls } from "three/addons/controls/OrbitControls.js" -import Face from "./face" +import Chunk from "./chunk" import Block from "./block" import TextureLoader from "./textureLoader" -// import TextureLoader from "./textureLoader" const scene = new THREE.Scene() const camera = new THREE.PerspectiveCamera( @@ -21,120 +20,32 @@ const controls = new OrbitControls(camera, renderer.domElement) controls.update() document.body.appendChild(renderer.domElement) -let grassTextures = [] as THREE.Texture[] -let dirtTextures = [] as THREE.Texture[] +let textures: { [name: string]: THREE.Texture[] } = {} async function loadTextures() { const textureLoader = new TextureLoader(16, 16) - grassTextures = await textureLoader.load("/grass.png") - dirtTextures = await textureLoader.load("/dirt.png") - // const debugTextures = await textureLoader.load("/debug.png") - onTextureLoaded() + textures["grass"] = await textureLoader.load("/grass.png") + textures["dirt"] = await textureLoader.load("/dirt.png") + textures["stone"] = await textureLoader.load("/stone.png") + onTexturesLoaded() } -// const gridHelper = new THREE.GridHelper(1000, 1000) -// scene.add(gridHelper) +function onTexturesLoaded() { + const radius = 128 + const chunk = new Chunk(radius, textures) -// const axesHelper = new THREE.AxesHelper(500) -// scene.add(axesHelper) - -const FACES_OFFSETS: { [key: string]: THREE.Vector3 } = { - Up: new THREE.Vector3(0, 1, 0), - North: new THREE.Vector3(0, 0, 1), - South: new THREE.Vector3(0, 0, -1), - East: new THREE.Vector3(-1, 0, 0), - West: new THREE.Vector3(1, 0, 0), - Down: new THREE.Vector3(0, -1, 0) -} - -function filterFaces( - faces: Face[], - block: THREE.Vector3, - chunkSet: Set -): Face[] { - return faces.filter((face) => { - const offset = FACES_OFFSETS[face.orientation] - const adjacentBlock = new THREE.Vector3( - block.x + offset.x, - block.y + offset.y, - block.z + offset.z - ) - return !chunkSet.has(adjacentBlock.toArray().toString()) - }) -} - -function countVisibleFaces( - chunkSet: Set, - chunk: THREE.Vector3[] -): { [key: string]: number } { - const faceCounts: { [key: string]: number } = { - Up: 0, - North: 0, - South: 0, - East: 0, - West: 0, - Down: 0 - } - - chunk.forEach((block) => { - Object.keys(FACES_OFFSETS).forEach((orientation) => { - const offset = FACES_OFFSETS[orientation] - const adjacentBlock = new THREE.Vector3( - block.x + offset.x, - block.y + offset.y, - block.z + offset.z - ) - if (!chunkSet.has(adjacentBlock.toArray().toString())) { - faceCounts[orientation]++ - } - }) - }) - - return faceCounts -} - -function onTextureLoaded() { - const chunk = [] as THREE.Vector3[] - const chunkSet = new Set() - const radius = 32 - for (let i = 0; i < radius; i++) { - for (let j = 0; j < radius; j++) { - const max = Math.ceil(Math.sin(i / 30) * 10 + Math.cos(j / 30) * 10) - for (let k = -64; k < max; k++) { - const vec3 = new THREE.Vector3(i, k, j) - chunk.push(vec3) - chunkSet.add(vec3.toArray().toString()) - } - } - } - - const faceCounts = countVisibleFaces(chunkSet, chunk) - - const grassFaces = [ - new Face("Up", faceCounts.Up, grassTextures[0]), - new Face("North", faceCounts.North, grassTextures[1]), - new Face("South", faceCounts.South, grassTextures[2]), - new Face("East", faceCounts.East, grassTextures[3]), - new Face("West", faceCounts.West, grassTextures[4]), - new Face("Down", faceCounts.Down, grassTextures[5]) - ] - - const dirtFaces = [ - new Face("Up", faceCounts.Up, dirtTextures[0]), - new Face("North", faceCounts.North, dirtTextures[1]), - new Face("South", faceCounts.South, dirtTextures[2]), - new Face("East", faceCounts.East, dirtTextures[3]), - new Face("West", faceCounts.West, dirtTextures[4]), - new Face("Down", faceCounts.Down, dirtTextures[5]) - ] + chunk.countVisibleFaces() const cubes = [] as Block[] - chunk.forEach((block) => { - cubes.push(new Block(filterFaces(grassFaces, block, chunkSet), block)) + chunk.chunk.forEach(({ position, textureName }) => { + const faces = chunk.filterFaces(position, textureName) + cubes.push(new Block(faces, position)) }) - grassFaces.forEach((face) => { - if (face.instancedMesh) scene.add(face.instancedMesh) + Object.values(chunk.faces).forEach((faceArray) => { + faceArray.forEach((face) => { + if (face.instancedMesh) scene.add(face.instancedMesh) + }) }) }