我已经制作了一个允许阴影的照明引擎。它适用于网格系统,其中每个像素都有一个以整数形式存储在数组中的光照值。这是其外观的演示:
java - 不完整的光圈-LMLPHP

阴影和实际像素着色效果很好。唯一的问题是未照亮的像素在圆圈中更远,由于某种原因,这会形成非常有趣的图案(您可能需要放大图像才能看到它)。这是吸引人的代码。

public void implementLighting(){
    lightLevels = new int[Game.WIDTH*Game.HEIGHT];
    //Resets the light level map to replace it with the new lighting
    for(LightSource lightSource : lights) {
        //Iterates through all light sources in the world
        double circumference =  (Math.PI * lightSource.getRadius() * 2),
                segmentToDegrees = 360 / circumference, distanceToLighting = lightSource.getLightLevel() / lightSource.getRadius();
                //Degrades in brightness further out
        for (double i = 0; i < circumference; i++) {
            //Draws a ray to every outer pixel of the light source's reach
            double radians =  Math.toRadians(i*segmentToDegrees),
                    sine =  Math.sin(radians),
                    cosine =  Math.cos(radians),
                    x = lightSource.getVector().getScrX() + cosine,
                    y = lightSource.getVector().getScrY() + sine,
                    nextLit = 0;
            for (double j = 0; j < lightSource.getRadius(); j++) {
                int lighting = (int)(distanceToLighting * (lightSource.getRadius() - j));
                        double pixelHeight = super.getPixelHeight((int) x, (int)y);
                if((int)j==(int)nextLit) addLighting((int)x, (int)y, lighting);
                //If light is projected to have hit the pixel
                if(pixelHeight > 0) {
                    double slope = (lightSource.getEmittingHeight() - pixelHeight) / (0 - j);
                    nextLit = (-lightSource.getRadius()) / slope;
                    /*If something is blocking it
                    * Using heightmap and emitting height, project where next lit pixel will be
                     */
                }
                else nextLit++;
                //Advances the light by one pixel if nothing is blocking it
                x += cosine;
                y += sine;
            }
        }
    }
    lights = new ArrayList<>();
}


我正在使用的算法应考虑光源半径内未被物体遮挡的每个像素,因此我不确定为什么缺少一些外部像素。
谢谢。

编辑:我发现的是,光源半径内未照明的像素实际上比其他像素更暗。这是addLighting方法的结果,它不仅更改了像素的照明,而且将其添加到已经存在的值中。这意味着“未点亮”是仅被添加一次的那些。
    为了检验该假设,我制作了一个程序,该程序以与生成照明相同的方式绘制一个圆。这是绘制圆圈的代码:

    BufferedImage image = new BufferedImage(WIDTH, HEIGHT,
    BufferedImage.TYPE_INT_RGB);
    Graphics g = image.getGraphics();
    g.setColor(Color.white);
    g.fillRect(0, 0, WIDTH, HEIGHT);
    double radius = 100,
            x = (WIDTH-radius)/2,
            y = (HEIGHT-radius)/2,
            circumference = Math.PI*2*radius,
            segmentToRadians = (360*Math.PI)/(circumference*180);
    for(double i = 0; i < circumference; i++){
        double radians = segmentToRadians*i,
                cosine = Math.cos(radians),
                sine = Math.sin(radians),
                xPos = x + cosine,
                yPos = y + sine;
        for (int j = 0; j < radius; j++) {
            if(xPos >= 0 && xPos < WIDTH && yPos >= 0 && yPos < HEIGHT) {
                int rgb = image.getRGB((int) Math.round(xPos), (int) Math.round(yPos));
                if (rgb == Color.white.getRGB()) image.setRGB((int) Math.round(xPos), (int) Math.round(yPos), 0);
                else image.setRGB((int) Math.round(xPos), (int) Math.round(yPos), Color.red.getRGB());
            }
            xPos += cosine;
            yPos += sine;
        }
    }


结果如下:
java - 不完整的光圈-LMLPHP

白色像素是未着色的像素
黑色像素是彩色一次的像素
红色像素是2次或更多次上色的像素

所以它实际上比我最初提出的还要糟糕。它是未点亮的像素和多次点亮的像素的组合。

最佳答案

您应该遍历真实图像像素,而不是极点栅格点。

因此正确的像素遍历代码可能看起来像

for(int x = 0; x < WIDTH; ++x) {
  for(int y = 0; y < HEIGHT; ++y) {
    double distance = Math.hypot(x - xCenter, y - yCenter);
    if(distance <= radius) {
      image.setRGB(x, y, YOUR_CODE_HERE);
    }
  }
}


当然,可以选择良好的填充多边形而不是矩形来优化此代码段。

关于java - 不完整的光圈,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/44249056/

10-10 11:51