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

修复Java 3D图形引擎中的透视正确纹理映射问题

修复3D图形引擎的透视纹理映射深度问题

我多年前用Java编写了一款3D图形引擎,它具备纹理映射功能,但未考虑深度因素,导致纹理映射效果不正确(例如地面的表现存在明显错误)。

我认为问题的修复点应该在TexturedPolygon3dRenderer类中,代码如下:

package rcs.feyn.three.render.renderers;

import java.util.Optional;

import rcs.feyn.color.ColorUtils;
import rcs.feyn.math.MathUtils;
import rcs.feyn.math.Vector2d;
import rcs.feyn.math.Vector3d;
import rcs.feyn.three.gfx.Graphics3d;
import rcs.feyn.three.gfx.TextureRaster;

public class TexturedPolygon3dRenderer {

  public static void render(
      Graphics3d graphics,
      Vector3d[] deviceCoordinates,
      double intensity,
      Optional<int[]> colors,
      TextureRaster textureData,
      Vector2d[] textureCoordinates,
      int alpha) {

    if (deviceCoordinates.length != 3) {
      throw new IllegalArgumentException("Can only render triangles");
    }

    Vector3d va = deviceCoordinates[0];
    Vector3d vb = deviceCoordinates[1];
    Vector3d vc = deviceCoordinates[2];

    double xa = va.x();
    double xb = vb.x();
    double xc = vc.x();
    double xd = (xa+xb+xc)/3;

    double ya = va.y();
    double yb = vb.y();
    double yc = vc.y();
    double yd = (ya+yb+yc)/3;

    double za = va.z();
    double zb = vb.z();
    double zc = vc.z();
    double zd = (za+zb+zc)/3;

    double u1 = xb - xa;
    double v1 = xc - xa;
    double u2 = yb - ya;
    double v2 = yc - ya;
    double u3 = zb - za;
    double v3 = zc - za;

    double aa = u2*v3 - u3*v2;
    double bb = u3*v1 - u1*v3;
    double cc = u1*v2 - u2*v1;

    double dInvZdx = -aa/cc;
    double dZdy = -bb/cc;

    int screenW = graphics.getRaster().getWidth();
    int screenH = graphics.getRaster().getHeight();

    int ymin = MathUtils.roundToInt(MathUtils.max(MathUtils.min(ya, yb, yc), 0));
    int ymax = MathUtils.roundToInt(MathUtils.min(MathUtils.max(ya, yb, yc), screenH));

    boolean interpolateColor = colors.isPresent();

    int tdw = textureData.getWidth();
    int tdh = textureData.getHeight();

    for (int y = ymin; y <= ymax; y++) {
      double ximin = Integer.MIN_VALUE;
      double xjmin = Integer.MIN_VALUE;
      double xkmin = Integer.MIN_VALUE;
      double ximax = Integer.MAX_VALUE;
      double xjmax = Integer.MAX_VALUE;
      double xkmax = Integer.MAX_VALUE;

      if ((y - yb) * (y - yc) <= 0 && yb != yc) {
        ximax = xc + (y - yc)/(yb - yc) * (xb - xc);
        ximin = ximax;
      }
      if ((y - yc) * (y - ya) <= 0 && yc != ya) {
        xjmax = xa + (y - ya)/(yc - ya) * (xc - xa);
        xjmin = xjmax;
      }
      if ((y - ya) * (y - yb) <= 0 && ya != yb) {
        xkmax = xb + (y - yb)/(ya - yb) * (xa - xb);
        xkmin = xkmax;
      }

      int xmin =
          MathUtils.roundToInt(MathUtils.max(MathUtils.min(ximax, xjmax, xkmax), 0));
      int xmax =
          MathUtils.roundToInt(MathUtils.min(MathUtils.max(ximin, xjmin, xkmin), screenW));

      double invZ = zd + (y - yd) * dZdy + (xmin - xd) * dInvZdx;

      for (int x = xmin; x < xmax; x++, invZ += dInvZdx) {
        Vector3d bary = RenderUtils.cartesianToBarycentric(x, y, va, vb, vc);

        Vector2d interpolatedTextureCoordinate = RenderUtils.barycentricToCartesian(
            bary, textureCoordinates[0], textureCoordinates[1], textureCoordinates[2]);

        double textureX = interpolatedTextureCoordinate.x();
        double textureY = interpolatedTextureCoordinate.y();

        int textureXInt = MathUtils.clamp((int) textureX, 0, tdw - 1);
        int textureYInt = MathUtils.clamp((int) textureY, 0, tdh - 1);

        int pixel = textureData.getPixel(textureXInt, textureYInt);

        int colorWithIntensity = ColorUtils.mulRGB(pixel, intensity);

        if (interpolateColor) {
          int[] colorz = colors.get();

          int interpolatedColor = ColorUtils.addRGBA(
              ColorUtils.mulRGBA(colorz[0], bary.x()),
              ColorUtils.addRGBA(
                  ColorUtils.mulRGBA(colorz[1], bary.y()),
                  ColorUtils.mulRGBA(colorz[2], bary.z())));

          colorWithIntensity = ColorUtils.blendRGB(
              colorWithIntensity,
              interpolatedColor,
              intensity);
        }

        int finalColor = ColorUtils.setAlphaToRGBA(colorWithIntensity, alpha);

        graphics.putPixel(x, y, invZ, finalColor);
      }
    }
  }
}

由于时隔太久,我已经记不清其中的数学细节,希望能得到修复该透视纹理映射问题的方法,如需更多信息可告知。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 17:10:02