You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JavaScript给2D坐标加默认高度创建3D对象问题排查及替代方案咨询

Hey there! Let's break down what's going wrong with your Three.js code and fix it step by step, then I'll cover alternative ways to create a 3D-like shape without Three.js.

Key Issues in Your Code

  • Scope & Incorrect THREE.Shape Setup: You're defining shape inside your for loop, so it's not accessible in the init() function. Also, THREE.Shape doesn't accept a flat array of [x1,y1,x2,y2,...] directly—you need to build the path using moveTo() and lineTo() with individual points, or pass an array of THREE.Vector2 objects.
  • Unnecessary 2D Canvas Code: The ctx.moveTo()/ctx.lineTo() part is for 2D canvas rendering, which has nothing to do with your Three.js 3D model. It's also causing potential array out-of-bounds errors when i+2 exceeds the length of coords.
  • Undefined mycanvas Variable: You're passing mycanvas to THREE.WebGLRenderer but never defining it—this will cause a renderer initialization failure.
  • Camera Position Not Set: The default camera position is (0,0,0), which is inside your extruded mesh, so you won't see anything. You need to move it back along the Z-axis.
  • Missing Semicolons & Minor Syntax: Some lines (like dirLight.shadowMapHeight = 2048) are missing semicolons, which can lead to unexpected behavior.

Fixed Three.js Code

$(document).ready(function(){
  // Store coordinates as THREE.Vector2 objects instead of flat values
  function storeCoordinate(x, y, array) {
    array.push(new THREE.Vector2(x, y));
  }

  var coords = [];
  storeCoordinate(3, 5, coords);
  storeCoordinate(10, 100, coords);
  storeCoordinate(30, 120, coords);
  storeCoordinate(3, 5, coords); // Close the shape

  // Create the Shape correctly by building the path
  var shape = new THREE.Shape();
  // Move to the first point
  shape.moveTo(coords[0].x, coords[0].y);
  // Draw lines to subsequent points
  for (var i = 1; i < coords.length; i++) {
    shape.lineTo(coords[i].x, coords[i].y);
  }

  var scene, camera, renderer, extrudedMesh, controls;

  init();
  animate();

  function init(){
    scene = new THREE.Scene();
    
    // Set up camera and move it back
    camera = new THREE.PerspectiveCamera(75, window.innerWidth/window.innerHeight, 1, 1000);
    camera.position.z = 300; // Move camera away from the mesh

    // Create extruded geometry from the shape
    var extrudedGeometry = new THREE.ExtrudeGeometry(shape, {
      amount: 5, 
      bevelEnabled: false
    });
    extrudedMesh = new THREE.Mesh(
      extrudedGeometry, 
      new THREE.MeshPhongMaterial({color: 0xff0000})
    );
    scene.add(extrudedMesh);

    // Mouse rotation (fixed to use correct event properties)
    document.body.onmousemove = function(e){
      extrudedMesh.rotation.z = (e.clientX / window.innerWidth) * Math.PI * 2;
      extrudedMesh.rotation.x = (e.clientY / window.innerHeight) * Math.PI * 2;
    }

    // Lights setup
    const dirLight = new THREE.DirectionalLight(0xffffff);
    dirLight.intensity = 0.9;
    dirLight.position.set(500, 140, 500);
    dirLight.castShadow = true;
    dirLight.shadowMapHeight = 2048;
    dirLight.shadowMapWidth = 2048;
    dirLight.shadowDarkness = 0.15;
    scene.add(dirLight);

    const spotLight = new THREE.PointLight(0xffffff);
    spotLight.intensity = 0.5;
    spotLight.position.set(-500, 140, -500);
    scene.add(spotLight);

    const ambientLight = new THREE.AmbientLight(0x020202, 1);
    scene.add(ambientLight);

    // Renderer setup (either use existing canvas or let Three.js create one)
    renderer = new THREE.WebGLRenderer({antialias: true});
    renderer.setSize(window.innerWidth, window.innerHeight);
    document.body.appendChild(renderer.domElement);

    // OrbitControls setup (make sure you've included the OrbitControls script)
    controls = new THREE.OrbitControls(camera, renderer.domElement);
    controls.autoRotate = true;
    controls.enableZoom = true;
    controls.enablePan = true;
    controls.rotateSpeed = 3.0;
    controls.zoomSpeed = 1.0;
    controls.panSpeed = 2.0;
    controls.enableDamping = true;
    controls.dampingFactor = 0.25;
    controls.minDistance = 1.1;
    controls.maxDistance = 1000;
    controls.keys = [65, 83, 68]; // [ rotateKey, zoomKey, panKey ]
  }

  function animate() {
    window.requestAnimationFrame(animate);
    controls.update(); // Update controls for damping
    render();
  }

  function render() {
    renderer.render(scene, camera);
  }
});

