first round of hacking on implementing rendering of models for detailed ray picking

This commit is contained in:
ZappoMan 2014-12-04 12:00:38 -08:00
parent 11f10f9512
commit b6fd3628c8
6 changed files with 468 additions and 2 deletions

View file

@ -0,0 +1,25 @@
#version 120
//
// simple.frag
// fragment shader
//
// Created by Andrzej Kapolka on 9/15/14.
// Copyright 2014 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
//
// the interpolated normal
varying vec4 normal;
// the glow intensity
uniform float glowIntensity;
void main(void) {
// set the diffuse, normal, specular data
gl_FragData[0] = vec4(1.0f, 1.0f, 0.0f, 0.0f); //vec4(gl_Color.rgb, glowIntensity);
gl_FragData[1] = vec4(1.0f, 1.0f, 0.0f, 0.0f); //normalize(normal) * 0.5 + vec4(0.5, 0.5, 0.5, 1.0);
gl_FragData[2] = vec4(1.0f, 1.0f, 0.0f, 0.0f); //vec4(gl_FrontMaterial.specular.rgb, gl_FrontMaterial.shininess / 128.0);
}

View file

@ -0,0 +1,26 @@
#version 120
//
// simple.vert
// vertex shader
//
// Created by Andrzej Kapolka on 9/15/14.
// Copyright 2014 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
//
// the interpolated normal
varying vec4 normal;
void main(void) {
// transform and store the normal for interpolation
normal = normalize(gl_ModelViewMatrix * vec4(gl_Normal, 0.0));
// pass along the diffuse color
gl_FrontColor = vec4(1.0f, 0.0f, 0.0f, 0.0f); //gl_Color;
// use standard pipeline transform
gl_Position = ftransform();
}

View file

