Как сделать спрайт прозрачным unity

Добавил пользователь Евгений Кузнецов
Обновлено: 04.10.2024

Очень часто, при создании почти каждой 2D игры, нам нужно положить на весь background одну картинку, или градиент, которые будут выступать фоном игры или определенной сцены. Как правило, для этого мы просто ставим спрайт и накладываем текстуру.

Хочу показать вам вариант с разбором непрозрачного шейдера спрайта, без возможности менять цвет и альфу с минимальным функционалом:

Разбираем:

где lerp это 3 раза для 3-х компонентов rgb:

Результаты тестов на Xiaomi Redmi Note 4 (1920×1080):

На все тесты влияет вертикальная синхронизация телефона! На всех тестах N спрайтов на весь экран телефона.

Тест №1: 1 спрайт. Оба вариант не падают ниже 60 fps

Тест №2: 10 спрайтов. Дефолтные спрайты прыгают между 30-60 fps. Оптимизированные стабильно 60 fps

Тест №3: 20 спрайтов. Дефолтные стабильно 20 fps. Оптимизированные стабильно 30 fps.

Тест №4: 30 спрайтов. Дефолтные стабильно 15 fps. Оптимизированные прыгают между 20-30 fps.

Тест №5: 40 спрайтов. Дефолтные прыгают между 10-12 fps. Оптимизированные между 15-20 fps.

Тест №6: 50 спрайтов. Дефолтные стабильно 10 fps. Оптимизированные прыгают между 12-15 fps.

001

Тесты не могут быть точными из-за профайлинга, лимита в 60fps, вертикальной синхронизации и вывода текста на экран.


Примечания:

Если ваш background спрайт всегда не прозрачен и рисуется на весь экран, то есть смысл у вашей камеры поставить Clear Flag — Depth Only, вместо Solid Color (по умолчанию). Тогда каждый новый кадр, перед начало отрисовки кадра, камера не будет заливать весь экран цветом (что занимает время).

Если вы не используете сложные эффекты пост обработки, то есть смысл у камеры отключить опцию Allow HDR. Это сильно сэкономит память.

Рекомендации к применению:

Создайте несколько шейдеров на разные случаи жизни. Не только для background. Это могут быть прозрачные, но без цвета, прозрачные и из цвета брать только альфа канал и пр.

Выводы:

На одном спрайте background вы не заметите прирост производительности, но сэкономленные наносекунды поднимут fps и сэкономят аккумулятор в тандеме со всеми вашими оптимизациями.

P.S. Компилированные варианты шейдеров:

compiled_variant

Все варианты скомпиленных шейдеров для дефолтного шейдера вышли на 1123 строки, а наш оптимизированный шейдер на 235 строки.

Подскажите : как сделать фон предмета в юнити прозрачным, я новичок .


Я знаю, что раздел неподходящий, но я не знал куда его вставить .

Загружаешь .jpg файл с прозрачным фоном и делаешь его спрайтом.
Только .jpg файл.

это и есть спрайт он не делается прозрачным, видна сетка прозрачного фона формат тот же.

Мы постоянно добавляем новый функционал в основной интерфейс проекта. К сожалению, старые браузеры не в состоянии качественно работать с современными программными продуктами. Для корректной работы используйте последние версии браузеров Chrome, Mozilla Firefox, Opera, Microsoft Edge или установите браузер Atom.

Как в Unity сделать перекрывающуюся область двух спрайтов прозрачной? Не могли бы вы написать об этом шейдер? После некоторых исследований я узнал, что мне следует использовать буфер трафарета, но я не знаю, как это сделать. Для меня это жизненно важно. Мне нужно выполнить этот школьный проект за 6 дней. Пожалуйста, помогите.. = (

1 ответ

Итак, имейте в виду, что это первый раз, когда я использую трафарет, поэтому, возможно, я сделал что-то менее оптимальное. Но он работает со спрайтами, как вы и просили.

Вот процедура загрузки png изображений из моего старого проекта. Обрати внимание на цикл.

glGenTextures( 1, &id );
glBindTexture( GL_TEXTURE_2D, id );
GLuint *pTexData = new GLuint[ image.width() * image.height() ];
GLuint *sdata = (GLuint *)image.bits();
GLuint *tdata = pTexData;


for (int y = 0; y > 8) & 255) > 16) & 255) > 24) & 255)
Не следует обманывать инспектора
Pipmak Assistant
Love2D Exporter
Love2D-Helpers
Old Consoles Games

Да, с прозрачностью. Старый потому что времени нет его допиливать )


