为什么我的着色器适用于 BoxGeometry 而不是我在 ThreeJs 中的自定义 BufferGeometry?

问题描述 投票:0回答:0

我有一个问题,我有一个着色器在网格的几何边缘周围绘制白色边框(从@prisoner849 借用和修改,在这里参考他的 jsfiddle(https://jsfiddle.net/prisoner849/kmau6591/ )).

我让它使用一种类型的几何体 (

BoxGeometry
) 但不是
BufferGeometry
这是我希望它处理的,因为我需要对顶点进行自定义操作。我创建了一个 JSFiddle 来演示您可以在哪里看到着色器在通过(
new BoxGeometry
)创建的盒子上工作,另一个是使用
BufferGeometry
创建并手动设置属性。

我怀疑我一定没有正确设置属性,但我不确定该怎么做,因为我找不到任何关于如何正确设置

BufferGeometry
的信息。

下面附上我的 JSFiddle 演示这个问题。

https://jsfiddle.net/gentleman_goat66/o5wn3bpf/135/

感兴趣的代码行如下:

工作箱代码:

const geometryBox = new THREE.BoxGeometry();
    const sample_box = new THREE.Mesh(geometryBox, shader_material);
    sample_box.scale.y = 3;
    this.heatmap.add(sample_box);

我的自定义邮箱代码(不工作!)

const geometry = new THREE.BufferGeometry();
    const vertices = [
      -2, 0, 1,//0, floor, bottom left
      -1, 0, 1,//1, floor, bottom right
      -1, 0, -1,//2, floor, top right
      -2, 0, -1,//3 floor, top left
      -2, 3, 1,//4 roof, bottom left
      -1, 3, 1,//5 roof, bottom right
      -1, 3, -1,//6 roof, top right
      -2, 3, -1//7 roof, top left
    ];
    const indices = [
      0, 1, 2,//floor, first triangle
      2, 3, 0,//floor, second triangle
      4, 5, 6,//roof, first triangle
      6, 7, 4,//roof, second triangle
      3, 0, 4,//west wall, first triangle
      3, 4, 7,//west wall, second triangle
      0, 1, 5,//south wall, first triangle
      0, 5, 4,//south wall, first triangle
      1, 2, 6,//east wall, first triangle
      1, 6, 5,//east wall, second triangle
      2, 3, 7,//north wall, first triangle
      2, 7, 6,//north wall, second triangle
    ];
    const colors = [
      2,0,0, // bottom left
      0,2,0, // bottom right
      0,2,0, // top right
      2,0,0,  // top left
      2,0,0, // bottom left
      0,2,0, // bottom right
      0,2,0, // top right
      2,0,0  // top left
    ];
    geometry.setIndex(indices);
    geometry.setAttribute('position', new THREE.Float32BufferAttribute(vertices, 3));
    geometry.setAttribute('color', new THREE.Float32BufferAttribute(colors, 3));
    geometry.computeVertexNormals();
    const material = new THREE.MeshStandardMaterial({side:THREE.FrontSide,vertexColors:true,color: 0xFFFFFF });
    var shader_material = new THREE.ShaderMaterial( {
      vertexShader: document.getElementById( 'vertexShader' ).textContent,
      fragmentShader: document.getElementById( 'fragmentShader' ).textContent,
      uniforms: {
        thickness: {
          value: 1.5
        }
      }
    });
    const sample_rectangle = new THREE.Mesh(geometry, shader_material);
    this.heatmap.add(sample_rectangle);

HTML

<script type="importmap">
{
"imports": 
  {
    "three": "https://unpkg.com/[email protected]/build/three.module.js",
    "OrbitControls": "https://unpkg.com/[email protected]/examples/jsm/controls/OrbitControls.js"
  }
}
</script>
<script id="vertexShader" type="x-shader/x-vertex">

            #include <common>
      #include <uv_pars_vertex>
      #include <displacementmap_pars_vertex>
      #include <color_pars_vertex>
      #include <fog_pars_vertex>
      #include <morphtarget_pars_vertex>
      #include <skinning_pars_vertex>
      #include <shadowmap_pars_vertex>
      #include <specularmap_pars_fragment>
      #include <logdepthbuf_pars_vertex>
      #include <clipping_planes_pars_vertex>
      
            varying vec2 vUv;
      
            void main() {
            
                #include <beginnormal_vertex>
                #include <morphnormal_vertex>
                #include <begin_vertex>
                #include <morphtarget_vertex>
                
        vUv = uv;
        
                //gl_Position = vec4( transformed, 1.0 );
        gl_Position = projectionMatrix * modelViewMatrix * vec4(position,1.0);

            }

</script>
<script id="fragmentShader" type="x-shader/x-fragment">
            varying vec2 vUv;
        uniform float thickness;
      
      float edgeFactor(vec2 p){
        vec2 grid = abs(fract(p - 0.5) - 0.5) / fwidth(p) / thickness;
        return min(grid.x, grid.y);
        }
      
            void main() {

                float a = edgeFactor(vUv);
      
        vec3 c = mix(vec3(1), vec3(0), a);
      
        gl_FragColor = vec4(c, 1.0);

            }

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

JS

import * as THREE from 'three';
import { OrbitControls } from 'OrbitControls';

class Heatmap {
  constructor(){
    console.log("Heatmap - constructor()");
    
    //ThreeJS Variables
    this.camera = null;
    this.scene = null;
    this.renderer = new THREE.WebGLRenderer({antialias: true});
    this.orbital_controls = null;
    this.ambientLight = null;
    this.heatmap = new THREE.Object3D(); //This will hold all the meshes that make up the heatmap
    
    //Animation Related Variables
    this.clock = new THREE.Clock();
    this.delta = 0;
    this.fps = 60; //60 fps
        this.interval = 1/this.fps;
        this.seconds = 2; //seconds for animation
        this.timeSoFar = 0;
        this.targetTime = 3;
    
    //Setup
    this.scene = new THREE.Scene();
    this.setUpCamera();
    this.setUpRenderer();
    this.setUpLighting();
    this.setUpOrbitalControls();
    
    //Add optional GridHelper for Debug
    this.scene.add(new THREE.GridHelper());
    
    //TODO: Create the heatmap here
    this.createDataRectangle();
    
    //Add the finished heatmap to the scene
    this.scene.add(this.heatmap);
    this.render();
    this.animate();
  }
  setUpRenderer(){
    console.log("Heatmap - setUpRenderer()");
    let width = $('#container').width();
    let height = $('#container').height();
    this.renderer.setPixelRatio(window.devicePixelRatio);
    this.renderer.setSize(width,height);
    this.renderer.setClearColor(0x404040);
 
    $("#container").html(this.renderer.domElement);
    
    window.addEventListener("resize", event => {
      this.camera.aspect = innerWidth / innerHeight;
      this.camera.updateProjectionMatrix();
      this.renderer.setSize(innerWidth, innerHeight);
    });
  }
  setUpCamera(){
    console.log("Heatmap - setUpCamera()");
    this.camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 0.01, 100);
    this.camera.position.z = 4;
  }
  setUpLighting(){
    console.log("Heatmap - setUpLighting()");
    this.ambientLight = new THREE.AmbientLight(0xffffff, 1);
    this.scene.add(this.ambientLight);
  }
  setUpOrbitalControls(){
    console.log("Heatmap - setUpOrbitalControls()");
    this.orbital_controls = new OrbitControls( this.camera, this.renderer.domElement );
    this.orbital_controls.target.set(0, 0, 0);
    this.orbital_controls.enableDamping = true;
    this.orbital_controls.dampingFactor = 0.025;
    this.orbital_controls.maxPolarAngle = Math.PI/2.0;
    this.orbital_controls.minDistance = 2.0;
    this.orbital_controls.maxDistance = 80.0;
    this.orbital_controls.update();
    
    this.orbital_controls.addEventListener( 'change', function(){
      if (this.target.y < 0){
          this.target.y = 0;
          /* camera.position.y = -1; */
      } else if (this.target.y > 1){
          this.target.y = 1;
          /* camera.position.y = 1; */
      }
    });
  }
  createDataRectangle(){ //TODO: Make this create at a position specified
    console.log("Heatmap - createDataRectangle()");
    const geometry = new THREE.BufferGeometry();
    const vertices = [
      -2, 0, 1,//0, floor, bottom left
      -1, 0, 1,//1, floor, bottom right
      -1, 0, -1,//2, floor, top right
      -2, 0, -1,//3 floor, top left
      -2, 3, 1,//4 roof, bottom left
      -1, 3, 1,//5 roof, bottom right
      -1, 3, -1,//6 roof, top right
      -2, 3, -1//7 roof, top left
    ];
    const indices = [
      0, 1, 2,//floor, first triangle
      2, 3, 0,//floor, second triangle
      4, 5, 6,//roof, first triangle
      6, 7, 4,//roof, second triangle
      3, 0, 4,//west wall, first triangle
      3, 4, 7,//west wall, second triangle
      0, 1, 5,//south wall, first triangle
      0, 5, 4,//south wall, first triangle
      1, 2, 6,//east wall, first triangle
      1, 6, 5,//east wall, second triangle
      2, 3, 7,//north wall, first triangle
      2, 7, 6,//north wall, second triangle
    ];
    const colors = [
      2,0,0, // bottom left
      0,2,0, // bottom right
      0,2,0, // top right
      2,0,0,  // top left
      2,0,0, // bottom left
      0,2,0, // bottom right
      0,2,0, // top right
      2,0,0  // top left
    ];
    geometry.setIndex(indices);
    geometry.setAttribute('position', new THREE.Float32BufferAttribute(vertices, 3));
    geometry.setAttribute('color', new THREE.Float32BufferAttribute(colors, 3));
    geometry.computeVertexNormals();
    const material = new THREE.MeshStandardMaterial({side:THREE.FrontSide,vertexColors:true,color: 0xFFFFFF });
    var shader_material = new THREE.ShaderMaterial( {
      vertexShader: document.getElementById( 'vertexShader' ).textContent,
      fragmentShader: document.getElementById( 'fragmentShader' ).textContent,
      uniforms: {
        thickness: {
          value: 1.5
        }
      }
    });
    const sample_rectangle = new THREE.Mesh(geometry, shader_material);
    this.heatmap.add(sample_rectangle);
    
    //Demo showing that the same shader material works on a box geometry!
    const geometryBox = new THREE.BoxGeometry();
    const sample_box = new THREE.Mesh(geometryBox, shader_material);
    sample_box.scale.y = 3;
    this.heatmap.add(sample_box);
  }
  animate(){
  
    requestAnimationFrame(() => {
      this.animate()
    });

    this.orbital_controls.update();//Required for Damping on OrbitControls

    this.delta += this.clock.getDelta();

    if (this.delta  > this.interval) {
      //this.timeSoFar = this.timeSoFar + (1 * morphDirection);

      this.render();
      this.delta = this.delta % this.interval;
    }
  }
  render(){
    this.renderer.render(this.scene, this.camera);
  }
}

$(document).ready(function(){
  console.log("DOM ready!");
  new Heatmap();
});

CSS

body,html{
  margin: 0;
  width: 100%;
  height: 100%;
}
#container {
  width: 100%;
  height: 100%;
  background-color: black;
  margin: 0;
}
javascript three.js glsl shader
© www.soinside.com 2019 - 2024. All rights reserved.