Вычисление матрицы преобразования для размещения объекта на сфере в glsl - PullRequest
0 голосов
/ 01 марта 2020

Я пытаюсь сгенерировать некоторые матрицы для размещения деревьев на PL anet на GPU. Положение каждого дерева предопределено - на основе карты биома и различных данных карты высот - но эти данные являются резидентными для GPU, поэтому я не могу сделать это на CPU. В настоящий момент я использую геометрический шейдер для создания экземпляров - это изменится на традиционное создание экземпляров, если производительность плохая, и я бы затем вычислял матрицы моделей для каждого дерева вычислительного шейдера.

Я дошел до попытки использовать модифицированную версию lookAt (), но я не могу заставить ее работать, и даже если бы я это сделал, деревья были бы перпендикулярны pl anet вместо вставать. Я знаю, что могу определить ось использования 3, то есть нормаль сферы, тангенс и битангенс, но, учитывая, что мне все равно, в каком направлении находятся эти тангенс и битангенс, какой бы быстрый способ вычислить эта матрица в GLSL? Спасибо!

void drawInstance(vec3 offset)
{
  //Grab the model's position from the model matrix
  vec3 modelPos = vec3(modelMatrix[3][0],modelMatrix[3][1],modelMatrix[3][2]);
  //Add the offset
  modelPos +=offset;

  //Eye = where the new pos is, look in x direction for now, planet is at origin so up is just the modelPos normalized
  mat4 m = lookAt(modelPos, modelPos + vec3(1,0,0), normalize(modelPos));

  //Lookat is intended as a camera matrix, fix this
  m = inverse(m);

  vec3 pos = gl_in[0].gl_Position.xyz;
  gl_Position = vp * m *vec4(pos, 1.0);
  EmitVertex();

  pos = gl_in[1].gl_Position.xyz ;
  gl_Position = vp * m *vec4(pos, 1.0);
  EmitVertex();

  pos = gl_in[2].gl_Position.xyz;
  gl_Position = vp * m * vec4(pos, 1.0);
  EmitVertex();

  EndPrimitive();
}

void main()
{   
  vp = proj * view;
  mvp = proj * view * modelMatrix;

  drawInstance(vec3(0,20,0));
  // drawInstance(vec3(0,20,0));
  // drawInstance(vec3(0,20,-40));
  // drawInstance(vec3(40,40,0));
  // drawInstance(vec3(-40,0,0));

}

Ответы [ 2 ]

1 голос
/ 01 марта 2020

Я бы рекомендовал полностью использовать другой подход.

Во-первых, не используйте геометрические шейдеры для репликации геометрии. Вот для чего glDrawArraysInstanced.

Во-вторых, сложно определить такую ​​матрицу процедурно. Это связано с теоремой о волосатых шариках .

Вместо этого я бы генерировал несколько случайных вращений на процессоре. Используйте этот метод , чтобы создать равномерно распределенный кватернион. Передайте этот кватернион вершинному шейдеру как отдельный инстансированный атрибут vec4. В вершинном шейдере:

  1. Сместить вершину дерева на (0, 0, radiusOfThePlanet), чтобы она находилась на северном полюсе (при условии, что ось Z направлена ​​вверх).
  2. Применить вращение кватернионов ( он будет вращаться вокруг центра pl anet, чтобы дерево оставалось на поверхности).
  3. Примените матрицы проекции pl anet модели и камеры как обычно.

Это даст беспристрастный равномерно распределенный случайный набор деревьев.

0 голосов
/ 01 марта 2020

Нашел решение проблемы, которое позволяет мне размещать объекты на поверхности сферы, обращенной в правильных направлениях. Вот код:

  mat4 m = mat4(1);

  vec3 worldPos = getWorldPoint(sphericalCoords);


  //Add a random number to the world pos, then normalize it so that it is a point on a unit sphere slightly different to the world pos. The vector between them is a tangent. Change this value to rotate the object once placed on the sphere
  vec3 xAxis = normalize(normalize(worldPos + vec3(0.0,0.2,0.0)) - normalize(worldPos));

  //Planet is at 0,0,0 so world pos can be used as the normal, and therefore the y axis
  vec3 yAxis = normalize(worldPos);

  //We can cross the y and x axis to generate a bitangent to use as the z axis
  vec3 zAxis = normalize(cross(yAxis, xAxis));

  //This is our rotation matrix!
  mat3 baseMat = mat3(xAxis, yAxis, zAxis);

  //Fill this into our 4x4 matrix
  m = mat4(baseMat);

  //Transform m by the Radius in the y axis to put it on the surface
  mat4 m2 = transformMatrix(mat4(1), vec3(0,radius,0));
  m = m  * m2;

  //Multiply by the MVP to project correctly
  m = mvp* m;

  //Draw an instance of your object
  drawInstance(m);
...