Utilizing Three.js to create a vertex shader that dynamically adjusts pixel coloring according to its position on the screen

In my project using Three.js, I have created a vertex shader that assigns colors to each point in a plane based on the quadrant of the screen where a pixel is rendered.

// customized vertex shader
uniform float width;
uniform float height;
varying float x;
varying float y;
void main() 
{ 
    vec4 v = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
    x = v.x; 
    y = v.y;
    gl_Position = v;
}

// updated fragment shader
varying float x;
varying float y;
void main() 
{
    gl_FragColor = vec4(x, y, 0.0, 1.0);
}  

For a live demonstration, visit this jsFiddle link: http://jsfiddle.net/Stemkoski/ST4aM/

I am looking to adjust the shader so that x represents 0 on the left side of the screen and 1 on the right side, while y signifies 0 at the top and 1 at the bottom. My initial attempt was to modify x = v.x / width and y = v.y / height with the assumption that it would give me the desired outcome (where width and height hold the window's dimensions). Unfortunately, after making this alteration, the colors on each screen pixel appeared to change when zooming in or out on the plane.

What adjustments can be made to the shader code to achieve the intended result?

Answer №1

Your variable v has been transformed to clip space. To convert it to normalized device coordinates (NDC) in the range of [-1, 1] and then map it to [0, 1], you can follow these steps:

    vec4 v = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
    x = v.x / v.z;
    y = v.y / v.z;

    gl_FragColor = vec4(0.5 * x + 0.5, -0.5 * y + 0.5, 0.0, 1.0);

Check out the fiddle for a working example: http://jsfiddle.net/ST4aM/4/

Using three.js version r.62

Answer №2

Expanding on WestLangley's response.

I came across a minor issue where the calculation of my vertex position was slightly off, falling within the range of (-1.1, 1.1). Through experimentation, I discovered that v.z was not entirely accurate and depended on the near field clip plane, typically set to 1 in camera configuration. By adding 2 to v.z, the issue seemed to have been resolved. It's puzzling why it's 2 instead of 1.

x = v.x / (v.z + 2.0); // depth + 2 x near clip space plane dist (camera setting)

If you're dealing with large objects like in WestLangley's scenario, this discrepancy might go unnoticed. However, for small objects positioned closely to the camera, the error becomes apparent.

I adjusted the aforementioned example to restrict color clipping if the position falls outside (0,1) for Y and corrected X calculation. The plane size is 20, and the camera distance is 30.

https://i.sstatic.net/1jeXt.png

jsFiddle

It's not flawless yet. When an object moves very close to the camera, the position still gets distorted. Nevertheless, this modification ensures better performance with medium-sized objects.

https://i.sstatic.net/MZHIW.png

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

Executing Javascript with Ajax requested data - A guide to making your script run smoothly

Battlefield Page In the graphic provided, there is a battlefield page featuring 20 users. To capture and store this data in a MySQL database, I have created a JavaScript script. However, an issue arises when trying to collect data from the next page after ...

Design a three-dimensional world map for a first-person shooter video game using Three.js technology

I'm interested in developing a 3D map similar to those seen in Counter-Strike using Three.js. Can anyone suggest the best format and tool to use for creating it? ...

Deciphering the creation process behind the "WhatsApp Web" front-end page

I'm currently exploring the creation process of the front-end page for WhatsApp Web, specifically focusing on the list of contacts located on the left side (<div id="pane-side">). The contact names within this list are identified by the class "e ...

An assessment consisting of three parts, with the initial section required to match the size of the browser window using jQuery and Javascript

UPDATE: The issue was resolved by adding the Doctype at the top of the page - "<!DOCTYPE html>" (no spaces between tags < , > and other characters) I am experimenting with a webpage that contains four sections. The first section should take up ...

Execute two operations using jQuery and PHP

I recently created a form for users to fill out, with the data being sent to my email. However, I also wanted the email information to be posted to my MailChimp account using their API. Unfortunately, this feature is currently not functioning correctly. B ...

Each time the website refreshes, Object.entries() rearranges the orders

After reading the discussion on Does JavaScript guarantee object property order? It seems that Object.entries() should maintain order. However, I encountered an issue with my Angular website where the order of keys in Object.entries() changed upon refres ...

The issue with the jQuery class change not being triggered in Internet Explorer seems to be isolated, as Chrome and

This little jQuery script I have is supposed to show a fixed navigation menu once the page has been scrolled below 200px, and then change the class on each menu list item to "current" when that section reaches the top of the viewport. The issue is that th ...

The jQuery .hasClass() function does not work properly with SVG elements

I am working with a group of SVG elements that are assigned the classes node and link. My goal is to determine whether an element contains either the node or link class when hovering over any of the SVG components. However, I am encountering an issue where ...

Is it possible for me to utilize pure JavaScript for loading JSON data?

I am interested in dynamically creating a Google Map by loading data through AJAX. To achieve this, I am using a JSON object that mimics the structure of the GM API to construct the map and jQuery for AJAX loading. For example: "object": { "div": "ma ...

What is the best way to separate one dropdown area from another dropdown area?

I have two dropdown menus where, when an option with the value "other" is clicked, it generates a text area just below the dropdown menu. Both sections are functioning correctly, but I had to create separate parent wrappers for each in order to do so. How ...

The Cy.visit() function in Cypress times out and bypasses tests specifically when navigating to a VueJS web application

Having trouble with the Cypress cy.visit() function timing out and aborting tests on a VueJS Web Application? It seems to work fine when opening other non-VueJS sites. Below is my basic configuration setup: [package.json] "dependencies": { "cypres ...

Obtain access to global.window.localStorage within getServerSideProps

I have a component that receives props with data and renders the data. In my functionality within the getServerSideProps, I am attempting to retrieve data from localStorage. However, due to window being undefined, I am unable to do so. I have tried using ...

Incorporate real-time validation observables with the power of rxjs

Currently, I am working on implementing an observable for a validation task. There are 2 observables, frontEndValidate and backEndValidate, which I need to process sequentially in a specific order. If any of these observables throws an error, the entire pi ...

Chrome and Firefox: Images cling together

I've encountered an issue with my recently launched website. Some images in a grid appear to be stuck together, but this problem only occurs in Firefox and Chrome browsers. Oddly enough, zooming in to around 110% then back to 100% seems to temporarily ...

Unlocking the Power of mapState in JavaScript Files

How can I access my states from a `.js` file using `mapState` in Vue.js? I attempted to do so with the following code: import { mapState } from 'vuex'; const foo = { ...mapState(['axios']), }; foo.axios.get('...'); Unfo ...

Creating a Yeoman application with a personalized Node.js server

As I embark on the journey of developing a node.js and angular application using the powerful Yeoman tool, I can't help but wonder about one thing. Upon generating my application, I noticed that there are predefined tasks for grunt, such as a server ...

Check if all items in the array exist in Mongodb, then update them; if not, insert

In my database, I have a collection of tags and I want to perform the following actions when a user enters an array of tags: If a tag in the array already exists, update its count If a tag in the array does not exist, insert it with a count of 0 Current ...

Retrieve information for AJAX tooltip from a specific URL

I am currently utilizing a script for tooltips. Is there a method available to dynamically load the content of a tooltip from a URL (using dynamic content loaded from a PHP script) rather than specifying the path to an html/php file? For Example What I ...

TYPESCRIPT: The argument labeled as 'typeof X' cannot be assigned to the parameter labeled as 'Y' that extends

As I venture into coding with TypeScript, I am encountering some compilation issues. It appears that I am facing a hierarchy problem with several classes. The first class (A) defines a set of properties/functions. The second class (B) inherits from class ...

Live notification application using node.js

I am looking to create a recipe maker webapp for practice purposes. This webapp will consist of 2 main pages: the index page and the recipes page. On the "index" page, users can create their own recipes. On the "recipes" page, users can view a table ...