What is the best way to combine two vertex positions using a distance-based blending technique relative to the camera's position?

My goal is to achieve a smooth transition between two different vertex positions based on the distance from the camera. Specifically, I aim to create a visual effect that seamlessly shifts between a horizontal plane near the camera and a vertical plane in the background. The desired outcome is a curved plane that extends upwards and away from the camera's current position.

From a plane lying flat on the ground: https://i.sstatic.net/OGvtA.png

To the same plane rotated 90 degrees: https://i.sstatic.net/wL0Uy.png

Although I've made progress in my implementation, I still feel like there are missing pieces that prevent me from completing it successfully. I drew inspiration from a Tangram demo (shader code), but I struggle to achieve similar results. The Tangram example uses a different setup compared to my Three.js environment, making replication challenging.

Here is my current progress: https://jsfiddle.net/robhawkes/a97tu864/

varying float distance;

mat4 rotateX(float rotationX) {
  return mat4(
    vec4(1.0,0.0,0.0,0.0),
    vec4(0.0,cos(rotationX),-sin(rotationX),0.0),
    vec4(0.0,sin(rotationX),cos(rotationX),0.0),
    vec4(0.0,0.0,0.0,1.0)
  );
}

void main() 
{
  vec4 vPosition = vec4(position, 1.0);
  vec4 modelViewPosition = modelViewMatrix * vPosition;

  float bend = radians(-90.0);
  vec4 newPos = rotateX(bend) * vPosition;

  distance = -modelViewPosition.z;

  float factor = 0.0;

  vPosition = mix(vPosition, newPos, factor);

  gl_Position = projectionMatrix * modelViewMatrix * vPosition;
}

The steps I'm taking are:

  • Compute the rotated position of the vertex (vertical version)
  • Determine the distance between the vertex and the camera
  • Utilize mix to blend between the horizontal and vertical positions based on the distance

Despite my efforts, I am unable to achieve the desired outcome accurately.

Any insights or guidance to steer me in the right direction would be greatly appreciated, given my limited knowledge of shaders and matrices.

Answer №1

The main problem lies in the fact that you are only tessellating the THREE.PlaneBufferGeometry in width segments and not in height segments:

groundGeometry = new THREE.PlaneBufferGeometry( 
    1000, 10000, 
    100,    // <----- widthSegments 
    100 );  // <----- heightSegments should be added

To address this issue, you can now utilize the z coordinate of the view space for the interpolation:

float factor = -modelViewPosition.z / 2000.0;

var camera, controls, scene, renderer;
var groundGeometry, groundMaterial, groundMesh;
var ambientLight;

init();
initLight();
initGround();
animate();

function init() {
 
  camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 0.01, 10000 );
  camera.position.y = 500;
  camera.position.z = 1000;
  
  controls = new THREE.MapControls( camera );
  controls.maxPolarAngle = Math.PI / 2;

  scene = new THREE.Scene();
  
  scene.add(camera);
  
  var axesHelper = new THREE.AxesHelper( 500 );
scene.add( axesHelper );

  renderer = new THREE.WebGLRenderer( { antialias: true } );
  renderer.setSize( window.innerWidth, window.innerHeight );
        
  document.body.appendChild( renderer.domElement );
 
}

function initLight() {
  ambientLight = new THREE.AmbientLight( 0x404040 );
scene.add( ambientLight );
}

function initGround() {
groundMaterial = new THREE.ShaderMaterial({
    vertexShader: document.getElementById( 'vertexShader' ).textContent,
    fragmentShader: document.getElementById( 'fragmentShader' ).textContent,
    transparent: true
  });
  
  groundGeometry = new THREE.PlaneBufferGeometry( 1000, 10000, 100, 100 );
  groundMesh = new THREE.Mesh( groundGeometry, groundMaterial );
  groundMesh.position.z = -3000;
  groundMesh.position.y = -100;
  groundMesh.rotateX(-Math.PI / 2)
  scene.add( groundMesh );
}

function animate() {
 
  requestAnimationFrame( animate );
  
  controls.update();
  
  renderer.render( scene, camera );
 
}
<script type="x-shader/x-vertex" id="vertexShader">
varying float distance;

mat4 rotateX(float rotationX) {
  return mat4(
    vec4(1.0,0.0,0.0,0.0),
    vec4(0.0,cos(rotationX),-sin(rotationX),0.0),
    vec4(0.0,sin(rotationX),cos(rotationX),0.0),
    vec4(0.0,0.0,0.0,1.0)
  );
}

void main() 
{
  vec4 vPosition = vec4(position, 1.0);
  vec4 modelViewPosition = modelViewMatrix * vPosition;
    
  float bend = radians(-90.0);
  vec4 newPos = rotateX(bend) * vPosition;
  
  distance = -modelViewPosition.z;
  
  float factor = -modelViewPosition.z / 2000.0;
  
  vPosition = mix(vPosition, newPos, factor);
  
  gl_Position = projectionMatrix * modelViewMatrix * vPosition;
}
</script>
<script type="x-shader/x-fragment" id="fragmentShader">
varying float distance;

void main() {
  if (distance < 3000.0) {
    gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
  } else {
    gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
  }
}
</script>

<script src="https://threejs.org/build/three.min.js"></script>

<script src="https://rawgit.com/mrdoob/three.js/dev/examples/js/controls/MapControls.js"></script>

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

Steps to hide a div after it has been displayed once during a user's session