Тут тоже всё разом считывается. В цикле то как раз и делается, чтобы было прозрачно. Без него у меня неправильно отображалось.
Не следует обманывать инспектора
Pipmak Assistant
Love2D Exporter
Love2D-Helpers
Old Consoles Games


Да любой файл с прозрачностью скачай и всё.
Не следует обманывать инспектора
Pipmak Assistant
Love2D Exporter
Love2D-Helpers
Old Consoles Games

import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import main.Engine;
import org.lwjgl.BufferUtils;
import org.lwjgl.opengl.ARBVertexBufferObject;
import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.GL13.*;
import static org.lwjgl.opengl.GL15.*;
import static org.lwjgl.util.glu.GLU.*;
import org.lwjgl.util.vector.Vector2f;
import org.lwjgl.util.vector.Vector4f;
import org.newdawn.slick.opengl.ImageDataFactory;
import org.newdawn.slick.opengl.InternalTextureLoader;
import org.newdawn.slick.opengl.LoadableImageData;
import org.newdawn.slick.opengl.TextureImpl;
import org.newdawn.slick.util.ResourceLoader;

public class Sprite
public static final int
NORMAL = 0,
FLIP_VERTICAL = 1,
FLIP_HORIZONTAL = 2;

private int texID = 0;
private int texWidth = 0;
private int texHeight = 0;
private int imageWidth = 0;
private int imageHeight = 0;
private FloatBuffer quadVertices = null;
private FloatBuffer quadTexVertices = null;
private int vboQuadHandle = 0;
private int vboQuadTexHandle = 0;

public Sprite( String fileName )
try
InputStream in = ResourceLoader.getResourceAsStream( fileName );
texID = InternalTextureLoader.createTextureID();
TextureImpl texture = new TextureImpl( fileName, GL_TEXTURE_2D, texID );
glBindTexture( GL_TEXTURE_2D, texID );

LoadableImageData imageData = ImageDataFactory.getImageDataFor( fileName );
ByteBuffer textureBuffer = imageData.loadImage( new BufferedInputStream( in ), false, null );

int width = imageData.getWidth();
int height = imageData.getHeight();
boolean hasAlpha = imageData.getDepth() == 32;

texture.setTextureWidth( imageData.getTexWidth() );
texture.setTextureHeight( imageData.getTexHeight() );

texWidth = texture.getTextureWidth();
texHeight = texture.getTextureHeight();

IntBuffer temp = BufferUtils.createIntBuffer( 16 );
glGetInteger( GL_MAX_TEXTURE_SIZE, temp );
int max = temp.get(0);

if ((texWidth > max) || (texHeight > max))
System.err.println("Attempt to allocate a texture to big for the current hardware");
Engine.Ptr().Window.close();
>

int srcPixelFormat = hasAlpha ? GL_RGBA : GL_RGB;
int componentCount = hasAlpha ? 4 : 3;

texture.setWidth( width );
texture.setHeight( height );
texture.setAlpha( hasAlpha );

imageWidth = texture.getImageWidth();
imageHeight = texture.getImageHeight();

glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP );
gluBuild2DMipmaps( GL_TEXTURE_2D, componentCount,
InternalTextureLoader.get2Fold( width ),
InternalTextureLoader.get2Fold( height ),
srcPixelFormat, GL_UNSIGNED_BYTE, textureBuffer );
glBindTexture( GL_TEXTURE_2D, 0 );

float[] vert = 0.0f, 0.0f,
(float)texWidth, 0.0f,
(float)texWidth, (float)texHeight,
0.0f, (float)texHeight
>;

float[] texVertices = 0.0f, 0.0f,
1.0f, 0.0f,
1.0f, 1.0f,
0.0f, 1.0f
>;

vboQuadHandle = glGenBuffers();
vboQuadTexHandle = glGenBuffers();

quadVertices = BufferUtils.createFloatBuffer( 4 * 2 );
quadVertices.put( vert );
quadVertices.flip();

quadTexVertices = BufferUtils.createFloatBuffer( 4 * 2 );
quadTexVertices.put( texVertices );
quadTexVertices.flip();

ARBVertexBufferObject.glBindBufferARB( ARBVertexBufferObject.GL_ARRAY_BUFFER_ARB, vboQuadHandle );
ARBVertexBufferObject.glBufferDataARB( ARBVertexBufferObject.GL_ARRAY_BUFFER_ARB, quadVertices,
ARBVertexBufferObject.GL_STREAM_DRAW_ARB );

