在three.js中使用带着色器的置换贴图

时间:2018-09-26 22:01:29

标签: javascript three.js shader

我正在尝试创建位移贴图,但是当涉及到在沙子中的岩石上有位移的大型平面等时,仅一个10x10方形平面就需要一个高质量的位移所需要的1000个段就显得异常缓慢,并产生帧速率问题。我希望该平面的高度为500x500,这将需要50,000个分段,并且每个纹理上都有位移贴图。

作为位移的解决方案,这确实很糟糕,但是我不知道如何制作着色器!

我阅读了着色器,我知道它们是如何工作的,但是我不知道从THREE.js r96开始。特别是r96,因为着色器的属性属于几何体(无论如何,我认为这就是它的工作方式),而不是材质。我挖出的每个教程都使用带有基于GLSL代码的着色器属性的着色器材料。

如何在THREE.js中使用着色器解决位移问题?

代码(对眼睛和/或大脑受损致歉):

<!DOCTYPE html>
<html id="html">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>Home</title>
    <script src="js/jquery.min.js"></script>
    <script src="js/scene.js"></script>
    <script src="js/cannon.min.js"></script>
    <script src="three.min.js"></script>
  <script src="js/THREEx.keyboardstate.js"></script>
  <script src="js/controls.js"></script>
  <link rel="stylesheet" href="codemirror/lib/codemirror.css">
  <link rel="stylesheet" href="codemirror\theme\tomorrow-night-bright.css">
  <link rel="stylesheet" href="codemirror\theme\3024-night.css">
  <script src="codemirror/lib/codemirror.js"></script>
  <script src="codemirror/mode/javascript/javascript.js"></script>
  <script type="text/plain" id="vertexshader">
    attribute float displacement;
varying vec3 vNormal;

void main() {

  vNormal = normal;

  // push the displacement into the
  // three slots of a 3D vector so
  // it can be used in operations
  // with other 3D vectors like
  // positions and normals
  vec3 newPosition = position +
    normal * vec3(displacement);

  gl_Position = projectionMatrix *
                modelViewMatrix *
                vec4(newPosition, 1.0);
}
  </script>
  <script type="text/plain" id="fragmentshader">
    varying vec3 vNormal;

void main() {

  // calc the dot product and clamp
  // 0 -> 1 rather than -1 -> 1
  vec3 light = vec3(0.5, 0.2, 1.0);

  // ensure it's normalized
  light = normalize(light);

  // calculate the dot product of
  // the light to the vertex normal
  float dProd = max(0.0,
                    dot(vNormal, light));

  // feed into our frag colour
  gl_FragColor = vec4(dProd, // R
                      dProd, // G
                      dProd, // B
                      1.0);  // A

}
  </script>
    <style>
     @import url('https://fonts.googleapis.com/css?family=Titillium+Web');
     @import url('https://fonts.googleapis.com/css?family=Quicksand&subset=latin-ext');
    ::-webkit-scrollbar { 
    display: none; 
    }
        #container {
            margin:0;
      border:none;
      padding:none;
      position:fixed;
      overflow:hidden;
      height:100%;
      width:100%;
        }
    textarea {
      background:black;
      color:white;
      border:none;
      outline:none;
      display:none;
    }
        html{
      -ms-overflow-style: -ms-autohiding-scrollbar;
      margin:0;
      border:none;
      padding:none;
            overflow:hidden;
      overflow-x:hidden;
      height:100%;
      width:100%;
        }
    body {
      width:100%;
      height:100%;
      border:none;
      margin:0;
    }
    form {
      position:absolute;
      bottom:100px;
      position:fixed;
      display:none;
    }
    html {
      font-family: 'Quicksand', sans-serif;
    }
    .error {
      background-color:red;
      color:black;
    }
    .log {
      outline: 1px solid black;
    }
    .bluetext {
      color:blue;
    }
    #consoleOutputError {
      display: none;
    }
    </style>
</head>
<body>
  <div id="container"></div>
  <form id="consoleForm" onsubmit="return false;" style="width:30%">
    <textarea rows="20" spellcheck="false" cols="70" type="text" id="consoletext"></textarea>
    <input type="button" onclick="evaluateTheConsole()" value="Run code">
    <input type="button" onclick="document.getElementById('consoleOutputError').innerHTML=''" value="">
  </form>
  <ul style="color:red;position:absolute;right:10px;top:0px;width:10%" id="consoleOutputError"></ul>
