Sending arbitrary data to a shader

Questions about the LÖVE API, installing LÖVE and other support related questions go here.
Forum rules
Before you make a thread asking for help, read this.
Post Reply
Kimapr
Prole
Posts: 2
Joined: Wed Dec 19, 2018 1:14 pm

Sending arbitrary data to a shader

Post by Kimapr »

I want to make a voxel raycaster, and to make this I need ability to send arbitrary data to the shader. This is because of uniforms limit and other limitations of GLSL structuring. I tried to make this with VolumeImages, but that does not work. I made a demo to test it, and I found that the result is very weird. Normally, it should look just like example.png:
example.png
example.png (169.1 KiB) Viewed 3019 times
But instead it looks random. I don't know how to fix it. I guess there is something in ridat function inside the shader, but I'm not sure. Here is the code (use up/down arrows to adjust resolution of the data):

Code: Select all

local shader=[[extern ivec2 size;
extern VolumeImage data;
extern int res;
int d(int i1,int i2){return int(mod(i1,i2));}
int di(int i1,int i2){return int(float(i1)/float(i2));}
int ridat(int realindex,int res,VolumeImage data)
{
  int veci=di(realindex,4);
  int ivi=d(realindex,4);
  ivec3 pos=ivec3(d(veci,res),d(di(veci,res),res),di(di(veci,res),res));
  vec3 realpos=vec3(float(pos.x)/float(res)+0.5,float(pos.y)/float(res)+0.5,float(pos.z)/float(res)+0.5);
  vec4 c=Texel(data,realpos);
  if (ivi==0) {
    return int(c.r*255);
  } else if (ivi==1) {
    return int(c.g*255);
  } else if (ivi==2) {
    return int(c.b*255);
  } else if (ivi==3) {
    return int(c.a*255);
  } else {
    return 128;
  }
}
vec4 indexdat(ivec2 pos)
{
  int realindex=int((pos.x+pos.y*size.y))*3;
  vec4 c=vec4(float(ridat(realindex,res,data))/255,
              float(ridat(realindex+1,res,data))/255,
              float(ridat(realindex+2,res,data))/255,
              1);
  return c;
}
vec4 effect(vec4 color,Image img, vec2 uvs,vec2 sp) {
  ivec2 pos=ivec2(uvs*size);
  vec4 c=indexdat(pos);
  return c;
}
]]

love.keyboard.setKeyRepeat(true)
effect=love.graphics.newShader(shader)
local img=love.graphics.newImage(love.image.newImageData(1,1)) -- This is placeholder image, just because shaders don't work good for non-textured polygons.
local function pack(dat,res)
  local imgs={}
  local function writebyte(luaindex,byte)
    local realindex=luaindex-1
    local veci=math.floor(realindex/4)
    local ivi=realindex%4
    local x=veci%res
    local y=math.floor(veci/res)%res
    local z=math.floor(math.floor(veci/res)/res)+1
    imgs[z]=imgs[z] or love.image.newImageData(res,res)
    local img=imgs[z]
    local r,g,b,a=img:getPixel(x,y)
    local deb=false
    if ivi==0 then
      img:setPixel(x,y,byte/255,g,b,a)if deb then print("Writing to r",realindex,veci,ivi,x,y,z,byte)end
    elseif ivi==1 then
      img:setPixel(x,y,r,byte/255,b,a)if deb then print("Writing to g",realindex,veci,ivi,x,y,z,byte)end
    elseif ivi==2 then
      img:setPixel(x,y,r,g,byte/255,a)if deb then print("Writing to b",realindex,veci,ivi,x,y,z,byte)end
    elseif ivi==3 then
      img:setPixel(x,y,r,g,b,byte/255)if deb then print("Writing to a",realindex,veci,ivi,x,y,z,byte)end
    end
  end
  local imgsize=res*res*res*4
  local datsize=#dat
  assert(datsize<=imgsize,"Data is too big, please use less data or increase resolution of the VolumeImage")
  for k,v in ipairs(dat) do
    writebyte(k,v)
  end
  local img=love.graphics.newVolumeImage(imgs)
  img:setFilter("nearest","nearest")
  return img
end

-- THIS SECTION IS NOT RELATED TO THE PROBLEM --
local mx,my=0,0
local function getAbsoluteMP(x,y)
  local wx,wy=love.window.getPosition()
  return love.window.toPixels(x)+wx,love.window.toPixels(y)+wy
end
local amx,amy=getAbsoluteMP(love.mouse.getPosition())
function love.mousemoved(x,y)
  amx,amy=getAbsoluteMP(x,y)
end
function love.mousepressed(x,y,k)
  local x,y=love.window.getPosition()
  local imx,imy=amx,amy
  if k==1 then
    mx,my=imx-x,imy-y
  end
end
function love.update(dt)
  local x,y=love.window.getPosition()
  local imx,imy=amx,amy
  --print(x,y,imx,imy,mx,my)
  if love.mouse.isDown(1) then
    love.window.setPosition(imx-mx,imy-my)
  end
end
local res,size=41,256
function love.keypressed(key)
  if key=="up" then
    size=size+1
  elseif key=="down" then
    size=size-1
  end
  size=math.min(512,math.max(1,size))
  if (res-1)^3 >= size^2 then
    res=res-1
  end
  while (res)^3 < size^2 do
    res=res+1
  end
end
love.window.updateMode(800,600,{borderless=true})
-- END OF NON-PROBLEM-RELATED SECTION --

function love.draw()
  love.graphics.setShader(effect)
  effect:send("size",{size,size});
  effect:send("res",res)
  local t={}
  for x=0,size-1 do
    for y=0,size-1 do
      local i=((x+y*size))*3+1
      --print(i,i+1,i+2,i+3,i+4)
      t[i]=x/size*255
      t[i+1]=y/size*255
      t[i+2]=math.random()*255
    end
  end
  local t2=pack(t,res)
  effect:send("data",t2)
  
  love.graphics.draw(img,0,0,0,800,600)
  love.graphics.setShader()
end
Post Reply

Who is online

Users browsing this forum: Google [Bot] and 28 guests