Как я могу передать позиции мыши от JS до шейдера через униформу? - PullRequest
0 голосов
/ 25 апреля 2019

Я хочу передать положение мыши для шейдера через форму, чтобы при перемещении мыши цвет изменялся в интерактивном режиме.

Пожалуйста, смотрите комментарии со знаком "★", где, как я полагаю, указаны коды клавиш для моей проблемы..

Я очень плохо знаком с шейдерами и создаю это только для тренировок.Я хочу знать, как передать положение мыши из js (я использую three.js) в шейдер и как использовать его в шейдере.(Я полагаю, что его необходимо нормализовать, чтобы использовать значения в r, g и b?)

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">

    <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/104/three.min.js"></script>
    <title>Document</title>
</head>

<body>

    <div id="container"></div>

    <script id="vertexShader" type="x-shader/x-vertex">
    void main(){
        gl_Position = vec4(position, 1.0);
    }
    </script>

    <script id="fragmentShader" type="x-shader/x-fragment">
        uniform vec2 u_resolution;
        uniform float u_time;
        uniform vec2 u_mouse;


      //★set the mouse positions to the colors    
        void main(){
            vec2 st = gl_FragCoord.xy / u_resolution.xy;
            vec2 um = u_mouse.xy;

            gl_FragColor = vec4(um.x, um.y, 0.0, 0.1);
        } 

    </script>

    <script>
        var container;
        var camera, scene, renderer;
        var uniforms;

        init();
        animate();

        function init() {
            container = document.getElementById('container');

            camera = new THREE.Camera();
            camera.position.z = 1;

            scene = new THREE.Scene();

            var geometry = new THREE.PlaneBufferGeometry(2, 2);

            uniforms = {

                u_time: { type: "f", value: 1.0 },
                u_resolution: { type: "v2", value: new THREE.Vector2() },
                u_mouse: { type: "v2", value: new THREE.Vector2() }
            };

            var material = new THREE.ShaderMaterial({
                uniforms: uniforms,
                vertexShader: document.getElementById('vertexShader').textContent,
                fragmentShader: document.getElementById('fragmentShader').textContent
            });

            var mesh = new THREE.Mesh(geometry, material);
            scene.add(mesh);

            renderer = new THREE.WebGLRenderer();
            renderer.setPixelRatio(window.devicePixelRatio);

            container.appendChild(renderer.domElement);

            onWindowResize();
            window.addEventListener('resize', onWindowResize, false);


        }

        function onWindowResize(e) {
            renderer.setSize(window.innerWidth, window.innerHeight);
            uniforms.u_resolution.value.x = renderer.domElement.width;
            uniforms.u_resolution.value.y = renderer.domElement.height;
        }

        function animate() {
            requestAnimationFrame(animate);
            render();
        }

      //★set the mouse positions to shader
        function render() {
            uniforms.u_time.value += 0.05;
            document.onmousemove = function (e) {
                uniforms.u_mouse.x = e.pageX;
                uniforms.u_mouse.y = (e.pageY;

            }
            renderer.render(scene, camera);
        }

    </script>

</body>

</html>

1 Ответ

0 голосов
/ 25 апреля 2019

Прежде всего, пожалуйста, узнайте, как использовать фрагмент для дальнейших вопросов.Вот хороший пример здесь

Во-вторых, ответ на ваш вопрос в вашем вопросе.Вы видите разницу между

uniforms.u_resolution.value.x = renderer.domElement.width;
uniforms.u_resolution.value.y = renderer.domElement.height;

и этим?

uniforms.u_mouse.x = e.pageX;
uniforms.u_mouse.y = e.pageY;

Униформа Three.js имеет форму uniforms.<name>.value.property.Вы не поместили часть 'value'.

Другие проблемы, однако, Цвета в three.js изменяются с 0 на 1, поэтому использование e.pageX и e.pageY не даст вам никаких цветов, кромечерный в верхнем левом углу страницы и белый везде, так как значения будут 1 или больше везде

Вы можете попробовать

uniforms.u_mouse.x = e.pageX / window.innerWidth;
uniforms.u_mouse.y = e.pageY / window.innerHeight;

Чтобы, возможно, дать вам более подходящее значение.Я говорю возможно , потому что не ясно, в каком контексте вы хотите изменить цвет.Над окном, над страницей, над холстом, над каким-то другим элементом все они могут отличаться.

Еще одна вещь, вы обычно не хотите назначать событие внутри цикла рендеринга.Вы назначаете его один раз во время инициализации.

Вот код, работающий во фрагменте

var container;
var camera, scene, renderer;
var uniforms;

init();
animate();

function init() {
  container = document.getElementById('container');

  camera = new THREE.Camera();
  camera.position.z = 1;

  scene = new THREE.Scene();

  var geometry = new THREE.PlaneBufferGeometry(2, 2);

  uniforms = {

    u_time: {
      type: "f",
      value: 1.0
    },
    u_resolution: {
      type: "v2",
      value: new THREE.Vector2()
    },
    u_mouse: {
      type: "v2",
      value: new THREE.Vector2()
    }
  };

  var material = new THREE.ShaderMaterial({
    uniforms: uniforms,
    vertexShader: document.getElementById('vertexShader').textContent,
    fragmentShader: document.getElementById('fragmentShader').textContent
  });

  var mesh = new THREE.Mesh(geometry, material);
  scene.add(mesh);

  renderer = new THREE.WebGLRenderer();
  renderer.setPixelRatio(window.devicePixelRatio);

  container.appendChild(renderer.domElement);

  onWindowResize();
  window.addEventListener('resize', onWindowResize, false);


}

function onWindowResize(e) {
  renderer.setSize(window.innerWidth, window.innerHeight);
  uniforms.u_resolution.value.x = renderer.domElement.width;
  uniforms.u_resolution.value.y = renderer.domElement.height;
}

function animate() {
  requestAnimationFrame(animate);
  render();
}

document.onmousemove = function(e) {
  uniforms.u_mouse.value.x = e.pageX / window.innerWidth;
  uniforms.u_mouse.value.y = e.pageY / window.innerHeight;
}


//★set the mouse positions to shader
function render() {
  uniforms.u_time.value += 0.05;
    renderer.render(scene, camera);
  }
body { margin: 0; }
canvas { display: block; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/104/three.min.js"></script>

<div id="container"></div>

<script id="vertexShader" type="x-shader/x-vertex">
  void main(){
    gl_Position = vec4(position, 1.0);
  }
</script>

<script id="fragmentShader" type="x-shader/x-fragment">
  uniform vec2 u_resolution;
  uniform float u_time;
  uniform vec2 u_mouse;
  //set the mouse positions to the colors
  void main(){
    vec2 st = gl_FragCoord.xy / u_resolution.xy;
    vec2 um = u_mouse.xy;
    gl_FragColor = vec4(um.x, um.y, 0.0, 0.1);
  }
</script>
...