3D instancer

This commit is contained in:
MakhamDev 2023-10-28 15:53:11 +07:00
parent 9245b35c1f
commit fdb2858378
22 changed files with 338 additions and 41 deletions

View file

@ -648,6 +648,7 @@
{"name":"sh_3d_extrude_filler","order":8,"path":"shaders/sh_3d_extrude_filler/sh_3d_extrude_filler.yy",},
{"name":"quarternionBox","order":32,"path":"scripts/quarternionBox/quarternionBox.yy",},
{"name":"s_window_exit","order":2,"path":"sprites/s_window_exit/s_window_exit.yy",},
{"name":"node_3d_particle","order":4,"path":"scripts/node_3d_particle/node_3d_particle.yy",},
{"name":"s_node_color_remove","order":7,"path":"sprites/s_node_color_remove/s_node_color_remove.yy",},
{"name":"sh_average","order":7,"path":"shaders/sh_average/sh_average.yy",},
{"name":"sh_warp_4points_pers","order":10,"path":"shaders/sh_warp_4points_pers/sh_warp_4points_pers.yy",},
@ -1434,6 +1435,7 @@
{"name":"s_node_RGB","order":34,"path":"sprites/s_node_RGB/s_node_RGB.yy",},
{"name":"fd_rectangle_draw","order":9,"path":"scripts/fd_rectangle_draw/fd_rectangle_draw.yy",},
{"name":"node_color_palette_replacement","order":14,"path":"scripts/node_color_palette_replacement/node_color_palette_replacement.yy",},
{"name":"d3d_object_instancer","order":10,"path":"scripts/d3d_object_instancer/d3d_object_instancer.yy",},
{"name":"sh_BGR","order":2,"path":"shaders/sh_BGR/sh_BGR.yy",},
{"name":"oRigidbody","order":2,"path":"objects/oRigidbody/oRigidbody.yy",},
{"name":"node_grey_to_alpha","order":4,"path":"scripts/node_grey_to_alpha/node_grey_to_alpha.yy",},
@ -1620,6 +1622,7 @@
{"name":"s_node_wav_file_read","order":16,"path":"sprites/s_node_wav_file_read/s_node_wav_file_read.yy",},
{"name":"o_dialog_assetbox","order":3,"path":"objects/o_dialog_assetbox/o_dialog_assetbox.yy",},
{"name":"node_lerp","order":2,"path":"scripts/node_lerp/node_lerp.yy",},
{"name":"node_3d_instancer","order":3,"path":"scripts/node_3d_instancer/node_3d_instancer.yy",},
{"name":"s_node_pixel_sort","order":42,"path":"sprites/s_node_pixel_sort/s_node_pixel_sort.yy",},
{"name":"sh_mask_expand","order":55,"path":"shaders/sh_mask_expand/sh_mask_expand.yy",},
{"name":"node_texture_remap","order":2,"path":"scripts/node_texture_remap/node_texture_remap.yy",},

View file

