Home Web Front-end JS Tutorial THREE.JS introductory tutorial (3) Shader-Part 2_Basic knowledge

THREE.JS introductory tutorial (3) Shader-Part 2_Basic knowledge

May 16, 2016 pm 05:43 PM

Translation
Three.js is a great open source WebGL library. WebGL allows JavaScript to operate the GPU and achieve true 3D on the browser side. However, this technology is still in the development stage, and the information is extremely scarce. Enthusiasts basically have to learn through the Demo source code and the source code of Three.js itself.

. Introduction
This is the second half of the WebGL shader tutorial. If you have not read the previous one, reading this tutorial may make you confused. It is recommended You read the previous tutorial.

At the end of the previous article, we drew a beautiful pink sphere in the center of the screen. Now I'm going to start creating something more interesting.

In this tutorial, we will take a moment to add an animation loop, then vertex attributes variables and a uniform variable. We also need to add some varying variables so that the vertex shader can pass information to the fragment shader. The end result is a pink sphere that "ignites" from the top to the sides and then moves in a regular pattern. This is a bit psychedelic, but it will help you get a better understanding of the three variables in the shader: they are related to each other and implement the entire assembly. Of course we will do this in the Three.js framework.
1. Simulate lighting
Let’s update the colors so the sphere doesn’t look like a flat, dark circle. If we want to see how Three.js handles lighting, I'm sure you'll find it's a lot more complicated than we need, so let's simulate lighting first. You should take a look at the fantastic shaders in Three.js, as well as some from a recent WebGL project by Chris Milk and Google, Rome.
Back to the shader, we need to update the vertex shader to pass the vertex normal vector to the fragment shader. Use a varying variable:
Copy code The code is as follows:

// Create a varying variable vNormal , both the vertex shader and the fragment shader contain this variable
varying vec3 vNormal;
void main() {
// Set vNormal to normal, which is created by Three.js and passed to The attribute variable of the shader
vNormal = normal;
gl_Position = projectionMatrix *
modelViewMatrix *
vec4(position, 1.0);
}

in the fragment In the shader, we will create a variable with the same name, then dot-multiply the normal vector with another vector representing the ray from the top right, and apply the result to the color. The end result looks a bit like directional light.
Copy code The code is as follows:

// The same variable vNormal as in the vertex shader
varying vec3 vNormal;
void main() {
// Define the light vector
vec3 light = vec3(0.5,0.2,1.0);
// Make sure it is normalized
light = normalize(light);
// Calculate the dot product of the light vector and the normal vector. If the dot product is less than 0 (that is, the light cannot reach it), set it to 0
float dProd = max(0.0, dot(vNormal, light));
// Fill fragment color
gl_FragColor = vec4(dProd, // R
dProd, // G
dProd, // B
1.0) ; // A
}

The reason for using dot product is: the dot product of two vectors shows how "similar" they are. If both vectors are normalized and their directions are exactly the same, the value of the dot product is 1; if the directions of the two vectors happen to be exactly opposite, the value of the dot product is -1. What we do is apply the dot product value to the fiber, so if this point is on the upper right side of the sphere, the dot product value is 1, which means it is fully illuminated; and for the point on the other side, we get The dot product value is close to 0 or even -1. Any negative values ​​we get are set to 0. When you pass in the data, you will see the most basic lighting effect.

What’s below? We will incorporate the coordinates of the vertices.
2. Attribut variable
Next I need to pass a random number to each vertex through the Attribute variable. This random number is used to push the vertex a certain distance along the normal vector. The new result is a bit like a weird irregular object that changes randomly every time the page is refreshed. For now, he won't move (I'll make him move later), but after a few refreshes you can nicely see that his shape is random.
Let’s start adding attribute variables to the vertex shader:
Copy the code The code is as follows:

attribute float displacement;
varying vec3 vNormal;
void main() {
vNormal = normal;
// Convert the random number displacement into a three-dimensional vector, so that it can be combined with The normals are multiplied
vec3 newPosition = position
normal * vec3(displacement);
gl_Position = projectionMatrix *
modelViewMatrix *
vec4(newPosition, 1.0);
}