What Changed:

  1. Coordinate Storage: We now store each point as a THREE.Vector2 to make building the shape easier.
  2. Shape Construction: We manually build the shape path with moveTo() and lineTo() instead of passing a flat array.
  3. Removed 2D Canvas Code: We got rid of the irrelevant 2D canvas rendering logic.
  4. Defined Camera Position: Moved the camera back along the Z-axis so you can see the mesh.
  5. Fixed Renderer Initialization: Let Three.js create its own canvas (you can still attach it to an existing one if needed).
  6. Added controls.update(): Required for OrbitControls damping to work.
  7. Cleaned Up Light Setup: Fixed semicolons and added scene.add() for lights where missing.

Alternatives Without Three.js

If you want to create a 3D-like effect without using Three.js, here are two simple options:

1. CSS 3D Transforms

You can use CSS perspective, transform-style: preserve-3d, and rotateX/rotateY to create a pseudo-3D shape. For example, extruding a 2D div into a 3D prism:

<style>
  .container {
    perspective: 800px;
    width: 100vw;
    height: 100vh;
    display: flex;
    justify-content: center;
    align-items: center;
  }

  .prism {
    position: relative;
    transform-style: preserve-3d;
    animation: rotate 10s infinite linear;
  }

  .face {
    position: absolute;
    background: rgba(255, 0, 0, 0.8);
    border: 1px solid #000;
  }

  /* Front face (your 2D shape) */
  .front {
    width: 200px;
    height: 150px;
    transform: translateZ(2.5px); /* Half the extrusion depth */
    clip-path: polygon(3px 5px, 10px 100px, 30px 120px, 3px 5px);
  }

  /* Back face */
  .back {
    width: 200px;
    height: 150px;
    transform: translateZ(-2.5px) rotateY(180deg);
    clip-path: polygon(3px 5px, 10px 100px, 30px 120px, 3px 5px);
  }

  /* Side face example */
  .side1 {
    width: 5px;
    height: 150px;
    transform: rotateY(90deg) translateZ(3px);
    left: -2.5px;
  }

  @keyframes rotate {
    from { transform: rotateY(0) rotateX(0); }
    to { transform: rotateY(360deg) rotateX(360deg); }
  }
</style>

<div class="container">
  <div class="prism">
    <div class="face front"></div>
    <div class="face back"></div>
    <div class="face side1"></div>
    <!-- Add other side faces based on your shape's edges -->
  </div>
</div>

Note: This works best for simple shapes, as you have to manually create each side face.

2. 2D Canvas with Pseudo-3D Drawing

You can use 2D canvas to draw a "flat 3D" representation by projecting your 2D points into a pseudo-3D space:

const canvas = document.getElementById('myCanvas');
const ctx = canvas.getContext('2d');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;

// Your 2D coordinates
const coords = [
  {x: 3, y: 5},
  {x: 10, y: 100},
  {x: 30, y: 120},
  {x: 3, y: 5}
];

// Extrusion depth (Z-axis offset)
const depth = 20;
// Perspective factor
const perspective = 0.1;

function drawPseudo3DShape() {
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  ctx.translate(canvas.width/2, canvas.height/2); // Center the shape

  // Draw front face
  ctx.fillStyle = 'rgba(255,0,0,0.8)';
  ctx.beginPath();
  ctx.moveTo(coords[0].x, coords[0].y);
  for(let i=1; i<coords.length; i++) {
    ctx.lineTo(coords[i].x, coords[i].y);
  }
  ctx.fill();

  // Draw back face (offset by depth, scaled for perspective)
  ctx.fillStyle = 'rgba(200,0,0,0.5)';
  ctx.beginPath();
  ctx.moveTo(coords[0].x + depth*perspective, coords[0].y + depth*perspective);
  for(let i=1; i<coords.length; i++) {
    ctx.lineTo(coords[i].x + depth*perspective, coords[i].y + depth*perspective);
  }
  ctx.fill();

  // Draw connecting lines between front and back points
  ctx.strokeStyle = '#000';
  ctx.lineWidth = 2;
  for(let i=0; i<coords.length-1; i++) {
    ctx.beginPath();
    ctx.moveTo(coords[i].x, coords[i].y);
    ctx.lineTo(coords[i].x + depth*perspective, coords[i].y + depth*perspective);
    ctx.stroke();
  }
}

drawPseudo3DShape();

This creates a simple flat 3D illusion without any 3D libraries.

内容的提问来源于stack exchange,提问作者Daniel Bisceanu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 07:20:17