[C++, *nix] Делаем спрайт разных цветов
Автор
Сообщение
news_bot ®
Стаж: 6 лет 9 месяцев
Сообщений: 27286
Я пробую делать игры. Пишу код, пробую рисовать и хочу научиться делать музыку. Я прорисовал персонажа и мне нужно было сделать так, чтобы ему можно было менять цвет одежды. Решение пришло сначала одно, но потом додумался до более простого.
первое решение до чего я додумался, это сделать у стен разную прозрачность и тогда можно с помощью шейдера задавать прозрачность. В шейдере уже проверяется прозрачность и указывается заданный цвет. Может вам будет это интересно, но я всё таки приведу код класса спрайта и шейдера. Мне нравиться серый цвет и я как то обычно в его оттенках рисую что-то. Вот нарисовал человечка.
как можно заметить вся одежка в оттенках серого цвета. Это оказалось удобным. я выписал числовые коды цветов в отдельный файл.
human colors
-------------------------------------------
body front #6a6a6a 0.41 0.41 0.41
body up #959595 0.58 0.58 0.58
arm #a6a6a6 0.65 0.65 0.65
arm blick #c1c1c1 0.75 0.75 0.75
arm blacked #8a8a8a 0.23
body down #5b5b5b 0.35 0.35 0.35
left legs blacked #4c4c4c 0.29 0.29 0.29
left legs blick #5c5c5c 0.36 0.36 0.36
right legs blacked #656565 0.39 0.39 0.39
right legs blick #808080 0.50 0.50 0.50
вот код конструктора.
Sprite::Sprite (int x, int y, int z, const char *path) {
this->visibility = true;
this->isAnimate = false;
this->animator = new Animator ();
this->check = 0;
this->commonData = nullptr;
this->frame = nullptr;
this->trigger_shadow = 0;
this->z = glm::vec2 ((float) z, 1.0f);
GameObject::ortho = glm::ortho (0.0f, 1.0f, 1.0f, 0.0f, -100.0f, 100.0f);
float xx = ((float) x) / ((float) mea_width);
float yy = ((float) y) / ((float) mea_height);
float zz = z;
GameObject::pos = glm::translate (glm::mat4(1.0f), glm::vec3 (xx, yy, zz));
GameObject::model = glm::mat4(1.0f);
this->shader = shaderController->program[SHADERS::SPRITE];
this->type_shader = SHADERS::SPRITE;
gl::UseProgram (shaderController->program[SHADERS::SPRITE]);
this->location_view = gl::GetUniformLocation (shaderController->program[SHADERS::SPRITE], "view");
this->location_tex = gl::GetUniformLocation (shaderController->program[SHADERS::SPRITE], "tex");
this->location_pos = gl::GetUniformLocation (shaderController->program[SHADERS::SPRITE], "pos");
this->location_model = gl::GetUniformLocation (shaderController->program[SHADERS::SPRITE], "model");
this->location_scale = gl::GetUniformLocation (shaderController->program[SHADERS::SPRITE], "scale");
this->location_z = gl::GetUniformLocation (shaderController->program[SHADERS::SPRITE], "zCoord");
if (path != nullptr) loadSprite (path);
}
Как я помню, в играх указывают что например 1920x1080 разрешение рекомендуемое и я додумался сделать так - создать переменные mea_width = 1920 и mea_height = 1080. Ortho я выставляю в 1.0f расстояние, но чтобы одинаково везде было, я высчитываю деление на mea_*. То есть для тестирования и удобной работы я использую full hd экран и мне удобней ориентироваться в этих координатах. В игре я также оперирую координатами 1920x1080, но они преобразуются в 1.0f. Это делается очень просто, вот так.
float xx = ((float) x) / ((float) mea_width);
float yy = ((float) y) / ((float) mea_height);
Потом есть загрузка шейдера в спрайт, для спрайта мы просто указываем тип шейдера.
void Sprite::setShader (int shader) {
this->type_shader = shader;
switch (shader) {
case SHADERS::SPRITE:
this->shader = shaderController->program[SHADERS::SPRITE];
shader = this->shader;
gl::UseProgram (shader);
this->location_view = gl::GetUniformLocation (shader, "view");
this->location_tex = gl::GetUniformLocation (shader, "tex");
this->location_pos = gl::GetUniformLocation (shader, "pos");
this->location_model = gl::GetUniformLocation (shader, "model");
this->location_scale = gl::GetUniformLocation (shader, "scale");
this->location_z = gl::GetUniformLocation (shader, "zCoord");
break;
case SHADERS::SPRITE_WITH_ALPHA_COLORS:
this->shader = shaderController->program[SHADERS::SPRITE_WITH_ALPHA_COLORS];
shader = this->shader;
gl::UseProgram (shader);
this->location_view = gl::GetUniformLocation (shader, "view");
this->location_tex = gl::GetUniformLocation (shader, "tex");
this->location_pos = gl::GetUniformLocation (shader, "pos");
this->location_model = gl::GetUniformLocation (shader, "model");
this->location_scale = gl::GetUniformLocation (shader, "scale");
this->location_z = gl::GetUniformLocation (shader, "zCoord");
this->location_one = gl::GetUniformLocation (shader, "color_wall");
this->location_two = gl::GetUniformLocation (shader, "color_floor");
break;
case SHADERS::SPRITE_HUMAN:
this->shader = shaderController->program[SHADERS::SPRITE_HUMAN];
shader = this->shader;
gl::UseProgram (shader);
this->location_view = gl::GetUniformLocation (shader, "view");
this->location_tex = gl::GetUniformLocation (shader, "tex");
this->location_pos = gl::GetUniformLocation (shader, "pos");
this->location_model = gl::GetUniformLocation (shader, "model");
this->location_scale = gl::GetUniformLocation (shader, "scale");
this->location_z = gl::GetUniformLocation (shader, "zCoord");
this->location_one = gl::GetUniformLocation (shader, "color_up");
this->location_two = gl::GetUniformLocation (shader, "color_down");
break;
}
}
Как и объяснялось ранее, я координаты указываю within 1920x1080.
void Sprite::setPos (int x, int y, int z) {
float xx = ((float) x) / ((float) mea_width);
float yy = ((float) y) / ((float) mea_height);
float zz = z;
GameObject::pos = glm::translate (glm::mat4(1.0f), glm::vec3 (xx, yy, zz));
this->x = x;
this->y = y;
}
тот же расчет я использую и для задания размера спрайта, но код наверное не буду здесь приводить.отрисовка происходит по типу спрайта и вот пример отрисовки с нужным кадром.
void Sprite::draw_frame_with_color (int frame) {
gl::UseProgram (this->shader);
gl::Uniform1i (this->location_tex, 0);
gl::ActiveTexture (gl::TEXTURE0);
gl::BindTexture (gl::TEXTURE_2D, this->frame[frame]);
gl::Uniform3f (this->location_one, this->color_one.r, this->color_one.g, this->color_one.b);
gl::Uniform3f (this->location_two, this->color_two.r, this->color_two.g, this->color_two.b);
gl::UniformMatrix4fv (this->location_view, 1, gl::FALSE_, &GameObject::ortho[0][0]);
gl::UniformMatrix4fv (this->location_pos, 1, gl::FALSE_, &GameObject::pos[0][0]);
gl::UniformMatrix4fv (this->location_model, 1, gl::FALSE_, &GameObject::model[0][0]);
gl::UniformMatrix4fv (this->location_scale, 1, gl::FALSE_, &GameObject::scale[0][0]);
gl::Uniform2f (this->location_z, this->z[0], this->z[1]);
gl::BindVertexArray (this->vao);
gl::EnableVertexAttribArray (0);
gl::EnableVertexAttribArray (1);
gl::DrawArrays (gl::TRIANGLES, 0, 6);
}
Как видно из кода, я передаю в шейдер две uniform переменные, color_one и color_two. Они как раз и служат целью задания цвета для одежды персонажа. Шейдер фрагментный получился такой.
#version 330 core
out vec4 fragColor;
in vec2 texCoord;
uniform sampler2D tex;
uniform vec3 color_up;
uniform vec3 color_down;
void main () {
vec3 color = texture (tex, texCoord).rgb;
float r = color.r;
float g = color.g;
float b = color.b;
r *= 100;
g *= 100;
b *= 100;
int rr = int(r);
int gg = int(g);
int bb = int(b);
r = rr;
g = gg;
b = bb;
r *= 0.01;
g *= 0.01;
b *= 0.01;
color = vec3 (r, g, b);
if (color == vec3 (0.41, 0.41, 0.41)) {
fragColor = vec4 (color_up, 1.0);
} else if (color == vec3 (0.58, 0.58, 0.58)) {
vec3 col = color_up + vec3 (0.17, 0.17, 0.17);
fragColor = vec4 (col, 1.0);
} else if (color == vec3 (0.65, 0.65, 0.65)) {
vec3 col = color_up + vec3 (0.24, 0.24, 0.24);
fragColor = vec4 (col, 1.0);
} else if (color == vec3 (0.75, 0.75, 0.75)) {
vec3 col = color_up + vec3 (0.34, 0.34, 0.34);
fragColor = vec4 (col, 1.0);
} else if (color == vec3 (0.23, 0.23, 0.23)) {
vec3 col = color_up - vec3 (0.18, 0.18, 0.18);
fragColor = vec4 (col, 1.0);
} else if (color == vec3 (0.35, 0.35, 0.35)) {
fragColor = vec4 (color_down, 1.0);
} else if (color == vec3 (0.29, 0.29, 0.29)) {
vec3 col = color_down - vec3 (0.06, 0.06, 0.06);
fragColor = vec4 (col, 1.0);
} else if (color == vec3 (0.36, 0.36, 0.36)) {
vec3 col = color_down + vec3 (0.01, 0.01, 0.01);
fragColor = vec4 (col, 1.0);
} else if (color == vec3 (0.39, 0.39, 0.39)) {
vec3 col = color_down + vec3 (0.04, 0.04, 0.04);
fragColor = vec4 (col, 1.0);
} else if (color == vec3 (0.50, 0.50, 0.50)) {
vec3 col = color_down + vec3 (0.15, 0.15, 0.15);
fragColor = vec4 (col, 1.0);
} else {
fragColor = texture (tex, texCoord);
}
}
Как видно из кода, он просто проверяет на оттенок цвета и плюсует или минусует оттенок, чтобы добиться правильного цвета. Я такой же шейдер подключил и для столов и теперь когда персонаж подходит к столу и исчезает, он передает свои цвета столу и стол по этим оттенкам уже указывает нужный цвет. И начинает казаться, что персонаж действительно тот, который подходил к столу.
===========
Источник:
habr.com
===========
Похожие новости:
- [Настройка Linux, *nix] Краткое руководство по LXC в ОС Эльбрус
- [Разработка игр] Недельный геймдев: #25 — 4 июля, 2021
- [C++, Программирование микроконтроллеров] Использование coroutines из С++20 в связке с NRF52832 и GTest
- [Настройка Linux, *nix, Разработка под Linux, Учебный процесс в IT, DevOps] Зачем уметь работать в командной строке?
- [Open source, Программирование, Учебный процесс в IT] Как я учил студентов Северной Кореи разрабатывать ПО с открытым исходным кодом (перевод)
- [Разработка игр, Продвижение игр] Chronicles of cyberpunk — Deep sleep
- [Разработка под iOS, Разработка мобильных приложений, Разработка под Android, Swift] Онлайн-митап DevDay Mobile: C++ -> Swift, скрытый API Android и будни разработчика
- [Open source, C++, Qt, Софт] Haiku, Inc. проспонсировала приобретение RISC-V материнских плат для портирования системы Haiku
- [Разработка игр, Unity, CGI (графика), Разработка под AR и VR] Материалы в Unity: Акрил
- [Интервью] Комьюнити менеджмент в GameDev — это не про мемы, а про сервис, комфорт и вовлеченность
Теги для поиска: #_c++, #_*nix, #_shejder (шейдер), #_gamedev, #_razrabotka_igr (разработка игр), #_c++, #_*nix
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 08:24
Часовой пояс: UTC + 5
Автор | Сообщение |
---|---|
news_bot ®
Стаж: 6 лет 9 месяцев |
|
Я пробую делать игры. Пишу код, пробую рисовать и хочу научиться делать музыку. Я прорисовал персонажа и мне нужно было сделать так, чтобы ему можно было менять цвет одежды. Решение пришло сначала одно, но потом додумался до более простого. первое решение до чего я додумался, это сделать у стен разную прозрачность и тогда можно с помощью шейдера задавать прозрачность. В шейдере уже проверяется прозрачность и указывается заданный цвет. Может вам будет это интересно, но я всё таки приведу код класса спрайта и шейдера. Мне нравиться серый цвет и я как то обычно в его оттенках рисую что-то. Вот нарисовал человечка. как можно заметить вся одежка в оттенках серого цвета. Это оказалось удобным. я выписал числовые коды цветов в отдельный файл. human colors
------------------------------------------- body front #6a6a6a 0.41 0.41 0.41 body up #959595 0.58 0.58 0.58 arm #a6a6a6 0.65 0.65 0.65 arm blick #c1c1c1 0.75 0.75 0.75 arm blacked #8a8a8a 0.23 body down #5b5b5b 0.35 0.35 0.35 left legs blacked #4c4c4c 0.29 0.29 0.29 left legs blick #5c5c5c 0.36 0.36 0.36 right legs blacked #656565 0.39 0.39 0.39 right legs blick #808080 0.50 0.50 0.50 Sprite::Sprite (int x, int y, int z, const char *path) {
this->visibility = true; this->isAnimate = false; this->animator = new Animator (); this->check = 0; this->commonData = nullptr; this->frame = nullptr; this->trigger_shadow = 0; this->z = glm::vec2 ((float) z, 1.0f); GameObject::ortho = glm::ortho (0.0f, 1.0f, 1.0f, 0.0f, -100.0f, 100.0f); float xx = ((float) x) / ((float) mea_width); float yy = ((float) y) / ((float) mea_height); float zz = z; GameObject::pos = glm::translate (glm::mat4(1.0f), glm::vec3 (xx, yy, zz)); GameObject::model = glm::mat4(1.0f); this->shader = shaderController->program[SHADERS::SPRITE]; this->type_shader = SHADERS::SPRITE; gl::UseProgram (shaderController->program[SHADERS::SPRITE]); this->location_view = gl::GetUniformLocation (shaderController->program[SHADERS::SPRITE], "view"); this->location_tex = gl::GetUniformLocation (shaderController->program[SHADERS::SPRITE], "tex"); this->location_pos = gl::GetUniformLocation (shaderController->program[SHADERS::SPRITE], "pos"); this->location_model = gl::GetUniformLocation (shaderController->program[SHADERS::SPRITE], "model"); this->location_scale = gl::GetUniformLocation (shaderController->program[SHADERS::SPRITE], "scale"); this->location_z = gl::GetUniformLocation (shaderController->program[SHADERS::SPRITE], "zCoord"); if (path != nullptr) loadSprite (path); } float xx = ((float) x) / ((float) mea_width);
float yy = ((float) y) / ((float) mea_height); void Sprite::setShader (int shader) {
this->type_shader = shader; switch (shader) { case SHADERS::SPRITE: this->shader = shaderController->program[SHADERS::SPRITE]; shader = this->shader; gl::UseProgram (shader); this->location_view = gl::GetUniformLocation (shader, "view"); this->location_tex = gl::GetUniformLocation (shader, "tex"); this->location_pos = gl::GetUniformLocation (shader, "pos"); this->location_model = gl::GetUniformLocation (shader, "model"); this->location_scale = gl::GetUniformLocation (shader, "scale"); this->location_z = gl::GetUniformLocation (shader, "zCoord"); break; case SHADERS::SPRITE_WITH_ALPHA_COLORS: this->shader = shaderController->program[SHADERS::SPRITE_WITH_ALPHA_COLORS]; shader = this->shader; gl::UseProgram (shader); this->location_view = gl::GetUniformLocation (shader, "view"); this->location_tex = gl::GetUniformLocation (shader, "tex"); this->location_pos = gl::GetUniformLocation (shader, "pos"); this->location_model = gl::GetUniformLocation (shader, "model"); this->location_scale = gl::GetUniformLocation (shader, "scale"); this->location_z = gl::GetUniformLocation (shader, "zCoord"); this->location_one = gl::GetUniformLocation (shader, "color_wall"); this->location_two = gl::GetUniformLocation (shader, "color_floor"); break; case SHADERS::SPRITE_HUMAN: this->shader = shaderController->program[SHADERS::SPRITE_HUMAN]; shader = this->shader; gl::UseProgram (shader); this->location_view = gl::GetUniformLocation (shader, "view"); this->location_tex = gl::GetUniformLocation (shader, "tex"); this->location_pos = gl::GetUniformLocation (shader, "pos"); this->location_model = gl::GetUniformLocation (shader, "model"); this->location_scale = gl::GetUniformLocation (shader, "scale"); this->location_z = gl::GetUniformLocation (shader, "zCoord"); this->location_one = gl::GetUniformLocation (shader, "color_up"); this->location_two = gl::GetUniformLocation (shader, "color_down"); break; } } void Sprite::setPos (int x, int y, int z) {
float xx = ((float) x) / ((float) mea_width); float yy = ((float) y) / ((float) mea_height); float zz = z; GameObject::pos = glm::translate (glm::mat4(1.0f), glm::vec3 (xx, yy, zz)); this->x = x; this->y = y; } void Sprite::draw_frame_with_color (int frame) {
gl::UseProgram (this->shader); gl::Uniform1i (this->location_tex, 0); gl::ActiveTexture (gl::TEXTURE0); gl::BindTexture (gl::TEXTURE_2D, this->frame[frame]); gl::Uniform3f (this->location_one, this->color_one.r, this->color_one.g, this->color_one.b); gl::Uniform3f (this->location_two, this->color_two.r, this->color_two.g, this->color_two.b); gl::UniformMatrix4fv (this->location_view, 1, gl::FALSE_, &GameObject::ortho[0][0]); gl::UniformMatrix4fv (this->location_pos, 1, gl::FALSE_, &GameObject::pos[0][0]); gl::UniformMatrix4fv (this->location_model, 1, gl::FALSE_, &GameObject::model[0][0]); gl::UniformMatrix4fv (this->location_scale, 1, gl::FALSE_, &GameObject::scale[0][0]); gl::Uniform2f (this->location_z, this->z[0], this->z[1]); gl::BindVertexArray (this->vao); gl::EnableVertexAttribArray (0); gl::EnableVertexAttribArray (1); gl::DrawArrays (gl::TRIANGLES, 0, 6); } #version 330 core
out vec4 fragColor; in vec2 texCoord; uniform sampler2D tex; uniform vec3 color_up; uniform vec3 color_down; void main () { vec3 color = texture (tex, texCoord).rgb; float r = color.r; float g = color.g; float b = color.b; r *= 100; g *= 100; b *= 100; int rr = int(r); int gg = int(g); int bb = int(b); r = rr; g = gg; b = bb; r *= 0.01; g *= 0.01; b *= 0.01; color = vec3 (r, g, b); if (color == vec3 (0.41, 0.41, 0.41)) { fragColor = vec4 (color_up, 1.0); } else if (color == vec3 (0.58, 0.58, 0.58)) { vec3 col = color_up + vec3 (0.17, 0.17, 0.17); fragColor = vec4 (col, 1.0); } else if (color == vec3 (0.65, 0.65, 0.65)) { vec3 col = color_up + vec3 (0.24, 0.24, 0.24); fragColor = vec4 (col, 1.0); } else if (color == vec3 (0.75, 0.75, 0.75)) { vec3 col = color_up + vec3 (0.34, 0.34, 0.34); fragColor = vec4 (col, 1.0); } else if (color == vec3 (0.23, 0.23, 0.23)) { vec3 col = color_up - vec3 (0.18, 0.18, 0.18); fragColor = vec4 (col, 1.0); } else if (color == vec3 (0.35, 0.35, 0.35)) { fragColor = vec4 (color_down, 1.0); } else if (color == vec3 (0.29, 0.29, 0.29)) { vec3 col = color_down - vec3 (0.06, 0.06, 0.06); fragColor = vec4 (col, 1.0); } else if (color == vec3 (0.36, 0.36, 0.36)) { vec3 col = color_down + vec3 (0.01, 0.01, 0.01); fragColor = vec4 (col, 1.0); } else if (color == vec3 (0.39, 0.39, 0.39)) { vec3 col = color_down + vec3 (0.04, 0.04, 0.04); fragColor = vec4 (col, 1.0); } else if (color == vec3 (0.50, 0.50, 0.50)) { vec3 col = color_down + vec3 (0.15, 0.15, 0.15); fragColor = vec4 (col, 1.0); } else { fragColor = texture (tex, texCoord); } } =========== Источник: habr.com =========== Похожие новости:
|
|
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 08:24
Часовой пояс: UTC + 5