多边形顶点作为UV坐标

时间:2014-02-08 02:46:08

标签: java swing graphics 3d

我正在使用Graphics类在Java中使用3D渲染器,它现在能够绘制任何带有彩色面的形状,但是我想知道是否可以对面部进行纹理化?我见过很多人在Javascript中创建软件渲染器,所以肯定有一个等效的函数/方法,但他们在Java中这样做... 到目前为止我已经环顾四周但是我能找到的只是Graphics.setClip(Shape),我觉得它不合适,因为它只是设置背景纹理,如果顶点移动也不会拉伸纹理 - 这只是在2D中,它需要在与相机成一定角度时拉伸/倾斜纹理(想想旋转立方体的两侧)。

我真的不知道从哪里开始,我不能使用XOR模式,因为没有歪斜,如果我不得不手动操作,我真的不知道怎么做数学。
这些Javascript软件渲染器如何做得这么好?

3 个答案:

答案 0 :(得分:7)

您可以利用java.awt.TexturePaint,图示为herehere。在这种情况下,您应该知道TexturePaint与渲染表面的栅格对齐,而不是与形状的边界对齐。

image

附录:虽然shading是一个广泛的主题,但也可以考虑使用带有 alpha 的渐变着色的基于像素的方法,如引用的KineticModel here所示。请注意,此类渐变可应用于WritableRaster的{​​{1}}。

对于非仿射变换,请参阅TexturePaint,引用here

答案 1 :(得分:5)

我把这看作是OpenGL功能的“后备”,由于JOGL问题而无法在某些机器上运行。我没有成功。这些是导致我停止工作的未解决的问题:

  • 隐藏表面去除。我找不到在Graphics2d原语下实现z-buffer的方法。

  • 透视纹理变换。如果图像投影是平行的,而不是透视,则Graphics2d中可用的AffineTransform具有足够的力量来映射纹理。

  • 2d剪辑不匹配。纹理化的最后一个操作必须是对2d掩码进行裁剪。事实证明,Graphics2d剪辑中存在一个错误。如果您剪切完全相邻的2d多边形,则剪裁的补丁不能完美匹配。边界处的单个像素没有阴影。

  • 性能。虽然最近版本的Graphics2d管道尝试使用硬件加速,但是原始多边形渲染仍然比JOGL慢了一个数量级,这对我的目的来说还不够好。

我看过的Javascript 3d库都是基于WebGL构建的,而WebGL又是在HTML 5 Canvas对象中实现的。 WebGL是一个必须由浏览器实现的OpenGL API。其他3d Javascript库使用插件来获取硬件加速图形。所以它们不是关于如何在Swing中做3d的有用信息来源。

<强>加成

也许值得添加我所做的事情。为了替换用户可以通过移动相机“飞过”的3D JOGL场景,我选择了一个固定的单一视点并且“硬连线”了绘图顺序,有效地实现了the Painter's Algorithm的固定逻辑来确定排序顺序,渲染或多或少与JOGL视图相同的模型。我使用渐变填充多边形实现了Gouraud着色,这是我发现上面提到的剪辑错误的地方。它一切正常,并且运行成千上万份,但它很混乱,我不想再这样做了。

答案 2 :(得分:2)

我假设您只使用Swing / AWT框架进行图形处理。如果这是错误的,请更新您的问题。

如果您正在使用Swing和Graphics2D类(使用类摆动组件),那么您正在处理2D框架。这只意味着没有内置花哨的3D东西 - 你必须自己实现转换(或者开始抓取3D类来完成你的工作)。

所以,你在正确的轨道上 - 你必须先设置剪辑(所以它适合你的形状),然后进行旋转(所以它以正确的角度出现)。

话虽这么说,做基本的旋转变换并不太困难。 (基本)轮换here有一个很好的轮廓。当然,当您的旋转不仅仅基于一个轴时,它会变得有点复杂。但正如文章后面解释的那样,如果你将矩阵(Rx)(Ry)(Rz)相乘,你可以使用得到的矩阵来确定你的像素位置。

我创建了一个在Y轴上旋转的快速示例。请注意我制作了一个愚蠢的算法( MagicVanishingpointTechnology®)来给出模糊的深度幻觉。我假设你已经有了一些东西 - 它可能更正确。

import java.awt.*;
import java.awt.image.*;
import java.io.*;

import javax.imageio.ImageIO;
import javax.swing.*;

public class Rotation3D extends JPanel{
    Image img;

    BufferedImage rotatedImage;
    final int ROTATION_DEGREES = 70;

    int vanishX = 0;
    int vanishY = 0;
    int vanishZ = -1000;

    public Rotation3D(){

        try {
            //Grabbed an image from the java folder - hopefully your computer has it
            img = ImageIO.read(new File(System.getProperty("java.home") + "/lib/deploy/splash.gif"));
            setPreferredSize(new Dimension(img.getWidth(this) * 2,img.getHeight(this) * 2));

            //Create a buffered image with the appropriate size, and draw the image on it
            BufferedImage shadedImage = new BufferedImage(img.getWidth(this), img.getWidth(this), BufferedImage.TYPE_INT_ARGB);
            shadedImage.getGraphics().drawImage(img, 0, 0, this);
            Raster r = shadedImage.getData();

            //Not really necessary unless you're using Magic Vanishingpoint Technology®
            vanishX = shadedImage.getWidth() /2;
            vanishY = shadedImage.getHeight() /2;

            //Create a Wraster for the transformed image
            WritableRaster wr = r.createCompatibleWritableRaster();

            //Do the transformation
            for(int i = 0; i < shadedImage.getWidth(); i++){
                for(int j = 0; j < shadedImage.getHeight(); j++){
                    //Remapping the pixel based on a matrix rotation
                    int[] result = r.getPixel(i, j, new int[4]);
                    Double radians = Math.toRadians(ROTATION_DEGREES);
                    Double newX, newY, newZ;
                    //newX = ((i-vanishX) * Math.cos(radians)) + vanishX; // places the rotation in the middle of the image
                    // x * cos(θ) + y * 0 + z * sin(θ)
                    newX = i * Math.cos(radians); //places the rotation in the y=0 axis
                    // x * 0 + y * 1 + z * 0
                    newY = j * 1.0;
                    // x * -sin(θ) + y * 0 + z * cos(θ)
                    newZ= i * Math.sin(radians) * -1;

                    //Apply Magic Vanishingpoint Technology®
                    //(Not actually trademarked or correct - just something thrown together)
                    if(newZ < vanishZ){
                        newX = 0.0;
                        newY = 0.0;
                    }else if(newZ < 0){
                        double magicVanish =  newZ / vanishZ;
                        newX += magicVanish * newX;
                        newY += magicVanish * newY;
                    }

                    //Print the pixel if it fits on the screen to the new Raster
                    if(newX > 0 && newX < shadedImage.getWidth() && newY > 0 && newY < shadedImage.getHeight())
                        wr.setPixel(newX.intValue(), newY.intValue(), result);
                }
            }

            //Create an image based on the raster.
            rotatedImage = new BufferedImage(img.getWidth(this), img.getWidth(this), BufferedImage.TYPE_INT_ARGB);
            rotatedImage.setData(wr);

        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    public void paintComponent(Graphics g){
        super.paintComponent(g);
        g.drawImage(rotatedImage, 0, 0, this);
    }

    public static void main(String[] args){
        final JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(new Rotation3D());
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }
}