ARBVertexBufferObject.glBindBufferARB( ARBVertexBufferObject.GL_ARRAY_BUFFER_ARB, vboQuadTexHandle );
ARBVertexBufferObject.glBufferDataARB( ARBVertexBufferObject.GL_ARRAY_BUFFER_ARB, quadTexVertices,
ARBVertexBufferObject.GL_STREAM_DRAW_ARB );

ARBVertexBufferObject.glBindBufferARB( ARBVertexBufferObject.GL_ARRAY_BUFFER_ARB, 0 );
>
catch (IOException e)
System.out.println( "Can't load texture from file " + fileName + ": " + e.getLocalizedMessage() );
Engine.Ptr().Window.close();
>
>

public void use()
glBindTexture( GL_TEXTURE_2D, texID );
>

public Vector2f size()
return new Vector2f( texWidth, texHeight );
>

public int width()
return texWidth;
>

public int height()
return texHeight;
>

public Vector2f imageSize()
return new Vector2f( imageWidth, imageHeight );
>

public int imageWidth()
return imageWidth;
>

public int imageHeight()
return imageHeight;
>

public int ID()
return texID;
>

public void destroy()
glDeleteTextures( texID );
ARBVertexBufferObject.glDeleteBuffersARB( vboQuadHandle );
ARBVertexBufferObject.glDeleteBuffersARB( vboQuadTexHandle );
>

public void setTexEnvi( int param1, int param2 )
glTexEnvi( GL_TEXTURE_ENV, param1, param2 );
>

public static void activeTexture( int num )
glActiveTexture( GL_TEXTURE0 + num );
glEnable( GL_TEXTURE_2D );
>

public static void deactiveTextures( int count )
for (int i = count - 1; i > -1; --i)
glActiveTexture( GL_TEXTURE0 + i );
glBindTexture( GL_TEXTURE_2D, 0 );
glDisable( GL_TEXTURE_2D );
>
>

public void draw( Vector4f geom, float angle, float alpha, boolean centered, int mode )
float[] vert = 0.0f, 0.0f,
geom.getZ(), 0.0f,
geom.getZ(), geom.getW(),
0.0f, geom.getW()
>;

if (centered)
vert = new float[] -geom.getZ() / 2.0f, -geom.getW() / 2.0f,
geom.getZ() / 2.0f, -geom.getW() / 2.0f,
geom.getZ() / 2.0f, geom.getW() / 2.0f,
-geom.getZ() / 2.0f, geom.getW() / 2.0f
>;
>

quadVertices.clear();
quadVertices.put( vert );
quadVertices.flip();

// Normal render
float[] texVertices = 0.0f, 0.0f,
1.0f, 0.0f,
1.0f, 1.0f,
0.0f, 1.0f
>;

// Flip vertical
if (mode == FLIP_VERTICAL)
texVertices = new float[] 0.0f, 1.0f,
1.0f, 1.0f,
1.0f, 0.0f,
0.0f, 0.0f
>;
>

// Flip horizontal
else if (mode == FLIP_HORIZONTAL)
texVertices = new float[] 1.0f, 0.0f,
0.0f, 0.0f,
0.0f, 1.0f,
1.0f, 1.0f
>;
>

quadTexVertices.clear();
quadTexVertices.put( texVertices );
quadTexVertices.flip();

ARBVertexBufferObject.glBindBufferARB( ARBVertexBufferObject.GL_ARRAY_BUFFER_ARB, vboQuadHandle );
ARBVertexBufferObject.glBufferSubDataARB( ARBVertexBufferObject.GL_ARRAY_BUFFER_ARB, 0L, quadVertices );
glVertexPointer( 2, GL_FLOAT, 0, 0L );

ARBVertexBufferObject.glBindBufferARB( ARBVertexBufferObject.GL_ARRAY_BUFFER_ARB, vboQuadTexHandle );
ARBVertexBufferObject.glBufferSubDataARB( ARBVertexBufferObject.GL_ARRAY_BUFFER_ARB, 0L, quadTexVertices );
glTexCoordPointer( 2, GL_FLOAT, 0, 0L );

ARBVertexBufferObject.glBindBufferARB( ARBVertexBufferObject.GL_ARRAY_BUFFER_ARB, 0 );

if (centered)
glTranslatef( geom.getX(), geom.getY(), 0.0f );
glRotatef( angle, 0.0f, 0.0f, 1.0f );
>
else
glTranslatef( geom.getX() + geom.getZ() / 2.0f, geom.getY() + geom.getW() / 2.0f, 0.0f );
glRotatef( angle, 0.0f, 0.0f, 1.0f );
glTranslatef( -geom.getZ() / 2.0f, -geom.getW() / 2.0f, 0.0f );
>

