【问题标题】:Polygon vertices as UV coordinates多边形顶点作为 UV 坐标
【发布时间】:2014-02-08 02:46:08
【问题描述】:

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

我真的不知道从哪里开始,因为没有倾斜,我不能使用 XOR 模式,如果我必须手动计算,我真的不知道如何计算。
这些 Javascript 软件渲染器是怎么做到的?

【问题讨论】:

    标签: java swing graphics 3d


    【解决方案1】:

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

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

    对于非仿射变换,请参阅javax.media.jai.Warp.Warp,引用here

    【讨论】:

      【解决方案2】:

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

      • 隐藏表面移除。我找不到在 Graphics2d 基元下实现 z 缓冲区的方法。

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

      • 二维剪裁不匹配。纹理的最后一个操作必须是对 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 着色,这就是我发现上面提到的剪切错误的地方。这一切都有效,并且正在运行数十万份,但它又乱又脆弱,我不想再这样做了。

      【讨论】:

      • 对..这如何回答我的问题?你有没有研究过LWJGL?它适用于任何带有 OpenGL 的机器,因为它基本上是 Java 到 OGL 的 C++ 管道补丁。我还找到了一种使用面法线去除隐藏表面的方法,不需要 Z 缓冲区。
      • @LeeAllan Culling with face normals 仅适用于一个凸对象。当物体相互遮挡时,它没有帮助。我见过的 Javascript 渲染器使用 3d 画布对象,该对象在后台使用 OpenGL 或类似对象。如果你举一个没有的例子,我会看看它。 LWJGL 有自己的问题。
      • @LeeAllan 对不起,我应该补充说你是对的:我没有直接回答你的问题。我的目的是让您避免 99% 肯定会浪费时间的事情:我花了同样的 3-4 小时研究得出上述结论。我还在上面添加了关于 Javascript 3d 渲染的注释。
      • 我完全同意 Gene 的观点。尝试重新发明轮子只有在您同时不尝试使轮子变成方形时才有意义...使用 2D 渲染框架来处理 3D 数据/使用实际 3D 视口进行渲染不仅是浪费时间 - 它基本上迫使你:
      • a) 从头开始​​编写软件渲染器(没有意义,因为你应该使用例如 Mesa OpenGL 软件驱动程序),b) 使用渲染器来解析和渲染数据(没有意义,因为你不会获得足够的帧速率或高质量的硬件渲染器或良好的 SR 提供​​),c)使用 2D 框架来显示它,导致进一步的线程/效率问题(也显然毫无意义)。 tl;博士 - 你只是徒劳地浪费你的时间。
      【解决方案3】:

      我假设您只是将 Swing/AWT 框架用于图形。如果这是错误的,请更新您的问题。

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

      所以,您走在正确的轨道上 - 您必须先设置剪辑(使其适合您的形状),然后执行旋转(使其以正确的角度显示)。

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

      我创建了一个在 Y 轴上旋转的快速示例。请注意,我编造了一个愚蠢的算法(Magic Vanishingpoint Technology®)来给出一种模糊的深度错觉。我假设您已经对此有所了解 - 这可能更正确。

      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);
          }
      }
      

      【讨论】:

      • 我确实只是在使用 Swing。该代码非常有趣,并且有可能绘制 3D 图元,但是我觉得有两件事会干扰;为什么旋转超过 180° 看起来/行为与第一个 180° 不同?难道它不能更快​​吗?..否则我认为它无法以超过 5FPS 的速度绘制具有超过..10 个面孔的模型。
      • 除非您开始使用显卡进行处理,否则您将无法获得太多 FPS(因为它将在您的 cpu 上运行)。 OpenGL 实际上利用了您的显卡——这就是它运行速度更快的原因。就旋转/180° 而言,它对我来说似乎在 300 度等角度上工作得很好。你没有得到深度的感觉,因为我的 Magic Vanishingpoint Technology® 并不完全完美,但它确实可以旋转。
      猜你喜欢
      • 1970-01-01
      • 2011-03-27
      • 1970-01-01
      • 2019-12-27
      • 2013-03-11
      • 1970-01-01
      • 1970-01-01
      • 2019-02-14
      相关资源
      最近更新 更多