WebGL Shader,根据变量修改位置
WebGL Shader, modify position according to variable
我正在遵循 . I want this blob to turn into other 3D models and back (like this 中的建议。这使我走上了变形之路,但我想使用着色器。 SO post(第一个 link)有一个基本的 运行-through 如何做到这一点。我目前正在根据变量 time
调整 post 中的示例 link,使其从 start position
变为 end position
。但是,精灵要么不显示,要么固定在结束位置。请看一下,让我知道我的逻辑哪里不对。
这是一个片段:
<!DOCTYPE html>
<html lang="en">
<head>
<title>three.js webgl - custom attributes [particles]</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<link type="text/css" rel="stylesheet" href="main.css">
</head>
<body>
<div id="info"><a href="https://threejs.org" target="_blank" rel="noopener">three.js</a> - custom attributes example - particles</div>
<div id="container"></div>
<script type="x-shader/x-vertex" id="vertexshader">
attribute float size;
attribute vec3 customColor;
attribute vec4 endposition;
uniform float time;
varying vec3 vColor;
void main() {
vColor = customColor;
vec4 offset = endposition;
// offset.xyz *= time;
vec4 mvPosition = modelViewMatrix * vec4( position, 1.0);
gl_PointSize = size * ( 300.0 / -mvPosition.z );
gl_Position = projectionMatrix * mvPosition;
gl_Position += offset;
}
</script>
<script type="x-shader/x-fragment" id="fragmentshader">
uniform vec3 color;
uniform sampler2D pointTexture;
varying vec3 vColor;
void main() {
gl_FragColor = vec4( color * vColor, 1.0 );
gl_FragColor = gl_FragColor * texture2D( pointTexture, gl_PointCoord );
}
</script>
<script type="module">
import * as THREE from 'https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.module.min.js';
import Stats from 'https://cdnjs.cloudflare.com/ajax/libs/stats.js/r17/Stats.min.js';
let renderer, scene, camera, stats;
let sphere, material;
const WIDTH = window.innerWidth;
const HEIGHT = window.innerHeight;
init();
animate();
function init() {
camera = new THREE.PerspectiveCamera( 40, WIDTH / HEIGHT, 1, 10000 );
camera.position.z = 300;
scene = new THREE.Scene();
const amount = 1000;
const radius = 20;
const positions = new Float32Array( amount * 3 );
const colors = new Float32Array( amount * 3 );
const sizes = new Float32Array( amount );
const vertex = new THREE.Vector3();
const color = new THREE.Color( 0xffffff );
const endpositions = new Float32Array( amount * 3);
const endvertex = new THREE.Vector3();
const endradius = 100;
for ( let i = 0; i < amount; i ++ ) {
vertex.x = ( Math.random() * 2 - 1 ) * radius;
vertex.y = ( Math.random() * 2 - 1 ) * radius;
vertex.z = ( Math.random() * 2 - 1 ) * radius;
vertex.toArray( positions, i * 3 );
endvertex.x = ( Math.random() * 2 - 1 ) * endradius;
endvertex.y = ( Math.random() * 2 - 1 ) * endradius;
endvertex.z = ( Math.random() * 2 - 1 ) * endradius;
endvertex.toArray( endpositions, i * 3 );
if ( vertex.x < 0 ) {
color.setHSL( 0.5 + 0.1 * ( i / amount ), 0.7, 0.5 );
} else {
color.setHSL( 0.0 + 0.1 * ( i / amount ), 0.9, 0.5 );
}
color.toArray( colors, i * 3 );
sizes[ i ] = 10;
}
const geometry = new THREE.BufferGeometry();
geometry.setAttribute( 'position', new THREE.BufferAttribute( positions, 3 ) );
geometry.setAttribute( 'customColor', new THREE.BufferAttribute( colors, 3 ) );
geometry.setAttribute( 'size', new THREE.BufferAttribute( sizes, 1 ) );
geometry.setAttribute( 'endposition', new THREE.BufferAttribute( endpositions, 3 ) );
//
material = new THREE.ShaderMaterial( {
uniforms: {
color: { value: new THREE.Color( 0xffffff ) },
pointTexture: { value: new THREE.TextureLoader().load( "https://images-na.ssl-images-amazon.com/images/I/31-ijjGFI1L._SY291_BO1,204,203,200_QL40_FMwebp_.jpg" ) },
time: { type: 'f', value: 0}
},
vertexShader: document.getElementById( 'vertexshader' ).textContent,
fragmentShader: document.getElementById( 'fragmentshader' ).textContent,
blending: THREE.AdditiveBlending,
depthTest: false,
transparent: true
} );
//
sphere = new THREE.Points( geometry, material );
scene.add( sphere );
//
renderer = new THREE.WebGLRenderer();
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( WIDTH, HEIGHT );
const container = document.getElementById( 'container' );
container.appendChild( renderer.domElement );
stats = new Stats();
container.appendChild( stats.dom );
//
window.addEventListener( 'resize', onWindowResize );
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
function animate() {
requestAnimationFrame( animate );
render();
stats.update();
}
function render() {
let time = 0
for (let i = 0; i < 1; i+=0.1) {
time=i
}
material.uniforms.time.value = time;
renderer.render( scene, camera );
}
</script>
</body>
</html>
您的时间变量没有更新,如果它在 animate() 函数中,它会更新。
着色器:
vec3 altposition = mix(position.xyz, endposition.xyz, time);
盒子在这里像死星一样爆炸了。
<!DOCTYPE html>
<html lang="en">
<head>
<title>three.js webgl - custom attributes [particles]</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<link type="text/css" rel="stylesheet" href="main.css">
</head>
<body>
<div id="info"><a href="https://threejs.org" target="_blank" rel="noopener">three.js</a> - custom attributes example - particles</div>
<div id="container"></div>
<script type="x-shader/x-vertex" id="vertexshader">
attribute float size;
attribute vec3 customColor;
attribute vec4 endposition;
uniform float time;
varying vec3 vColor;
void main() {
vColor = customColor;
vec3 altposition = mix(position.xyz, endposition.xyz, time);
// offset.xyz *= time;
vec4 mvPosition = modelViewMatrix * vec4( altposition, 1.0);
gl_PointSize = size * ( 300.0 / -mvPosition.z );
gl_Position = projectionMatrix * mvPosition;
}
</script>
<script type="x-shader/x-fragment" id="fragmentshader">
uniform vec3 color;
uniform sampler2D pointTexture;
varying vec3 vColor;
void main() {
gl_FragColor = vec4( color * vColor, 1.0 );
gl_FragColor = gl_FragColor * texture2D( pointTexture, gl_PointCoord );
}
</script>
<script type="module">
import * as THREE from 'https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.module.min.js';
import Stats from 'https://cdnjs.cloudflare.com/ajax/libs/stats.js/r17/Stats.min.js';
let renderer, scene, camera, stats;
let sphere, material;
const WIDTH = window.innerWidth;
const HEIGHT = window.innerHeight;
init();
animate();
function init() {
camera = new THREE.PerspectiveCamera( 40, WIDTH / HEIGHT, 1, 10000 );
camera.position.z = 300;
scene = new THREE.Scene();
const amount = 1000;
const radius = 20;
const positions = new Float32Array( amount * 3 );
const colors = new Float32Array( amount * 3 );
const sizes = new Float32Array( amount );
const vertex = new THREE.Vector3();
const color = new THREE.Color( 0xffffff );
const endpositions = new Float32Array( amount * 3);
const endvertex = new THREE.Vector3();
const endradius = 100;
for ( let i = 0; i < amount; i ++ ) {
vertex.x = ( Math.random() * 2 - 1 ) * radius;
vertex.y = ( Math.random() * 2 - 1 ) * radius;
vertex.z = ( Math.random() * 2 - 1 ) * radius;
vertex.toArray( positions, i * 3 );
endvertex.x = ( Math.random() * 2 - 1 ) * endradius;
endvertex.y = ( Math.random() * 2 - 1 ) * endradius;
endvertex.z = ( Math.random() * 2 - 1 ) * endradius;
endvertex.toArray( endpositions, i * 3 );
if ( vertex.x < 0 ) {
color.setHSL( 0.5 + 0.1 * ( i / amount ), 0.7, 0.5 );
} else {
color.setHSL( 0.0 + 0.1 * ( i / amount ), 0.9, 0.5 );
}
color.toArray( colors, i * 3 );
sizes[ i ] = 10;
}
const geometry = new THREE.BufferGeometry();
geometry.setAttribute( 'position', new THREE.BufferAttribute( positions, 3 ) );
geometry.setAttribute( 'customColor', new THREE.BufferAttribute( colors, 3 ) );
geometry.setAttribute( 'size', new THREE.BufferAttribute( sizes, 1 ) );
geometry.setAttribute( 'endposition', new THREE.BufferAttribute( endpositions, 3 ) );
//
material = new THREE.ShaderMaterial( {
uniforms: {
color: { value: new THREE.Color( 0xffffff ) },
pointTexture: { value: new THREE.TextureLoader().load( "https://images-na.ssl-images-amazon.com/images/I/31-ijjGFI1L._SY291_BO1,204,203,200_QL40_FMwebp_.jpg" ) },
time: { type: 'f', value: 0}
},
vertexShader: document.getElementById( 'vertexshader' ).textContent,
fragmentShader: document.getElementById( 'fragmentshader' ).textContent,
blending: THREE.AdditiveBlending,
depthTest: false,
transparent: true
} );
//
sphere = new THREE.Points( geometry, material );
scene.add( sphere );
//
renderer = new THREE.WebGLRenderer();
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( WIDTH, HEIGHT );
const container = document.getElementById( 'container' );
container.appendChild( renderer.domElement );
stats = new Stats();
container.appendChild( stats.dom );
//
window.addEventListener( 'resize', onWindowResize );
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
var then = 0;
var time = -1.633;
var reverse = 1;
function animate(now) {
now *= 0.001;
const delta = now - then;
then = now;
if(time > 15) {
reverse *= -1;
}
if(time < -4) {
reverse *= -1;
}
time = time + delta * 1.0 * reverse;
material.uniforms.time.value = Math.max(0.0, time);
requestAnimationFrame( animate );
render();
stats.update();
}
function render() {
renderer.render( scene, camera );
}
</script>
</body>
</html>
我正在遵循 time
调整 post 中的示例 link,使其从 start position
变为 end position
。但是,精灵要么不显示,要么固定在结束位置。请看一下,让我知道我的逻辑哪里不对。
这是一个片段:
<!DOCTYPE html>
<html lang="en">
<head>
<title>three.js webgl - custom attributes [particles]</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<link type="text/css" rel="stylesheet" href="main.css">
</head>
<body>
<div id="info"><a href="https://threejs.org" target="_blank" rel="noopener">three.js</a> - custom attributes example - particles</div>
<div id="container"></div>
<script type="x-shader/x-vertex" id="vertexshader">
attribute float size;
attribute vec3 customColor;
attribute vec4 endposition;
uniform float time;
varying vec3 vColor;
void main() {
vColor = customColor;
vec4 offset = endposition;
// offset.xyz *= time;
vec4 mvPosition = modelViewMatrix * vec4( position, 1.0);
gl_PointSize = size * ( 300.0 / -mvPosition.z );
gl_Position = projectionMatrix * mvPosition;
gl_Position += offset;
}
</script>
<script type="x-shader/x-fragment" id="fragmentshader">
uniform vec3 color;
uniform sampler2D pointTexture;
varying vec3 vColor;
void main() {
gl_FragColor = vec4( color * vColor, 1.0 );
gl_FragColor = gl_FragColor * texture2D( pointTexture, gl_PointCoord );
}
</script>
<script type="module">
import * as THREE from 'https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.module.min.js';
import Stats from 'https://cdnjs.cloudflare.com/ajax/libs/stats.js/r17/Stats.min.js';
let renderer, scene, camera, stats;
let sphere, material;
const WIDTH = window.innerWidth;
const HEIGHT = window.innerHeight;
init();
animate();
function init() {
camera = new THREE.PerspectiveCamera( 40, WIDTH / HEIGHT, 1, 10000 );
camera.position.z = 300;
scene = new THREE.Scene();
const amount = 1000;
const radius = 20;
const positions = new Float32Array( amount * 3 );
const colors = new Float32Array( amount * 3 );
const sizes = new Float32Array( amount );
const vertex = new THREE.Vector3();
const color = new THREE.Color( 0xffffff );
const endpositions = new Float32Array( amount * 3);
const endvertex = new THREE.Vector3();
const endradius = 100;
for ( let i = 0; i < amount; i ++ ) {
vertex.x = ( Math.random() * 2 - 1 ) * radius;
vertex.y = ( Math.random() * 2 - 1 ) * radius;
vertex.z = ( Math.random() * 2 - 1 ) * radius;
vertex.toArray( positions, i * 3 );
endvertex.x = ( Math.random() * 2 - 1 ) * endradius;
endvertex.y = ( Math.random() * 2 - 1 ) * endradius;
endvertex.z = ( Math.random() * 2 - 1 ) * endradius;
endvertex.toArray( endpositions, i * 3 );
if ( vertex.x < 0 ) {
color.setHSL( 0.5 + 0.1 * ( i / amount ), 0.7, 0.5 );
} else {
color.setHSL( 0.0 + 0.1 * ( i / amount ), 0.9, 0.5 );
}
color.toArray( colors, i * 3 );
sizes[ i ] = 10;
}
const geometry = new THREE.BufferGeometry();
geometry.setAttribute( 'position', new THREE.BufferAttribute( positions, 3 ) );
geometry.setAttribute( 'customColor', new THREE.BufferAttribute( colors, 3 ) );
geometry.setAttribute( 'size', new THREE.BufferAttribute( sizes, 1 ) );
geometry.setAttribute( 'endposition', new THREE.BufferAttribute( endpositions, 3 ) );
//
material = new THREE.ShaderMaterial( {
uniforms: {
color: { value: new THREE.Color( 0xffffff ) },
pointTexture: { value: new THREE.TextureLoader().load( "https://images-na.ssl-images-amazon.com/images/I/31-ijjGFI1L._SY291_BO1,204,203,200_QL40_FMwebp_.jpg" ) },
time: { type: 'f', value: 0}
},
vertexShader: document.getElementById( 'vertexshader' ).textContent,
fragmentShader: document.getElementById( 'fragmentshader' ).textContent,
blending: THREE.AdditiveBlending,
depthTest: false,
transparent: true
} );
//
sphere = new THREE.Points( geometry, material );
scene.add( sphere );
//
renderer = new THREE.WebGLRenderer();
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( WIDTH, HEIGHT );
const container = document.getElementById( 'container' );
container.appendChild( renderer.domElement );
stats = new Stats();
container.appendChild( stats.dom );
//
window.addEventListener( 'resize', onWindowResize );
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
function animate() {
requestAnimationFrame( animate );
render();
stats.update();
}
function render() {
let time = 0
for (let i = 0; i < 1; i+=0.1) {
time=i
}
material.uniforms.time.value = time;
renderer.render( scene, camera );
}
</script>
</body>
</html>
您的时间变量没有更新,如果它在 animate() 函数中,它会更新。
着色器:
vec3 altposition = mix(position.xyz, endposition.xyz, time);
盒子在这里像死星一样爆炸了。
<!DOCTYPE html>
<html lang="en">
<head>
<title>three.js webgl - custom attributes [particles]</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<link type="text/css" rel="stylesheet" href="main.css">
</head>
<body>
<div id="info"><a href="https://threejs.org" target="_blank" rel="noopener">three.js</a> - custom attributes example - particles</div>
<div id="container"></div>
<script type="x-shader/x-vertex" id="vertexshader">
attribute float size;
attribute vec3 customColor;
attribute vec4 endposition;
uniform float time;
varying vec3 vColor;
void main() {
vColor = customColor;
vec3 altposition = mix(position.xyz, endposition.xyz, time);
// offset.xyz *= time;
vec4 mvPosition = modelViewMatrix * vec4( altposition, 1.0);
gl_PointSize = size * ( 300.0 / -mvPosition.z );
gl_Position = projectionMatrix * mvPosition;
}
</script>
<script type="x-shader/x-fragment" id="fragmentshader">
uniform vec3 color;
uniform sampler2D pointTexture;
varying vec3 vColor;
void main() {
gl_FragColor = vec4( color * vColor, 1.0 );
gl_FragColor = gl_FragColor * texture2D( pointTexture, gl_PointCoord );
}
</script>
<script type="module">
import * as THREE from 'https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.module.min.js';
import Stats from 'https://cdnjs.cloudflare.com/ajax/libs/stats.js/r17/Stats.min.js';
let renderer, scene, camera, stats;
let sphere, material;
const WIDTH = window.innerWidth;
const HEIGHT = window.innerHeight;
init();
animate();
function init() {
camera = new THREE.PerspectiveCamera( 40, WIDTH / HEIGHT, 1, 10000 );
camera.position.z = 300;
scene = new THREE.Scene();
const amount = 1000;
const radius = 20;
const positions = new Float32Array( amount * 3 );
const colors = new Float32Array( amount * 3 );
const sizes = new Float32Array( amount );
const vertex = new THREE.Vector3();
const color = new THREE.Color( 0xffffff );
const endpositions = new Float32Array( amount * 3);
const endvertex = new THREE.Vector3();
const endradius = 100;
for ( let i = 0; i < amount; i ++ ) {
vertex.x = ( Math.random() * 2 - 1 ) * radius;
vertex.y = ( Math.random() * 2 - 1 ) * radius;
vertex.z = ( Math.random() * 2 - 1 ) * radius;
vertex.toArray( positions, i * 3 );
endvertex.x = ( Math.random() * 2 - 1 ) * endradius;
endvertex.y = ( Math.random() * 2 - 1 ) * endradius;
endvertex.z = ( Math.random() * 2 - 1 ) * endradius;
endvertex.toArray( endpositions, i * 3 );
if ( vertex.x < 0 ) {
color.setHSL( 0.5 + 0.1 * ( i / amount ), 0.7, 0.5 );
} else {
color.setHSL( 0.0 + 0.1 * ( i / amount ), 0.9, 0.5 );
}
color.toArray( colors, i * 3 );
sizes[ i ] = 10;
}
const geometry = new THREE.BufferGeometry();
geometry.setAttribute( 'position', new THREE.BufferAttribute( positions, 3 ) );
geometry.setAttribute( 'customColor', new THREE.BufferAttribute( colors, 3 ) );
geometry.setAttribute( 'size', new THREE.BufferAttribute( sizes, 1 ) );
geometry.setAttribute( 'endposition', new THREE.BufferAttribute( endpositions, 3 ) );
//
material = new THREE.ShaderMaterial( {
uniforms: {
color: { value: new THREE.Color( 0xffffff ) },
pointTexture: { value: new THREE.TextureLoader().load( "https://images-na.ssl-images-amazon.com/images/I/31-ijjGFI1L._SY291_BO1,204,203,200_QL40_FMwebp_.jpg" ) },
time: { type: 'f', value: 0}
},
vertexShader: document.getElementById( 'vertexshader' ).textContent,
fragmentShader: document.getElementById( 'fragmentshader' ).textContent,
blending: THREE.AdditiveBlending,
depthTest: false,
transparent: true
} );
//
sphere = new THREE.Points( geometry, material );
scene.add( sphere );
//
renderer = new THREE.WebGLRenderer();
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( WIDTH, HEIGHT );
const container = document.getElementById( 'container' );
container.appendChild( renderer.domElement );
stats = new Stats();
container.appendChild( stats.dom );
//
window.addEventListener( 'resize', onWindowResize );
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
var then = 0;
var time = -1.633;
var reverse = 1;
function animate(now) {
now *= 0.001;
const delta = now - then;
then = now;
if(time > 15) {
reverse *= -1;
}
if(time < -4) {
reverse *= -1;
}
time = time + delta * 1.0 * reverse;
material.uniforms.time.value = Math.max(0.0, time);
requestAnimationFrame( animate );
render();
stats.update();
}
function render() {
renderer.render( scene, camera );
}
</script>
</body>
</html>