Sunday, August 12, 2018

c# - vertex manipulation in instanced shader hlsl SHARPDX 4.2


[SOLVED] - The project is here https://drive.google.com/open?id=1-kum0phM_iBMc8xRxYShmCNRWRs6W0Aw


I am using the same vertex shader and pixel shader for my instances. I am sending ONE FLAT array that contains all the instanced chunk bytes that make the cube of the Minecraft terrain. My goal is to make ONE DRAW CALL... Nothing is working. I am able to use an input element that has the specific index of the vertex logged in memory so all of the instances vertexes share the same index. It should be super easy after that to fetch the byte 0 or 1 inside of the flat chunk array that contains all of the data.


It should be working. The indexes of the vertices are perfect. The indexes of the instanced chunks are perfect...


What the h*** is NOT working? It feels as if something is wrong with the array as the chunks bytes are rendered randomly on my computer display. Everything that i see is wrong. I padded all of my structs to send to the shader and padded correctly the InputElements...??? I tried sending an array of Matrices instead... Each Matrix M11 to M44 contains the index of the bytes and I send that as an array to the shader and BAM... nothing is still working... Doing it on the cpu would be completely fine as i've done it a thousand times already.


enter image description here




cbuffer MatrixBuffer :register(b0)

{
float4x4 world;
float4x4 view;
float4x4 proj;
};

cbuffer inData:register(b1)
{
int chunkMap[4096];
}


struct VertexInputType
{
float4 position : POSITION;
float4 indexPos : POSITION1;
float4 instancePosition1 : INSTANCEPOSITION1;
};

struct PixelInputType
{

float4 position : SV_POSITION;
float4 color : COLOR;
};

float planeSize = 1;

static int mapWidth = 4;
static int mapHeight = 4;
static int mapDepth = 4;


static int tinyChunkWidth = 4;
static int tinyChunkHeight = 4;
static int tinyChunkDepth = 4;

bool IsTransparent(int xMain, int yMain, int zMain, int x, int y, int z)
{
int indexMain = xMain + mapWidth * (yMain + mapHeight * zMain);
int indexSec = x + tinyChunkWidth * (y + tinyChunkHeight * z);

if ((x < 0) || (y < 0) || (z < 0) || (x >= tinyChunkWidth) || (y >= tinyChunkHeight) || (z >= tinyChunkDepth)) return true;

{
return chunkMap[(indexMain * 64) + indexSec] == 0;
}
}
PixelInputType TextureVertexShader(VertexInputType input)
{
PixelInputType output;

input.position.w = 1.0f;


int xMain = 0;
int yMain = 0;
int zMain = 0;



xMain = round(fmod((input.instancePosition1.x*10), mapWidth*tinyChunkWidth));
yMain = round(fmod((input.instancePosition1.y*10), mapHeight*tinyChunkHeight));
zMain = round(fmod((input.instancePosition1.z*10), mapDepth*tinyChunkDepth));


xMain = round(xMain / mapWidth);
yMain = round(yMain / mapHeight);
zMain = round(zMain / mapDepth);


int x = input.indexPos.x;
int y = input.indexPos.y;
int z = input.indexPos.z;

int indexMain = xMain + mapWidth * (yMain + mapHeight * zMain);


int indexSec = x + tinyChunkWidth * (y + tinyChunkHeight * z);

int currentByte = chunkMap[(indexMain * 64) + indexSec];

input.position.x += input.instancePosition1.x;
input.position.y += input.instancePosition1.y;
input.position.z += input.instancePosition1.z;

output.position = mul(input.position, world);

output.position = mul(output.position, view);
output.position = mul(output.position, proj);

if (currentByte == 1)
{
output.color = float4(0,1,0,1);
return output;
}
else
{


output.color = float4(0,0,1,1);
return output;
}
}


This is my current result. And it doesn't make sense and I don't understand why...


enter image description here


Seriously though. What is going on. I am sending a simple array to the GPU. Whatever padding I put shouldnt really matter since there is a single element in the struct for the buffer. Is it the GPU pipeline that is causing issues? is it because the GPU randomly puts data in the array which doesnt make any sense if it does? It is IMPOSSIBLE that the problem is my index of each vertex because I am setting those up BEFORE even starting rendering, they are setup as an input element Vector4 with x,y,z beeing the index position of the byte.


Or what I am trying is impossible? It shouldn't be unless it's related to some funky things the GPU is doing when instancing objects. Or I am just blind and I don't know what the f*** im coding.



EDIT 2019-03-30: WHAT IT SHOULD LOOK LIKE (down below) - pic of chunk data that are drawn individually - more draw calls as each instance has its own draw calls...But this tiny picture shows instanced chunks with 4096 total instances. Each object created has 64 instances and there is 64 objects. There is 4096 draw calls in here at which point you can argue those aren't really instanced at all but they are! Each instance has its own draw call in order to modify the vertexes and indexes of each instances. It's a very bad programing test and no one should ever attempt this as it's completely useless... I mean, I could probably have better results even without instancing the chunks.


enter image description here


EDIT 2019-03-30: WHAT IT LOOKS RIGHT NOW (down below)- I am almost there but again it's not working yet. I am able to send chunk data another way instead of a constant buffer and it seems to do "half" of the job. I'm gonna keep at it. 1 draw call and i could make the terrain as big as I want it. Same thing with the chunks, 64 objects and 64 instances per object. BUT there is only 64 draw calls here hehe. Of course, I benchmarking at the same time and the final version won't be tiny chunksBytes of 4*4*4 by instances 4*4*4 by objects 4*4*4, they will be bigger.