You see nothing has changed, because the attribute variable displacement has not been set yet, so the shader uses 0 as the default value. Displacement has not yet taken effect at this time, but we will soon add attribute variables to the shader material, and then Three.js will automatically tie them together and run them.

Also note the fact that I assigned the updated position to a new three-dimensional vector variable, because the original position variable, like all attribute variables, is read-only .
3. Update the shader material
Now we update the shader material and pass something into the attribute object displacement. Remember, attribute objects correspond to vertices one-to-one, so we have a value for each vertex of the sphere, like this:
Copy code The code is as follows:

var attributes = {
displacement: {
type: 'f', // Floating point number
value: [] // Empty array
}
};
var vShader = $('#vertexshader');
var fShader = $('#fragmentshader');
// Create an attribute containing Shader Material
var shaderMaterial =
new THREE.MeshShaderMaterial({
attributes: attributes,
vertexShader: vShader.text(),
fragmentShader: fShader.text()
} );
// Fill displacement with random numbers
var verts = sphere.geometry.vertices;
var values ​​= attributes.displacement.value;
for(var v = 0; v < verts.length; v ) {
values.push(Math.random() * 30);
}

In this way, you can see a deformed sphere. The coolest thing is: all these transformations are done in the GPU.
4. Move it
What should I do to make this thing move? Well, should do these two things.
A uniform variable amplitude controls the actual displacement caused by displacement at each frame. We can use the sine or cosine function to generate it in each frame, as these two functions take values ​​from -1 to 1.
A frame loop.

We need to add this uniform variable to the shader material, and also need to add it to the vertex shader. Let’s look at the vertex shader first:
Copy the code The code is as follows:

uniform float amplitude;
attribute float displacement;
varying vec3 vNormal;
void main() {
vNormal = normal;
// Multiply displacement by amplitude as we smoothly change amplitude in each frame , the screen moves
vec3 newPosition =
position
normal *
vec3(displacement *
amplitude);
gl_Position = projectionMatrix *
modelViewMatrix *
vec4 (newPosition, 1.0);
}

Then update the shader material:
Copy code The code is as follows:

var uniforms = {
amplitude: {
type: 'f', // a float
value: 0
}
} ;
var vShader = $('#vertexshader');
var fShader = $('#fragmentshader');
// Create the final shader material
var shaderMaterial =
new THREE.MeshShaderMaterial({
uniforms: uniforms,
attributes: attributes,
vertexShader: vShader.text(),
fragmentShader: fShader.text()
});

Our shader is also ready. But we seem to have taken another step backward, and there are only smooth balls left on the screen. Don't worry, this is because the amplitude value is set to 0, and since we multiplied the amplitude by the displacement, we won't see any change now. We haven't set up the loop yet, so amplitude can only be 0.

In our JavaScript, we need to package the rendering process into a function, and then use requestAnimationFrame to call the function. In this function, we update the value of uniform (Translator's Note: amplitude).
Copy code The code is as follows:

var frame = 0;
function update() {
// amplitude comes from the sine value of frame
uniforms.amplitude.value =
Math.sin(frame);
// Update the global variable frame
frame = 0.1;
renderer.render(scene, camera);
// Specify that the next time the screen is refreshed, call update
requestAnimFrame(update);
}
requestAnimFrame(update);

5. Summary
That’s it! You see the sphere pulsing strangely. There's a lot that I haven't covered yet about shaders, but I hope this tutorial was helpful. Now, when you see some of the other shaders, I hope you understand them, and you should feel confident enough to create your own!

As usual, I packaged the source code of this lesson
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

Video Face Swap

Video Face Swap

Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Tools

Notepad++7.3.1

Notepad++7.3.1

Easy-to-use and free code editor

SublimeText3 Chinese version

SublimeText3 Chinese version

Chinese version, very easy to use

Zend Studio 13.0.1

Zend Studio 13.0.1

Powerful PHP integrated development environment

Dreamweaver CS6

Dreamweaver CS6

Visual web development tools

SublimeText3 Mac version

SublimeText3 Mac version

God-level code editing software (SublimeText3)

Hot Topics

Java Tutorial
1662
14
PHP Tutorial
1262
29
C# Tutorial
1235
24
Demystifying JavaScript: What It Does and Why It Matters Demystifying JavaScript: What It Does and Why It Matters Apr 09, 2025 am 12:07 AM

JavaScript is the cornerstone of modern web development, and its main functions include event-driven programming, dynamic content generation and asynchronous programming. 1) Event-driven programming allows web pages to change dynamically according to user operations. 2) Dynamic content generation allows page content to be adjusted according to conditions. 3) Asynchronous programming ensures that the user interface is not blocked. JavaScript is widely used in web interaction, single-page application and server-side development, greatly improving the flexibility of user experience and cross-platform development.

