我正在使用Graphics类在Java中使用3D渲染器,它现在能够绘制任何带有彩色面的形状,但是我想知道是否可以对面部进行纹理化?我见过很多人在Javascript中创建软件渲染器,所以肯定有一个等效的函数/方法,但他们在Java中这样做... 到目前为止我已经环顾四周但是我能找到的只是Graphics.setClip(Shape),我觉得它不合适,因为它只是设置背景纹理,如果顶点移动也不会拉伸纹理 - 这只是在2D中,它需要在与相机成一定角度时拉伸/倾斜纹理(想想旋转立方体的两侧)。
我真的不知道从哪里开始,我不能使用XOR模式,因为没有歪斜,如果我不得不手动操作,我真的不知道怎么做数学。
这些Javascript软件渲染器如何做得这么好?
答案 0 :(得分:7)
您可以利用java.awt.TexturePaint
,图示为here和here。在这种情况下,您应该知道TexturePaint
与渲染表面的栅格对齐,而不是与形状的边界对齐。
附录:虽然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);
}
}