@ -762,6 +762,11 @@
{"resourceType":"GMIncludedFile","resourceVersion":"1.0","name":"tile_0126.png","CopyToMask":-1,"filePath":"datafiles/Sample Projects",},
{"resourceType":"GMIncludedFile","resourceVersion":"1.0","name":"Tree sway.png","CopyToMask":-1,"filePath":"datafiles/Sample Projects",},
{"resourceType":"GMIncludedFile","resourceVersion":"1.0","name":"Tree sway.pxc","CopyToMask":-1,"filePath":"datafiles/Sample Projects",},
{"resourceType":"GMIncludedFile","resourceVersion":"1.0","name":"3dInstancePS.hlsl","CopyToMask":-1,"filePath":"datafiles/Shaders/3dInstance",},
{"resourceType":"GMIncludedFile","resourceVersion":"1.0","name":"3dInstanceVS.hlsl","CopyToMask":-1,"filePath":"datafiles/Shaders/3dInstance",},
{"resourceType":"GMIncludedFile","resourceVersion":"1.0","name":"CommonPS.hlsl","CopyToMask":-1,"filePath":"datafiles/Shaders/3dInstance",},
{"resourceType":"GMIncludedFile","resourceVersion":"1.0","name":"CommonVS.hlsl","CopyToMask":-1,"filePath":"datafiles/Shaders/3dInstance",},
{"resourceType":"GMIncludedFile","resourceVersion":"1.0","name":"rubber_duck_toy_1k.bin","CopyToMask":-1,"filePath":"datafiles/Shaders/3dInstance",},
{"resourceType":"GMIncludedFile","resourceVersion":"1.0","name":"Steamworks_Extension_Documentation.html","CopyToMask":0,"filePath":"datafiles",},
{"resourceType":"GMIncludedFile","resourceVersion":"1.0","name":"ucrtbased.dll","ConfigValues":{},"CopyToMask":-1,"filePath":"datafiles",},
{"resourceType":"GMIncludedFile","resourceVersion":"1.0","name":"webpmux.exe","CopyToMask":-1,"filePath":"datafiles/webp",},
@ -1257,6 +1262,7 @@
{"id":{"name":"quarternionBox","path":"scripts/quarternionBox/quarternionBox.yy",},},
{"id":{"name":"s_window_exit","path":"sprites/s_window_exit/s_window_exit.yy",},},
{"id":{"name":"d3d_gizmo_sphere","path":"scripts/d3d_gizmo_sphere/d3d_gizmo_sphere.yy",},},
{"id":{"name":"node_3d_particle","path":"scripts/node_3d_particle/node_3d_particle.yy",},},
{"id":{"name":"s_node_color_remove","path":"sprites/s_node_color_remove/s_node_color_remove.yy",},},
{"id":{"name":"sh_average","path":"shaders/sh_average/sh_average.yy",},},
{"id":{"name":"sh_warp_4points_pers","path":"shaders/sh_warp_4points_pers/sh_warp_4points_pers.yy",},},
@ -2162,6 +2168,7 @@
{"id":{"name":"s_node_export","path":"sprites/s_node_export/s_node_export.yy",},},
{"id":{"name":"texture_set_interpolation","path":"scripts/texture_set_interpolation/texture_set_interpolation.yy",},},
{"id":{"name":"node_color_palette_replacement","path":"scripts/node_color_palette_replacement/node_color_palette_replacement.yy",},},
{"id":{"name":"d3d_object_instancer","path":"scripts/d3d_object_instancer/d3d_object_instancer.yy",},},
{"id":{"name":"sh_BGR","path":"shaders/sh_BGR/sh_BGR.yy",},},
{"id":{"name":"oRigidbody","path":"objects/oRigidbody/oRigidbody.yy",},},
{"id":{"name":"node_grey_to_alpha","path":"scripts/node_grey_to_alpha/node_grey_to_alpha.yy",},},
@ -2376,6 +2383,7 @@
{"id":{"name":"s_node_wav_file_read","path":"sprites/s_node_wav_file_read/s_node_wav_file_read.yy",},},
{"id":{"name":"o_dialog_assetbox","path":"objects/o_dialog_assetbox/o_dialog_assetbox.yy",},},
{"id":{"name":"node_lerp","path":"scripts/node_lerp/node_lerp.yy",},},
{"id":{"name":"node_3d_instancer","path":"scripts/node_3d_instancer/node_3d_instancer.yy",},},
{"id":{"name":"s_node_pixel_sort","path":"sprites/s_node_pixel_sort/s_node_pixel_sort.yy",},},
{"id":{"name":"sh_mask_expand","path":"shaders/sh_mask_expand/sh_mask_expand.yy",},},
{"id":{"name":"node_texture_remap","path":"scripts/node_texture_remap/node_texture_remap.yy",},},

View file

@ -0,0 +1,23 @@
#include "CommonPS.hlsl"
struct VS_out
{
float4 Position : SV_POSITION;
float3 Normal : NORMAL0;
float4 Color : COLOR0;
float2 TexCoord : TEXCOORD0;
};
struct PS_out
{
float4 Color : SV_Target0;
};
void main(in VS_out IN, out PS_out OUT)
{
OUT.Color = gm_BaseTextureObject.Sample(gm_BaseTexture, IN.TexCoord);
float3 N = normalize(IN.Normal);
float3 L = normalize(float3(1.0, 1.0, 1.0));
float NdotL = saturate(dot(N, L));
OUT.Color.rgb *= lerp(0.2, 1.0, NdotL);
}

View file

