- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我正在尝试使用 LibGDX 制作一个复古风格的小游戏,我想让玩家选择几个角色的颜色,所以我想到加载 png 索引图像,然后以编程方式更新调色板。 .. 我错了^^U
调色板似乎已经成为过去,而且获得类似结果的最佳选择似乎是使用着色器。
这是一张解释我现在正在尝试的图片:
我打算使用 2 张图片。其中之一,pixel_guy.png
是一个只有 6 种颜色的 png 图像(这些颜色是它的原始调色板)。另一个图像 colortable.png
是一个 6x6 像素的 png,包含 6 个调色板,每个调色板有 6 种颜色(每行是一个不同的调色板)。 colortable.png
第一行像素的颜色将匹配 pixel_guy.png
中使用的颜色,这将是第一个/原始调色板,其他行将是调色板 2 到 6。我尝试实现的是使用 colortable 的第一个调色板来索引 pixelguy 颜色,然后通过向着色器发送一个数字(从 2 到 6)来更改调色板。
经过一些研究,我发现了一个 post in gamedev stackexchange ,显然这就是我要找的东西,所以我试着测试一下。
我创建了顶点着色器和 fragment 着色器并加载了我的纹理(我想交换其调色板的纹理,以及包含多个调色板的纹理),但输出是一张意想不到的白色图像。
我的顶点着色器:
attribute vec4 a_position;
attribute vec4 a_color;
attribute vec2 a_texCoord0;
uniform mat4 u_projTrans;
varying vec4 v_color;
varying vec2 v_texCoords;
void main() {
v_color = a_color;
v_texCoords = a_texCoord0;
gl_Position = u_projTrans * a_position;
}
我的 fragment 着色器:
// Fragment shader
// Thanks to Zack The Human https://gamedev.stackexchange.com/questions/43294/creating-a-retro-style-palette-swapping-effect-in-opengl/
uniform sampler2D texture; // Texture to which we'll apply our shader? (should its name be u_texture?)
uniform sampler2D colorTable; // Color table with 6x6 pixels (6 palettes of 6 colors each)
uniform float paletteIndex; // Index that tells the shader which palette to use (passed here from Java)
void main()
{
vec2 pos = gl_TexCoord[0].xy;
vec4 color = texture2D(texture, pos);
vec2 index = vec2(color.r + paletteIndex, 0);
vec4 indexedColor = texture2D(colorTable, index);
gl_FragColor = indexedColor;
}
我用来制作纹理绑定(bind)并将调色板编号传递给着色器的代码:
package com.test.shaderstest;
import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.glutils.ShaderProgram;
public class ShadersTestMain extends ApplicationAdapter {
SpriteBatch batch;
Texture imgPixelGuy;
Texture colorTable;
private ShaderProgram shader;
private String shaderVertIndexPalette, shaderFragIndexPalette;
@Override
public void create () {
batch = new SpriteBatch();
imgPixelGuy = new Texture("pixel_guy.png"); // Texture to which we'll apply our shader
colorTable = new Texture("colortable.png"); // Color table with 6x6 pixels (6 palettes of 6 colors each)
shaderVertIndexPalette = Gdx.files.internal("shaders/indexpalette.vert").readString();
shaderFragIndexPalette = Gdx.files.internal("shaders/indexpalette.frag").readString();
ShaderProgram.pedantic = false; // important since we aren't using some uniforms and attributes that SpriteBatch expects
shader = new ShaderProgram(shaderVertIndexPalette, shaderFragIndexPalette);
if(!shader.isCompiled()) {
System.out.println("Problem compiling shader :(");
}
else{
batch.setShader(shader);
System.out.println("Shader applied :)");
}
shader.begin();
shader.setUniformi("colorTable", 1); // Set an uniform called "colorTable" with index 1
shader.setUniformf("paletteIndex", 2.0f); // Set a float uniform called "paletteIndex" with a value 2.0f, to select the 2nd palette
shader.end();
colorTable.bind(1); // We bind the texture colorTable to the uniform with index 1 called "colorTable"
}
@Override
public void render () {
Gdx.gl.glClearColor(0.3f, 0.3f, 0.3f, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
batch.begin();
batch.draw(imgPixelGuy, 0, 0); // Draw the image with the shader applied
batch.end();
}
}
我不知道这是否是将浮点值传递给 fragment 制服的正确方法。也不确定我尝试使用的代码 fragment 是如何工作的。
编辑:我尝试了 TenFour04 建议的更改,它们工作得很好 :)
这是预处理后的 Sprite
我已经用更改更新了存储库,(Java 代码 here, fragment 着色器 here),如果有人感兴趣,可以在这里下载:https://bitbucket.org/hcito/libgdxshadertest
编辑 2: 我刚刚将 TenFour04 建议的最后优化添加到存储库(将调色板索引传递给调用 sprite.setColor() 方法的 R channel 中的每个 Sprite ),以及它再次完美运行:)
最佳答案
我注意到了一些问题。
1) 在 fragment 着色器中,vec2 index = vec2(color.r + paletteIndex, 0);
不应该是 vec2 index = vec2(color.r, paletteIndex);
, Sprite 纹理告诉您哪一行,而 paletteIndex 告诉您要查看颜色表的哪一列?
2) 调色板索引被用作纹理坐标,因此它需要是一个介于 0 和 1 之间的数字。像这样设置它:
int currentPalette = 2; //A number from 0 to (colorTable.getHeight() - 1)
float paletteIndex = (currentPalette + 0.5f) / colorTable.getHeight();
//The +0.5 is so you are sampling from the center of each texel in the texture
3) 对 shader.end
的调用发生在 batch.end
中,因此您需要在每一帧上设置制服,而不是在 create
中>。在每一帧也绑定(bind)你的次级纹理可能是个好主意,以防你以后做任何多纹理。
@Override
public void render () {
Gdx.gl.glClearColor(0.3f, 0.3f, 0.3f, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
colorTable.bind(1);
//Must return active texture unit to default of 0 before batch.end
//because SpriteBatch does not automatically do this. It will bind the
//sprite's texture to whatever the current active unit is, and assumes
//the active unit is 0
Gdx.gl.glActiveTexture(GL20.GL_TEXTURE0);
batch.begin(); //shader.begin is called internally by this line
shader.setUniformi("colorTable", 1);
shader.setUniformf("paletteIndex", paletteIndex);
batch.draw(imgPixelGuy, 0, 0);
batch.end(); //shader.end is called internally by this line
}
4) GPU 可能无论如何都会为你做这件事,但由于你没有使用顶点颜色,你可以从你的顶点着色器中删除涉及 v_color
的两行。
5) 您可能还希望透明像素保持透明。所以我会更改 fragment 着色器的最后一行以保留 alpha:
gl_FragColor = vec4(indexedColor.rgb, color.a);
6) 这可能是您变白的原因。在您的 fragment 着色器中,您应该使用 v_texCoords
而不是 gl_TexCoord[0].xy
,后者来自桌面 OpenGL 而未在 OpenGL ES 中使用。所以你的 fragment 着色器应该是:
uniform sampler2D texture; // Texture to which we'll apply our shader? (should its name be u_texture?)
uniform sampler2D colorTable; // Color table with 6x6 pixels (6 palettes of 6 colors each)
uniform float paletteIndex; // Index that tells the shader which palette to use (passed here from Java)
varying vec2 v_texCoords;
void main()
{
vec4 color = texture2D(texture, v_texCoords);
vec2 index = vec2(color.r, paletteIndex);
vec4 indexedColor = texture2D(colorTable, index);
gl_FragColor = vec4(indexedColor.rgb, color.a); // This way we'll preserve alpha
}
7) 您的源 Sprite 需要进行预处理以映射到您的调色板查找表的列。您的着色器正在从纹理的红色 channel 中拉取坐标。因此,您需要对源图像中的每个像素颜色进行颜色替换。您可以提前手动完成此操作。这是一个例子:
肤色是六列 (0-5) 中的索引 2。所以就像我们计算 paletteIndex 一样,我们将它归一化到像素中心:skinToneValue = (2+0.5)/6 = 0.417
。 6 代表六列。然后在您的绘图程序中,您需要适当的红色值。
0.417 * 255 = 106
,十六进制为 6A,因此您需要颜色 #6A0000。用这种颜色替换所有皮肤像素。其他色调依此类推。
编辑:
另一个优化是您可能希望能够将所有 Sprite 一起批处理。按照现在的方式,您必须分别为每个调色板对所有 Sprite 进行分组,并为每个 Sprite 调用 batch.end
。您可以通过将 paletteIndex
放入每个 Sprite 的顶点颜色中来避免这种情况,因为无论如何我们都没有使用顶点颜色。
因此您可以将其设置为 Sprite 四个颜色 channel 中的任何一个,比方说 R channel 。如果使用 Sprite 类,可以调用 sprite.setColor(paletteIndex, 0,0,0);
否则调用 batch.setColor(paletteIndex,0,0,0);
在为每个 Sprite 调用 batch.draw
之前。
顶点着色器需要声明 varying float paletteIndex;
并像这样设置它:
paletteIndex = a_color.r;
fragment 着色器需要声明 varying float paletteIndex;
而不是 uniform float paletteIndex;
。
当然,您不应再调用 shader.setUniformf("paletteIndex", paletteIndex);
。
关于android - 使用 OpenGL 着色器模拟调色板交换(在 LibGDX 中),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26132160/
我之前让 dll 注入(inject)器变得简单,但我有 Windows 7,我用 C# 和 C++ 做了它,它工作得很好!但是现在当我在 Windows 8 中尝试相同的代码时,它似乎没有以正确的方
我正在尝试制作一个名为 core-splitter 的元素,该元素在 1.0 中已弃用,因为它在我们的项目中起着关键作用。 如果您不知道 core-splitter 的作用,我可以提供一个简短的描述。
我有几个不同的蜘蛛,想一次运行所有它们。基于 this和 this ,我可以在同一个进程中运行多个蜘蛛。但是,我不知道如何设计一个信号系统来在所有蜘蛛都完成后停止 react 器。 我试过了: cra
有没有办法在达到特定条件时停止扭曲 react 器。例如,如果一个变量被设置为某个值,那么 react 器应该停止吗? 最佳答案 理想情况下,您不会将变量设置为一个值并停止 react 器,而是调用
https://code.angularjs.org/1.0.0rc9/angular-1.0.0rc9.js 上面的链接定义了外部js文件,我不知道Angular-1.0.0rc9.js的注入(in
我正在尝试运行一个函数并将服务注入(inject)其中。我认为这可以使用 $injector 轻松完成.所以我尝试了以下(简化示例): angular.injector().invoke( [ "$q
在 google Guice 中,我可以使用函数 createInjector 创建基于多个模块的注入(inject)器。 因为我使用 GWT.create 在 GoogleGin 中实例化注入(in
我在 ASP.NET Core 1.1 解决方案中使用配置绑定(bind)。基本上,我在“ConfigureServices Startup”部分中有一些用于绑定(bind)的简单代码,如下所示: s
我在 Spring MVC 中设置 initBinder 时遇到一些问题。我有一个 ModelAttribute,它有一个有时会显示的字段。 public class Model { privat
我正在尝试通过jquery post发布knockoutjs View 模型 var $form = $('#barcodeTemplate form'); var data = ko.toJS(vm
如何为包含多态对象集合的复杂模型编写自定义模型绑定(bind)程序? 我有下一个模型结构: public class CustomAttributeValueViewModel { publi
您好,我正在尝试实现我在 this article 中找到的扩展方法对于简单的注入(inject)器,因为它不支持开箱即用的特定构造函数的注册。 根据这篇文章,我需要用一个假的委托(delegate)
你好,我想自动注册我的依赖项。 我现在拥有的是: public interface IRepository where T : class public interface IFolderReposi
我正在使用 Jasmine 测试一些 Angular.js 代码。为此,我需要一个 Angular 注入(inject)器: var injector = angular.injector(['ng'
我正在使用 Matlab 代码生成器。不可能包含代码风格指南。这就是为什么我正在寻找一个工具来“ reshape ”、重命名和重新格式化生成的代码,根据我的: 功能横幅约定 文件横幅约定 命名约定 等
这个问题在这里已经有了答案: Where and why do I have to put the "template" and "typename" keywords? (8 个答案) 关闭 8
我开发了一种工具,可以更改某些程序的外观。为此,我需要在某些进程中注入(inject)一个 dll。 现在我基本上使用这个 approach .问题通常是人们无法注入(inject) dll,因为他们
我想使用 swing、spring 和 hibernate 编写一个 java 应用程序。 我想使用数据绑定(bind)器用 bean 的值填充 gui,并且我还希望它反射(reflect) gui
我有这段代码,当两个蜘蛛完成后,程序仍在运行。 #!C:\Python27\python.exe from twisted.internet import reactor from scrapy.cr
要点是 Spring Batch (v2) 测试框架具有带有 @Autowired 注释的 JobLauncherTestUtils.setJob。我们的测试套件有多个 Job 类提供者。因为这个类不
我是一名优秀的程序员,十分优秀!