glEnable( GL_BLEND );
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
glEnable( GL_TEXTURE_2D );
glBindTexture( GL_TEXTURE_2D, texID );

glColor4f( 1.0f, 1.0f, 1.0f, alpha );

glEnableClientState( GL_VERTEX_ARRAY );
glEnableClientState( GL_TEXTURE_COORD_ARRAY );

glDrawArrays( GL_QUADS, 0, 4 );

glDisableClientState( GL_TEXTURE_COORD_ARRAY );
glDisableClientState( GL_VERTEX_ARRAY );

glDisable( GL_TEXTURE_2D );
glDisable( GL_BLEND );
>

public void drawPart( Vector4f geom, Vector4f partGeom, float angle, float alpha,
boolean centered, int mode )
float[] vert = 0.0f, 0.0f,
geom.getZ(), 0.0f,
geom.getZ(), geom.getW(),
0.0f, geom.getW()
>;

if (centered)
vert = new float[] -geom.getZ() / 2.0f, -geom.getW() / 2.0f,
geom.getZ() / 2.0f, -geom.getW() / 2.0f,
geom.getZ() / 2.0f, geom.getW() / 2.0f,
-geom.getZ() / 2.0f, geom.getW() / 2.0f
>;
>

quadVertices.clear();
quadVertices.put( vert );
quadVertices.flip();

float tx = partGeom.getX() / (float)texWidth;
float ty = partGeom.getY() / (float)texHeight;
float tw = partGeom.getZ() / (float)texWidth;
float th = partGeom.getW() / (float)texHeight;

// Normal render
float[] texVertices = tx, ty,
tx + tw, ty,
tx + tw, ty + th,
tx, ty + th
>;

// Flip vertical
if (mode == FLIP_VERTICAL)
texVertices = new float[] tx, ty + th,
tx + tw, ty + th,
tx + tw, ty,
tx, ty
>;
>

// Flip horizontal
else if (mode == FLIP_HORIZONTAL)
texVertices = new float[] tx + tw, ty,
tx, ty,
tx, ty + th,
tx + tw, ty + th
>;
>

quadTexVertices.clear();
quadTexVertices.put( texVertices );
quadTexVertices.flip();

ARBVertexBufferObject.glBindBufferARB( ARBVertexBufferObject.GL_ARRAY_BUFFER_ARB, vboQuadHandle );
ARBVertexBufferObject.glBufferSubDataARB( ARBVertexBufferObject.GL_ARRAY_BUFFER_ARB, 0L, quadVertices );
glVertexPointer( 2, GL_FLOAT, 0, 0L );

ARBVertexBufferObject.glBindBufferARB( ARBVertexBufferObject.GL_ARRAY_BUFFER_ARB, vboQuadTexHandle );
ARBVertexBufferObject.glBufferSubDataARB( ARBVertexBufferObject.GL_ARRAY_BUFFER_ARB, 0L, quadTexVertices );
glTexCoordPointer( 2, GL_FLOAT, 0, 0L );

ARBVertexBufferObject.glBindBufferARB( ARBVertexBufferObject.GL_ARRAY_BUFFER_ARB, 0 );

if (centered)
glTranslatef( geom.getX(), geom.getY(), 0.0f );
glRotatef( angle, 0.0f, 0.0f, 1.0f );
>
else
glTranslatef( geom.getX() + geom.getZ() / 2.0f, geom.getY() + geom.getW() / 2.0f, 0.0f );
glRotatef( angle, 0.0f, 0.0f, 1.0f );
glTranslatef( -geom.getZ() / 2.0f, -geom.getW() / 2.0f, 0.0f );
>

glEnable( GL_BLEND );
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
glEnable( GL_TEXTURE_2D );
glBindTexture( GL_TEXTURE_2D, texID );

glColor4f( 1.0f, 1.0f, 1.0f, alpha );

glEnableClientState( GL_VERTEX_ARRAY );
glEnableClientState( GL_TEXTURE_COORD_ARRAY );

glDrawArrays( GL_QUADS, 0, 4 );

glDisableClientState( GL_TEXTURE_COORD_ARRAY );
glDisableClientState( GL_VERTEX_ARRAY );

glDisable( GL_TEXTURE_2D );
glDisable( GL_BLEND );
>
>

Читайте также: