What techniques can be applied with Three.js to create terrain with voxel generators?

I came across voxel js, but it appears to be outdated and utilizes node js, which I am not interested in using. My goal is to generate basic terrain using for loops and a function to build a block.

Below is the function I have created:

function createBlock(block, x, y, z, top, bottom, front, back, left, right) {
    var geometry;
    var meshFaceMaterial;
    var mesh;
    var material;
    var blockObj = {};
    if (top == true) {
        geometry = new THREE.PlaneGeometry(1, 1);
        material = new THREE.MeshPhongMaterial({map: THREE.ImageUtils.loadTexture(blocks[block].top)});
        meshFaceMaterial = new THREE.MeshFaceMaterial(material);
        mesh = new THREE.Mesh(geometry, meshFaceMaterial);
        mesh.position.z = z;
        mesh.position.x = x;
        mesh.position.y = y+5;
        mesh.rotation.x = (-90 * Math.PI)/180;
        blockObj.top = mesh;
    }
    if (bottom == true) {
        geometry = new THREE.PlaneGeometry(1, 1);
        material = new THREE.MeshPhongMaterial({map: THREE.ImageUtils.loadTexture(blocks[block].bottom)});
        meshFaceMaterial = new THREE.MeshFaceMaterial(material);
        mesh = new THREE.Mesh(geometry, meshFaceMaterial);
        mesh.position.z = z;
        mesh.position.x = x;
        mesh.position.y = y-5;
        mesh.rotation.x = (90 * Math.PI)/180;
        blockObj.bottom = mesh;
    }
    if (back == true) {
        geometry = new THREE.PlaneGeometry(1, 1);
        material = new THREE.MeshPhongMaterial({map: THREE.ImageUtils.loadTexture(blocks[block].side)});
        meshFaceMaterial = new THREE.MeshFaceMaterial(material);
        mesh = new THREE.Mesh(geometry, meshFaceMaterial);
        mesh.position.z = z-5;
        mesh.position.x = x;
        mesh.position.y = y;
        mesh.rotation.y = (180 * Math.PI)/180;
        blockObj.back = mesh;
    }
    if (right == true) {
        geometry = new THREE.PlaneGeometry(1, 1);
        material = new THREE.MeshPhongMaterial({map: THREE.ImageUtils.loadTexture(blocks[block].side)});
        meshFaceMaterial = new THREE.MeshFaceMaterial(material);
        mesh = new THREE.Mesh(geometry, meshFaceMaterial);
        mesh.position.z = z;
        mesh.position.x = x+5;
        mesh.position.y = y;
        mesh.rotation.y = (90 * Math.PI)/180;
        blockObj.right = mesh;
    }
    if (left == true) {
        geometry = new THREE.PlaneGeometry(1, 1);
        material = new THREE.MeshPhongMaterial({map: THREE.ImageUtils.loadTexture(blocks[block].side)});
        meshFaceMaterial = new THREE.MeshFaceMaterial(material);
        mesh = new THREE.Mesh(geometry, meshFaceMaterial);
        mesh.position.z = z;
        mesh.position.x = x-5;
        mesh.position.y = y;
        mesh.rotation.y = (-90 * Math.PI)/180;
        blockObj.left = mesh;
    }
    if (front == true) {
        geometry = new THREE.PlaneGeometry(1, 1);
        material = new THREE.MeshPhongMaterial({map: THREE.ImageUtils.loadTexture(blocks[block].side)});
        meshFaceMaterial = new THREE.MeshFaceMaterial(material);
        mesh = new THREE.Mesh(geometry, meshFaceMaterial);
        mesh.position.z = z+5;
        mesh.position.x = x;
        mesh.position.y = y;
        blockObj.front = mesh;
    }

    blockObjects.push(blockObj);

    return blockObj;
}

I would appreciate any assistance on this matter.

Answer №1

Presented below is an innovative algorithm designed to construct cubes and create a unique terrain using them. In this scenario, the algorithm ensures that the change in height of the terrain is limited to one cube height higher than the adjacent cubes. Each cube is assigned a random green color, although the possibility exists to utilize any texture that suits your vision.

