简体   繁体   中英

How to use Javascript tranfrom 3D effect the image data? capture the CSS effects on rotateX, rotateY, perspective on the original image

I use rotateX, rotateY, perspective to achieve the effect of flipping (x-axis and y-axis) pictures and perspective

How can I do this to the actual image?

Because I need to save the transformed image

I need cut red mask scope in origin image (use canvas? or three part library api?)

instead of just applying visual effects on css

I've researched some workarounds, the canvas api doesn't seem to be able to do this? three.js seems to be the easier way, but I don't know where to start

my example code

video demo: https://imgur.com/SegKmTL

sorry my english is bad

  <style>
    .container {
      perspective: 300px;
      background-color: green;
      width: 300px;
      display: flex;
      align-items: center;
      justify-content: center;
      margin: 100px auto;
    }
    .mask {
      position: absolute;
      width: 100%;
      height: 100%;
      border: 2px solid red;
      z-index: 100;
    }
    .image {
      border: 1px solid blue;
    }
  </style>
  <body>
    <input
      id="roateXSlider"
      type="range"
      min="0"
      max="50"
      step="1"
      value="25"
    />
    RotateX
    <input
      id="roateYSlider"
      type="range"
      min="0"
      max="50"
      step="1"
      value="25"
    />
    RoateY
    <div class="container">
      <!-- mask is cut image scope in origin image  -->
      <div class="mask"></div>
      <img
        id="source"
        class="image"
        src="https://i.imgur.com/3Qnbg4J.jpeg"
        style="width: 100%;"
      />
    </div>
  </body>ource"
        class="image"
        src="https://i.imgur.com/3Qnbg4J.jpeg"
        style="width: 100%;"
      />
    </div>
  </body>
const source = document.getElementById("source");

const roateXSlider = document.getElementById("roateXSlider");
const roateYSlider = document.getElementById("roateYSlider");

const image3dInfo = {
  keystoneH: 0,
  keystoneV: 0,
  rotateX: 0,
  rotateY: 0,
};

// Rotate X or Y range => 335deg <= 360(0)deg => 25deg
// on X axis (origin top or bottom)
// on Y axis (origin left or right)
// Image element lement perspective => 300px

roateXSlider.oninput = function () {
  let value = parseInt(this.value, 10);
  if (value <= 25) {
    image3dInfo.keystoneV = 0;
    image3dInfo.rotateX = 25 - value;
  } else {
    image3dInfo.keystoneV = 100;
    image3dInfo.rotateX = 360 - value + 25;
  }
  update3dTransform();
};

roateYSlider.oninput = function () {
  let value = parseInt(this.value, 10);
  if (value <= 25) {
    image3dInfo.keystoneH = 100;
    image3dInfo.rotateY = 25 - value;
  } else {
    image3dInfo.keystoneH = 0;
    image3dInfo.rotateY = 360 - value + 25;
  }
  update3dTransform();
};

function update3dTransform() {
  source.style.transformOrigin = `${image3dInfo.keystoneH}% ${image3dInfo.keystoneV}% 0px`;
  source.style.transform =` rotateX(${image3dInfo.rotateX}deg) rotateY(${image3dInfo.rotateY}deg)`;
  
  captureImage();
}

function captureImage() {
  // capture red mask scope on origin image draw to canvas
}

Here's an example of how to use THREE.js to perform the transformation in a canvas, which has the toDataURL method that can retrieve the last rendered frame. In the below example this is written to the console when the download button is pressed.

You'll need to tweak the transformation to properly match your original, however this should be enough to get you started, see the Object3D docs here for transformation properties.

 const source = document.getElementById("source"); const roateXSlider = document.getElementById("roateXSlider"); const roateYSlider = document.getElementById("roateYSlider"); document.getElementById("dl").addEventListener("click", captureImage); const image3dInfo = { keystoneH: 0, keystoneV: 0, rotateX: 0, rotateY: 0, }; // Rotate X or Y range => 335deg <= 360(0)deg => 25deg // on X axis (origin top or bottom) // on Y axis (origin left or right) // Image element lement perspective => 300px roateXSlider.oninput = function () { let value = parseInt(this.value, 10); if (value <= 25) { image3dInfo.keystoneV = 0; image3dInfo.rotateX = 25 - value; } else { image3dInfo.keystoneV = 100; image3dInfo.rotateX = 360 - value + 25; } update3dTransform(); }; roateYSlider.oninput = function () { let value = parseInt(this.value, 10); if (value <= 25) { image3dInfo.keystoneH = 100; image3dInfo.rotateY = 25 - value; } else { image3dInfo.keystoneH = 0; image3dInfo.rotateY = 360 - value + 25; } update3dTransform(); }; let cvs; function setupGl() { const wid = 300; const hgt = 230; const scene = new THREE.Scene(); const camera = new THREE.PerspectiveCamera(75, 1.0, 0.1, 1000); const renderer = new THREE.WebGLRenderer({ antialias: true, preserveDrawingBuffer: true }); renderer.setSize(wid, hgt); document.body.appendChild(renderer.domElement); (cvs = renderer.domElement).className = "container"; const plane = new THREE.Mesh( new THREE.PlaneGeometry(8, 8), new THREE.MeshBasicMaterial({ side: THREE.DoubleSide, map: new THREE.TextureLoader().load("https://i.imgur.com/3Qnbg4J.jpeg") })); scene.add(plane); camera.position.z = 5; const drawFrame = () => { plane.rotation.x = THREE.Math.degToRad(-image3dInfo.rotateX); plane.rotation.y = THREE.Math.degToRad(image3dInfo.rotateY); renderer.render(scene, camera); requestAnimationFrame(drawFrame); }; drawFrame(); } setupGl(); function update3dTransform() { source.style.transformOrigin = `${image3dInfo.keystoneH}% ${image3dInfo.keystoneV}% 0px`; source.style.transform =` rotateX(${image3dInfo.rotateX}deg) rotateY(${image3dInfo.rotateY}deg)`; } function captureImage() { let capture = cvs.toDataURL("image/jpeg"); console.log("Frame data:", capture); }
 .container { perspective: 300px; background-color: green; width: 300px; display: flex; align-items: center; justify-content: center; margin: 25px auto; overflow: hidden; }.mask { position: absolute; width: 100%; height: 100%; border: 2px solid red; z-index: 100; }.image { border: 1px solid blue; }
 <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script> <input id="roateXSlider" type="range" min="0" max="50" step="1" value="25" /> RotateX <input id="roateYSlider" type="range" min="0" max="50" step="1" value="25" /> RoateY <button id="dl">Download</button> <div class="container"> <:-- mask is cut image scope in origin image --> <div class="mask"></div> <img id="source" class="image" src="https.//i.imgur.com/3Qnbg4J:jpeg" style="width; 100%;" /> </div>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM