mirror of
https://github.com/overte-org/overte.git
synced 2025-08-09 06:38:29 +02:00
Reimplement renderGrid to use frag shader
This commit is contained in:
parent
e3ae2baa7b
commit
2bfbf1b5fd
3 changed files with 123 additions and 179 deletions
|
@ -22,17 +22,19 @@
|
||||||
#include "TextureCache.h"
|
#include "TextureCache.h"
|
||||||
#include "RenderUtilsLogging.h"
|
#include "RenderUtilsLogging.h"
|
||||||
|
|
||||||
#include "standardTransformPNTC_vert.h"
|
|
||||||
#include "standardDrawTexture_frag.h"
|
|
||||||
|
|
||||||
#include "gpu/StandardShaderLib.h"
|
#include "gpu/StandardShaderLib.h"
|
||||||
|
|
||||||
#include "model/TextureMap.h"
|
#include "model/TextureMap.h"
|
||||||
|
|
||||||
|
#include "standardTransformPNTC_vert.h"
|
||||||
|
#include "standardDrawTexture_frag.h"
|
||||||
|
|
||||||
#include "simple_vert.h"
|
#include "simple_vert.h"
|
||||||
#include "simple_textured_frag.h"
|
#include "simple_textured_frag.h"
|
||||||
#include "simple_textured_emisive_frag.h"
|
#include "simple_textured_emisive_frag.h"
|
||||||
|
|
||||||
|
#include "grid_frag.h"
|
||||||
|
|
||||||
//#define WANT_DEBUG
|
//#define WANT_DEBUG
|
||||||
|
|
||||||
const int GeometryCache::UNKNOWN_ID = -1;
|
const int GeometryCache::UNKNOWN_ID = -1;
|
||||||
|
@ -564,186 +566,42 @@ void GeometryCache::renderWireSphere(gpu::Batch& batch) {
|
||||||
renderWireShape(batch, Sphere);
|
renderWireShape(batch, Sphere);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GeometryCache::renderGrid(gpu::Batch& batch,
|
||||||
|
const glm::vec2& minCorner, const glm::vec2& maxCorner,
|
||||||
|
int rows, int cols, const glm::vec4& color, float edge, int id) {
|
||||||
|
static const glm::vec2 minTexCoord(0.0f, 1.0f);
|
||||||
|
static const glm::vec2 maxTexCoord(1.0f, 0.0f);
|
||||||
|
|
||||||
void GeometryCache::renderGrid(gpu::Batch& batch, int xDivisions, int yDivisions, const glm::vec4& color) {
|
|
||||||
IntPair key(xDivisions, yDivisions);
|
|
||||||
Vec3Pair colorKey(glm::vec3(color.x, color.y, yDivisions), glm::vec3(color.z, color.y, xDivisions));
|
|
||||||
|
|
||||||
int vertices = (xDivisions + 1 + yDivisions + 1) * 2;
|
|
||||||
if (!_gridBuffers.contains(key)) {
|
|
||||||
auto verticesBuffer = std::make_shared<gpu::Buffer>();
|
|
||||||
|
|
||||||
float* vertexData = new float[vertices * 2];
|
|
||||||
float* vertex = vertexData;
|
|
||||||
|
|
||||||
for (int i = 0; i <= xDivisions; i++) {
|
|
||||||
float x = (float)i / xDivisions;
|
|
||||||
|
|
||||||
*(vertex++) = x;
|
|
||||||
*(vertex++) = 0.0f;
|
|
||||||
|
|
||||||
*(vertex++) = x;
|
|
||||||
*(vertex++) = 1.0f;
|
|
||||||
}
|
|
||||||
for (int i = 0; i <= yDivisions; i++) {
|
|
||||||
float y = (float)i / yDivisions;
|
|
||||||
|
|
||||||
*(vertex++) = 0.0f;
|
|
||||||
*(vertex++) = y;
|
|
||||||
|
|
||||||
*(vertex++) = 1.0f;
|
|
||||||
*(vertex++) = y;
|
|
||||||
}
|
|
||||||
|
|
||||||
verticesBuffer->append(sizeof(float) * vertices * 2, (gpu::Byte*) vertexData);
|
|
||||||
delete[] vertexData;
|
|
||||||
|
|
||||||
_gridBuffers[key] = verticesBuffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!_gridColors.contains(colorKey)) {
|
|
||||||
auto colorBuffer = std::make_shared<gpu::Buffer>();
|
|
||||||
_gridColors[colorKey] = colorBuffer;
|
|
||||||
|
|
||||||
int compactColor = ((int(color.x * 255.0f) & 0xFF)) |
|
|
||||||
((int(color.y * 255.0f) & 0xFF) << 8) |
|
|
||||||
((int(color.z * 255.0f) & 0xFF) << 16) |
|
|
||||||
((int(color.w * 255.0f) & 0xFF) << 24);
|
|
||||||
|
|
||||||
int* colorData = new int[vertices];
|
|
||||||
int* colorDataAt = colorData;
|
|
||||||
|
|
||||||
for(int v = 0; v < vertices; v++) {
|
|
||||||
*(colorDataAt++) = compactColor;
|
|
||||||
}
|
|
||||||
|
|
||||||
colorBuffer->append(sizeof(int) * vertices, (gpu::Byte*) colorData);
|
|
||||||
delete[] colorData;
|
|
||||||
}
|
|
||||||
gpu::BufferPointer verticesBuffer = _gridBuffers[key];
|
|
||||||
gpu::BufferPointer colorBuffer = _gridColors[colorKey];
|
|
||||||
|
|
||||||
const int VERTICES_SLOT = 0;
|
|
||||||
const int COLOR_SLOT = 1;
|
|
||||||
auto streamFormat = std::make_shared<gpu::Stream::Format>(); // 1 for everyone
|
|
||||||
|
|
||||||
streamFormat->setAttribute(gpu::Stream::POSITION, VERTICES_SLOT, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::XYZ), 0);
|
|
||||||
streamFormat->setAttribute(gpu::Stream::COLOR, COLOR_SLOT, gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA));
|
|
||||||
|
|
||||||
gpu::BufferView verticesView(verticesBuffer, 0, verticesBuffer->getSize(), streamFormat->getAttributes().at(gpu::Stream::POSITION)._element);
|
|
||||||
gpu::BufferView colorView(colorBuffer, streamFormat->getAttributes().at(gpu::Stream::COLOR)._element);
|
|
||||||
|
|
||||||
batch.setInputFormat(streamFormat);
|
|
||||||
batch.setInputBuffer(VERTICES_SLOT, verticesView);
|
|
||||||
batch.setInputBuffer(COLOR_SLOT, colorView);
|
|
||||||
batch.draw(gpu::LINES, vertices, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: why do we seem to create extra BatchItemDetails when we resize the window?? what's that??
|
|
||||||
void GeometryCache::renderGrid(gpu::Batch& batch, int x, int y, int width, int height, int rows, int cols, const glm::vec4& color, int id) {
|
|
||||||
#ifdef WANT_DEBUG
|
|
||||||
qCDebug(renderutils) << "GeometryCache::renderGrid(x["<<x<<"], "
|
|
||||||
"y["<<y<<"],"
|
|
||||||
"w["<<width<<"],"
|
|
||||||
"h["<<height<<"],"
|
|
||||||
"rows["<<rows<<"],"
|
|
||||||
"cols["<<cols<<"],"
|
|
||||||
" id:"<<id<<")...";
|
|
||||||
#endif
|
|
||||||
|
|
||||||
bool registered = (id != UNKNOWN_ID);
|
bool registered = (id != UNKNOWN_ID);
|
||||||
Vec3Pair key(glm::vec3(x, y, width), glm::vec3(height, rows, cols));
|
Vec2FloatPair key(glm::vec2(rows, cols), edge);
|
||||||
Vec3Pair colorKey(glm::vec3(color.x, color.y, rows), glm::vec3(color.z, color.y, cols));
|
|
||||||
|
|
||||||
int vertices = (cols + 1 + rows + 1) * 2;
|
// Make the gridbuffer
|
||||||
if ((registered && (!_registeredAlternateGridBuffers.contains(id) || _lastRegisteredAlternateGridBuffers[id] != key))
|
if ((registered && (!_registeredGridBuffers.contains(id) || _lastRegisteredGridBuffer[id] != key)) ||
|
||||||
|| (!registered && !_alternateGridBuffers.contains(key))) {
|
(!registered && !_gridBuffers.contains(key))) {
|
||||||
|
GridSchema gridSchema;
|
||||||
|
GridBuffer gridBuffer = std::make_shared<gpu::Buffer>(sizeof(GridSchema), (const gpu::Byte*) &gridSchema);
|
||||||
|
|
||||||
if (registered && _registeredAlternateGridBuffers.contains(id)) {
|
if (registered && _registeredGridBuffers.contains(id)) {
|
||||||
_registeredAlternateGridBuffers[id].reset();
|
gridBuffer = _registeredGridBuffers[id];
|
||||||
#ifdef WANT_DEBUG
|
|
||||||
qCDebug(renderutils) << "renderGrid()... RELEASING REGISTERED VERTICES BUFFER";
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto verticesBuffer = std::make_shared<gpu::Buffer>();
|
|
||||||
if (registered) {
|
if (registered) {
|
||||||
_registeredAlternateGridBuffers[id] = verticesBuffer;
|
_registeredGridBuffers[id] = gridBuffer;
|
||||||
_lastRegisteredAlternateGridBuffers[id] = key;
|
_lastRegisteredGridBuffer[id] = key;
|
||||||
} else {
|
} else {
|
||||||
_alternateGridBuffers[key] = verticesBuffer;
|
_gridBuffers[key] = gridBuffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
float* vertexData = new float[vertices * 2];
|
gridBuffer.edit<GridSchema>().period = glm::vec2(cols, rows);
|
||||||
float* vertex = vertexData;
|
gridBuffer.edit<GridSchema>().offset.x = -(edge / cols) / 2;
|
||||||
|
gridBuffer.edit<GridSchema>().offset.y = -(edge / rows) / 2;
|
||||||
int dx = width / cols;
|
gridBuffer.edit<GridSchema>().balance = glm::vec2(1 - edge);
|
||||||
int dy = height / rows;
|
|
||||||
int tx = x;
|
|
||||||
int ty = y;
|
|
||||||
|
|
||||||
// Draw horizontal grid lines
|
|
||||||
for (int i = rows + 1; --i >= 0; ) {
|
|
||||||
*(vertex++) = x;
|
|
||||||
*(vertex++) = ty;
|
|
||||||
|
|
||||||
*(vertex++) = x + width;
|
|
||||||
*(vertex++) = ty;
|
|
||||||
|
|
||||||
ty += dy;
|
|
||||||
}
|
|
||||||
// Draw vertical grid lines
|
|
||||||
for (int i = cols + 1; --i >= 0; ) {
|
|
||||||
*(vertex++) = tx;
|
|
||||||
*(vertex++) = y;
|
|
||||||
|
|
||||||
*(vertex++) = tx;
|
|
||||||
*(vertex++) = y + height;
|
|
||||||
tx += dx;
|
|
||||||
}
|
|
||||||
|
|
||||||
verticesBuffer->append(sizeof(float) * vertices * 2, (gpu::Byte*) vertexData);
|
|
||||||
delete[] vertexData;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_gridColors.contains(colorKey)) {
|
// Set the grid pipeline
|
||||||
auto colorBuffer = std::make_shared<gpu::Buffer>();
|
useGridPipeline(batch, registered ? _registeredGridBuffers[id] : _gridBuffers[key]);
|
||||||
_gridColors[colorKey] = colorBuffer;
|
|
||||||
|
|
||||||
int compactColor = ((int(color.x * 255.0f) & 0xFF)) |
|
renderQuad(batch, minCorner, maxCorner, minTexCoord, maxTexCoord, color, id);
|
||||||
((int(color.y * 255.0f) & 0xFF) << 8) |
|
|
||||||
((int(color.z * 255.0f) & 0xFF) << 16) |
|
|
||||||
((int(color.w * 255.0f) & 0xFF) << 24);
|
|
||||||
|
|
||||||
int* colorData = new int[vertices];
|
|
||||||
int* colorDataAt = colorData;
|
|
||||||
|
|
||||||
|
|
||||||
for(int v = 0; v < vertices; v++) {
|
|
||||||
*(colorDataAt++) = compactColor;
|
|
||||||
}
|
|
||||||
|
|
||||||
colorBuffer->append(sizeof(int) * vertices, (gpu::Byte*) colorData);
|
|
||||||
delete[] colorData;
|
|
||||||
}
|
|
||||||
gpu::BufferPointer verticesBuffer = registered ? _registeredAlternateGridBuffers[id] : _alternateGridBuffers[key];
|
|
||||||
|
|
||||||
gpu::BufferPointer colorBuffer = _gridColors[colorKey];
|
|
||||||
|
|
||||||
const int VERTICES_SLOT = 0;
|
|
||||||
const int COLOR_SLOT = 1;
|
|
||||||
auto streamFormat = std::make_shared<gpu::Stream::Format>(); // 1 for everyone
|
|
||||||
|
|
||||||
streamFormat->setAttribute(gpu::Stream::POSITION, VERTICES_SLOT, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::XYZ), 0);
|
|
||||||
streamFormat->setAttribute(gpu::Stream::COLOR, COLOR_SLOT, gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA));
|
|
||||||
|
|
||||||
gpu::BufferView verticesView(verticesBuffer, 0, verticesBuffer->getSize(), streamFormat->getAttributes().at(gpu::Stream::POSITION)._element);
|
|
||||||
gpu::BufferView colorView(colorBuffer, streamFormat->getAttributes().at(gpu::Stream::COLOR)._element);
|
|
||||||
|
|
||||||
batch.setInputFormat(streamFormat);
|
|
||||||
batch.setInputBuffer(VERTICES_SLOT, verticesView);
|
|
||||||
batch.setInputBuffer(COLOR_SLOT, colorView);
|
|
||||||
batch.draw(gpu::LINES, vertices, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GeometryCache::updateVertices(int id, const QVector<glm::vec2>& points, const glm::vec4& color) {
|
void GeometryCache::updateVertices(int id, const QVector<glm::vec2>& points, const glm::vec4& color) {
|
||||||
|
@ -1772,7 +1630,6 @@ void GeometryCache::useSimpleDrawPipeline(gpu::Batch& batch, bool noBlend) {
|
||||||
|
|
||||||
auto state = std::make_shared<gpu::State>();
|
auto state = std::make_shared<gpu::State>();
|
||||||
|
|
||||||
|
|
||||||
// enable decal blend
|
// enable decal blend
|
||||||
state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA);
|
state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA);
|
||||||
|
|
||||||
|
@ -1792,6 +1649,23 @@ void GeometryCache::useSimpleDrawPipeline(gpu::Batch& batch, bool noBlend) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GeometryCache::useGridPipeline(gpu::Batch& batch, GridBuffer gridBuffer) {
|
||||||
|
if (!_gridPipeline) {
|
||||||
|
auto vs = gpu::Shader::createVertex(std::string(standardTransformPNTC_vert));
|
||||||
|
auto ps = gpu::Shader::createPixel(std::string(grid_frag));
|
||||||
|
auto program = gpu::Shader::createProgram(vs, ps);
|
||||||
|
gpu::Shader::makeProgram((*program));
|
||||||
|
|
||||||
|
auto state = std::make_shared<gpu::State>();
|
||||||
|
state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA);
|
||||||
|
|
||||||
|
_gridPipeline = gpu::Pipeline::create(program, state);
|
||||||
|
_gridSlot = program->getBuffers().findLocation("gridBuffer");
|
||||||
|
}
|
||||||
|
batch.setPipeline(_gridPipeline);
|
||||||
|
batch.setUniformBuffer(_gridSlot, gridBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class SimpleProgramKey {
|
class SimpleProgramKey {
|
||||||
|
|
|
@ -32,7 +32,7 @@
|
||||||
class SimpleProgramKey;
|
class SimpleProgramKey;
|
||||||
|
|
||||||
typedef glm::vec3 Vec3Key;
|
typedef glm::vec3 Vec3Key;
|
||||||
|
typedef QPair<glm::vec2, float> Vec2FloatPair;
|
||||||
typedef QPair<glm::vec2, glm::vec2> Vec2Pair;
|
typedef QPair<glm::vec2, glm::vec2> Vec2Pair;
|
||||||
typedef QPair<Vec2Pair, Vec2Pair> Vec2PairPair;
|
typedef QPair<Vec2Pair, Vec2Pair> Vec2PairPair;
|
||||||
typedef QPair<glm::vec3, glm::vec3> Vec3Pair;
|
typedef QPair<glm::vec3, glm::vec3> Vec3Pair;
|
||||||
|
@ -203,8 +203,10 @@ public:
|
||||||
void renderWireSphere(gpu::Batch& batch);
|
void renderWireSphere(gpu::Batch& batch);
|
||||||
size_t getSphereTriangleCount();
|
size_t getSphereTriangleCount();
|
||||||
|
|
||||||
void renderGrid(gpu::Batch& batch, int xDivisions, int yDivisions, const glm::vec4& color);
|
void renderGrid(gpu::Batch& batch, const glm::vec2& minCorner, const glm::vec2& maxCorner, int rows, int cols, const glm::vec4& color, float edge = 0.01f, int id = UNKNOWN_ID);
|
||||||
void renderGrid(gpu::Batch& batch, int x, int y, int width, int height, int rows, int cols, const glm::vec4& color, int id = UNKNOWN_ID);
|
void renderGrid(gpu::Batch& batch, int x, int y, int width, int height, int rows, int cols, const glm::vec4& color, float edge = 0.01f, int id = UNKNOWN_ID) {
|
||||||
|
renderGrid(batch, glm::vec2(x, y), glm::vec2(x + width, y + height), rows, cols, color, edge, id);
|
||||||
|
}
|
||||||
|
|
||||||
void renderBevelCornersRect(gpu::Batch& batch, int x, int y, int width, int height, int bevelDistance, const glm::vec4& color, int id = UNKNOWN_ID);
|
void renderBevelCornersRect(gpu::Batch& batch, int x, int y, int width, int height, int bevelDistance, const glm::vec4& color, int id = UNKNOWN_ID);
|
||||||
|
|
||||||
|
@ -310,6 +312,18 @@ private:
|
||||||
gpu::BufferPointer _shapeVertices{ std::make_shared<gpu::Buffer>() };
|
gpu::BufferPointer _shapeVertices{ std::make_shared<gpu::Buffer>() };
|
||||||
gpu::BufferPointer _shapeIndices{ std::make_shared<gpu::Buffer>() };
|
gpu::BufferPointer _shapeIndices{ std::make_shared<gpu::Buffer>() };
|
||||||
|
|
||||||
|
class GridSchema {
|
||||||
|
public:
|
||||||
|
glm::vec2 period;
|
||||||
|
glm::vec2 offset;
|
||||||
|
glm::vec2 balance;
|
||||||
|
glm::vec2 _;
|
||||||
|
};
|
||||||
|
using GridBuffer = gpu::BufferView;
|
||||||
|
void useGridPipeline(gpu::Batch& batch, GridBuffer gridBuffer);
|
||||||
|
gpu::PipelinePointer _gridPipeline;
|
||||||
|
int _gridSlot;
|
||||||
|
|
||||||
class BatchItemDetails {
|
class BatchItemDetails {
|
||||||
public:
|
public:
|
||||||
static int population;
|
static int population;
|
||||||
|
@ -366,11 +380,9 @@ private:
|
||||||
QHash<Vec3PairVec2Pair, BatchItemDetails> _dashedLines;
|
QHash<Vec3PairVec2Pair, BatchItemDetails> _dashedLines;
|
||||||
QHash<int, BatchItemDetails> _registeredDashedLines;
|
QHash<int, BatchItemDetails> _registeredDashedLines;
|
||||||
|
|
||||||
QHash<IntPair, gpu::BufferPointer> _gridBuffers;
|
QHash<int, Vec2FloatPair> _lastRegisteredGridBuffer;
|
||||||
QHash<Vec3Pair, gpu::BufferPointer> _alternateGridBuffers;
|
QHash<Vec2FloatPair, GridBuffer> _gridBuffers;
|
||||||
QHash<int, gpu::BufferPointer> _registeredAlternateGridBuffers;
|
QHash<int, GridBuffer> _registeredGridBuffers;
|
||||||
QHash<int, Vec3Pair> _lastRegisteredAlternateGridBuffers;
|
|
||||||
QHash<Vec3Pair, gpu::BufferPointer> _gridColors;
|
|
||||||
|
|
||||||
QHash<QUrl, QWeakPointer<NetworkGeometry> > _networkGeometry;
|
QHash<QUrl, QWeakPointer<NetworkGeometry> > _networkGeometry;
|
||||||
|
|
||||||
|
|
58
libraries/render-utils/src/grid.slf
Normal file
58
libraries/render-utils/src/grid.slf
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
<@include gpu/Config.slh@>
|
||||||
|
<$VERSION_HEADER$>
|
||||||
|
// Generated on <$_SCRIBE_DATE$>
|
||||||
|
// grid.slf
|
||||||
|
// fragment shader
|
||||||
|
//
|
||||||
|
// Created by Zach Pomerantz on 2/16/2016.
|
||||||
|
// Copyright 2016 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
float paintStripe(float value, float offset, float scale, float balance) {
|
||||||
|
float width = fwidth(value);
|
||||||
|
float normalizedWidth = width * scale;
|
||||||
|
|
||||||
|
float x0 = (value + offset) * scale - normalizedWidth / 2;
|
||||||
|
float x1 = x0 + normalizedWidth;
|
||||||
|
|
||||||
|
float i0 = balance * floor(x0) + max(0.0, fract(x0) - balance);
|
||||||
|
float i1 = balance * floor(x1) + max(0.0, fract(x1) - balance);
|
||||||
|
float strip = (i1 - i0) / normalizedWidth;
|
||||||
|
|
||||||
|
return clamp(strip, 0.0, 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
float paintGrid(vec2 value, vec2 offset, vec2 scale, vec2 balance) {
|
||||||
|
return max(
|
||||||
|
paintStripe(value.x, offset.x, scale.x, balance.x),
|
||||||
|
paintStripe(value.y, offset.y, scale.y, balance.y));
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Grid {
|
||||||
|
vec2 period;
|
||||||
|
vec2 offset;
|
||||||
|
vec2 balance;
|
||||||
|
vec2 _;
|
||||||
|
};
|
||||||
|
|
||||||
|
uniform gridBuffer { Grid grid; };
|
||||||
|
Grid getGrid() { return grid; };
|
||||||
|
|
||||||
|
in vec2 varTexCoord0;
|
||||||
|
in vec4 varColor;
|
||||||
|
|
||||||
|
out vec4 outFragColor;
|
||||||
|
|
||||||
|
void main(void) {
|
||||||
|
Grid grid = getGrid();
|
||||||
|
|
||||||
|
float alpha = paintGrid(varTexCoord0, grid.offset, grid.period, grid.balance);
|
||||||
|
if (alpha == 0.0) {
|
||||||
|
discard;
|
||||||
|
}
|
||||||
|
|
||||||
|
outFragColor = vec4(varColor.xyz, varColor.w * alpha);
|
||||||
|
}
|
Loading…
Reference in a new issue