@ -133,6 +133,9 @@ void RenderableModelEntityItem::render(RenderArgs* args) {
getModel(renderer);
}
if (_model) {
// handle animations..
if (hasAnimation()) {
@ -257,7 +260,386 @@ EntityItemProperties RenderableModelEntityItem::getProperties() const {
return properties;
}
bool RenderableModelEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face,
void** intersectedObject) const {
// extents is the entity relative, scaled, centered extents of the entity
glm::mat4 rotation = glm::mat4_cast(getRotation());
glm::mat4 translation = glm::translate(getPosition());
glm::mat4 entityToWorldMatrix = translation * rotation;
glm::mat4 worldToEntityMatrix = glm::inverse(entityToWorldMatrix);
glm::vec3 entityFrameOrigin = glm::vec3(worldToEntityMatrix * glm::vec4(origin, 1.0f));
glm::vec3 entityFrameDirection = glm::vec3(worldToEntityMatrix * glm::vec4(direction, 0.0f));
float depth = depthOfRayIntersection(entityFrameOrigin, entityFrameDirection);
return true; // we only got here if we intersected our non-aabox
}
/*
void RenderableModelEntityItem::renderEntityAsBillboard() {
TextureCache* textureCache = Application->getInstance()->getTextureCache();
textureCache->getPrimaryFramebufferObject()->bind();
const int BILLBOARD_SIZE = 64;
renderRearViewMirror(QRect(0, _glWidget->getDeviceHeight() - BILLBOARD_SIZE, BILLBOARD_SIZE, BILLBOARD_SIZE), true);
//QImage image(BILLBOARD_SIZE, BILLBOARD_SIZE, QImage::Format_ARGB32);
//glReadPixels(0, 0, BILLBOARD_SIZE, BILLBOARD_SIZE, GL_BGRA, GL_UNSIGNED_BYTE, image.bits());
textureCache->getPrimaryFramebufferObject()->release();
return image;
}
*/
float RenderableModelEntityItem::depthOfRayIntersection(const glm::vec3& entityFrameOrigin, const glm::vec3& entityFrameDirection) const {
qDebug() << "RenderableModelEntityItem::depthOfRayIntersection()....";
Application::getInstance()->getTextureCache()->getPrimaryFramebufferObject()->bind();
glEnable(GL_SCISSOR_TEST);
glEnable(GL_LIGHTING); // enable?
glEnable(GL_DEPTH_TEST);
glDisable(GL_BLEND); // we don't need blending
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glMatrixMode(GL_PROJECTION);
glPushMatrix();
// * we know the direction that the ray is coming into our bounding box.
// * we know the location on our bounding box that the ray intersected
// * because this API is theoretically called for things that aren't on the screen,
// or could be off in the distance, but with an original ray pick origin ALSO off
// in the distance, we don't really know the "pixel" size of the model at that
// place in space. In fact that concept really doesn't make sense at all... so
// we need to pick our own "scale" based on whatever level of precision makes
// sense... what makes sense?
// * we could say that we allow ray intersections down to some N meters (say 1cm
// or 0.01 meters) in real space. The model's bounds in meters are known.
//
//
float renderGranularity = 0.01f; // 1cm of render granularity - this could be ridiculous for large models
qDebug() << " renderGranularity:" << renderGranularity;
// note: these are in tree units, not meters
glm::vec3 dimensions = getDimensions();
glm::vec3 registrationPoint = getRegistrationPoint();
glm::vec3 corner = -(dimensions * registrationPoint);
AABox entityFrameBox(corner, dimensions);
entityFrameBox.scale((float)TREE_SCALE);
// rotationBetween(v1, v2) -- Helper function return the rotation from the first vector onto the second
//glm::quat viewRotation = rotationBetween(entityFrameDirection, IDENTITY_FRONT);
//glm::quat viewRotation = rotationBetween(IDENTITY_FRONT, entityFrameDirection);
glm::quat viewRotation = rotationBetween(glm::vec3(0.0f, 1.0f, 0.0f), IDENTITY_FRONT);
//glm::quat viewRotation = rotationBetween(IDENTITY_FRONT, IDENTITY_FRONT);
// I'd like to calculate the tightest bounding box around the entity for
// the direction of the
glm::vec3 minima(FLT_MAX, FLT_MAX, FLT_MAX);
glm::vec3 maxima(-FLT_MAX, -FLT_MAX, -FLT_MAX);
const int VERTEX_COUNT = 8;
for (int j = 0; j < VERTEX_COUNT; j++) {
glm::vec3 vertex = entityFrameBox.getVertex((BoxVertex)j);
qDebug() << " vertex[" << j <<"]:" << vertex;
glm::vec3 rotated = viewRotation * vertex;
qDebug() << " rotated[" << j <<"]:" << rotated;
minima = glm::min(minima, rotated);
maxima = glm::max(maxima, rotated);
}
qDebug() << " minima:" << minima;
qDebug() << " maxima:" << maxima;
int width = glm::round((maxima.x - minima.x) / renderGranularity);
int height = glm::round((maxima.y - minima.y) / renderGranularity);
qDebug() << " width:" << width;
qDebug() << " height:" << height;
glViewport(0, 0, width, height);
glScissor(0, 0, width, height);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
glOrtho(minima.x, maxima.x, minima.y, maxima.y, -maxima.z, -minima.z);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glm::vec3 axis = glm::axis(viewRotation);
glRotatef(glm::degrees(glm::angle(viewRotation)), axis.x, axis.y, axis.z);
glm::vec3 entityFrameOriginInMeters = entityFrameOrigin * (float)TREE_SCALE;
glm::vec3 entityFrameDirectionInMeters = entityFrameDirection * (float)TREE_SCALE;
//glTranslatef(entityFrameOriginInMerters.x, entityFrameOriginInMerters.y, entityFrameOriginInMerters.z);
Application::getInstance()->setupWorldLight();
Application::getInstance()->updateUntranslatedViewMatrix();
bool renderAsModel = true;
if (renderAsModel) {
const float alpha = 1.0f;
glm::vec3 position = getPositionInMeters();
glm::vec3 center = getCenterInMeters();
dimensions = getDimensions() * (float)TREE_SCALE;
glm::quat rotation = getRotation();
const float MAX_COLOR = 255.0f;
glColor4f(1.0f, 0.0f, 0.0f, 1.0f);
glPushMatrix();
{
//glTranslatef(position.x, position.y, position.z);
//glm::vec3 axis = glm::axis(rotation);
//glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z);
glPushMatrix();
glm::vec3 positionToCenter = center - position;
//glTranslatef(positionToCenter.x, positionToCenter.y, positionToCenter.z);
//glScalef(dimensions.x, dimensions.y, dimensions.z);
//Application::getInstance()->getDeferredLightingEffect()->renderSolidSphere(0.5f, 15, 15);
//_model->setRotation(rotation);
//_model->setScaleToFit(true, glm::vec3(1.0f,1.0f,1.0f));
//glm::vec3(0.0f,2.0f,0.0f)
_model->setSnapModelToRegistrationPoint(true, glm::vec3(0.5f,0.5f,0.5f));
_model->setTranslation(glm::vec3(0.0f,0.0f,0.0f));
_model->simulate(0.0f);
_model->render(alpha, Model::DEFAULT_RENDER_MODE);
//_model->render(1.0f, Model::DEFAULT_RENDER_MODE);
//_model->setScaleToFit(true, dimensions);
_model->setSnapModelToRegistrationPoint(true, getRegistrationPoint());
_model->setTranslation(position);
_model->simulate(0.0f);
glPushMatrix();
glScalef(dimensions.x, dimensions.y, dimensions.z);
Application::getInstance()->getDeferredLightingEffect()->renderWireSphere(0.5f, 15, 15);
glPopMatrix();
/*
glBegin(GL_LINES);
// low-z side - blue
glColor4f(0.0f, 0.0f, 1.0f, 1.0f);
glVertex3f(-0.5f, -0.5f, -0.5f);
glVertex3f(0.5f, -0.5f, -0.5f);
glVertex3f(-0.5f, 0.5f, -0.5f);
glVertex3f(0.5f, 0.5f, -0.5f);
glVertex3f(0.5f, 0.5f, -0.5f);
glVertex3f(0.5f, -0.5f, -0.5f);
glVertex3f(-0.5f, 0.5f, -0.5f);
glVertex3f(-0.5f, -0.5f, -0.5f);
// high-z side - cyan
glColor4f(0.0f, 1.0f, 1.0f, 1.0f);
glVertex3f(-0.5f, -0.5f, 0.5f);
glVertex3f( 0.5f, -0.5f, 0.5f);
glVertex3f(-0.5f, 0.5f, 0.5f);
glVertex3f( 0.5f, 0.5f, 0.5f);
glVertex3f( 0.5f, 0.5f, 0.5f);
glVertex3f( 0.5f, -0.5f, 0.5f);
glVertex3f(-0.5f, 0.5f, 0.5f);
glVertex3f(-0.5f, -0.5f, 0.5f);
// low-x side - yellow
glColor4f(1.0f, 1.0f, 0.0f, 1.0f);
glVertex3f(-0.5f, -0.5f, -0.5f);
glVertex3f(-0.5f, -0.5f, 0.5f);
glVertex3f(-0.5f, -0.5f, 0.5f);
glVertex3f(-0.5f, 0.5f, 0.5f);
glVertex3f(-0.5f, 0.5f, 0.5f);
glVertex3f(-0.5f, 0.5f, -0.5f);
glVertex3f(-0.5f, 0.5f, -0.5f);
glVertex3f(-0.5f, -0.5f, -0.5f);
// high-x side - red
glColor4f(1.0f, 0.0f, 0.0f, 1.0f);
glVertex3f(0.5f, -0.5f, -0.5f);
glVertex3f(0.5f, -0.5f, 0.5f);
glVertex3f(0.5f, -0.5f, 0.5f);
glVertex3f(0.5f, 0.5f, 0.5f);
glVertex3f(0.5f, 0.5f, 0.5f);
glVertex3f(0.5f, 0.5f, -0.5f);
glVertex3f(0.5f, 0.5f, -0.5f);
glVertex3f(0.5f, -0.5f, -0.5f);
// origin and direction - green
float distanceToHit;
BoxFace ignoreFace;
entityFrameBox.findRayIntersection(entityFrameOriginInMeters, entityFrameDirectionInMeters, distanceToHit, ignoreFace);
glm::vec3 pointOfIntersection = entityFrameOriginInMeters + (entityFrameDirectionInMeters * distanceToHit);
qDebug() << "distanceToHit: " << distanceToHit;
qDebug() << "pointOfIntersection: " << pointOfIntersection;
glm::vec3 pointA = pointOfIntersection + (entityFrameDirectionInMeters * -1.0f);
glm::vec3 pointB = pointOfIntersection + (entityFrameDirectionInMeters * 1.0f);
qDebug() << "pointA: " << pointA;
qDebug() << "pointB: " << pointB;
glColor4f(0.0f, 1.0f, 0.0f, 1.0f);
glVertex3f(pointA.x, pointA.y, pointA.z);
glVertex3f(pointB.x, pointB.y, pointB.z);
glEnd();
*/
glPopMatrix();
}
glPopMatrix();
} else {
glm::vec3 position = getPositionInMeters();
glm::vec3 center = getCenterInMeters();
dimensions = getDimensions() * (float)TREE_SCALE;
glm::quat rotation = getRotation();
glColor4f(1.0f, 0.0f, 1.0f, 1.0f);
glLineWidth(2.0f);
glPushMatrix();
{
//glTranslatef(position.x, position.y, position.z);
glm::vec3 axis = glm::axis(rotation);
glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z);
glPushMatrix();
glm::vec3 positionToCenter = center - position;
glTranslatef(positionToCenter.x, positionToCenter.y, positionToCenter.z);
glScalef(dimensions.x, dimensions.y, dimensions.z);
//Application::getInstance()->getDeferredLightingEffect()->renderWireCube(1.0f);
Application::getInstance()->getDeferredLightingEffect()->renderWireSphere(0.5f, 15, 15);
glBegin(GL_LINES);
// low-z side - blue
glColor4f(0.0f, 0.0f, 1.0f, 1.0f);
glVertex3f(-0.5f, -0.5f, -0.5f);
glVertex3f(0.5f, -0.5f, -0.5f);
glVertex3f(-0.5f, 0.5f, -0.5f);
glVertex3f(0.5f, 0.5f, -0.5f);
glVertex3f(0.5f, 0.5f, -0.5f);
glVertex3f(0.5f, -0.5f, -0.5f);
glVertex3f(-0.5f, 0.5f, -0.5f);
glVertex3f(-0.5f, -0.5f, -0.5f);
// high-z side - cyan
glColor4f(0.0f, 1.0f, 1.0f, 1.0f);
glVertex3f(-0.5f, -0.5f, 0.5f);
glVertex3f( 0.5f, -0.5f, 0.5f);
glVertex3f(-0.5f, 0.5f, 0.5f);
glVertex3f( 0.5f, 0.5f, 0.5f);
glVertex3f( 0.5f, 0.5f, 0.5f);
glVertex3f( 0.5f, -0.5f, 0.5f);
glVertex3f(-0.5f, 0.5f, 0.5f);
glVertex3f(-0.5f, -0.5f, 0.5f);
// low-x side - yellow
glColor4f(1.0f, 1.0f, 0.0f, 1.0f);
glVertex3f(-0.5f, -0.5f, -0.5f);
glVertex3f(-0.5f, -0.5f, 0.5f);
glVertex3f(-0.5f, -0.5f, 0.5f);
glVertex3f(-0.5f, 0.5f, 0.5f);
glVertex3f(-0.5f, 0.5f, 0.5f);
glVertex3f(-0.5f, 0.5f, -0.5f);
glVertex3f(-0.5f, 0.5f, -0.5f);
glVertex3f(-0.5f, -0.5f, -0.5f);
// high-x side - red
glColor4f(1.0f, 0.0f, 0.0f, 1.0f);
glVertex3f(0.5f, -0.5f, -0.5f);
glVertex3f(0.5f, -0.5f, 0.5f);
glVertex3f(0.5f, -0.5f, 0.5f);
glVertex3f(0.5f, 0.5f, 0.5f);
glVertex3f(0.5f, 0.5f, 0.5f);
glVertex3f(0.5f, 0.5f, -0.5f);
glVertex3f(0.5f, 0.5f, -0.5f);
glVertex3f(0.5f, -0.5f, -0.5f);
// origin and direction - green
float distanceToHit;
BoxFace ignoreFace;
entityFrameBox.findRayIntersection(entityFrameOriginInMeters, entityFrameDirectionInMeters, distanceToHit, ignoreFace);
glm::vec3 pointOfIntersection = entityFrameOriginInMeters + (entityFrameDirectionInMeters * distanceToHit);
qDebug() << "distanceToHit: " << distanceToHit;
qDebug() << "pointOfIntersection: " << pointOfIntersection;
glm::vec3 pointA = pointOfIntersection + (entityFrameDirectionInMeters * -1.0f);
glm::vec3 pointB = pointOfIntersection + (entityFrameDirectionInMeters * 1.0f);
qDebug() << "pointA: " << pointA;
qDebug() << "pointB: " << pointB;
glColor4f(0.0f, 1.0f, 0.0f, 1.0f);
glVertex3f(pointA.x, pointA.y, pointA.z);
glVertex3f(pointB.x, pointB.y, pointB.z);
glEnd();
glPopMatrix();
}
glPopMatrix();
}
QImage colorData(width, height, QImage::Format_ARGB32);
QVector<float> depthData(width * height);
glReadPixels(0, 0, width, height, GL_BGRA, GL_UNSIGNED_BYTE, colorData.bits());
glReadPixels(0, 0, width, height, GL_DEPTH_COMPONENT, GL_FLOAT, depthData.data());
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
glEnable(GL_BLEND);
glDisable(GL_SCISSOR_TEST);
Application::getInstance()->getTextureCache()->getPrimaryFramebufferObject()->release();
glViewport(0, 0, Application::getInstance()->getGLWidget()->width(), Application::getInstance()->getGLWidget()->height());
QImage imageData = colorData.mirrored(false,true);
bool saved = imageData.save("/Users/zappoman/Development/foo.bmp");
qDebug() << " saved:" << saved;
return 0.0f;
}