The Evolution of JavaScript: Current Trends and Future Prospects The Evolution of JavaScript: Current Trends and Future Prospects Apr 10, 2025 am 09:33 AM

The latest trends in JavaScript include the rise of TypeScript, the popularity of modern frameworks and libraries, and the application of WebAssembly. Future prospects cover more powerful type systems, the development of server-side JavaScript, the expansion of artificial intelligence and machine learning, and the potential of IoT and edge computing.

JavaScript Engines: Comparing Implementations JavaScript Engines: Comparing Implementations Apr 13, 2025 am 12:05 AM

Different JavaScript engines have different effects when parsing and executing JavaScript code, because the implementation principles and optimization strategies of each engine differ. 1. Lexical analysis: convert source code into lexical unit. 2. Grammar analysis: Generate an abstract syntax tree. 3. Optimization and compilation: Generate machine code through the JIT compiler. 4. Execute: Run the machine code. V8 engine optimizes through instant compilation and hidden class, SpiderMonkey uses a type inference system, resulting in different performance performance on the same code.

JavaScript: Exploring the Versatility of a Web Language JavaScript: Exploring the Versatility of a Web Language Apr 11, 2025 am 12:01 AM

JavaScript is the core language of modern web development and is widely used for its diversity and flexibility. 1) Front-end development: build dynamic web pages and single-page applications through DOM operations and modern frameworks (such as React, Vue.js, Angular). 2) Server-side development: Node.js uses a non-blocking I/O model to handle high concurrency and real-time applications. 3) Mobile and desktop application development: cross-platform development is realized through ReactNative and Electron to improve development efficiency.

Python vs. JavaScript: The Learning Curve and Ease of Use Python vs. JavaScript: The Learning Curve and Ease of Use Apr 16, 2025 am 12:12 AM

Python is more suitable for beginners, with a smooth learning curve and concise syntax; JavaScript is suitable for front-end development, with a steep learning curve and flexible syntax. 1. Python syntax is intuitive and suitable for data science and back-end development. 2. JavaScript is flexible and widely used in front-end and server-side programming.

How to Build a Multi-Tenant SaaS Application with Next.js (Frontend Integration) How to Build a Multi-Tenant SaaS Application with Next.js (Frontend Integration) Apr 11, 2025 am 08:22 AM

This article demonstrates frontend integration with a backend secured by Permit, building a functional EdTech SaaS application using Next.js. The frontend fetches user permissions to control UI visibility and ensures API requests adhere to role-base

From C/C   to JavaScript: How It All Works From C/C to JavaScript: How It All Works Apr 14, 2025 am 12:05 AM

The shift from C/C to JavaScript requires adapting to dynamic typing, garbage collection and asynchronous programming. 1) C/C is a statically typed language that requires manual memory management, while JavaScript is dynamically typed and garbage collection is automatically processed. 2) C/C needs to be compiled into machine code, while JavaScript is an interpreted language. 3) JavaScript introduces concepts such as closures, prototype chains and Promise, which enhances flexibility and asynchronous programming capabilities.

Building a Multi-Tenant SaaS Application with Next.js (Backend Integration) Building a Multi-Tenant SaaS Application with Next.js (Backend Integration) Apr 11, 2025 am 08:23 AM

I built a functional multi-tenant SaaS application (an EdTech app) with your everyday tech tool and you can do the same. First, what’s a multi-tenant SaaS application? Multi-tenant SaaS applications let you serve multiple customers from a sing

See all articles