var camera, scene, renderer;
    var mesh;

    var cubesize = 30;
    var landscape_width = 30;
    var landscape_length = 30;
    var heights = [];
    var camera_offset = cubesize * landscape_width *0.7;
    var camera_height = cubesize * landscape_width / 2;

    function init() {
        camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 1, 10000 );
        camera.position.set(0,camera_offset,camera_height);
        camera.up = new THREE.Vector3(0,0,1);
        camera.lookAt(new THREE.Vector3(0,0,0));
        scene = new THREE.Scene();

        geom = new THREE.CubeGeometry( cubesize, cubesize, cubesize );
        cubes = new THREE.Object3D();
        scene.add( cubes );

        var xoff = landscape_width * cubesize / 2;
        var yoff = landscape_length * cubesize / 2;
        for(var i=0; i<landscape_width; i++) heights[i,0] = 0;
        for(var j=0; j<landscape_length; j++) heights[0,j] = 0;

        for(var i=1; i<landscape_width; i++) {
            var h = heights[i-1,0];
            for(var j=1; j< landscape_length; j++ ) {
                var rand = Math.random();
                if(heights[i-1,j] == heights[i,j-1]) { // level ground, go up dn or stay
                    if(rand < 0.33) 
                        heights[i,j] = heights[i-1,j] - cubesize;
                    else if (rand > 0.66)
                        heights[i,j] = heights[i-1,j] + cubesize;
                    else 
                        heights[i,j] = heights[i-1,j];                            
                }
                else if(Math.abs(heights[i-1,j] - heights[i,j-1]) > cubesize) { // two edges are wide apart, split the difference
                    heights[i,j] = (heights[i-1,j] +heights[i,j-1])/2;
                }
                else {
                    if(rand > 0.5)
                        heights[i,j] = heights[i-1,j];
                    else 
                        heights[i,j] = heights[i,j-1];                            
                }

                var grayness = Math.random() * 0.5 + 0.25,
                    mat = new THREE.MeshBasicMaterial(),
                    cube = new THREE.Mesh( geom, mat );
                mat.color.setRGB( 0, grayness, 0 );
                cube.position.set( i*cubesize - xoff, j*cubesize - yoff, heights[i,j] );
                cubes.add( cube );                        
            }
        }

        renderer = new THREE.WebGLRenderer();
        renderer.setPixelRatio( window.devicePixelRatio );
        renderer.setSize( window.innerWidth, window.innerHeight );
        document.body.appendChild( renderer.domElement );
        //
        window.addEventListener( 'resize', onWindowResize, false );
    }
    function onWindowResize() {
        camera.aspect = window.innerWidth / window.innerHeight;
        camera.updateProjectionMatrix();
        renderer.setSize( window.innerWidth, window.innerHeight );
    }
    var angle = 0;
    function animate() {
        angle += 0.5;
        var rads = angle * Math.PI /180;
        camera.position.set(Math.cos(rads)*camera_offset,Math.sin(rads)*camera_offset,camera_height);
        camera.lookAt(scene.position);
        requestAnimationFrame( animate );
        renderer.render( scene, camera );
    }

    init();

    animate();
body {
        margin: 0px;
        background-color: #000000;
        overflow: hidden;
    }
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/85/three.js"></script>

Answer №2

If I understand correctly, you are inquiring about loops that can iterate through your function in three dimensions: x, y, and z.

You can achieve this using the following code:

for (var i = 0; i < SIZEX; i++) {
  for (var j = 0; j < SIZEY; j++) {
    for (var k = 0; k < SIZEZ; k++) {
      createBlock(block, i, j, k, (k == SIZEZ-1), (k == 0), (j == SIZEY-1), (j == 0), (i == SIZEX-1), (i == 0));
    }
  }
}

This code allows for traversal in three dimensions. If (k == SIZEZ-1) evaluates to true, then top is set to true in the function. The same logic applies to the other conditions.

It is unclear what the variable block represents in this context.

I hope this provides the information you were seeking.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Creating an interactive Google line chart in MVC4