View file

@ -28,6 +28,9 @@
#include <ModelEntityItem.h>
#include <BoxEntityItem.h>
#include <QOpenGLFramebufferObject>
#include <QRgb>
class RenderableModelEntityItem : public ModelEntityItem {
public:
static EntityItem* factory(const EntityItemID& entityID, const EntityItemProperties& properties);
@ -51,6 +54,11 @@ public:
virtual void somethingChangedNotification() { _needsInitialSimulation = true; }
virtual void render(RenderArgs* args);
virtual bool supportsDetailedRayIntersection() const { return true; }
virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face,
void** intersectedObject) const;
Model* getModel(EntityTreeRenderer* renderer);
private:
void remapTextures();
@ -63,6 +71,9 @@ private:
QString _currentTextures;
QStringList _originalTextures;
bool _originalTexturesRead;
float depthOfRayIntersection(const glm::vec3& entityFrameOrigin, const glm::vec3& entityFrameDirection) const;
};
#endif // hifi_RenderableModelEntityItem_h

View file

@ -103,6 +103,9 @@ Model::SkinLocations Model::_skinNormalSpecularMapLocations;
Model::SkinLocations Model::_skinShadowLocations;
Model::SkinLocations Model::_skinTranslucentLocations;
ProgramObject Model::_selectProgram;
Model::Locations Model::_selectLocations;
void Model::setScale(const glm::vec3& scale) {
setScaleInternal(scale);
// if anyone sets scale manually, then we are no longer scaled to fit
@ -269,7 +272,7 @@ void Model::init() {
_program.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/model.vert");
_program.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + "shaders/model.frag");
_program.link();
initProgram(_program, _locations);
_normalMapProgram.addShaderFromSourceFile(QGLShader::Vertex,
@ -387,6 +390,14 @@ void Model::init() {
_skinTranslucentProgram.link();
initSkinProgram(_skinTranslucentProgram, _skinTranslucentLocations);
// select/ray picking program
_selectProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/select.vert");
_selectProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + "shaders/select.frag");
_selectProgram.link();
initProgram(_selectProgram, _selectLocations);
}
}
@ -2148,6 +2159,13 @@ void Model::pickPrograms(gpu::Batch& batch, RenderMode mode, bool translucent, f
ProgramObject* activeProgram = program;
Locations* activeLocations = locations;
// XXXBHG - hack to render yellow
if (mode == SELECT_RENDER_MODE) {
//activeProgram = &_selectProgram;
//activeLocations = &_selectLocations;
// need skin version
}
if (isSkinned) {
activeProgram = skinProgram;
activeLocations = skinLocations;

View file

@ -86,7 +86,7 @@ public:
void reset();
virtual void simulate(float deltaTime, bool fullUpdate = true);
enum RenderMode { DEFAULT_RENDER_MODE, SHADOW_RENDER_MODE, DIFFUSE_RENDER_MODE, NORMAL_RENDER_MODE };
enum RenderMode { DEFAULT_RENDER_MODE, SHADOW_RENDER_MODE, DIFFUSE_RENDER_MODE, NORMAL_RENDER_MODE, SELECT_RENDER_MODE };
bool render(float alpha = 1.0f, RenderMode mode = DEFAULT_RENDER_MODE, RenderArgs* args = NULL);
@ -318,6 +318,8 @@ private:
static ProgramObject _skinTranslucentProgram;
static ProgramObject _skinShadowProgram;
static ProgramObject _selectProgram;
static int _normalMapTangentLocation;
static int _normalSpecularMapTangentLocation;
@ -343,6 +345,8 @@ private:
static Locations _lightmapSpecularMapLocations;
static Locations _lightmapNormalSpecularMapLocations;
static Locations _selectLocations;
static void initProgram(ProgramObject& program, Locations& locations, int specularTextureUnit = 1);
class SkinLocations : public Locations {