After a successful login, I have a div that displays a success message and then hides after 4 seconds using the following JavaScript code: document.getElementById('success').style.display = 'none'; }, 4000); While this functionality wo ...

Substituting Hebrew characters for Mandaic characters within certain HTML tags can cause links to malfunction

What causes the JavaScript code provided to replace Mandaic characters with Hebrew characters on a webpage to also disable all links on the page? The code snippet is as shown below: function replaceMandaicCharacters() { const mandaicLetters = "&bsol ...

Passing the value in a td element to a JavaScript function using Thymeleaf onClick

Trying to utilize "Thymeleaf" for the first time, I am attempting to pass a value to JavaScript with the following code: onclick="getPropId('${properties.id}')" The corresponding function is as follows: getPropId(inputID){alert(inputId);} Unf ...

Observing the evolution of Vue with Observable notifications

I'm currently working on creating a method to verify a user's login status using firebase's firebase.auth().onAuthStateChanged(). My intention is to make this functionality accessible throughout my app as a global variable. Presently, I am ...

How can I retrieve a list of downloads utilizing the Chrome.downloads api?

I have developed an extension that needs to display all the downloads from the user's downloads folder on a webpage instead of opening the download folder directly. Below is the code I have implemented: window.onload = function(){ var maxNumOfEn ...

Clicking in Javascript can hide the scroll and smoothly take you to the top of the page

For my website, I found this useful tool: It's been working great for me, but one issue I've encountered is that when I click on a picture using the tool, its opacity changes to 0 but the link remains in the same spot. I'm trying to figure ...

Utilize formData to upload an image to a database with ajax

I'm struggling with the process of uploading an image from an HTML form. The goal is for the form to send the image name along with other data to a PHP page. Instead of using the serialized function, I opted for formData as it has the capability to h ...

Retrieving the hidden field value using JavaScript on the server side

I'm encountering an issue with asp:hiddenfield where, after changing its value on the client side and trying to retrieve it on the server side, it returns null. Here is my client-side code: function pageLoad() { var gV = $('#<%=Hidden ...

"Exploring the possibilities of Ajax in conjunction with Sol

I recently completed a tutorial on Ajax Solr and followed the instructions in step one. Below is the code I wrote: header.php: <script type="text/javascript" src="static/js/ajax-solr/core/Core.js"></script> <script type="text/javascript" s ...

What is the process for creating a multi-word argument?

Is there a way to create multi-word arguments, such as reasons for bans or mutes? Currently, I am using args[2], args[3], args[4], args[5]... but this approach is limited and if nothing is written in those arguments, it will display "undefined". If you k ...

Error SCRIPT1002 was encountered in the vendor.js file while using Angular 8 on Internet Explorer 11

Having trouble getting Angular to function properly in IE 11. I've tried all the solutions I could find online. The errors I'm encountering are as follows: SCRIPT1002: Syntax error File: vendor.js, Line: 110874, Column: 40 At line 110874 args[ ...

Retrieving and securely storing information using fetch() on authenticated REST services

Currently, I have successfully set up a React application that communicates with a REST backend which is built using Python and Flask. The specific functionality I have achieved involves downloading data from a database and saving it as a CSV file through ...

Guidelines for Implementing Particle Animation in Your Shiny Application

I'm curious about implementing Particle-animation in the background of my Shiny app, similar to the effects in Here's the current state of my Shiny code. ui.R library(shiny) fluidPage( tagList(tags$head(includeCSS("CSS.css"), includeScrip ...

When it comes to optimizing JavaScript, what is the best approach for replacing multiple substrings in a string with various strings?

While working on the code I develop and maintain, I encountered an issue. There is a function in my code that takes a query (in the form of a string) and replaces certain substrings within that string with different ones. For instance, if a user inputs th ...

Obtain the text content in cases where the DOM is missing both the title and value fields

I am trying to extract the value from a text-box using selenium, but the text-box is marked as readonly and aria-live is set to off. Here is the DOM structure: <input autocomplete="off" class="abc" type="text" role="t ...

After successfully sending a GET request to the API, the Next.js 13.4.3 website still does not reflect new posts added on the hosting platform

I am currently using Next.js version 13.4.3 in my app directory to create a blog site. However, I am facing an issue. When I run npm run build locally on my computer and then start with npm run start, the new posts are displayed normally after adding them ...

Issues concerning date and time manipulation - Library Moment.js

As a beginner in JavaScript, I've been working on an activity that generates a table of train times based on user input. However, I'm facing issues with formatting the arrival time correctly. Whenever I input the arrival time in military format ( ...

What is the best way to retrieve the file name from the current document's URL using JavaScript?

I need help with a Javascript function that can extract the current file name without any parameters. $(location).attr('href').match(/([a-zA-Z\-\_0-9]+\.\w+)$/); var current_path = RegExp.$1; if ((current_path == 'index. ...

Trouble with downloading files using the anchor (a) tag in React

Every time I try to click on the a tag to download the file named approved_leads.zip, I keep receiving an error message saying "failed - no file". It seems like the path is correct, so I'm not sure what is causing the issue. <a href="../../ass ...

Using dataloader on ammap effectively involves importing the necessary data into the platform

I've been attempting to implement the dataloader feature on ammap without success. Here is my current approach: var birth_map = AmCharts.makeChart( "il_bazinda_dogum_say_dagilim", { "type": "map", "data": { ...