I am currently working on a dynamic line chart that needs to be able to adjust the number of lines (Standard, Latest, Earliest, Average) based on the database records. My code structure is similar to this example. function drawChart() { var data = ...

Place the `service` parameter into the `run` function

What are some examples of when to utilize the angular.run method? I have a service that is resource-intensive and takes a significant amount of time to initialize before it can be used in conjunction with my view. angular.module('myApp').service ...

Find the quantity of items in each list individually and add them to a new list

Seeking a solution for a seemingly simple issue. I am attempting to calculate the number of list items and then add this count to the list in the parent div. The problem lies in the fact that it always displays the value of the last item in the list. For i ...

JavaScript Alert: The Ajax XMLHttpRequest Response has Returned Null

Below is the code snippet: <script type="text/javascript"> var xmlhttp; $(document).ready(function (){ xmlhttp=new XMLHttpRequest(); ...

Passing events from a grandchild component up to its grandparent component in VueJS 2.0

Vue.js 2.0 appears to have a limitation where events cannot be emitted directly from a grand child component to its grand parent. Vue.component('parent', { template: '<div>I am the parent - {{ action }} <child @eventtriggered="pe ...

What is the best way to link optional and undefined paths in AngularJS routing?

When it comes to AngularJS routing, I have a question. How can we combine the use of a star (*) to match paths with slashes and a question mark (?) to match optional paths? Specifically, I am looking to match both /admin/tasks and /admin/tasks/arbitrary/pa ...

tips on locating the next immediate downloadable cell in a table

My table includes cells with colspan and rowspan attributes. <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script> <table border=1 id="mytable" > <tr><td>A1</td> <td> A2 < ...

Choosing between JavaScript and Handlebars.js depends on the specific needs

Can anyone explain the advantages of utilizing Handlebars.js or similar libraries over solely relying on JavaScript? Thus far, I haven't come across any functionality in Handlebars that cannot be achieved with just pure JavaScript. ...

The functionality of Object.assign in REACT is producing unexpected and incorrect results

Hey everyone, I have a project in React with 3 components. My goal is to extract the state from these 3 components and combine them into one JSON object on a final page. The components are not nested as child and parent, so my workaround was to set the st ...

Divide the table row and store each cell using regular expressions

Here is the original source text: gi0/1 1G-Fiber -- -- -- -- Down -- -- Access gi0/2 1G-Fiber -- -- -- -- Down -- -- gi0/3 1G-Fiber -- -- -- -- Down -- -- gi0/4 1G-Fiber -- -- -- -- Down -- -- gi0/5 1G-Fiber -- -- -- -- Down -- -- gi0/0/1 1G-Fiber -- ...

How can we rearrange the positions of three items in an array?

I am dealing with a function that returns an array of objects structured like this const allGreen = _.filter( sidebarLinks, side => !isServicePage(side.slug.current) ); https://i.stack.imgur.com/dR8FL.png I am attempting to rearrange the positions of ...

What is the best way to extract the lodash score from a URL using JSON parsing?

Can someone help me figure out how to extract and store the names from a URL into an array, then parse JSON data to retrieve the lodash score and convert it into a whole number? Any assistance would be greatly appreciated. <head> <title> ...

How can I create 3 conditions in an AJAX request to verify a user's ID?

I am trying to create 3 conditions in Ajax to check when creating a new user id. It works for 2 conditions (username can be used and username is already in use), but I encounter a problem when the user leaves the username field empty, and it still displays ...

Modifying the appearance of radio buttons using jQuery

I'm new to jQuery and I'm finding it challenging. Currently, I have a set of three radio buttons with the third button already prechecked. My aim is to change the CSS class of the checked button, making it similar to an unchecked button with the ...

Ways to display the chosen value based on the item's index using Javascript in Angular

If you want to view the complete code, just click on this link. I have identified the main issue here. Check out the code here: https://stackblitz.com/edit/test-trainin-2?file=src/app/app.component.html The problem is when you interact with the green bal ...

Separating a sphere into various textures

My current project involves a sphere with an earth texture that I am creating dynamically using the canvas element from an SVG file and then manipulating it. The texture size I am working with is 16384x8192. If I go any lower, the image starts to look blu ...

Automate logging in and out of Gmail chat by programmatically simulating clicks on the span elements that represent the chat status in Gmail

When I'm at work, I prefer using Gmail's encrypted chat feature because it logs chats without saving anything to the hard drive. However, when I'm at home, I switch to Pidgin as logging into Gmail chat at home can lead to messages ending up ...

Can you provide the keycodes for the numpad keys: "/" and "." specifically for the libraries I am utilizing or any other library that does not overlook them?

I've hit a roadblock with my Chrome Extension development. Despite using two different methods to add keyboard functionality, the keys "/" for divide and "." for decimal on the keypad are just not registering. I've attempted to tackle this issue ...

I'm encountering a strange issue where Node JS is mistakenly claiming that the method doesn't exist, even though

Ah, it seems I've encountered an error in my test project. The issue lies with Node JS not being able to locate the getStr function within the Another object. Allow me to share the code with you: test.js var Another = require('./another.js&apo ...

Requesting Access-Control-Request-Headers using jQuery Ajax POST method

I am attempting to send an AJAX request to my server. Initially, I referenced a library (in the web) within a <script> tag in my HTML document and executed it using the following code: $.ajax({ url: api_url + "movie/create", type : "POST", con ...