- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
(注意:在此问题的末尾提供了一个最小,完整和可验证的示例)
摘要
背景,目标与问题
我对作者的解释和出处的理解(可能是错误的?)-请注意:我必须向您解释,因为我的错误可能来自对执行方法的错误理解或代表我的错误实现。
我做了什么
预期结果,实际结果和问题
最小,完整和可验证的示例
背景,目标与问题
我根据http://fabiensanglard.net/doom_fire_psx/研究了著名的DOOM游戏的动画,其中包括生火。
作者代码的完整版本为:https://github.com/fabiensanglard/DoomFirePSX/blob/master/flames.html
我以这个实现结束了,但是我得到的结果是噪声的动画(这就是问题所在)。确实,在此动画的结尾,我得到了以下结果:
我对作者的解释和出处的理解(可能是错误的?)
第一种方法:实施主要原理,并简化火灾(因为已替换为简单的颜色渐变)
设置精确填充的颜色集:此颜色集定义了看起来像火的渐变。从白色到黑色共有36种颜色,其中有黄色,橙色和红色。此集不包含任何重复项。
第一次在画布像素上进行迭代。此处的目标是将所有像素着色为黑色(即:该组的最后一种颜色)。
在画布上第二次迭代。这次,我们必须将底部第一行像素的像素涂成白色(即:该组的第一色)。
再次在画布上进行迭代,但仅从第二个底线(包括)进行迭代,而不是从第一个底线(因此将其排除在外)。对于每个迭代像素,我们以这种方式修改其颜色:我们采用其直接下方像素的颜色,我们在所有颜色中找到该颜色的索引,然后向该索引加1:我们获得另一个索引,称为i2,找到索引为i2的颜色,然后将此颜色应用于此迭代像素。
执行完成后,将有多个渐变,每个渐变包含36行(36种颜色)。
使它看起来真的像火。
当然,由http://fabiensanglard.net/doom_fire_psx/解释的程序还远远不止于此:它使用伪随机两次,得到的东西看起来不像是简单的渐变,但看起来像是火。
这个想法如下。对于要迭代的像素:
我们得到位于下方的像素的颜色索引。然后,我们在颜色集中获得该颜色,其索引是该索引+一个随机数,其中包含一个轻微的偏移(如果我没有记错的话,最大为2个正方形)。因此,我们可以模拟颗粒温度变化的加速度。
并且,此外,我们认为位于要迭代的像素左侧一点的像素。 “一点” =根据芯片号1的相同随机数。正是该像素位于左侧一点,将分配在芯片N°1中恢复的颜色。因此,我们可以模拟火焰左侧的水平位移。
因此,我们看到这是一个三角形的工作(因为我们将像素进行迭代,一个像素在下面,另一个像素在左边)。
伪随机模型用于模拟粒子温度变化加速度
生成一个随机数,其中包含0到3之间的一个随机数,并在此处使用:firePixels[src - FIRE_WIDTH ] = pixel - (rand & 1);
因此,要施加的颜色略有变化。
伪随机模型用于模拟火焰左侧的水平位移。
除了我们刚刚看到的以外,还使用了每行像素的伪随机数。
在此重复使用相同的随机数:var dst = src - rand + 1;
firePixels[dst - FIRE_WIDTH ] = pixel - (rand & 1);
在此,水平方向略微移位。
我做了什么
以上所有说明均已实现,但是我的程序输出了不好的结果。所以:
我不是很了解这个想法,
否则我执行得不好。
您可以在下面找到实现的源。
预期结果,实际结果和问题
我希望有几个垂直渐变(每个从下到上)。 “多个”是因为画布的高度大于渐变颜色的数量,并且因为我使用模数来选择要应用的颜色。这些渐变必须类似于诅咒(http://fabiensanglard.net/doom_fire_psx/)的渐变。
实际结果是:我得到了一些声音。
我的问题是:为什么不起作用?我想我该怎么做。也许我忘记了实施中的某些内容,但是呢?
我的问题是:为什么不起作用?我想我该怎么做。也许我忘记了实施中的某些内容,但是呢?
最小,完整和可验证的示例
Launcher.java
import java.util.ArrayList;
public class Launcher {
public static void main(String args[]) {
int width = 800, height = 800;
Gui gui = new Gui(width, height);
gui.setUp("DOOM-like fire");
gui.setVisible(true);
Colors colors = new FireColors(new ArrayList<>());
gui.colorize(colors.getLastColor(), -1, -1); // Setting black anywhere
gui.colorize(colors.getColorAtIndex(0), -1, height - 1); // Setting white, in a lower line
new ThreadPainter(0, colors, gui, width, height).schedulePainting();
}
}
import java.awt.*;
import javax.swing.*;
import java.awt.image.BufferedImage;
class Gui extends JFrame {
private JPanel panel;
private BufferedImage buffered_image;
Gui(int width, int height) {
buffered_image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
panel = new JPanel() {
public void paintComponent(Graphics graphics) {
super.paintComponent(graphics);
graphics.drawImage(buffered_image, 0, 0, null);
}
};
}
void setUp(String title) {
setTitle(title);
setLayout(null);
setSize(buffered_image.getWidth(), buffered_image.getHeight());
setContentPane(panel);
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
}
void colorize(Color color, int x_parameter, int y_parameter) {
for(int y = (y_parameter == -1 ? 0 : y_parameter); y <= (y_parameter == -1 ? this.getHeight() - 1 : y_parameter); y++) {
for(int x = (x_parameter == -1 ? 0 : x_parameter); x <= (x_parameter== -1 ? this.getWidth() - 1 : x_parameter); x++) {
buffered_image.setRGB(x, y, color.getRGB());
}
}
panel.repaint();
}
int getRGBAtCoordinates(int x, int y) {
return buffered_image.getRGB(x, y);
}
}
import java.util.Timer;
import java.util.TimerTask;
class ThreadPainter extends Timer {
private Gui gui;
private Colors colors;
private int delay;
private int height;
private int width;
ThreadPainter(int delay, Colors colors, Gui gui, int width, int height) {
this.colors = colors;
this.gui = gui;
this.delay = delay;
this.width = width;
this.height = height;
}
void schedulePainting() {
this.schedule(new TimerTask() {
@Override
public void run() {
try {
int number_of_colored_portions = height / colors.getSize();
// int locking_changement_of_color = 0;
for(int y = height - 2; y >= 0; y--) {
//if(locking_changement_of_color == number_of_colored_portions) {
//locking_changement_of_color = 0;
/*} else {
index_of_color_to_apply = index_of_found_color;
}*/
for(int x = 0; x < width; x++) {
int rand = (int) Math.round(Math.random() * 3.0) & 3;
int below_pixel_rgb = gui.getRGBAtCoordinates(x, y + 1);
int index_of_found_color = colors.getIndexOfColor(below_pixel_rgb);
int index_of_color_to_apply = (index_of_found_color + (rand & 1)) % colors.getSize();
int x_copy = x - rand + 1;
if(x_copy <= 0) {
x_copy = 0;
} else if(x_copy >= width) {
x_copy = width - 1;
}
gui.colorize(colors.getColorAtIndex(index_of_color_to_apply), x_copy, y);
}
//locking_changement_of_color++;
//Thread.sleep(10);
}
} catch(Exception e) {
System.err.println("Exception: " + e.getMessage());
}
}
}, this.delay);
}
}
import java.awt.Color;
import java.util.List;
abstract class Colors {
List<Color> colors;
Color getColorAtIndex(int index) {
return colors.get(index);
}
int getIndexOfColor(int rgb) throws Exception {
for (int x = 0; x < colors.size(); x++) {
if(colors.get(x).getRGB() == rgb) {
return x;
}
}
throw new Exception("Color not found in the list!");
}
int getSize() {
return colors.size();
}
Color getLastColor() {
return colors.get(colors.size() - 1);
}
}
import java.awt.Color;
import java.util.List;
class FireColors extends Colors {
FireColors(List<Color> colors) {
this.colors = colors;
this.colors.add(new Color(255, 255, 255));
this.colors.add(new Color(239, 239, 199));
this.colors.add(new Color(223, 223, 159));
this.colors.add(new Color(207, 207, 111));
this.colors.add(new Color(183, 183, 55));
this.colors.add(new Color(183, 183, 47));
this.colors.add(new Color(183, 175, 47));
this.colors.add(new Color(191, 175, 47));
this.colors.add(new Color(191, 167, 39));
this.colors.add(new Color(191, 167, 39));
this.colors.add(new Color(191, 159, 31));
this.colors.add(new Color(191, 159, 31));
this.colors.add(new Color(199, 151, 31));
this.colors.add(new Color(199, 143, 23));
this.colors.add(new Color(199, 135, 23));
this.colors.add(new Color(207, 135, 23));
this.colors.add(new Color(207, 127, 15));
this.colors.add(new Color(207, 119, 15));
this.colors.add(new Color(207, 111, 15));
this.colors.add(new Color(215, 103, 15));
this.colors.add(new Color(215, 95, 7));
this.colors.add(new Color(223, 87, 7));
this.colors.add(new Color(223, 87, 7));
this.colors.add(new Color(223, 79, 7));
this.colors.add(new Color(199, 71, 7));
this.colors.add(new Color(191, 71, 7));
this.colors.add(new Color(175, 63, 7));
this.colors.add(new Color(159, 47, 7));
this.colors.add(new Color(143, 39, 7));
this.colors.add(new Color(119, 31, 7));
this.colors.add(new Color(103, 31, 7));
this.colors.add(new Color(87, 23, 7));
this.colors.add(new Color(71, 15, 7));
this.colors.add(new Color(47, 15, 7));
this.colors.add(new Color(7, 7, 7));
}
}
最佳答案
有很多小问题,因此这里是带注释的固定版本,供您理解(为了简化起见,我将类组合到一个文件中):
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.WindowConstants;
public class Launcher {
private static class Gui extends JFrame {
final int width;
final int height;
final JPanel panel;
final BufferedImage buffered_image;
Gui(final String title, final int width, final int height) {
this.width = width;
this.height = height;
this.buffered_image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
this.panel = new JPanel() {
@Override
public void paintComponent(final Graphics graphics) {
super.paintComponent(graphics);
graphics.drawImage(Gui.this.buffered_image, 0, 0, null);
}
};
this.setTitle(title);
this.setContentPane(this.panel);
this.setSize(width, height);
this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
this.setVisible(true);
}
void colorize(final Color color, final int x, final int y) {
if ((x < 0) || (x >= this.width) || (y < 0) || (y >= this.height))
return;
this.buffered_image.setRGB(x, y, color.getRGB());
}
int getRGBAtCoordinates(final int x, final int y) {
return this.buffered_image.getRGB(x, y);
}
}
public static void main(final String args[]) {
final List<Color> colors = new ArrayList<>();
colors.add(new Color(0, 0, 0)); // black
colors.add(new Color(7, 7, 7));
colors.add(new Color(47, 15, 7));
colors.add(new Color(71, 15, 7));
colors.add(new Color(87, 23, 7));
colors.add(new Color(103, 31, 7));
colors.add(new Color(119, 31, 7));
colors.add(new Color(143, 39, 7));
colors.add(new Color(159, 47, 7));
colors.add(new Color(175, 63, 7));
colors.add(new Color(191, 71, 7));
colors.add(new Color(199, 71, 7));
colors.add(new Color(223, 79, 7));
colors.add(new Color(223, 87, 7));
colors.add(new Color(223, 87, 7));
colors.add(new Color(215, 95, 7));
colors.add(new Color(215, 103, 15));
colors.add(new Color(207, 111, 15));
colors.add(new Color(207, 119, 15));
colors.add(new Color(207, 127, 15));
colors.add(new Color(207, 135, 23));
colors.add(new Color(199, 135, 23));
colors.add(new Color(199, 143, 23));
colors.add(new Color(199, 151, 31));
colors.add(new Color(191, 159, 31));
colors.add(new Color(191, 159, 31));
colors.add(new Color(191, 167, 39));
colors.add(new Color(191, 167, 39));
colors.add(new Color(191, 175, 47));
colors.add(new Color(183, 175, 47));
colors.add(new Color(183, 183, 47));
colors.add(new Color(183, 183, 55));
colors.add(new Color(207, 207, 111));
colors.add(new Color(223, 223, 159));
colors.add(new Color(239, 239, 199));
colors.add(new Color(255, 255, 255)); // white
final Gui gui = new Gui("DOOM-like fire", 800, 800);
final Color black = colors.get(0);
final Color white = colors.get(colors.size() - 1);
final Dimension dim = gui.getContentPane().getSize(); // get actual size, without title/borders
for (int y = 0; y < dim.height; y++) {
final Color clr = y < (dim.height - 1) ? black : white;
for (int x = 0; x < dim.width; x++)
gui.colorize(clr, x, y);
}
new Timer().schedule(new TimerTask() {
final Random rnd = new Random();
Color getColorAtIndex(final int index) {
if (index < 0)
return colors.get(0); // minimal color is black
return colors.get(index);
}
int getIndexOfColor(final int rgb) {
for (int x = 0; x < colors.size(); x++)
if (colors.get(x).getRGB() == rgb)
return x;
throw new RuntimeException("Color not found in the list!");
}
@Override
public void run() {
for (int x = 0; x < dim.width; x++) {
for (int y = 1; y < dim.height; y++) {
final int new_index = this.getIndexOfColor(gui.getRGBAtCoordinates(x, y)) - this.rnd.nextInt(2);
final int new_x = (x - this.rnd.nextInt(3)) + 1;
gui.colorize(this.getColorAtIndex(new_index), new_x, y - 1);
}
}
gui.repaint();
}
}, 0, 40); // start immediately and repeat every 40ms
}
}
关于java - “HOW DOOM FIRE WAS DONE” –重新实现会产生噪音动画的火灾动画,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54010139/
我今天尝试使用噪声在处理中生成伪随机角度,但它没有像我希望的那样工作。 float xoff = 0; float inc = 0.01; void draw(){ float vx = cos(
我正在使用 OpenCV 和 Python 处理图像。我需要去除图像中的点/噪声。 我尝试了使点变小的膨胀,但是文本被损坏了。我还尝试了两次循环扩张和一次腐 eclipse 。但这并没有给出令人满意的
我需要使用我编写的 perlin 噪声程序在 Java 中生成 3D 行星(球体)的纹理。但问题是左侧和右侧需要相同,上下也必须相同,这样您才能将纹理放在球体上。 我无法将柏林噪声源放在这里,因为它太
我想构建一个 android 应用程序,它可以识别我的声音,将其转换为文本,并显示我刚刚说的 toast 。我可以通过使用一个按钮来为我启动语音识别器来做到这一点。但现在我想让它只根据我的声音工作。
嗨,我正在使用我发现的算法来生成柏林噪声。我想做的是用更少的曲线创建更锐利的边缘Picture 。 private static final double F2 = 0.5*(Math.sqr
我正在尝试用 C++ 编写一个程序来播放一个小的 .wav 文件。我已经按照 DirectX SDK 文档对其进行了编程,以在辅助静态缓冲区上编写和播放。它运行正常,除了在任何 .wav 文件播放结束
在这个 short video 中听我的问题. 现在我更详细地解释: 在那个视频中,我已经播放了(点击按钮)一个音频文件三次,连续两次,最后一次有一点停顿。第一次听起来像 radio 正在调谐,第二次
所以在过去的几个小时里,我一直在尝试用 Dart 制作一个简单的 Perlin 噪声发生器。为此,我决定在 this page 上使用二维生成的伪代码。 (很棒的阅读!) 这是我的 Dart 实现的样
我正在为 android 开发一个 OCR 应用程序(构建为 java 应用程序)。我想从相机捕获的图像中检测文本并进行预处理我正在使用 OpenCV,但我得到了一些额外的行,这些行被读取为文本,我采
我正在使用 Ruby on Rails 3.1.1 和 pg gem。 在我的 Gemfile.lock 中,这是我拥有的 pg (0.11.0) 我的日志中充满了如下所示的信息。我没有用 sqlit
我在 javascript 中创建了一个带有实时对话模块的应用程序。我正在使用 WebRTC 设置对等连接。信号和候选人似乎都工作正常。对等点不在同一个网络上。 在某些时候,音频开始向流中添加点击。质
我在基于 android 的 csipsimple 应用程序中使用了一个 PJSIP 库。除一个问题外,一切正常。当我打开扬声器时,通话中有很多回声/噪音,无法进行通话。可能是什么问题以及如何处理这个
当您按下 alt+几乎任何其他键时,它会发出 clang 。噪音说“你已经尝试做一些你做不到的事情” 我想在多个组合中使用 alt 键作为网络应用程序的键盘快捷键。 尽管在按下 alt+* 时有一些事
我的目标是创建一个 SDL 窗口,绘制不同的波形并播放该波的不确定声音。通过按下特定的键,可以修改波的幅度、频率或波形等参数。 问题在于,即使是绘制时看起来不错的简单正弦波,听起来也很嘈杂。我不明白为
我收到大量这样的消息,围绕着我故意不支持的 SSL 协议(protocol),例如SSLv3、TLS1.0 等 2020-02-06 13:08:30,600 ERROR [io.undertow.r
我有错误s的情况通常是从 3rd-party JS 发出的,例如 Chartbeat 等。我想捕获并丢弃/静音这些错误以及相关的噪音。 所有此类 3rd 方脚本都会执行以下操作: 创建 DOM 标签
我对新 ffmpeg 中的重采样结果感到困惑。我将 AAC 音频解码为 PCM,ffmpeg 显示音频信息为: Stream #0:0: Audio: aac, 44100 Hz, stereo, f
我是一名优秀的程序员,十分优秀!