@ -0,0 +1,32 @@
#include "CommonVS.hlsl"
struct VS_in
{
float3 Position : POSITION;
float3 Normal : NORMAL0;
float4 Color : COLOR0;
float2 TexCoord : TEXCOORD0;
uint InstanceID : SV_InstanceID;
};
struct VS_out
{
float4 Position : SV_POSITION;
float3 Normal : NORMAL0;
float4 Color : COLOR0;
float2 TexCoord : TEXCOORD0;
};
cbuffer Data : register(b10)
{
float4 InstancePosition[4096];
};
void main(in VS_in IN, out VS_out OUT)
{
float3 position = IN.Position.xyz + InstancePosition[IN.InstanceID].xyz;
OUT.Position = mul(gm_Matrices[MATRIX_WORLD_VIEW_PROJECTION], float4(position.xyz, 1.0));
OUT.Normal = mul(gm_Matrices[MATRIX_WORLD], float4(IN.Normal.xyz, 0.0));
OUT.Color = IN.Color;
OUT.TexCoord = IN.TexCoord;
}

View file

@ -0,0 +1,7 @@
#ifndef __COMMONPS_HLSL__
#define __COMMONPS_HLSL__
Texture2D gm_BaseTextureObject : register(t0);
SamplerState gm_BaseTexture : register(s0);
#endif // __COMMONPS_HLSL__

View file

@ -0,0 +1,13 @@
#ifndef __COMMONVS_HLSL__
#define __COMMONVS_HLSL__
#define MATRIX_WORLD 0
#define MATRIX_WORLD_VIEW 1
#define MATRIX_WORLD_VIEW_PROJECTION 2
cbuffer Matrices : register(b0)
{
float4x4 gm_Matrices[3];
};
#endif // __COMMONVS_HLSL__

Binary file not shown.

View file

@ -83,6 +83,8 @@
log_message("SESSION", "> init Palette"); __initPalette();
log_message("SESSION", "> init Gradient"); __initGradient();
log_message("SESSION", "> init Ins Renderer"); __initInstanceRenderer();
setPanel();
loadAddon();

View file

