修复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
相关产品推荐
相关产品推荐