<script>
  var editor = CodeMirror.fromTextArea(document.getElementById("consoletext",function ( texture ) {texture.wrapS = texture.wrapT = THREE.RepeatWrapping;texture.offset.set( 0, 0 );texture.repeat.set( 1, 1 )}), {
    lineNumbers: true,
    mode: "text/javascript",
    theme: "3024-night"
  });
  function printColor(message,color,bkgrnd="none"){
    document.getElementById("consoleOutputError").innerHTML+="<li class='log' style='overflow-wrap: break-word;word-wrap:break-word;white-space:pre-line;padding:2px;list-style-type:none;color:"+color+";background-color:"+bkgrnd+"'>"+message+"</li>";
    document.getElementById("html").scrollTop = document.getElementById("html").scrollHeight;
  }
  (function(){
    var oldLog = console.log;
    console.log = function (message) {
      printColor(message,"black");
        oldLog.apply(console, arguments);
    };
})();
(function(){
    var oldErr = console.error;
    console.error = function (message) {
      printColor(message,"red");
        oldErr.apply(console, arguments);
    };
})();
(function(){
    var oldWrn = console.warn;
    console.warn = function (message) {
      printColor(message,"orange");
        oldWrn.apply(console, arguments);
    };
})();
  function evaluateTheConsole(){
    try {
      eval(editor.getValue());
} catch(err) {
  var recent = document.getElementById("consoleOutputError").innerHTML;
  printColor(err.message,"red");
document.getElementById("html").scrollTop = document.getElementById("html").scrollHeight;
}
  }
    // Set the scene size.
    const WIDTH = window.innerWidth;
    const HEIGHT = window.innerHeight;

    // Set some camera attributes.
    const VIEW_ANGLE = 45;
    const ASPECT = WIDTH / HEIGHT;
    const NEAR = 0.1;
    const FAR = 10000;

    // Get the DOM element to attach to
    const container =
        document.querySelector('#container');

    // Create a WebGL renderer, camera
    // and a scene
    const renderer = new THREE.WebGLRenderer();
    var camera =
        new THREE.PerspectiveCamera(
            VIEW_ANGLE,
            ASPECT,
            NEAR,
            FAR
        );

    const scene = new THREE.Scene();
    var stem = "./"
    scene.background = new THREE.CubeTextureLoader().load([
      stem+"xpos2.png",
      stem+"xneg2.png",
      stem+"ypos2.png",
      stem+"yneg2.png",
      stem+"zpos2.png",
      stem+"zneg2.png",
    ])
    // Add the camera to the scene.
    scene.add(camera);
    controls = new THREE.OrbitControls( camera, renderer.domElement );
    controls.target = new THREE.Vector3(0, 0, 0);
        camera.position.set(0,1,0)
    // Start the renderer.
    renderer.setSize(WIDTH, HEIGHT);

    // Attach the renderer-supplied
    // DOM element.
    container.appendChild(renderer.domElement);

    // create a point light
    var pointLight =
      new THREE.PointLight(0xFFFFFF);

    // set its position
    pointLight.position.x = 100;
    pointLight.position.y = 100;
    pointLight.position.z = 100;

     var pointLight2 =
      new THREE.PointLight(0xFFFFFF);

    // set its position
    pointLight2.position.x = -100;
    pointLight2.position.y = 100;
    pointLight2.position.z = -100;
    var setUVs = function(mesh,x,y){
      var uvs = mesh.geometry.attributes.uv;
      for ( var i = 0; i < uvs.count; i++ ) {
        uvs.setXY( i, uvs.getX( i ) * x, uvs.getY( i ) * y );
      }
      var i = 0;
    }
    // add to the scene
    scene.add(pointLight);
    // create the sphere's material
    var attributes = {
  displacement: {
    type: 'f', // a float
    value: [] // an empty array
  }
};

var vShader = $('#vertexshader');
var fShader = $('#fragmentshader');

// create the material and now
// include the attributes property
var shaderMesh =
  new THREE.Mesh(
    new THREE.BoxBufferGeometry(1,1,1),
    new THREE.ShaderMaterial({
      uniforms:     attributes,
      vertexShader:   vShader.text(),
      fragmentShader: fShader.text(),
      wireframe:true
    })
  );

// now populate the array of attributes
var verts =
  shaderMesh.geometry.vertices;

var values =
  shaderMesh.geometry.vertices;