@ -11,12 +11,9 @@
/// @desc Retrieves the last error message.
///
/// @return {String} The last error message.
function d3d11_get_error_string()
{
function d3d11_get_error_string() {
gml_pragma("forceinline");
static _fn = external_define(
GMD3D11_PATH, "d3d11_get_error_string", dll_cdecl, ty_string,
0);
static _fn = external_define(GMD3D11_PATH, "d3d11_get_error_string", dll_cdecl, ty_string, 0);
return external_call(_fn);
}
@ -29,12 +26,9 @@ function d3d11_get_error_string()
/// @param {Pointer.Texture} _texture The texture to pass.
///
/// @return {Real} Returns 1 on success or 0 on fail.
function d3d11_texture_set_stage_vs(_slot, _texture)
{
function d3d11_texture_set_stage_vs(_slot, _texture) {
gml_pragma("forceinline");
static _fn = external_define(
GMD3D11_PATH, "d3d11_texture_set_stage_vs", dll_cdecl, ty_real,
1, ty_real);
static _fn = external_define(GMD3D11_PATH, "d3d11_texture_set_stage_vs", dll_cdecl, ty_real, 1, ty_real);
texture_set_stage(0, _texture);
return external_call(_fn, _slot);
}
@ -49,11 +43,9 @@ function d3d11_texture_set_stage_vs(_slot, _texture)
/// @param {Pointer.Texture} _texture The texture to pass.
///
/// @see GMD3D11_IS_SUPPORTED
function texture_set_stage_vs(_slot, _texture)
{
function texture_set_stage_vs(_slot, _texture) {
gml_pragma("forceinline");
if (GMD3D11_IS_SUPPORTED)
{
if (GMD3D11_IS_SUPPORTED) {
d3d11_texture_set_stage_vs(_slot, _texture);
return;
}
@ -69,12 +61,9 @@ function texture_set_stage_vs(_slot, _texture)
/// @param {Pointer.Texture} _texture The texture to pass.
///
/// @return {Real} Returns 1 on success or 0 on fail.
function d3d11_texture_set_stage_ps(_slot, _texture)
{
function d3d11_texture_set_stage_ps(_slot, _texture) {
gml_pragma("forceinline");
static _fn = external_define(
GMD3D11_PATH, "d3d11_texture_set_stage_ps", dll_cdecl, ty_real,
1, ty_real);
static _fn = external_define(GMD3D11_PATH, "d3d11_texture_set_stage_ps", dll_cdecl, ty_real, 1, ty_real);
texture_set_stage(0, _texture);
return external_call(_fn, _slot);
}
@ -85,12 +74,9 @@ function d3d11_texture_set_stage_ps(_slot, _texture)
/// is submitted. After that the number is reset back to 0!
///
/// @param {Real} _count Number of instances to draw. Use 0 to disable instanced rendering.
function d3d11_draw_instanced(_count)
{
function d3d11_draw_instanced(_count) {
gml_pragma("forceinline");
static _fn = external_define(
GMD3D11_PATH, "d3d11_draw_instanced", dll_cdecl, ty_real,
1, ty_real);
static _fn = external_define(GMD3D11_PATH, "d3d11_draw_instanced", dll_cdecl, ty_real, 1, ty_real);
return external_call(_fn, _count);
}
@ -102,23 +88,27 @@ function d3d11_draw_instanced(_count)
/// @param {Constant.PrimitiveType} _prim The primitive type.
/// @param {Pointer.Texture} _texture The texture to use.
/// @param {Real} _count The number of instances to draw.
function vertex_submit_instanced(_vbuff, _prim, _texture, _count)
{
function vertex_submit_instanced(_vbuff, _prim, _texture, _count) {
gml_pragma("forceinline");
if (!d3d11_draw_instanced(_count))
{
return false;
}
vertex_submit(_vbuff, _prim, _texture);
return true;
}
if (GMD3D11_IS_SUPPORTED)
{
var _init = external_define(
GMD3D11_PATH, "d3d11_init", dll_cdecl, ty_real, 2, ty_string, ty_string);
var _osInfo = os_get_info();
var _device = _osInfo[? "video_d3d11_device"];
function vertex_buffer_load(_filename, _vformat) {
gml_pragma("forceinline");
var _buffer = buffer_load(_filename);
var _vbuffer = vertex_create_buffer_from_buffer(_buffer, _vformat);
buffer_delete(_buffer);
return _vbuffer;
}
if (GMD3D11_IS_SUPPORTED) {
var _init = external_define(GMD3D11_PATH, "d3d11_init", dll_cdecl, ty_real, 2, ty_string, ty_string);
var _osInfo = os_get_info();
var _device = _osInfo[? "video_d3d11_device"];
var _context = _osInfo[? "video_d3d11_context"];
external_call(_init, _device, _context);
}

View file

@ -59,7 +59,7 @@ function __3dCube() : __3dObject() constructor {
new __vertex( size, -size, -size).setNormal(0, -1, 0).setUV(1, 1),
new __vertex(-size, -size, -size).setNormal(0, -1, 0).setUV(0, 1),
]];
VB = build();
} initModel(1);
}

View file

@ -82,7 +82,7 @@ function __3dObject() constructor {
}
}
vertex_end(_buffer);
//vertex_freeze(_buffer);
vertex_freeze(_buffer);
return _buffer;
} #endregion

View file

@ -0,0 +1,87 @@
#region shader
globalvar INSTANCE_SHADER_VS, INSTANCE_SHADER_PS;
function __initInstanceRenderer() {
INSTANCE_SHADER_VS = d3d11_shader_compile_vs(working_directory + "Shaders/3dInstance/3dInstanceVS.hlsl", "main", "vs_4_0");
INSTANCE_SHADER_PS = d3d11_shader_compile_ps(working_directory + "Shaders/3dInstance/3dInstancePS.hlsl", "main", "ps_4_0");
if (!d3d11_shader_exists(INSTANCE_SHADER_VS)) noti_warning(d3d11_get_error_string());
if (!d3d11_shader_exists(INSTANCE_SHADER_PS)) noti_warning(d3d11_get_error_string());
}
#endregion
function __3dObjectInstancer() : __3dObject() constructor {
object_data = noone;
object_counts = 1;
VF = global.VF_POS_NORM_TEX_COL;
render_type = pr_trianglelist;
transform = new __transform();
size = new __vec3(1);
positions = [];
static setData = function() { #region
d3d11_cbuffer_begin();
d3d11_cbuffer_add_float(4 * object_counts);
object_data = d3d11_cbuffer_end();
var _buffer = buffer_create(d3d11_cbuffer_get_size(object_data), buffer_fixed, 1);
for(var i = 0; i < object_counts; i++) {
var pos = array_safe_get(positions, i, 0);
buffer_write(_buffer, buffer_f32, array_safe_get(pos, 0, 0));
buffer_write(_buffer, buffer_f32, array_safe_get(pos, 1, 0));
buffer_write(_buffer, buffer_f32, array_safe_get(pos, 2, 0));
buffer_write(_buffer, buffer_f32, 0);
}
d3d11_cbuffer_update(object_data, _buffer);
buffer_delete(_buffer);
} #endregion
static generateNormal = function(_s = normal_draw_size) {}
static submit = function(scene = {}, shader = noone) { submitVertex(scene, shader); }
static submitUI = function(scene = {}, shader = noone) { submitVertex(scene, shader); }
static submitSel = function(scene = {}, shader = noone) { submitVertex(scene, shader); }
static submitShader = function(scene = {}, shader = noone) {}
static submitShadow = function(scene = {}, object = noone) {}
static submitVertex = function(scene = {}, shader = noone) { #region
d3d11_shader_override_vs(INSTANCE_SHADER_VS);
d3d11_shader_override_ps(INSTANCE_SHADER_PS);
preSubmitVertex(scene);
transform.submitMatrix();
matrix_set(matrix_world, matrix_stack_top());
d3d11_shader_set_cbuffer_vs(10, object_data);
for( var i = 0, n = array_length(VB); i < n; i++ ) {
var _ind = array_safe_get(material_index, i, i);
var _mat = array_safe_get(materials, _ind, noone);
var _tex = _mat == noone? -1 : _mat.getTexture();
vertex_submit_instanced(VB[i], render_type, _tex, object_counts);
}
d3d11_shader_override_vs(-1);
d3d11_shader_override_ps(-1);
transform.clearMatrix();
matrix_set(matrix_world, matrix_build_identity());
postSubmitVertex(scene);
} #endregion
static clone = function(_vertex = true) {}
static destroy = function() {}
static onDestroy = function() {}
static toString = function() { return $"[D3D Instanced Object]\n\t({object_counts} instances\n\tPosition: {transform.position}\n\tRotation: {transform.rotation}\n\tScale: {transform.scale})" }
}

View file

@ -0,0 +1,11 @@
{
"resourceType": "GMScript",
"resourceVersion": "1.0",
"name": "d3d_object_instancer",
"isCompatibility": false,
"isDnD": false,
"parent": {
"name": "3d",
"path": "folders/functions/3d.yy",
},
}

View file

@ -0,0 +1,38 @@
function Node_3D_Instancer(_x, _y, _group = noone) : Node_3D_Modifier(_x, _y, _group) constructor {
name = "3D Instancer";
inputs[| in_mesh + 0] = nodeValue("Amounts", self, JUNCTION_CONNECT.input, VALUE_TYPE.integer, 1);
inputs[| in_mesh + 1] = nodeValue("Positions", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, [ 0, 0, 0 ])
.setDisplay(VALUE_DISPLAY.vector)
.setArrayDepth(1);
static processData = function(_output, _data, _output_index, _array_index = 0) {
var _obj = _data[0];
if(!is_instanceof(_obj, __3dObject)) return noone;
if(_obj.VF != global.VF_POS_NORM_TEX_COL) return noone;
var _amo = _data[in_mesh + 0];
var _pos = _data[in_mesh + 1];
if(_amo <= 0) return noone;
var _res = new __3dObjectInstancer();
_res.object_counts = max(1, _amo);
_res.positions = _pos;
_res.vertex = _obj.vertex;
_res.VB = _obj.VB;
_res.render_type = _obj.render_type;
_res.custom_shader = _obj.custom_shader;
_res.transform = _obj.transform.clone();
_res.size = _obj.size.clone();
_res.materials = _obj.materials;
_res.material_index = _obj.material_index;
_res.texture_flip = _obj.texture_flip;
_res.setData();
return _res;
}
}

View file

@ -0,0 +1,11 @@
{
"resourceType": "GMScript",
"resourceVersion": "1.0",
"name": "node_3d_instancer",
"isCompatibility": false,
"isDnD": false,
"parent": {
"name": "d3d modifier",
"path": "folders/nodes/data/3D/d3d modifier.yy",
},
}

View file

@ -0,0 +1,12 @@
{
"isDnD": false,
"isCompatibility": false,
"parent": {
"name": "variable",
"path": "folders/nodes/data/variable.yy",
},
"resourceVersion": "1.0",
"name": "node_counter",
"tags": [],
"resourceType": "GMScript",
}

View file

@ -0,0 +1,38 @@
function Node_3D_Particle(_x, _y, _group = noone) : Node_3D_Modifier(_x, _y, _group) constructor {
name = "3D Particle";
inputs[| in_mesh + 0] = nodeValue("Amounts", self, JUNCTION_CONNECT.input, VALUE_TYPE.integer, 1);
inputs[| in_mesh + 1] = nodeValue("Positions", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, [ 0, 0, 0 ])
.setDisplay(VALUE_DISPLAY.vector)
.setArrayDepth(1);
static processData = function(_output, _data, _output_index, _array_index = 0) {
var _obj = _data[0];
if(!is_instanceof(_obj, __3dObject)) return noone;
if(_obj.VF != global.VF_POS_NORM_TEX_COL) return noone;
var _amo = _data[in_mesh + 0];
var _pos = _data[in_mesh + 1];
if(_amo <= 0) return noone;
var _res = new __3dObjectInstancer();
_res.object_counts = max(1, _amo);
_res.positions = _pos;
_res.vertex = _obj.vertex;
_res.VB = _obj.VB;
_res.render_type = _obj.render_type;
_res.custom_shader = _obj.custom_shader;
_res.transform = _obj.transform.clone();
_res.size = _obj.size.clone();
_res.materials = _obj.materials;
_res.material_index = _obj.material_index;
_res.texture_flip = _obj.texture_flip;
_res.setData();
return _res;
}
}

View file

@ -0,0 +1,11 @@
{
"resourceType": "GMScript",
"resourceVersion": "1.0",
"name": "node_3d_particle",
"isCompatibility": false,
"isDnD": false,
"parent": {
"name": "d3d modifier",
"path": "folders/nodes/data/3D/d3d modifier.yy",
},
}

View file

@ -0,0 +1,12 @@
{
"isDnD": false,
"isCompatibility": false,
"parent": {
"name": "variable",
"path": "folders/nodes/data/variable.yy",
},
"resourceVersion": "1.0",
"name": "node_counter",
"tags": [],
"resourceType": "GMScript",
}

View file

@ -418,6 +418,8 @@ function NodeObject(_name, _spr, _node, _create, tags = []) constructor { #regio
ds_list_add(d3d, "Modify");
addNodeObject(d3d, "Discretize vertex", s_node_3d_discretize, "Node_3D_Round_Vertex", [1, Node_3D_Round_Vertex]).setVersion(11560);
addNodeObject(d3d, "Set Material", s_node_3d_set_material, "Node_3D_Set_Material", [1, Node_3D_Set_Material]).setVersion(11560);
/**/ addNodeObject(d3d, "3D Instancer", s_node_3d_set_material, "Node_3D_Instancer", [1, Node_3D_Instancer]).setVersion(11560);
/**/ addNodeObject(d3d, "3D Particle", s_node_3d_set_material, "Node_3D_Particle", [1, Node_3D_Particle]).setVersion(11560);
ds_list_add(d3d, "Legacy"); //////////////////////////////////////////////////////////////////////////////////////////////////////////////
addNodeObject(d3d, "3D Plane", s_node_3d_plane, "__Node_3D_Plane", [1, __Node_3D_Plane],, "Put 2D image on a plane in 3D space.").isDeprecated();

View file

@ -1,6 +1,3 @@
//
// Simple passthrough vertex shader
//
attribute vec3 in_Position;
attribute vec3 in_Normal;
attribute vec4 in_Colour;

View file

@ -14,7 +14,7 @@ void main() {
gl_FragColor = vec4(0.);
vec4 sam = texture2D( gm_BaseTexture, v_vTexcoord );
if(sam.r > 0.5) return;
if(sam.r > 0.) return;
for(float i = 1.; i <= 2.; i++) {
float base = 1.;
@ -30,7 +30,7 @@ void main() {
vec2 pxs = (pixelPosition + vec2( cos(ang), sin(ang)) * i) / dimension;
vec4 sam = texture2D( gm_BaseTexture, pxs );
if(sam.r > 0.5) {
if(sam.r > 0.) {
gl_FragColor = outlineColor;
return;
}