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

基于CMU图形库的3D方块渲染问题求助:无需额外导入,将面中心点转化为可渲染多边形并修正视角移动异常

Hey there! Let's break down your Minecraft-like block rendering issues step by step—you're already halfway there with the face center points, so let's turn those into solid polygons and fix the wonky movement/camera behavior.

1. Turning Face Centers into Polygon Faces

Right now you're rendering the center of each visible face, but to draw the full square face, you need to calculate all four vertices of the face, convert each to screen coordinates, then pass those points to the Polygon class. Here's how to approach it:

Step 1: Create a Reusable 3D-to-Screen Conversion Function

Your current code repeats the same angle math 6 times—let's fix that with a helper function that handles rotation and perspective for any 3D point. This will also fix the "flat" orthogonal look by adding proper perspective projection (so closer blocks appear larger):

import math

def world_to_screen(vertex_x, vertex_y, vertex_z, player):
    # Calculate offset from the player's position
    dx = vertex_x - player.x
    dy = vertex_y - player.y
    dz = vertex_z - player.z

    # Convert player's yaw/pitch to radians
    yaw_rad = math.radians(player.yaw)
    pitch_rad = math.radians(player.pitch)

    # Rotate for yaw (around Y-axis)
    rotated_x = dx * math.cos(yaw_rad) + dz * math.sin(yaw_rad)
    rotated_z = -dx * math.sin(yaw_rad) + dz * math.cos(yaw_rad)

    # Rotate for pitch (around X-axis)
    camera_x = rotated_x
    camera_y = dy * math.cos(pitch_rad) - rotated_z * math.sin(pitch_rad)
    camera_z = dy * math.sin(pitch_rad) + rotated_z * math.cos(pitch_rad)

    # Skip points behind the player
    if camera_z <= 0:
        return None

    # Perspective projection (adjust focal_length to tweak zoom)
    focal_length = 200
    screen_center_x = 200
    screen_center_y = 600  # Matches your existing code's Y origin
    screen_x = screen_center_x + (camera_x / camera_z) * focal_length
    screen_y = screen_center_y - (camera_y / camera_z) * focal_length  # Flip Y to match screen axis

    return (screen_x, screen_y)

Step 2: Render Full Faces with Polygon

For each visible face (like front, top, etc.), define its four world-space vertices, convert each to screen coordinates, then pass the list to Polygon. Here's an example for the front face:

def render(self, target):
    # Define your block's world position (replace with your actual block coords)
    block_x, block_y, block_z = self.x, self.y, self.z

    if self.front:
        # Front face vertices (square around the center point)
        front_vertices = [
            (block_x - 0.5, block_y - 0.5, block_z + 0.5),
            (block_x + 0.5, block_y - 0.5, block_z + 0.5),
            (block_x + 0.5, block_y + 0.5, block_z + 0.5),
            (block_x - 0.5, block_y + 0.5, block_z + 0.5)
        ]
        # Convert all vertices to screen points
        screen_points = []
        for v in front_vertices:
            sp = world_to_screen(v[0], v[1], v[2], target)
            if sp:
                screen_points.append(sp)
        # Render the polygon if all points are valid
        if len(screen_points) == 4:
            renderGroup.add(Polygon(screen_points))
        # Optional: Keep rendering the center point for debugging
        center_sp = world_to_screen(block_x, block_y, block_z + 0.5, target)
        if center_sp:
            renderGroup.add(Circle(center_sp[0], center_sp[1], 2))

    # Repeat this pattern for top/left/bottom/right/back faces with their respective vertices
    # Example for top face vertices:
    # top_vertices = [
    #     (block_x - 0.5, block_y + 0.5, block_z - 0.5),
    #     (block_x + 0.5, block_y + 0.5, block_z - 0.5),
    #     (block_x + 0.5, block_y + 0.5, block_z + 0.5),
    #     (block_x - 0.5, block_y + 0.5, block_z + 0.5)
    # ]

2. Fixing Camera/Movement Anomalies

Your weird point movement and 360° camera glitches come from two main issues: improper angle wrapping and unconstrained pitch rotation. Here's how to fix them:

Step 1: Properly Wrap Angles

Instead of manually checking if yaw > 360, use modulo arithmetic to keep angles in the 0-360 range (this handles negative angles too):

# When updating yaw (e.g., left/right arrow keys)
target.yaw = target.yaw % 360

Step 2: Constrain Pitch to Avoid Flip

Players shouldn't be able to look straight up/down beyond 90° (it causes perspective flip). Add limits when updating pitch:

# When updating pitch (e.g., up/down arrow keys)
target.pitch += 2  # Adjust speed as needed
if target.pitch > 90:
    target.pitch = 90
elif target.pitch < -90:
    target.pitch = -90

Step 3: Validate Movement Direction

Make sure WASD movement follows the player's yaw (facing direction), not world coordinates. For example:

# Example W (forward) movement
move_speed = 0.1
yaw_rad = math.radians(target.yaw)
target.x += math.cos(yaw_rad) * move_speed
target.z -= math.sin(yaw_rad) * move_speed  # Adjust sign based on your coordinate system

# Example A (left) movement
target.x -= math.sin(yaw_rad) * move_speed
target.z -= math.cos(yaw_rad) * move_speed

Test this by printing your player's x/z coordinates when moving—you should see movement align with your facing direction.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.27 09:12:34