As you can see, I got some good results finally where the chunks are correctly aligned and it seems that they are in the right position, but the chunks are missing bytes... I am wondering if it is a padding/packing issue because again, I went over the c# script many times to check the index position and it seems fine. Thanks for the response DMGregory. By the way, I am NOW using floats as the inputElements. Each float contains 16 digits that are made up of bytes 1 and 0. Each bytes represent if the chunkBytes faces should be drawn or not. The inputElement is instanced and 4 floats of 16 digits gives me 64 .... wow wait a minute. is this where I am doing it wrong? brb on this


PERLIN CHUNK DATA SENT TO SHADER


nevermind, i am doing it right as I am building the VertexBufferBinding with an array of floats dismantled into a single float containing 16 digits for each slot. In the shader, i am accessing the vertexBinding and it really is giving me the correct float bytes, i think, for each instance. So everything should be ok. but its not ok.


EDIT 2019-03-31: I have changed my shader to this instead.




cbuffer MatrixBuffer :register(b0)

{
float4x4 world;
float4x4 view;
float4x4 proj;
};

struct VertexInputType
{
float4 position : POSITION;
float4 indexPos : POSITION1;

float4 color : COLOR;
float3 normal : NORMAL;
float2 tex : TEXCOORD;
float3 dummyPad : NORMAL1;
float4 indexPosMain : INSTANCEPOSITION;
float4 instancePosition1 : INSTANCEPOSITION1;
};

struct PixelInputType
{

float4 position : SV_POSITION;
float4 color : COLOR;
float3 normal : NORMAL;
float2 tex : TEXCOORD;
};

float planeSize = 0.1f;

static int mapWidth = 4;
static int mapHeight = 4;

static int mapDepth = 4;

static int tinyChunkWidth = 4;
static int tinyChunkHeight = 4;
static int tinyChunkDepth = 4;

//[maxvertexcount(96)]
PixelInputType TextureVertexShader(VertexInputType input)
{
PixelInputType output;

input.position.w = 1.0f;

//int mainX = input.indexPosMain.x;
//int mainY = input.indexPosMain.y;
//int mainZ = input.indexPosMain.z;

int x = (input.indexPos.x);
int y = (input.indexPos.y);
int z = (input.indexPos.z);


float currentMapData;
float currentByte;

int currentIndex = x + tinyChunkWidth * (y + tinyChunkHeight * z);

if(currentIndex >= 0 && currentIndex <= 15)
{
currentMapData = input.indexPosMain.x;
currentIndex = currentIndex;
currentIndex = 15-currentIndex;

}
else if(currentIndex >= 16 && currentIndex <= 31)
{
currentMapData = input.indexPosMain.y;
currentIndex = 31 - currentIndex;
currentIndex = 15-currentIndex;
}
else if(currentIndex >= 32 && currentIndex <= 47)
{
currentMapData = input.indexPosMain.z;

currentIndex = 47 - currentIndex;
currentIndex = 15-currentIndex;
}
else if(currentIndex >= 48 && currentIndex <= 63)
{
currentMapData = input.indexPosMain.w;
currentIndex = 63 - currentIndex;
currentIndex = 15 - currentIndex;
}


if(currentIndex == 0)
{
float before = currentMapData * 0.1f;
float newIndex1 = round(before);
float lastIndex = before - newIndex1;
currentByte = round(lastIndex * 10);
}
else
{
int tempData = currentMapData;

for(int i = 0;i < 15-currentIndex; i++)
{
tempData = currentMapData * 0.1f;
currentMapData = round(tempData);
}

float before = currentMapData * 0.1f;
float newIndex1 = round(before);
float lastIndex = before - newIndex1;
float otherByte = lastIndex * 10;

currentByte = round(otherByte);

}

int current = currentByte;

if(current == 1) //current >= 5 || wtf
{
input.position.x += input.instancePosition1.x;
input.position.y += input.instancePosition1.y;

input.position.z += input.instancePosition1.z;

output.position = mul(input.position, world);
output.position = mul(output.position, view);
output.position = mul(output.position, proj);
}
else
{
input.position.x = input.instancePosition1.x;
input.position.y = input.instancePosition1.y;

input.position.z = input.instancePosition1.z;

output.position = mul(input.position, world);
output.position = mul(output.position, view);
output.position = mul(output.position, proj);
}

output.color = input.color;
output.tex = input.tex;


output.normal = mul(input.normal, world);
output.normal = normalize(output.normal);

return output;
}


EDIT: 2019-04-09 - 04h35am - I was able to make this work.



Answer



The project Version 1.0 is here: https://drive.google.com/open?id=1-kum0phM_iBMc8xRxYShmCNRWRs6W0Aw


The goal is achieved. It was to modify the vertex position inside of a Vertex Shader with using Vertex Binding Elements. The vertex binding is used both for storing the index of each byte (to which each vertex is assigned to) inside of each chunk instanced or not and also used to send the instance bytes in the form of integers.



In the end, the positions of each vertex is manipulated inside of the vertex shader but they are NOT removed from the scene. Hence why I will work on Version 1.1 and try to incorporate a Geometry shader to nullify triangles/faces that are not needed. In order to do that, I need to ask another question.


Oh... I forgot to mention one very important fact. In order to run the project, you need an Oculus Rift VR headset. Very soon, I will build the same project without the need of the VR headset. It does run faster without the headset as there is no need to draw twice for each eyes.


I didn't put a license on my shader and whatnot because I got bored searching on how to put the project on GitHub + I am the TUCO of coding, so every part of my code here and there uses parts of someone elses code so in the end, I didn't knew what to put a license on.


Special thanks to Craig Perko for creating the Minecraft Terrain Tutorial series 1 & 2 on YouTube.


No comments:

Post a Comment

Simple past, Present perfect Past perfect

Can you tell me which form of the following sentences is the correct one please? Imagine two friends discussing the gym... I was in a good s...