for (var v = 0; v < shaderMesh.geometry.vertices; v++) {
  values.push(Math.random() * 30);
}
scene.add(shaderMesh);
var tex = new THREE.TextureLoader().load("https://threejs.org/examples/textures/UV_Grid_Sm.jpg");
tex.wrapS = THREE.RepeatWrapping;
tex.wrapT = THREE.RepeatWrapping;

var geo = new THREE.PlaneBufferGeometry(2, 2);
var mat = new THREE.ShaderMaterial({
  uniforms:{
      time: {value: 0},
      texture1: {value: tex}
  },
  vertexShader:`
    varying vec2 vUv;
    void main() {
      vUv = uv;
      gl_Position = projectionMatrix * modelViewMatrix * vec4(position,2.0);
    }
  `,
  fragmentShader: `
    uniform float time;
    uniform sampler2D texture1;
    varying vec2 vUv;
    void main() {
      vec3 c = vec3(texture2D(texture1, vUv));
      float v = time + (vUv.x*0.5 + vUv.y*0.5);
      vec2 Uv2 = vec2(c.r + c.b+v, c.g + c.b + v);
      vec3 outcolor = vec3(texture2D(texture1, Uv2));
      gl_FragColor = vec4( outcolor, 1.0 );
    }
  `
});
var plane = new THREE.Mesh(geo, mat);
scene.add(plane);
plane.position.y = 15;
shaderMesh.position.y = 10;
    var sphereMaterial =
      new THREE.MeshPhongMaterial(
        {
          envMap: scene.background,
                    map: new THREE.TextureLoader().load("energyrock.jpg",function ( texture ) {texture.wrapS = texture.wrapT = THREE.RepeatWrapping;texture.offset.set( 0, 0 );texture.repeat.set( 1, 1 )}),
                    normalMap: new THREE.TextureLoader().load("energyrocknormal.jpg",function ( texture ) {texture.wrapS = texture.wrapT = THREE.RepeatWrapping;texture.offset.set( 0, 0 );texture.repeat.set( 1, 1 )}),
                    displacementMap: new THREE.TextureLoader().load("energyrockbump.jpg",function ( texture ) {texture.wrapS = texture.wrapT = THREE.RepeatWrapping;texture.offset.set( 0, 0 );texture.repeat.set( 1, 1 )}),
                    aoMap: new THREE.TextureLoader().load("energyrockao.jpg",function ( texture ) {texture.wrapS = texture.wrapT = THREE.RepeatWrapping;texture.offset.set( 0, 0 );texture.repeat.set( 1, 1 )}),
                    specularMap: new THREE.TextureLoader().load("energyrockspecular.jpg",function ( texture ) {texture.wrapS = texture.wrapT = THREE.RepeatWrapping;texture.offset.set( 0, 0 );texture.repeat.set( 1, 1 )}),
                    emissiveMap: new THREE.TextureLoader().load("energyrockemissive.jpg",function ( texture ) {texture.wrapS = texture.wrapT = THREE.RepeatWrapping;texture.offset.set( 0, 0 );texture.repeat.set( 1, 1 )}),
          color:"#ffffff",
          emissive:"#bb00bb",
          specular:"#000000",
          reflectivity:1,
          displacementScale:0.03
        });
        var sphereMaterial2 =
      new THREE.MeshPhongMaterial(
        {
          envMap: scene.background,
                    map: new THREE.TextureLoader().load("cobblestone.jpg",function ( texture ) {texture.wrapS = texture.wrapT = THREE.RepeatWrapping;texture.offset.set( 0, 0 );texture.repeat.set( 1, 1 )}),
                    displacementMap: new THREE.TextureLoader().load("cobblestonebump.jpg",function ( texture ) {texture.wrapS = texture.wrapT = THREE.RepeatWrapping;texture.offset.set( 0, 0 );texture.repeat.set( 1, 1 )}),
          specularMap: new THREE.TextureLoader().load("cobblestoneSpecular.jpg",function ( texture ) {texture.wrapS = texture.wrapT = THREE.RepeatWrapping;texture.offset.set( 0, 0 );texture.repeat.set( 1, 1 )}),
          aoMap: new THREE.TextureLoader().load("cobblestoneao.jpg",function ( texture ) {texture.wrapS = texture.wrapT = THREE.RepeatWrapping;texture.offset.set( 0, 0 );texture.repeat.set( 1, 1 )}),
          normalMap: new THREE.TextureLoader().load("cobblestoneicenormal.jpg",function ( texture ) {texture.wrapS = texture.wrapT = THREE.RepeatWrapping;texture.offset.set( 0, 0 );texture.repeat.set( 1, 1 )}),
          alphaMap:new THREE.TextureLoader().load("cobblestonealpha.jpg",function ( texture ) {texture.wrapS = texture.wrapT = THREE.RepeatWrapping;texture.offset.set( 0, 0 );texture.repeat.set( 1, 1 )}),
          //transparent:true,
          reflectivity:0.6,
          color: "#aaaaff",
          specular: "#4444aa",
         displacementBias: 0.0,// from original model
         displacementScale: 0.05,
        });
        var brickMaterial =
      new THREE.MeshPhongMaterial(
        {
          envMap: scene.background,
                    map: new THREE.TextureLoader().load("brick.jpg",function ( texture ) {texture.wrapS = texture.wrapT = THREE.RepeatWrapping;texture.offset.set( 0, 0 );texture.repeat.set( 1, 1 )}),
                    displacementMap: new THREE.TextureLoader().load("brickbump.jpg",function ( texture ) {texture.wrapS = texture.wrapT = THREE.RepeatWrapping;texture.offset.set( 0, 0 );texture.repeat.set( 1, 1 )}),
          bumpMap: new THREE.TextureLoader().load("brickbump.jpg",function ( texture ) {texture.wrapS = texture.wrapT = THREE.RepeatWrapping;texture.offset.set( 0, 0 );texture.repeat.set( 1, 1 )}),
          normalMap: new THREE.TextureLoader().load("bricknormal.jpg",function ( texture ) {texture.wrapS = texture.wrapT = THREE.RepeatWrapping;texture.offset.set( 0, 0 );texture.repeat.set( 1, 1 )}),
          specularMap: new THREE.TextureLoader().load("brickspecular.jpg",function ( texture ) {texture.wrapS = texture.wrapT = THREE.RepeatWrapping;texture.offset.set( 0, 0 );texture.repeat.set( 1, 1 )}),
          displacementScale:0.03,
          reflectivity:0.5,
          color: "#ffaaaa",
          specular: "#4444aa"
        });
        var rockMaterial =
      new THREE.MeshPhongMaterial(
        {
          envMap: scene.background,
                    map: new THREE.TextureLoader().load("granite.jpg",function ( texture ) {texture.wrapS = texture.wrapT = THREE.RepeatWrapping;texture.offset.set( 0, 0 );texture.repeat.set( 1, 1 )}),
          normalMap: new THREE.TextureLoader().load("granitenormal.jpg",function ( texture ) {texture.wrapS = texture.wrapT = THREE.RepeatWrapping;texture.offset.set( 0, 0 );texture.repeat.set( 1, 1 )}),
          bumpMap: new THREE.TextureLoader().load("granitebump.jpg",function ( texture ) {texture.wrapS = texture.wrapT = THREE.RepeatWrapping;texture.offset.set( 0, 0 );texture.repeat.set( 1, 1 )}),
          bumpScale:0,
          reflectivity:0.5,
          color: "#aaaaff",
          specular: "#4444aa"
        });
        var mudMaterial =
      new THREE.MeshPhongMaterial(
        {
          envMap: scene.background,
                    map: new THREE.TextureLoader().load("mud.jpg",function ( texture ) {texture.wrapS = texture.wrapT = THREE.RepeatWrapping;texture.offset.set( 0, 0 );texture.repeat.set( 1, 1 )}),
          normalMap: new THREE.TextureLoader().load("mudnormal.jpg",function ( texture ) {texture.wrapS = texture.wrapT = THREE.RepeatWrapping;texture.offset.set( 0, 0 );texture.repeat.set( 1, 1 )}),
          bumpMap: new THREE.TextureLoader().load("mudbump.jpg",function ( texture ) {texture.wrapS = texture.wrapT = THREE.RepeatWrapping;texture.offset.set( 0, 0 );texture.repeat.set( 1, 1 )}),
          aoMap: new THREE.TextureLoader().load("mudao.jpg",function ( texture ) {texture.wrapS = texture.wrapT = THREE.RepeatWrapping;texture.offset.set( 0, 0 );texture.repeat.set( 1, 1 )}),
          displacementMap: new THREE.TextureLoader().load("muddisplacement.jpg",function ( texture ) {texture.wrapS = texture.wrapT = THREE.RepeatWrapping;texture.offset.set( 0, 0 );texture.repeat.set( 1, 1 )}),
          specularMap: new THREE.TextureLoader().load("muddisplacement.jpg",function ( texture ) {texture.wrapS = texture.wrapT = THREE.RepeatWrapping;texture.offset.set( 0, 0 );texture.repeat.set( 1, 1 )}),
          displacementScale:0.015,
          reflectivity:0,
          color: "#ddccaa",
          specular: "#000000",
          //specular: "#4444aa"
        });

    // Set up the sphere vars
    const RADIUS = 1;
    const SEGMENTS = 16;
    const RINGS = 16;

    // Create a new mesh with
    // sphere geometry - we will cover
    // the sphereMaterial next!
    var sphere = new THREE.Mesh(

      new THREE.PlaneBufferGeometry(
        1, 1,100,100),

      sphereMaterial2.clone());
      var plane2 = new THREE.Mesh(

new THREE.PlaneBufferGeometry(
  1, 1,10,10),

sphereMaterial2.clone());
      sphere.rotation.x = Math.PI / -2;
      plane2.rotation.x = Math.PI / -2;
    var rocks = new THREE.Mesh(

      new THREE.BoxBufferGeometry(
        3, 3, 3,300,300),

      rockMaterial.clone());

    // Move the Sphere back in Z so we
    // can see it.
    sphere.position.z = 0;
    rocks.position.y = 3;
    camera.position.z = -3;

    // Finally, add the sphere to the scene.
    scene.add(sphere);
    //scene.add(plane2);
    plane2.position.y = 0.015
    scene.add(rocks);
    setUVs(sphere,1,1);
    setUVs(rocks,3,3);
    var g = 0;
    var b = 0;
    var vueDifference = 20;
    var speed = 1;
    var wow;
    var hColor = 0;
    var i=0;
    var tty = 0;
    var materialtextures = [];
    Object.keys(sphere.material).forEach(function(key) {
          console.log(key, sphere.material[key]);
          if(key=="map"&&sphere.material[key]!=null&&sphere.material[key]!=undefined){
            //materialtextures[tty]=sphere.materials[key];
            //materialtextures[tty].wrapS = materialtextures[tty].wrapT = THREE.RepeatWrapping;
            tty++;
          }
      });
    function announce(expression) {
      console.log(expression);
      return expression
    }
    var animationsEnabled = true;
    var colorAnimationEnabled = true;
    var customAnimationEnabled = true;
    var clockStopped = false;
    var i = 0;
    var iCurrent=0;
    function setAnimTimer(time) {
      console.log("Paused animation loop at " + time);
      i=time;
      clockStopped=true;
      iCurrent = time;
      return time;
    }
    var customAnimation = function(time){};
    var currentColor = 90;
    function update () {
      if(clockStopped==false){
      i++;
      if(customAnimationEnabled==true){
        customAnimation(i);
      }
      if(animationsEnabled==true){
  mat.uniforms.time.value = i;
  renderer.render(scene, camera);
      hColor = hColor + speed;
      if(Math.round((Math.sin(i/100)+1)*35)==0){
       currentColor = Math.floor((Math.random() * 360)+1);
      }else if(Math.round((Math.sin(i/100)+1)*50)==100){
        currentColor = Math.floor((Math.random() * 360)+1);
      };
      wow2 = String("hsl(" + currentColor + "," + 100 + "%" + "," + Math.round((Math.sin(i/100)+1)*50) + "%" + ")");
      wow = String("hsl(" + currentColor + "," + 100 + "%" + "," + Math.round((Math.sin(i/100)+1)*50) + "%" + ")");
      wow3 = String("hsl(" + (Math.sin(i/100)+1)*180 + "," + 100 + "%" + "," + 70 + "%" + ")");
      // Draw!
            //sphere.rotateY(0.01);
      if(colorAnimationEnabled==true){
        //sphere.material.emissive = new THREE.Color(wow2);
      }
      //sphere.rotateX(0.001);
      //sphere.rotateX(0.001);
      //sphere.material.specular = new THREE.Color(wow);
      //
      // Schedule the next frame.
      }
      //sphere.material.displacementScale = (Math.sin(i/100)+1)/60;
      controls.update;
      renderer.render(scene, camera);
      requestAnimationFrame(update);
      }else{
        i=iCurrent;
      }
    }
    // Schedule the first frame.
    requestAnimationFrame(update);
</script>
</body>
</html>

0 个答案:

没有答案